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