fst_session.c 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630
  1. /*
  2. * FST module - FST Session implementation
  3. * Copyright (c) 2014, Qualcomm Atheros, Inc.
  4. *
  5. * This software may be distributed under the terms of the BSD license.
  6. * See README for more details.
  7. */
  8. #include "utils/includes.h"
  9. #include "utils/common.h"
  10. #include "utils/eloop.h"
  11. #include "common/defs.h"
  12. #include "fst/fst_internal.h"
  13. #include "fst/fst_defs.h"
  14. #include "fst/fst_ctrl_iface.h"
  15. #ifdef CONFIG_FST_TEST
  16. #include "fst/fst_ctrl_defs.h"
  17. #endif /* CONFIG_FST_TEST */
  18. #define US_80211_TU 1024
  19. #define US_TO_TU(m) ((m) * / US_80211_TU)
  20. #define TU_TO_US(m) ((m) * US_80211_TU)
  21. #define FST_LLT_SWITCH_IMMEDIATELY 0
  22. #define fst_printf_session(s, level, format, ...) \
  23. fst_printf((level), "%u (0x%08x): [" MACSTR "," MACSTR "] :" format, \
  24. (s)->id, (s)->data.fsts_id, \
  25. MAC2STR((s)->data.old_peer_addr), \
  26. MAC2STR((s)->data.new_peer_addr), \
  27. ##__VA_ARGS__)
  28. #define fst_printf_siface(s, iface, level, format, ...) \
  29. fst_printf_session((s), (level), "%s: " format, \
  30. fst_iface_get_name(iface), ##__VA_ARGS__)
  31. #define fst_printf_sframe(s, is_old, level, format, ...) \
  32. fst_printf_siface((s), \
  33. (is_old) ? (s)->data.old_iface : (s)->data.new_iface, \
  34. (level), format, ##__VA_ARGS__)
  35. #define FST_LLT_MS_DEFAULT 50
  36. #define FST_ACTION_MAX_SUPPORTED FST_ACTION_ON_CHANNEL_TUNNEL
  37. const char * const fst_action_names[] = {
  38. [FST_ACTION_SETUP_REQUEST] = "Setup Request",
  39. [FST_ACTION_SETUP_RESPONSE] = "Setup Response",
  40. [FST_ACTION_TEAR_DOWN] = "Tear Down",
  41. [FST_ACTION_ACK_REQUEST] = "Ack Request",
  42. [FST_ACTION_ACK_RESPONSE] = "Ack Response",
  43. [FST_ACTION_ON_CHANNEL_TUNNEL] = "On Channel Tunnel",
  44. };
  45. struct fst_session {
  46. struct {
  47. /* Session configuration that can be zeroed on reset */
  48. u8 old_peer_addr[ETH_ALEN];
  49. u8 new_peer_addr[ETH_ALEN];
  50. struct fst_iface *new_iface;
  51. struct fst_iface *old_iface;
  52. u32 llt_ms;
  53. u8 pending_setup_req_dlgt;
  54. u32 fsts_id; /* FSTS ID, see spec, 8.4.2.147
  55. * Session Transition element */
  56. } data;
  57. /* Session object internal fields which won't be zeroed on reset */
  58. struct dl_list global_sessions_lentry;
  59. u32 id; /* Session object ID used to identify
  60. * specific session object */
  61. struct fst_group *group;
  62. enum fst_session_state state;
  63. Boolean stt_armed;
  64. };
  65. static struct dl_list global_sessions_list;
  66. static u32 global_session_id = 0;
  67. #define foreach_fst_session(s) \
  68. dl_list_for_each((s), &global_sessions_list, \
  69. struct fst_session, global_sessions_lentry)
  70. #define foreach_fst_session_safe(s, temp) \
  71. dl_list_for_each_safe((s), (temp), &global_sessions_list, \
  72. struct fst_session, global_sessions_lentry)
  73. static void fst_session_global_inc_id(void)
  74. {
  75. global_session_id++;
  76. if (global_session_id == FST_INVALID_SESSION_ID)
  77. global_session_id++;
  78. }
  79. int fst_session_global_init(void)
  80. {
  81. dl_list_init(&global_sessions_list);
  82. return 0;
  83. }
  84. void fst_session_global_deinit(void)
  85. {
  86. WPA_ASSERT(dl_list_empty(&global_sessions_list));
  87. }
  88. static inline void fst_session_notify_ctrl(struct fst_session *s,
  89. enum fst_event_type event_type,
  90. union fst_event_extra *extra)
  91. {
  92. foreach_fst_ctrl_call(on_event, event_type, NULL, s, extra);
  93. }
  94. static void fst_session_set_state(struct fst_session *s,
  95. enum fst_session_state state,
  96. union fst_session_state_switch_extra *extra)
  97. {
  98. if (s->state != state) {
  99. union fst_event_extra evext = {
  100. .session_state = {
  101. .old_state = s->state,
  102. .new_state = state,
  103. },
  104. };
  105. if (extra)
  106. evext.session_state.extra = *extra;
  107. fst_session_notify_ctrl(s, EVENT_FST_SESSION_STATE_CHANGED,
  108. &evext);
  109. fst_printf_session(s, MSG_INFO, "State: %s => %s",
  110. fst_session_state_name(s->state),
  111. fst_session_state_name(state));
  112. s->state = state;
  113. }
  114. }
  115. static u32 fst_find_free_session_id(void)
  116. {
  117. u32 i, id = FST_INVALID_SESSION_ID;
  118. struct fst_session *s;
  119. for (i = 0; i < (u32) -1; i++) {
  120. Boolean in_use = FALSE;
  121. foreach_fst_session(s) {
  122. if (s->id == global_session_id) {
  123. fst_session_global_inc_id();
  124. in_use = TRUE;
  125. break;
  126. }
  127. }
  128. if (!in_use) {
  129. id = global_session_id;
  130. fst_session_global_inc_id();
  131. break;
  132. }
  133. }
  134. return id;
  135. }
  136. static void fst_session_timeout_handler(void *eloop_data, void *user_ctx)
  137. {
  138. struct fst_session *s = user_ctx;
  139. union fst_session_state_switch_extra extra = {
  140. .to_initial = {
  141. .reason = REASON_STT,
  142. },
  143. };
  144. fst_printf_session(s, MSG_WARNING, "Session State Timeout");
  145. fst_session_set_state(s, FST_SESSION_STATE_INITIAL, &extra);
  146. }
  147. static void fst_session_stt_arm(struct fst_session *s)
  148. {
  149. /* Action frames sometimes get delayed. Use relaxed timeout (2*) */
  150. eloop_register_timeout(0, 2 * TU_TO_US(FST_DEFAULT_SESSION_TIMEOUT_TU),
  151. fst_session_timeout_handler, NULL, s);
  152. s->stt_armed = TRUE;
  153. }
  154. static void fst_session_stt_disarm(struct fst_session *s)
  155. {
  156. if (s->stt_armed) {
  157. eloop_cancel_timeout(fst_session_timeout_handler, NULL, s);
  158. s->stt_armed = FALSE;
  159. }
  160. }
  161. static Boolean fst_session_is_in_transition(struct fst_session *s)
  162. {
  163. /* See spec, 10.32.2.2 Transitioning between states */
  164. return s->stt_armed;
  165. }
  166. static int fst_session_is_in_progress(struct fst_session *s)
  167. {
  168. return s->state != FST_SESSION_STATE_INITIAL;
  169. }
  170. static int fst_session_is_ready_pending(struct fst_session *s)
  171. {
  172. return s->state == FST_SESSION_STATE_SETUP_COMPLETION &&
  173. fst_session_is_in_transition(s);
  174. }
  175. static int fst_session_is_ready(struct fst_session *s)
  176. {
  177. return s->state == FST_SESSION_STATE_SETUP_COMPLETION &&
  178. !fst_session_is_in_transition(s);
  179. }
  180. static int fst_session_is_switch_requested(struct fst_session *s)
  181. {
  182. return s->state == FST_SESSION_STATE_TRANSITION_DONE &&
  183. fst_session_is_in_transition(s);
  184. }
  185. static struct fst_session *
  186. fst_find_session_in_progress(const u8 *peer_addr, struct fst_group *g)
  187. {
  188. struct fst_session *s;
  189. foreach_fst_session(s) {
  190. if (s->group == g &&
  191. (os_memcmp(s->data.old_peer_addr, peer_addr,
  192. ETH_ALEN) == 0 ||
  193. os_memcmp(s->data.new_peer_addr, peer_addr,
  194. ETH_ALEN) == 0) &&
  195. fst_session_is_in_progress(s))
  196. return s;
  197. }
  198. return NULL;
  199. }
  200. static void fst_session_reset_ex(struct fst_session *s, enum fst_reason reason)
  201. {
  202. union fst_session_state_switch_extra evext = {
  203. .to_initial = {
  204. .reason = reason,
  205. },
  206. };
  207. if (s->state == FST_SESSION_STATE_SETUP_COMPLETION ||
  208. s->state == FST_SESSION_STATE_TRANSITION_DONE)
  209. fst_session_tear_down_setup(s);
  210. fst_session_stt_disarm(s);
  211. os_memset(&s->data, 0, sizeof(s->data));
  212. fst_session_set_state(s, FST_SESSION_STATE_INITIAL, &evext);
  213. }
  214. static int fst_session_send_action(struct fst_session *s, Boolean old_iface,
  215. const void *payload, size_t size,
  216. const struct wpabuf *extra_buf)
  217. {
  218. size_t len;
  219. int res;
  220. struct wpabuf *buf;
  221. u8 action;
  222. struct fst_iface *iface =
  223. old_iface ? s->data.old_iface : s->data.new_iface;
  224. WPA_ASSERT(payload != NULL);
  225. WPA_ASSERT(size != 0);
  226. action = *(const u8 *) payload;
  227. WPA_ASSERT(action <= FST_ACTION_MAX_SUPPORTED);
  228. if (!iface) {
  229. fst_printf_session(s, MSG_ERROR,
  230. "no %s interface for FST Action '%s' sending",
  231. old_iface ? "old" : "new",
  232. fst_action_names[action]);
  233. return -1;
  234. }
  235. len = sizeof(u8) /* category */ + size;
  236. if (extra_buf)
  237. len += wpabuf_size(extra_buf);
  238. buf = wpabuf_alloc(len);
  239. if (!buf) {
  240. fst_printf_session(s, MSG_ERROR,
  241. "cannot allocate buffer of %zu bytes for FST Action '%s' sending",
  242. len, fst_action_names[action]);
  243. return -1;
  244. }
  245. wpabuf_put_u8(buf, WLAN_ACTION_FST);
  246. wpabuf_put_data(buf, payload, size);
  247. if (extra_buf)
  248. wpabuf_put_buf(buf, extra_buf);
  249. res = fst_iface_send_action(iface,
  250. old_iface ? s->data.old_peer_addr :
  251. s->data.new_peer_addr, buf);
  252. if (res < 0)
  253. fst_printf_siface(s, iface, MSG_ERROR,
  254. "failed to send FST Action '%s'",
  255. fst_action_names[action]);
  256. else
  257. fst_printf_siface(s, iface, MSG_DEBUG, "FST Action '%s' sent",
  258. fst_action_names[action]);
  259. wpabuf_free(buf);
  260. return res;
  261. }
  262. static int fst_session_send_tear_down(struct fst_session *s)
  263. {
  264. struct fst_tear_down td;
  265. int res;
  266. if (!fst_session_is_in_progress(s)) {
  267. fst_printf_session(s, MSG_ERROR, "No FST setup to tear down");
  268. return -1;
  269. }
  270. WPA_ASSERT(s->data.old_iface != NULL);
  271. WPA_ASSERT(s->data.new_iface != NULL);
  272. os_memset(&td, 0, sizeof(td));
  273. td.action = FST_ACTION_TEAR_DOWN;
  274. td.fsts_id = host_to_le32(s->data.fsts_id);
  275. res = fst_session_send_action(s, TRUE, &td, sizeof(td), NULL);
  276. if (!res)
  277. fst_printf_sframe(s, TRUE, MSG_INFO, "FST TearDown sent");
  278. else
  279. fst_printf_sframe(s, TRUE, MSG_ERROR,
  280. "failed to send FST TearDown");
  281. return res;
  282. }
  283. static void fst_session_handle_setup_request(struct fst_iface *iface,
  284. const struct ieee80211_mgmt *mgmt,
  285. size_t frame_len)
  286. {
  287. struct fst_session *s;
  288. const struct fst_setup_req *req;
  289. struct fst_iface *new_iface = NULL;
  290. struct fst_group *g;
  291. u8 new_iface_peer_addr[ETH_ALEN];
  292. const struct wpabuf *peer_mbies;
  293. size_t plen;
  294. if (frame_len < IEEE80211_HDRLEN + 1 + sizeof(*req)) {
  295. fst_printf_iface(iface, MSG_WARNING,
  296. "FST Request dropped: too short (%zu < %zu)",
  297. frame_len,
  298. IEEE80211_HDRLEN + 1 + sizeof(*req));
  299. return;
  300. }
  301. plen = frame_len - IEEE80211_HDRLEN - 1;
  302. req = (const struct fst_setup_req *)
  303. (((const u8 *) mgmt) + IEEE80211_HDRLEN + 1);
  304. if (req->stie.element_id != WLAN_EID_SESSION_TRANSITION ||
  305. req->stie.length < 11) {
  306. fst_printf_iface(iface, MSG_WARNING,
  307. "FST Request dropped: invalid STIE");
  308. return;
  309. }
  310. if (req->stie.new_band_id == req->stie.old_band_id) {
  311. fst_printf_iface(iface, MSG_WARNING,
  312. "FST Request dropped: new and old band IDs are the same");
  313. return;
  314. }
  315. g = fst_iface_get_group(iface);
  316. if (plen > sizeof(*req)) {
  317. fst_iface_update_mb_ie(iface, mgmt->sa, (const u8 *) (req + 1),
  318. plen - sizeof(*req));
  319. fst_printf_iface(iface, MSG_INFO,
  320. "FST Request: MB IEs updated for " MACSTR,
  321. MAC2STR(mgmt->sa));
  322. }
  323. peer_mbies = fst_iface_get_peer_mb_ie(iface, mgmt->sa);
  324. if (peer_mbies) {
  325. new_iface = fst_group_get_new_iface_by_stie_and_mbie(
  326. g, wpabuf_head(peer_mbies), wpabuf_len(peer_mbies),
  327. &req->stie, new_iface_peer_addr);
  328. if (new_iface)
  329. fst_printf_iface(iface, MSG_INFO,
  330. "FST Request: new iface (%s:" MACSTR
  331. ") found by MB IEs",
  332. fst_iface_get_name(new_iface),
  333. MAC2STR(new_iface_peer_addr));
  334. }
  335. if (!new_iface) {
  336. new_iface = fst_group_find_new_iface_by_stie(
  337. g, iface, mgmt->sa, &req->stie,
  338. new_iface_peer_addr);
  339. if (new_iface)
  340. fst_printf_iface(iface, MSG_INFO,
  341. "FST Request: new iface (%s:" MACSTR
  342. ") found by others",
  343. fst_iface_get_name(new_iface),
  344. MAC2STR(new_iface_peer_addr));
  345. }
  346. if (!new_iface) {
  347. fst_printf_iface(iface, MSG_WARNING,
  348. "FST Request dropped: new iface not found");
  349. return;
  350. }
  351. s = fst_find_session_in_progress(mgmt->sa, g);
  352. if (s) {
  353. union fst_session_state_switch_extra evext = {
  354. .to_initial = {
  355. .reason = REASON_SETUP,
  356. },
  357. };
  358. /*
  359. * 10.32.2.2 Transitioning between states:
  360. * Upon receipt of an FST Setup Request frame, the responder
  361. * shall respond with an FST Setup Response frame unless it has
  362. * a pending FST Setup Request frame addressed to the initiator
  363. * and the responder has a numerically larger MAC address than
  364. * the initiator’s MAC address, in which case, the responder
  365. * shall delete the received FST Setup Request.
  366. */
  367. if (fst_session_is_ready_pending(s) &&
  368. /* waiting for Setup Response */
  369. os_memcmp(mgmt->da, mgmt->sa, ETH_ALEN) > 0) {
  370. fst_printf_session(s, MSG_WARNING,
  371. "FST Request dropped due to MAC comparison (our MAC is "
  372. MACSTR ")",
  373. MAC2STR(mgmt->da));
  374. return;
  375. }
  376. /*
  377. * State is SETUP_COMPLETION (either in transition or not) or
  378. * TRANSITION_DONE (in transition).
  379. * Setup Request arriving in this state could mean:
  380. * 1. peer sent it before receiving our Setup Request (race
  381. * condition)
  382. * 2. peer didn't receive our Setup Response. Peer is retrying
  383. * after STT timeout
  384. * 3. peer's FST state machines are out of sync due to some
  385. * other reason
  386. *
  387. * We will reset our session and create a new one instead.
  388. */
  389. fst_printf_session(s, MSG_WARNING,
  390. "resetting due to FST request");
  391. /*
  392. * If FST Setup Request arrived with the same FSTS ID as one we
  393. * initialized before, there's no need to tear down the session.
  394. * Moreover, as FSTS ID is the same, the other side will
  395. * associate this tear down with the session it initiated that
  396. * will break the sync.
  397. */
  398. if (le_to_host32(req->stie.fsts_id) != s->data.fsts_id)
  399. fst_session_send_tear_down(s);
  400. else
  401. fst_printf_session(s, MSG_WARNING,
  402. "Skipping TearDown as the FST request has the same FSTS ID as initiated");
  403. fst_session_set_state(s, FST_SESSION_STATE_INITIAL, &evext);
  404. fst_session_stt_disarm(s);
  405. }
  406. s = fst_session_create(g);
  407. if (!s) {
  408. fst_printf(MSG_WARNING,
  409. "FST Request dropped: cannot create session for %s and %s",
  410. fst_iface_get_name(iface),
  411. fst_iface_get_name(new_iface));
  412. return;
  413. }
  414. fst_session_set_iface(s, iface, TRUE);
  415. fst_session_set_peer_addr(s, mgmt->sa, TRUE);
  416. fst_session_set_iface(s, new_iface, FALSE);
  417. fst_session_set_peer_addr(s, new_iface_peer_addr, FALSE);
  418. fst_session_set_llt(s, FST_LLT_VAL_TO_MS(le_to_host32(req->llt)));
  419. s->data.pending_setup_req_dlgt = req->dialog_token;
  420. s->data.fsts_id = le_to_host32(req->stie.fsts_id);
  421. fst_session_stt_arm(s);
  422. fst_session_notify_ctrl(s, EVENT_FST_SETUP, NULL);
  423. fst_session_set_state(s, FST_SESSION_STATE_SETUP_COMPLETION, NULL);
  424. }
  425. static void fst_session_handle_setup_response(struct fst_session *s,
  426. struct fst_iface *iface,
  427. const struct ieee80211_mgmt *mgmt,
  428. size_t frame_len)
  429. {
  430. const struct fst_setup_res *res;
  431. size_t plen = frame_len - IEEE80211_HDRLEN - 1;
  432. enum hostapd_hw_mode hw_mode;
  433. u8 channel;
  434. union fst_session_state_switch_extra evext = {
  435. .to_initial = {
  436. .reject_code = 0,
  437. },
  438. };
  439. if (iface != s->data.old_iface) {
  440. fst_printf_session(s, MSG_WARNING,
  441. "FST Response dropped: %s is not the old iface",
  442. fst_iface_get_name(iface));
  443. return;
  444. }
  445. if (!fst_session_is_ready_pending(s)) {
  446. fst_printf_session(s, MSG_WARNING,
  447. "FST Response dropped due to wrong state: %s",
  448. fst_session_state_name(s->state));
  449. return;
  450. }
  451. if (plen < sizeof(*res)) {
  452. fst_printf_session(s, MSG_WARNING,
  453. "Too short FST Response dropped");
  454. return;
  455. }
  456. res = (const struct fst_setup_res *)
  457. (((const u8 *) mgmt) + IEEE80211_HDRLEN + 1);
  458. if (res->stie.element_id != WLAN_EID_SESSION_TRANSITION ||
  459. res->stie.length < 11) {
  460. fst_printf_iface(iface, MSG_WARNING,
  461. "FST Response dropped: invalid STIE");
  462. return;
  463. }
  464. if (res->dialog_token != s->data.pending_setup_req_dlgt) {
  465. fst_printf_session(s, MSG_WARNING,
  466. "FST Response dropped due to wrong dialog token (%u != %u)",
  467. s->data.pending_setup_req_dlgt,
  468. res->dialog_token);
  469. return;
  470. }
  471. if (res->status_code == WLAN_STATUS_SUCCESS &&
  472. le_to_host32(res->stie.fsts_id) != s->data.fsts_id) {
  473. fst_printf_session(s, MSG_WARNING,
  474. "FST Response dropped due to wrong FST Session ID (%u)",
  475. le_to_host32(res->stie.fsts_id));
  476. return;
  477. }
  478. fst_session_stt_disarm(s);
  479. if (res->status_code != WLAN_STATUS_SUCCESS) {
  480. /*
  481. * 10.32.2.2 Transitioning between states
  482. * The initiator shall set the STT to the value of the
  483. * FSTSessionTimeOut field at ... and at each ACK frame sent in
  484. * response to a received FST Setup Response with the Status
  485. * Code field equal to PENDING_ADMITTING_FST_SESSION or
  486. * PENDING_GAP_IN_BA_WINDOW.
  487. */
  488. evext.to_initial.reason = REASON_REJECT;
  489. evext.to_initial.reject_code = res->status_code;
  490. evext.to_initial.initiator = FST_INITIATOR_REMOTE;
  491. fst_session_set_state(s, FST_SESSION_STATE_INITIAL, &evext);
  492. fst_printf_session(s, MSG_WARNING,
  493. "FST Setup rejected by remote side with status %u",
  494. res->status_code);
  495. return;
  496. }
  497. fst_iface_get_channel_info(s->data.new_iface, &hw_mode, &channel);
  498. if (fst_hw_mode_to_band(hw_mode) != res->stie.new_band_id) {
  499. evext.to_initial.reason = REASON_ERROR_PARAMS;
  500. fst_session_set_state(s, FST_SESSION_STATE_INITIAL, &evext);
  501. fst_printf_session(s, MSG_WARNING,
  502. "invalid FST Setup parameters");
  503. fst_session_tear_down_setup(s);
  504. return;
  505. }
  506. fst_printf_session(s, MSG_INFO,
  507. "%s: FST Setup established for %s (llt=%u)",
  508. fst_iface_get_name(s->data.old_iface),
  509. fst_iface_get_name(s->data.new_iface),
  510. s->data.llt_ms);
  511. fst_session_notify_ctrl(s, EVENT_FST_ESTABLISHED, NULL);
  512. if (s->data.llt_ms == FST_LLT_SWITCH_IMMEDIATELY)
  513. fst_session_initiate_switch(s);
  514. }
  515. static void fst_session_handle_tear_down(struct fst_session *s,
  516. struct fst_iface *iface,
  517. const struct ieee80211_mgmt *mgmt,
  518. size_t frame_len)
  519. {
  520. const struct fst_tear_down *td;
  521. size_t plen = frame_len - IEEE80211_HDRLEN - 1;
  522. union fst_session_state_switch_extra evext = {
  523. .to_initial = {
  524. .reason = REASON_TEARDOWN,
  525. .initiator = FST_INITIATOR_REMOTE,
  526. },
  527. };
  528. if (plen < sizeof(*td)) {
  529. fst_printf_session(s, MSG_WARNING,
  530. "Too short FST Tear Down dropped");
  531. return;
  532. }
  533. td = (const struct fst_tear_down *)
  534. (((const u8 *) mgmt) + IEEE80211_HDRLEN + 1);
  535. if (le_to_host32(td->fsts_id) != s->data.fsts_id) {
  536. fst_printf_siface(s, iface, MSG_WARNING,
  537. "tear down for wrong FST Setup ID (%u)",
  538. le_to_host32(td->fsts_id));
  539. return;
  540. }
  541. fst_session_stt_disarm(s);
  542. fst_session_set_state(s, FST_SESSION_STATE_INITIAL, &evext);
  543. }
  544. static void fst_session_handle_ack_request(struct fst_session *s,
  545. struct fst_iface *iface,
  546. const struct ieee80211_mgmt *mgmt,
  547. size_t frame_len)
  548. {
  549. const struct fst_ack_req *req;
  550. size_t plen = frame_len - IEEE80211_HDRLEN - 1;
  551. struct fst_ack_res res;
  552. union fst_session_state_switch_extra evext = {
  553. .to_initial = {
  554. .reason = REASON_SWITCH,
  555. .initiator = FST_INITIATOR_REMOTE,
  556. },
  557. };
  558. if (!fst_session_is_ready(s) && !fst_session_is_switch_requested(s)) {
  559. fst_printf_siface(s, iface, MSG_ERROR,
  560. "cannot initiate switch due to wrong session state (%s)",
  561. fst_session_state_name(s->state));
  562. return;
  563. }
  564. WPA_ASSERT(s->data.new_iface != NULL);
  565. if (iface != s->data.new_iface) {
  566. fst_printf_siface(s, iface, MSG_ERROR,
  567. "Ack received on wrong interface");
  568. return;
  569. }
  570. if (plen < sizeof(*req)) {
  571. fst_printf_session(s, MSG_WARNING,
  572. "Too short FST Ack Request dropped");
  573. return;
  574. }
  575. req = (const struct fst_ack_req *)
  576. (((const u8 *) mgmt) + IEEE80211_HDRLEN + 1);
  577. if (le_to_host32(req->fsts_id) != s->data.fsts_id) {
  578. fst_printf_siface(s, iface, MSG_WARNING,
  579. "Ack for wrong FST Setup ID (%u)",
  580. le_to_host32(req->fsts_id));
  581. return;
  582. }
  583. os_memset(&res, 0, sizeof(res));
  584. res.action = FST_ACTION_ACK_RESPONSE;
  585. res.dialog_token = req->dialog_token;
  586. res.fsts_id = req->fsts_id;
  587. if (!fst_session_send_action(s, FALSE, &res, sizeof(res), NULL)) {
  588. fst_printf_sframe(s, FALSE, MSG_INFO, "FST Ack Response sent");
  589. fst_session_stt_disarm(s);
  590. fst_session_set_state(s, FST_SESSION_STATE_TRANSITION_DONE,
  591. NULL);
  592. fst_session_set_state(s, FST_SESSION_STATE_TRANSITION_CONFIRMED,
  593. NULL);
  594. fst_session_set_state(s, FST_SESSION_STATE_INITIAL, &evext);
  595. }
  596. }
  597. static void
  598. fst_session_handle_ack_response(struct fst_session *s,
  599. struct fst_iface *iface,
  600. const struct ieee80211_mgmt *mgmt,
  601. size_t frame_len)
  602. {
  603. const struct fst_ack_res *res;
  604. size_t plen = frame_len - IEEE80211_HDRLEN - 1;
  605. union fst_session_state_switch_extra evext = {
  606. .to_initial = {
  607. .reason = REASON_SWITCH,
  608. .initiator = FST_INITIATOR_LOCAL,
  609. },
  610. };
  611. if (!fst_session_is_switch_requested(s)) {
  612. fst_printf_siface(s, iface, MSG_ERROR,
  613. "Ack Response in inappropriate session state (%s)",
  614. fst_session_state_name(s->state));
  615. return;
  616. }
  617. WPA_ASSERT(s->data.new_iface != NULL);
  618. if (iface != s->data.new_iface) {
  619. fst_printf_siface(s, iface, MSG_ERROR,
  620. "Ack response received on wrong interface");
  621. return;
  622. }
  623. if (plen < sizeof(*res)) {
  624. fst_printf_session(s, MSG_WARNING,
  625. "Too short FST Ack Response dropped");
  626. return;
  627. }
  628. res = (const struct fst_ack_res *)
  629. (((const u8 *) mgmt) + IEEE80211_HDRLEN + 1);
  630. if (le_to_host32(res->fsts_id) != s->data.fsts_id) {
  631. fst_printf_siface(s, iface, MSG_ERROR,
  632. "Ack response for wrong FST Setup ID (%u)",
  633. le_to_host32(res->fsts_id));
  634. return;
  635. }
  636. fst_session_set_state(s, FST_SESSION_STATE_TRANSITION_CONFIRMED, NULL);
  637. fst_session_set_state(s, FST_SESSION_STATE_INITIAL, &evext);
  638. fst_session_stt_disarm(s);
  639. }
  640. struct fst_session * fst_session_create(struct fst_group *g)
  641. {
  642. struct fst_session *s;
  643. u32 id;
  644. WPA_ASSERT(!is_zero_ether_addr(own_addr));
  645. id = fst_find_free_session_id();
  646. if (id == FST_INVALID_SESSION_ID) {
  647. fst_printf(MSG_ERROR, "Cannot assign new session ID");
  648. return NULL;
  649. }
  650. s = os_zalloc(sizeof(*s));
  651. if (!s) {
  652. fst_printf(MSG_ERROR, "Cannot allocate new session object");
  653. return NULL;
  654. }
  655. s->id = id;
  656. s->group = g;
  657. s->state = FST_SESSION_STATE_INITIAL;
  658. s->data.llt_ms = FST_LLT_MS_DEFAULT;
  659. fst_printf(MSG_INFO, "Session %u created", s->id);
  660. dl_list_add_tail(&global_sessions_list, &s->global_sessions_lentry);
  661. foreach_fst_ctrl_call(on_session_added, s);
  662. return s;
  663. }
  664. void fst_session_set_iface(struct fst_session *s, struct fst_iface *iface,
  665. Boolean is_old)
  666. {
  667. if (is_old)
  668. s->data.old_iface = iface;
  669. else
  670. s->data.new_iface = iface;
  671. }
  672. void fst_session_set_llt(struct fst_session *s, u32 llt)
  673. {
  674. s->data.llt_ms = llt;
  675. }
  676. void fst_session_set_peer_addr(struct fst_session *s, const u8 *addr,
  677. Boolean is_old)
  678. {
  679. u8 *a = is_old ? s->data.old_peer_addr : s->data.new_peer_addr;
  680. os_memcpy(a, addr, ETH_ALEN);
  681. }
  682. int fst_session_initiate_setup(struct fst_session *s)
  683. {
  684. struct fst_setup_req req;
  685. int res;
  686. u32 fsts_id;
  687. u8 dialog_token;
  688. struct fst_session *_s;
  689. if (fst_session_is_in_progress(s)) {
  690. fst_printf_session(s, MSG_ERROR, "Session in progress");
  691. return -EINVAL;
  692. }
  693. if (is_zero_ether_addr(s->data.old_peer_addr)) {
  694. fst_printf_session(s, MSG_ERROR, "No old peer MAC address");
  695. return -EINVAL;
  696. }
  697. if (is_zero_ether_addr(s->data.new_peer_addr)) {
  698. fst_printf_session(s, MSG_ERROR, "No new peer MAC address");
  699. return -EINVAL;
  700. }
  701. if (!s->data.old_iface) {
  702. fst_printf_session(s, MSG_ERROR, "No old interface defined");
  703. return -EINVAL;
  704. }
  705. if (!s->data.new_iface) {
  706. fst_printf_session(s, MSG_ERROR, "No new interface defined");
  707. return -EINVAL;
  708. }
  709. if (s->data.new_iface == s->data.old_iface) {
  710. fst_printf_session(s, MSG_ERROR,
  711. "Same interface set as old and new");
  712. return -EINVAL;
  713. }
  714. if (!fst_iface_is_connected(s->data.old_iface, s->data.old_peer_addr,
  715. FALSE)) {
  716. fst_printf_session(s, MSG_ERROR,
  717. "The preset old peer address is not connected");
  718. return -EINVAL;
  719. }
  720. if (!fst_iface_is_connected(s->data.new_iface, s->data.new_peer_addr,
  721. FALSE)) {
  722. fst_printf_session(s, MSG_ERROR,
  723. "The preset new peer address is not connected");
  724. return -EINVAL;
  725. }
  726. _s = fst_find_session_in_progress(s->data.old_peer_addr, s->group);
  727. if (_s) {
  728. fst_printf_session(s, MSG_ERROR,
  729. "There is another session in progress (old): %u",
  730. _s->id);
  731. return -EINVAL;
  732. }
  733. _s = fst_find_session_in_progress(s->data.new_peer_addr, s->group);
  734. if (_s) {
  735. fst_printf_session(s, MSG_ERROR,
  736. "There is another session in progress (new): %u",
  737. _s->id);
  738. return -EINVAL;
  739. }
  740. dialog_token = fst_group_assign_dialog_token(s->group);
  741. fsts_id = fst_group_assign_fsts_id(s->group);
  742. os_memset(&req, 0, sizeof(req));
  743. fst_printf_siface(s, s->data.old_iface, MSG_INFO,
  744. "initiating FST setup for %s (llt=%u ms)",
  745. fst_iface_get_name(s->data.new_iface), s->data.llt_ms);
  746. req.action = FST_ACTION_SETUP_REQUEST;
  747. req.dialog_token = dialog_token;
  748. req.llt = host_to_le32(FST_LLT_MS_TO_VAL(s->data.llt_ms));
  749. /* 8.4.2.147 Session Transition element */
  750. req.stie.element_id = WLAN_EID_SESSION_TRANSITION;
  751. req.stie.length = sizeof(req.stie) - 2;
  752. req.stie.fsts_id = host_to_le32(fsts_id);
  753. req.stie.session_control = SESSION_CONTROL(SESSION_TYPE_BSS, 0);
  754. req.stie.new_band_id = fst_iface_get_band_id(s->data.new_iface);
  755. req.stie.new_band_op = 1;
  756. req.stie.new_band_setup = 0;
  757. req.stie.old_band_id = fst_iface_get_band_id(s->data.old_iface);
  758. req.stie.old_band_op = 1;
  759. req.stie.old_band_setup = 0;
  760. res = fst_session_send_action(s, TRUE, &req, sizeof(req),
  761. fst_iface_get_mbie(s->data.old_iface));
  762. if (!res) {
  763. s->data.fsts_id = fsts_id;
  764. s->data.pending_setup_req_dlgt = dialog_token;
  765. fst_printf_sframe(s, TRUE, MSG_INFO, "FST Setup Request sent");
  766. fst_session_set_state(s, FST_SESSION_STATE_SETUP_COMPLETION,
  767. NULL);
  768. fst_session_stt_arm(s);
  769. }
  770. return res;
  771. }
  772. int fst_session_respond(struct fst_session *s, u8 status_code)
  773. {
  774. struct fst_setup_res res;
  775. enum hostapd_hw_mode hw_mode;
  776. u8 channel;
  777. if (!fst_session_is_ready_pending(s)) {
  778. fst_printf_session(s, MSG_ERROR, "incorrect state: %s",
  779. fst_session_state_name(s->state));
  780. return -EINVAL;
  781. }
  782. if (is_zero_ether_addr(s->data.old_peer_addr)) {
  783. fst_printf_session(s, MSG_ERROR, "No peer MAC address");
  784. return -EINVAL;
  785. }
  786. if (!s->data.old_iface) {
  787. fst_printf_session(s, MSG_ERROR, "No old interface defined");
  788. return -EINVAL;
  789. }
  790. if (!s->data.new_iface) {
  791. fst_printf_session(s, MSG_ERROR, "No new interface defined");
  792. return -EINVAL;
  793. }
  794. if (s->data.new_iface == s->data.old_iface) {
  795. fst_printf_session(s, MSG_ERROR,
  796. "Same interface set as old and new");
  797. return -EINVAL;
  798. }
  799. if (!fst_iface_is_connected(s->data.old_iface,
  800. s->data.old_peer_addr, FALSE)) {
  801. fst_printf_session(s, MSG_ERROR,
  802. "The preset peer address is not in the peer list");
  803. return -EINVAL;
  804. }
  805. fst_session_stt_disarm(s);
  806. os_memset(&res, 0, sizeof(res));
  807. res.action = FST_ACTION_SETUP_RESPONSE;
  808. res.dialog_token = s->data.pending_setup_req_dlgt;
  809. res.status_code = status_code;
  810. res.stie.element_id = WLAN_EID_SESSION_TRANSITION;
  811. res.stie.length = sizeof(res.stie) - 2;
  812. if (status_code == WLAN_STATUS_SUCCESS) {
  813. res.stie.fsts_id = host_to_le32(s->data.fsts_id);
  814. res.stie.session_control = SESSION_CONTROL(SESSION_TYPE_BSS, 0);
  815. fst_iface_get_channel_info(s->data.new_iface, &hw_mode,
  816. &channel);
  817. res.stie.new_band_id = fst_hw_mode_to_band(hw_mode);
  818. res.stie.new_band_op = 1;
  819. res.stie.new_band_setup = 0;
  820. fst_iface_get_channel_info(s->data.old_iface, &hw_mode,
  821. &channel);
  822. res.stie.old_band_id = fst_hw_mode_to_band(hw_mode);
  823. res.stie.old_band_op = 1;
  824. res.stie.old_band_setup = 0;
  825. fst_printf_session(s, MSG_INFO,
  826. "%s: FST Setup Request accepted for %s (llt=%u)",
  827. fst_iface_get_name(s->data.old_iface),
  828. fst_iface_get_name(s->data.new_iface),
  829. s->data.llt_ms);
  830. } else {
  831. fst_printf_session(s, MSG_WARNING,
  832. "%s: FST Setup Request rejected with code %d",
  833. fst_iface_get_name(s->data.old_iface),
  834. status_code);
  835. }
  836. if (fst_session_send_action(s, TRUE, &res, sizeof(res),
  837. fst_iface_get_mbie(s->data.old_iface))) {
  838. fst_printf_sframe(s, TRUE, MSG_ERROR,
  839. "cannot send FST Setup Response with code %d",
  840. status_code);
  841. return -EINVAL;
  842. }
  843. fst_printf_sframe(s, TRUE, MSG_INFO, "FST Setup Response sent");
  844. if (status_code != WLAN_STATUS_SUCCESS) {
  845. union fst_session_state_switch_extra evext = {
  846. .to_initial = {
  847. .reason = REASON_REJECT,
  848. .reject_code = status_code,
  849. .initiator = FST_INITIATOR_LOCAL,
  850. },
  851. };
  852. fst_session_set_state(s, FST_SESSION_STATE_INITIAL, &evext);
  853. }
  854. return 0;
  855. }
  856. int fst_session_initiate_switch(struct fst_session *s)
  857. {
  858. struct fst_ack_req req;
  859. int res;
  860. u8 dialog_token;
  861. if (!fst_session_is_ready(s)) {
  862. fst_printf_session(s, MSG_ERROR,
  863. "cannot initiate switch due to wrong setup state (%d)",
  864. s->state);
  865. return -1;
  866. }
  867. dialog_token = fst_group_assign_dialog_token(s->group);
  868. WPA_ASSERT(s->data.new_iface != NULL);
  869. WPA_ASSERT(s->data.old_iface != NULL);
  870. fst_printf_session(s, MSG_INFO, "initiating FST switch: %s => %s",
  871. fst_iface_get_name(s->data.old_iface),
  872. fst_iface_get_name(s->data.new_iface));
  873. os_memset(&req, 0, sizeof(req));
  874. req.action = FST_ACTION_ACK_REQUEST;
  875. req.dialog_token = dialog_token;
  876. req.fsts_id = host_to_le32(s->data.fsts_id);
  877. res = fst_session_send_action(s, FALSE, &req, sizeof(req), NULL);
  878. if (!res) {
  879. fst_printf_sframe(s, FALSE, MSG_INFO, "FST Ack Request sent");
  880. fst_session_set_state(s, FST_SESSION_STATE_TRANSITION_DONE,
  881. NULL);
  882. fst_session_stt_arm(s);
  883. } else {
  884. fst_printf_sframe(s, FALSE, MSG_ERROR,
  885. "Cannot send FST Ack Request");
  886. }
  887. return res;
  888. }
  889. void fst_session_handle_action(struct fst_session *s,
  890. struct fst_iface *iface,
  891. const struct ieee80211_mgmt *mgmt,
  892. size_t frame_len)
  893. {
  894. switch (mgmt->u.action.u.fst_action.action) {
  895. case FST_ACTION_SETUP_REQUEST:
  896. WPA_ASSERT(0);
  897. break;
  898. case FST_ACTION_SETUP_RESPONSE:
  899. fst_session_handle_setup_response(s, iface, mgmt, frame_len);
  900. break;
  901. case FST_ACTION_TEAR_DOWN:
  902. fst_session_handle_tear_down(s, iface, mgmt, frame_len);
  903. break;
  904. case FST_ACTION_ACK_REQUEST:
  905. fst_session_handle_ack_request(s, iface, mgmt, frame_len);
  906. break;
  907. case FST_ACTION_ACK_RESPONSE:
  908. fst_session_handle_ack_response(s, iface, mgmt, frame_len);
  909. break;
  910. case FST_ACTION_ON_CHANNEL_TUNNEL:
  911. default:
  912. fst_printf_sframe(s, FALSE, MSG_ERROR,
  913. "Unsupported FST Action frame");
  914. break;
  915. }
  916. }
  917. int fst_session_tear_down_setup(struct fst_session *s)
  918. {
  919. int res;
  920. union fst_session_state_switch_extra evext = {
  921. .to_initial = {
  922. .reason = REASON_TEARDOWN,
  923. .initiator = FST_INITIATOR_LOCAL,
  924. },
  925. };
  926. res = fst_session_send_tear_down(s);
  927. fst_session_set_state(s, FST_SESSION_STATE_INITIAL, &evext);
  928. return res;
  929. }
  930. void fst_session_reset(struct fst_session *s)
  931. {
  932. fst_session_reset_ex(s, REASON_RESET);
  933. }
  934. void fst_session_delete(struct fst_session *s)
  935. {
  936. fst_printf(MSG_INFO, "Session %u deleted", s->id);
  937. dl_list_del(&s->global_sessions_lentry);
  938. foreach_fst_ctrl_call(on_session_removed, s);
  939. os_free(s);
  940. }
  941. struct fst_group * fst_session_get_group(struct fst_session *s)
  942. {
  943. return s->group;
  944. }
  945. struct fst_iface * fst_session_get_iface(struct fst_session *s, Boolean is_old)
  946. {
  947. return is_old ? s->data.old_iface : s->data.new_iface;
  948. }
  949. u32 fst_session_get_id(struct fst_session *s)
  950. {
  951. return s->id;
  952. }
  953. const u8 * fst_session_get_peer_addr(struct fst_session *s, Boolean is_old)
  954. {
  955. return is_old ? s->data.old_peer_addr : s->data.new_peer_addr;
  956. }
  957. u32 fst_session_get_llt(struct fst_session *s)
  958. {
  959. return s->data.llt_ms;
  960. }
  961. enum fst_session_state fst_session_get_state(struct fst_session *s)
  962. {
  963. return s->state;
  964. }
  965. struct fst_session * fst_session_get_by_id(u32 id)
  966. {
  967. struct fst_session *s;
  968. foreach_fst_session(s) {
  969. if (id == s->id)
  970. return s;
  971. }
  972. return NULL;
  973. }
  974. void fst_session_enum(struct fst_group *g, fst_session_enum_clb clb, void *ctx)
  975. {
  976. struct fst_session *s;
  977. foreach_fst_session(s) {
  978. if (!g || s->group == g)
  979. clb(s->group, s, ctx);
  980. }
  981. }
  982. void fst_session_on_action_rx(struct fst_iface *iface,
  983. const struct ieee80211_mgmt *mgmt,
  984. size_t len)
  985. {
  986. struct fst_session *s;
  987. if (len < IEEE80211_HDRLEN + 2 ||
  988. mgmt->u.action.category != WLAN_ACTION_FST) {
  989. fst_printf_iface(iface, MSG_ERROR,
  990. "invalid Action frame received");
  991. return;
  992. }
  993. if (mgmt->u.action.u.fst_action.action <= FST_ACTION_MAX_SUPPORTED) {
  994. fst_printf_iface(iface, MSG_DEBUG,
  995. "FST Action '%s' received!",
  996. fst_action_names[mgmt->u.action.u.fst_action.action]);
  997. } else {
  998. fst_printf_iface(iface, MSG_WARNING,
  999. "unknown FST Action (%u) received!",
  1000. mgmt->u.action.u.fst_action.action);
  1001. return;
  1002. }
  1003. if (mgmt->u.action.u.fst_action.action == FST_ACTION_SETUP_REQUEST) {
  1004. fst_session_handle_setup_request(iface, mgmt, len);
  1005. return;
  1006. }
  1007. s = fst_find_session_in_progress(mgmt->sa, fst_iface_get_group(iface));
  1008. if (s) {
  1009. fst_session_handle_action(s, iface, mgmt, len);
  1010. } else {
  1011. fst_printf_iface(iface, MSG_WARNING,
  1012. "FST Action '%s' dropped: no session in progress found",
  1013. fst_action_names[mgmt->u.action.u.fst_action.action]);
  1014. }
  1015. }
  1016. int fst_session_set_str_ifname(struct fst_session *s, const char *ifname,
  1017. Boolean is_old)
  1018. {
  1019. struct fst_group *g = fst_session_get_group(s);
  1020. struct fst_iface *i;
  1021. i = fst_group_get_iface_by_name(g, ifname);
  1022. if (!i) {
  1023. fst_printf_session(s, MSG_WARNING,
  1024. "Cannot set iface %s: no such iface within group '%s'",
  1025. ifname, fst_group_get_id(g));
  1026. return -1;
  1027. }
  1028. fst_session_set_iface(s, i, is_old);
  1029. return 0;
  1030. }
  1031. int fst_session_set_str_peer_addr(struct fst_session *s, const char *mac,
  1032. Boolean is_old)
  1033. {
  1034. u8 peer_addr[ETH_ALEN];
  1035. int res = fst_read_peer_addr(mac, peer_addr);
  1036. if (res)
  1037. return res;
  1038. fst_session_set_peer_addr(s, peer_addr, is_old);
  1039. return 0;
  1040. }
  1041. int fst_session_set_str_llt(struct fst_session *s, const char *llt_str)
  1042. {
  1043. char *endp;
  1044. long int llt = strtol(llt_str, &endp, 0);
  1045. if (*endp || llt < 0 || (unsigned long int) llt > FST_MAX_LLT_MS) {
  1046. fst_printf_session(s, MSG_WARNING,
  1047. "Cannot set llt %s: Invalid llt value (1..%u expected)",
  1048. llt_str, FST_MAX_LLT_MS);
  1049. return -1;
  1050. }
  1051. fst_session_set_llt(s, (u32) llt);
  1052. return 0;
  1053. }
  1054. void fst_session_global_on_iface_detached(struct fst_iface *iface)
  1055. {
  1056. struct fst_session *s;
  1057. foreach_fst_session(s) {
  1058. if (fst_session_is_in_progress(s) &&
  1059. (s->data.new_iface == iface ||
  1060. s->data.old_iface == iface))
  1061. fst_session_reset_ex(s, REASON_DETACH_IFACE);
  1062. }
  1063. }
  1064. struct fst_session * fst_session_global_get_first_by_group(struct fst_group *g)
  1065. {
  1066. struct fst_session *s;
  1067. foreach_fst_session(s) {
  1068. if (s->group == g)
  1069. return s;
  1070. }
  1071. return NULL;
  1072. }
  1073. #ifdef CONFIG_FST_TEST
  1074. static int get_group_fill_session(struct fst_group **g, struct fst_session *s)
  1075. {
  1076. const u8 *old_addr, *new_addr;
  1077. struct fst_get_peer_ctx *ctx;
  1078. os_memset(s, 0, sizeof(*s));
  1079. foreach_fst_group(*g) {
  1080. s->data.new_iface = fst_group_first_iface(*g);
  1081. if (s->data.new_iface)
  1082. break;
  1083. }
  1084. if (!s->data.new_iface)
  1085. return -EINVAL;
  1086. s->data.old_iface = dl_list_entry(s->data.new_iface->group_lentry.next,
  1087. struct fst_iface, group_lentry);
  1088. if (!s->data.old_iface)
  1089. return -EINVAL;
  1090. old_addr = fst_iface_get_peer_first(s->data.old_iface, &ctx, TRUE);
  1091. if (!old_addr)
  1092. return -EINVAL;
  1093. new_addr = fst_iface_get_peer_first(s->data.new_iface, &ctx, TRUE);
  1094. if (!new_addr)
  1095. return -EINVAL;
  1096. os_memcpy(s->data.old_peer_addr, old_addr, ETH_ALEN);
  1097. os_memcpy(s->data.new_peer_addr, new_addr, ETH_ALEN);
  1098. return 0;
  1099. }
  1100. #define FST_MAX_COMMAND_WORD_NAME_LENGTH 16
  1101. int fst_test_req_send_fst_request(const char *params)
  1102. {
  1103. int fsts_id;
  1104. Boolean is_valid;
  1105. char *endp;
  1106. struct fst_setup_req req;
  1107. struct fst_session s;
  1108. struct fst_group *g;
  1109. enum hostapd_hw_mode hw_mode;
  1110. u8 channel;
  1111. char additional_param[FST_MAX_COMMAND_WORD_NAME_LENGTH];
  1112. if (params[0] != ' ')
  1113. return -EINVAL;
  1114. params++;
  1115. fsts_id = fst_read_next_int_param(params, &is_valid, &endp);
  1116. if (!is_valid)
  1117. return -EINVAL;
  1118. if (get_group_fill_session(&g, &s))
  1119. return -EINVAL;
  1120. req.action = FST_ACTION_SETUP_REQUEST;
  1121. req.dialog_token = g->dialog_token;
  1122. req.llt = host_to_le32(FST_LLT_MS_DEFAULT);
  1123. /* 8.4.2.147 Session Transition element */
  1124. req.stie.element_id = WLAN_EID_SESSION_TRANSITION;
  1125. req.stie.length = sizeof(req.stie) - 2;
  1126. req.stie.fsts_id = host_to_le32(fsts_id);
  1127. req.stie.session_control = SESSION_CONTROL(SESSION_TYPE_BSS, 0);
  1128. fst_iface_get_channel_info(s.data.new_iface, &hw_mode, &channel);
  1129. req.stie.new_band_id = fst_hw_mode_to_band(hw_mode);
  1130. req.stie.new_band_op = 1;
  1131. req.stie.new_band_setup = 0;
  1132. fst_iface_get_channel_info(s.data.old_iface, &hw_mode, &channel);
  1133. req.stie.old_band_id = fst_hw_mode_to_band(hw_mode);
  1134. req.stie.old_band_op = 1;
  1135. req.stie.old_band_setup = 0;
  1136. if (!fst_read_next_text_param(endp, additional_param,
  1137. sizeof(additional_param), &endp)) {
  1138. if (!os_strcasecmp(additional_param, FST_CTR_PVAL_BAD_NEW_BAND))
  1139. req.stie.new_band_id = req.stie.old_band_id;
  1140. }
  1141. return fst_session_send_action(&s, TRUE, &req, sizeof(req),
  1142. s.data.old_iface->mb_ie);
  1143. }
  1144. int fst_test_req_send_fst_response(const char *params)
  1145. {
  1146. int fsts_id;
  1147. Boolean is_valid;
  1148. char *endp;
  1149. struct fst_setup_res res;
  1150. struct fst_session s;
  1151. struct fst_group *g;
  1152. enum hostapd_hw_mode hw_mode;
  1153. u8 status_code;
  1154. u8 channel;
  1155. char response[FST_MAX_COMMAND_WORD_NAME_LENGTH];
  1156. struct fst_session *_s;
  1157. if (params[0] != ' ')
  1158. return -EINVAL;
  1159. params++;
  1160. fsts_id = fst_read_next_int_param(params, &is_valid, &endp);
  1161. if (!is_valid)
  1162. return -EINVAL;
  1163. if (get_group_fill_session(&g, &s))
  1164. return -EINVAL;
  1165. status_code = WLAN_STATUS_SUCCESS;
  1166. if (!fst_read_next_text_param(endp, response, sizeof(response),
  1167. &endp)) {
  1168. if (!os_strcasecmp(response, FST_CS_PVAL_RESPONSE_REJECT))
  1169. status_code = WLAN_STATUS_PENDING_ADMITTING_FST_SESSION;
  1170. }
  1171. os_memset(&res, 0, sizeof(res));
  1172. res.action = FST_ACTION_SETUP_RESPONSE;
  1173. /*
  1174. * If some session has just received an FST Setup Request, then
  1175. * use the correct dialog token copied from this request.
  1176. */
  1177. _s = fst_find_session_in_progress(fst_session_get_peer_addr(&s, TRUE),
  1178. g);
  1179. res.dialog_token = (_s && fst_session_is_ready_pending(_s)) ?
  1180. _s->data.pending_setup_req_dlgt : g->dialog_token;
  1181. res.status_code = status_code;
  1182. res.stie.element_id = WLAN_EID_SESSION_TRANSITION;
  1183. res.stie.length = sizeof(res.stie) - 2;
  1184. if (res.status_code == WLAN_STATUS_SUCCESS) {
  1185. res.stie.fsts_id = host_to_le32(fsts_id);
  1186. res.stie.session_control = SESSION_CONTROL(SESSION_TYPE_BSS, 0);
  1187. fst_iface_get_channel_info(s.data.new_iface, &hw_mode,
  1188. &channel);
  1189. res.stie.new_band_id = fst_hw_mode_to_band(hw_mode);
  1190. res.stie.new_band_op = 1;
  1191. res.stie.new_band_setup = 0;
  1192. fst_iface_get_channel_info(s.data.old_iface, &hw_mode,
  1193. &channel);
  1194. res.stie.old_band_id = fst_hw_mode_to_band(hw_mode);
  1195. res.stie.old_band_op = 1;
  1196. res.stie.old_band_setup = 0;
  1197. }
  1198. if (!fst_read_next_text_param(endp, response, sizeof(response),
  1199. &endp)) {
  1200. if (!os_strcasecmp(response, FST_CTR_PVAL_BAD_NEW_BAND))
  1201. res.stie.new_band_id = res.stie.old_band_id;
  1202. }
  1203. return fst_session_send_action(&s, TRUE, &res, sizeof(res),
  1204. s.data.old_iface->mb_ie);
  1205. }
  1206. int fst_test_req_send_ack_request(const char *params)
  1207. {
  1208. int fsts_id;
  1209. Boolean is_valid;
  1210. char *endp;
  1211. struct fst_ack_req req;
  1212. struct fst_session s;
  1213. struct fst_group *g;
  1214. if (params[0] != ' ')
  1215. return -EINVAL;
  1216. params++;
  1217. fsts_id = fst_read_next_int_param(params, &is_valid, &endp);
  1218. if (!is_valid)
  1219. return -EINVAL;
  1220. if (get_group_fill_session(&g, &s))
  1221. return -EINVAL;
  1222. os_memset(&req, 0, sizeof(req));
  1223. req.action = FST_ACTION_ACK_REQUEST;
  1224. req.dialog_token = g->dialog_token;
  1225. req.fsts_id = host_to_le32(fsts_id);
  1226. return fst_session_send_action(&s, FALSE, &req, sizeof(req), NULL);
  1227. }
  1228. int fst_test_req_send_ack_response(const char *params)
  1229. {
  1230. int fsts_id;
  1231. Boolean is_valid;
  1232. char *endp;
  1233. struct fst_ack_res res;
  1234. struct fst_session s;
  1235. struct fst_group *g;
  1236. if (params[0] != ' ')
  1237. return -EINVAL;
  1238. params++;
  1239. fsts_id = fst_read_next_int_param(params, &is_valid, &endp);
  1240. if (!is_valid)
  1241. return -EINVAL;
  1242. if (get_group_fill_session(&g, &s))
  1243. return -EINVAL;
  1244. os_memset(&res, 0, sizeof(res));
  1245. res.action = FST_ACTION_ACK_RESPONSE;
  1246. res.dialog_token = g->dialog_token;
  1247. res.fsts_id = host_to_le32(fsts_id);
  1248. return fst_session_send_action(&s, FALSE, &res, sizeof(res), NULL);
  1249. }
  1250. int fst_test_req_send_tear_down(const char *params)
  1251. {
  1252. int fsts_id;
  1253. Boolean is_valid;
  1254. char *endp;
  1255. struct fst_tear_down td;
  1256. struct fst_session s;
  1257. struct fst_group *g;
  1258. if (params[0] != ' ')
  1259. return -EINVAL;
  1260. params++;
  1261. fsts_id = fst_read_next_int_param(params, &is_valid, &endp);
  1262. if (!is_valid)
  1263. return -EINVAL;
  1264. if (get_group_fill_session(&g, &s))
  1265. return -EINVAL;
  1266. os_memset(&td, 0, sizeof(td));
  1267. td.action = FST_ACTION_TEAR_DOWN;
  1268. td.fsts_id = host_to_le32(fsts_id);
  1269. return fst_session_send_action(&s, TRUE, &td, sizeof(td), NULL);
  1270. }
  1271. u32 fst_test_req_get_fsts_id(const char *params)
  1272. {
  1273. int sid;
  1274. Boolean is_valid;
  1275. char *endp;
  1276. struct fst_session *s;
  1277. if (params[0] != ' ')
  1278. return FST_FSTS_ID_NOT_FOUND;
  1279. params++;
  1280. sid = fst_read_next_int_param(params, &is_valid, &endp);
  1281. if (!is_valid)
  1282. return FST_FSTS_ID_NOT_FOUND;
  1283. s = fst_session_get_by_id(sid);
  1284. if (!s)
  1285. return FST_FSTS_ID_NOT_FOUND;
  1286. return s->data.fsts_id;
  1287. }
  1288. int fst_test_req_get_local_mbies(const char *request, char *buf, size_t buflen)
  1289. {
  1290. char *endp;
  1291. char ifname[FST_MAX_COMMAND_WORD_NAME_LENGTH];
  1292. struct fst_group *g;
  1293. struct fst_iface *iface;
  1294. if (request[0] != ' ')
  1295. return -EINVAL;
  1296. request++;
  1297. if (fst_read_next_text_param(request, ifname, sizeof(ifname), &endp) ||
  1298. !*ifname)
  1299. goto problem;
  1300. g = dl_list_first(&fst_global_groups_list, struct fst_group,
  1301. global_groups_lentry);
  1302. if (!g)
  1303. goto problem;
  1304. iface = fst_group_get_iface_by_name(g, ifname);
  1305. if (!iface || !iface->mb_ie)
  1306. goto problem;
  1307. return wpa_snprintf_hex(buf, buflen, wpabuf_head(iface->mb_ie),
  1308. wpabuf_len(iface->mb_ie));
  1309. problem:
  1310. return os_snprintf(buf, buflen, "FAIL\n");
  1311. }
  1312. #endif /* CONFIG_FST_TEST */