1 /* 2 * Copyright (c) 2012-2015,2020-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /** 19 * DOC: Implements general SM framework for connection manager 20 */ 21 22 #include "wlan_cm_main_api.h" 23 #include "wlan_cm_sm.h" 24 #include "wlan_cm_roam_sm.h" 25 26 void cm_set_state(struct cnx_mgr *cm_ctx, enum wlan_cm_sm_state state) 27 { 28 if (state < WLAN_CM_S_MAX) 29 cm_ctx->sm.cm_state = state; 30 else 31 mlme_err("vdev %d mlme state (%d) is invalid", 32 wlan_vdev_get_id(cm_ctx->vdev), state); 33 } 34 35 void cm_set_substate(struct cnx_mgr *cm_ctx, enum wlan_cm_sm_state substate) 36 { 37 if ((substate > WLAN_CM_S_MAX) && (substate < WLAN_CM_SS_MAX)) 38 cm_ctx->sm.cm_substate = substate; 39 else 40 mlme_err("vdev %d mlme sub state (%d) is invalid", 41 wlan_vdev_get_id(cm_ctx->vdev), substate); 42 } 43 44 void cm_sm_state_update(struct cnx_mgr *cm_ctx, 45 enum wlan_cm_sm_state state, 46 enum wlan_cm_sm_state substate) 47 { 48 if (!cm_ctx) 49 return; 50 51 cm_set_state(cm_ctx, state); 52 cm_set_substate(cm_ctx, substate); 53 } 54 55 /** 56 * cm_state_init_entry() - Entry API for init state for connection mgr 57 * @ctx: connection manager ctx 58 * 59 * API to perform operations on moving to init state 60 * 61 * Return: void 62 */ 63 static void cm_state_init_entry(void *ctx) 64 { 65 struct cnx_mgr *cm_ctx = ctx; 66 67 cm_sm_state_update(cm_ctx, WLAN_CM_S_INIT, WLAN_CM_SS_IDLE); 68 } 69 70 /** 71 * cm_state_init_exit() - Exit API for init state for connection mgr 72 * @ctx: connection manager ctx 73 * 74 * API to perform operations on exiting from init state 75 * 76 * Return: void 77 */ 78 static void cm_state_init_exit(void *ctx) 79 { 80 } 81 82 /** 83 * cm_state_init_event() - Init State event handler for connection mgr 84 * @ctx: connection manager ctx 85 * @event: event 86 * @data_len: length of @data 87 * @data: event data 88 * 89 * API to handle events in INIT state 90 * 91 * Return: bool 92 */ 93 static bool cm_state_init_event(void *ctx, uint16_t event, 94 uint16_t data_len, void *data) 95 { 96 struct cnx_mgr *cm_ctx = ctx; 97 bool event_handled = true; 98 QDF_STATUS status; 99 100 switch (event) { 101 case WLAN_CM_SM_EV_CONNECT_REQ: 102 status = cm_add_connect_req_to_list(cm_ctx, data); 103 if (QDF_IS_STATUS_ERROR(status)) { 104 /* if fail to add req return failure */ 105 event_handled = false; 106 break; 107 } 108 cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTING); 109 cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_CONNECT_START, 110 data_len, data); 111 break; 112 case WLAN_CM_SM_EV_CONNECT_FAILURE: 113 if (cm_is_link_switch_connect_resp(data)) { 114 /* 115 * If non-link switch connect fails, kernel will be 116 * notified so the driver and kernel are in sync, 117 * but link switch is internal to driver and any failure 118 * is not notified to kernel. 119 * This can lead to kernel and driver going out of sync 120 * and any new disconnect requests might get dropped as 121 * CM is in INIT state and kernel will assume that 122 * interface is still in connected state. 123 * To handle this situation, change the substate of CM 124 * to signify VDEV is in INIT state due to link switch, 125 * so that any later disconnect requests will not be 126 * dropped. 127 */ 128 cm_sm_transition_to(cm_ctx, 129 WLAN_CM_SS_IDLE_DUE_TO_LINK_SWITCH); 130 } 131 cm_connect_complete(cm_ctx, data); 132 break; 133 case WLAN_CM_SM_EV_DISCONNECT_DONE: 134 if (cm_is_link_switch_disconnect_resp(data)) { 135 /* 136 * Change the substate of CM incase the disconnect 137 * is due to link switch so that any disconnect requests 138 * from NB/SB will not get dropped when handling those 139 * in INIT state. 140 */ 141 cm_sm_transition_to(cm_ctx, 142 WLAN_CM_SS_IDLE_DUE_TO_LINK_SWITCH); 143 } 144 cm_disconnect_complete(cm_ctx, data); 145 break; 146 case WLAN_CM_SM_EV_DISCONNECT_REQ: 147 status = cm_handle_discon_req_in_non_connected_state(cm_ctx, data, 148 WLAN_CM_S_INIT); 149 if (QDF_IS_STATUS_ERROR(status)) { 150 /* 151 * Return not handled as this req need to be 152 * dropped and return failure to the requester 153 */ 154 event_handled = false; 155 } 156 break; 157 case WLAN_CM_SM_EV_ROAM_SYNC: 158 /** 159 * If it's a legacy to MLO roaming, bringup the link vdev to 160 * process ROAM_SYNC indication on the link vdev. 161 */ 162 if (wlan_vdev_mlme_is_mlo_link_vdev(cm_ctx->vdev)) { 163 cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED); 164 status = cm_sm_deliver_event_sync(cm_ctx, 165 WLAN_CM_SM_EV_ROAM_SYNC, 166 data_len, data); 167 if (QDF_IS_STATUS_ERROR(status)) { 168 cm_sm_transition_to(cm_ctx, WLAN_CM_S_INIT); 169 event_handled = false; 170 } 171 } else { 172 event_handled = false; 173 } 174 break; 175 default: 176 event_handled = false; 177 break; 178 } 179 180 return event_handled; 181 } 182 183 /** 184 * cm_state_connecting_entry() - Entry API for connecting state for 185 * connection mgr 186 * @ctx: connection manager ctx 187 * 188 * API to perform operations on moving to connecting state 189 * 190 * Return: void 191 */ 192 static void cm_state_connecting_entry(void *ctx) 193 { 194 struct cnx_mgr *cm_ctx = ctx; 195 196 cm_sm_state_update(cm_ctx, WLAN_CM_S_CONNECTING, WLAN_CM_SS_IDLE); 197 } 198 199 /** 200 * cm_state_connecting_exit() - Exit API for connecting state for 201 * connection mgr 202 * @ctx: connection manager ctx 203 * 204 * API to perform operations on exiting from connecting state 205 * 206 * Return: void 207 */ 208 static void cm_state_connecting_exit(void *ctx) 209 { 210 } 211 212 /** 213 * cm_state_connecting_event() - Connecting State event handler for 214 * connection mgr 215 * @ctx: connection manager ctx 216 * @event: event 217 * @data_len: length of @data 218 * @data: event data 219 * 220 * API to handle events in CONNECTING state 221 * 222 * Return: bool 223 */ 224 static bool cm_state_connecting_event(void *ctx, uint16_t event, 225 uint16_t data_len, void *data) 226 { 227 struct cnx_mgr *cm_ctx = ctx; 228 bool event_handled = true; 229 230 switch (event) { 231 case WLAN_CM_SM_EV_CONNECT_START: 232 cm_sm_transition_to(cm_ctx, WLAN_CM_SS_JOIN_PENDING); 233 cm_sm_deliver_event_sync(cm_ctx, event, data_len, data); 234 break; 235 default: 236 event_handled = false; 237 break; 238 } 239 240 return event_handled; 241 } 242 243 /** 244 * cm_state_connected_entry() - Entry API for connected state for 245 * connection mgr 246 * @ctx: connection manager ctx 247 * 248 * API to perform operations on moving to connected state 249 * 250 * Return: void 251 */ 252 static void cm_state_connected_entry(void *ctx) 253 { 254 struct cnx_mgr *cm_ctx = ctx; 255 256 cm_sm_state_update(cm_ctx, WLAN_CM_S_CONNECTED, WLAN_CM_SS_IDLE); 257 } 258 259 /** 260 * cm_state_connected_exit() - Exit API for connected state for 261 * connection mgr 262 * @ctx: connection manager ctx 263 * 264 * API to perform operations on exiting from connected state 265 * 266 * Return: void 267 */ 268 static void cm_state_connected_exit(void *ctx) 269 { 270 } 271 272 #if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) 273 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 274 static 275 bool cm_handle_fw_roam_connected_event(struct cnx_mgr *cm_ctx, uint16_t event, 276 uint16_t data_len, void *data) 277 { 278 bool event_handled = true; 279 QDF_STATUS status; 280 struct cm_req *roam_cm_req; 281 282 switch (event) { 283 case WLAN_CM_SM_EV_ROAM_INVOKE: 284 cm_sm_transition_to(cm_ctx, WLAN_CM_S_ROAMING); 285 cm_sm_deliver_event_sync(cm_ctx, event, data_len, data); 286 break; 287 case WLAN_CM_SM_EV_ROAM_ABORT: 288 case WLAN_CM_SM_EV_ROAM_INVOKE_FAIL: 289 case WLAN_CM_SM_EV_ROAM_HO_FAIL: 290 cm_remove_cmd(cm_ctx, data); 291 break; 292 case WLAN_CM_SM_EV_ROAM_START: 293 status = cm_prepare_roam_cmd(cm_ctx, &roam_cm_req, 294 CM_ROAMING_FW); 295 if (QDF_IS_STATUS_ERROR(status)) { 296 event_handled = false; 297 break; 298 } 299 cm_sm_transition_to(cm_ctx, WLAN_CM_S_ROAMING); 300 cm_sm_deliver_event_sync(cm_ctx, event, 301 sizeof(*roam_cm_req), roam_cm_req); 302 break; 303 case WLAN_CM_SM_EV_ROAM_SYNC: 304 status = cm_prepare_roam_cmd(cm_ctx, &roam_cm_req, 305 CM_ROAMING_FW); 306 if (QDF_IS_STATUS_ERROR(status)) { 307 event_handled = false; 308 break; 309 } 310 status = cm_add_fw_roam_cmd_to_list_n_ser(cm_ctx, roam_cm_req); 311 if (QDF_IS_STATUS_ERROR(status)) { 312 event_handled = false; 313 break; 314 } 315 cm_sm_transition_to(cm_ctx, WLAN_CM_S_ROAMING); 316 status = cm_sm_deliver_event_sync(cm_ctx, event, data_len, 317 data); 318 if (QDF_IS_STATUS_ERROR(status)) 319 event_handled = false; 320 break; 321 case WLAN_CM_SM_EV_ROAM_DONE: 322 cm_fw_roam_complete(cm_ctx, data); 323 break; 324 default: 325 event_handled = false; 326 break; 327 } 328 329 return event_handled; 330 } 331 #else /* WLAN_FEATURE_ROAM_OFFLOAD */ 332 static inline 333 bool cm_handle_fw_roam_connected_event(struct cnx_mgr *cm_ctx, uint16_t event, 334 uint16_t data_len, void *data) 335 { 336 return false; 337 } 338 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */ 339 340 static bool 341 cm_handle_roam_connected_event(struct cnx_mgr *cm_ctx, uint16_t event, 342 uint16_t data_len, void *data) 343 { 344 bool event_handled = true; 345 346 /* Handle roam event only if roam is enabled */ 347 if (!cm_is_roam_enabled(wlan_vdev_get_psoc(cm_ctx->vdev))) 348 return false; 349 350 switch (event) { 351 case WLAN_CM_SM_EV_ROAM_REQ: 352 cm_sm_transition_to(cm_ctx, WLAN_CM_S_ROAMING); 353 cm_sm_deliver_event_sync(cm_ctx, 354 WLAN_CM_SM_EV_ROAM_REQ, 355 data_len, data); 356 break; 357 default: 358 event_handled = 359 cm_handle_fw_roam_connected_event(cm_ctx, event, 360 data_len, data); 361 break; 362 } 363 364 return event_handled; 365 } 366 #else /* WLAN_FEATURE_HOST_ROAM || WLAN_FEATURE_ROAM_OFFLOAD */ 367 static inline 368 bool cm_handle_roam_connected_event(struct cnx_mgr *cm_ctx, uint16_t event, 369 uint16_t data_len, void *data) 370 { 371 return false; 372 } 373 #endif /* WLAN_FEATURE_HOST_ROAM || WLAN_FEATURE_ROAM_OFFLOAD */ 374 375 /** 376 * cm_state_connected_event() - Connected State event handler for 377 * connection mgr 378 * @ctx: connection manager ctx 379 * @event: event 380 * @data_len: length of @data 381 * @data: event data 382 * 383 * API to handle events in CONNECTED state 384 * 385 * Return: bool 386 */ 387 static bool cm_state_connected_event(void *ctx, uint16_t event, 388 uint16_t data_len, void *data) 389 { 390 struct cnx_mgr *cm_ctx = ctx; 391 bool event_handled = true; 392 QDF_STATUS status; 393 struct cm_req *roam_cm_req; 394 395 switch (event) { 396 case WLAN_CM_SM_EV_CONNECT_REQ: 397 status = cm_check_and_prepare_roam_req(cm_ctx, data, 398 &roam_cm_req); 399 if (QDF_IS_STATUS_SUCCESS(status)) { 400 cm_sm_deliver_event_sync(cm_ctx, 401 WLAN_CM_SM_EV_ROAM_REQ, 402 sizeof(*roam_cm_req), 403 roam_cm_req); 404 break; 405 } 406 status = cm_handle_connect_req_in_non_init_state(cm_ctx, data, 407 WLAN_CM_S_CONNECTED); 408 if (QDF_IS_STATUS_ERROR(status)) { 409 event_handled = false; 410 break; 411 } 412 cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTING); 413 cm_sm_deliver_event_sync(cm_ctx, 414 WLAN_CM_SM_EV_CONNECT_START, 415 data_len, data); 416 break; 417 case WLAN_CM_SM_EV_DISCONNECT_ACTIVE: 418 cm_disconnect_active(cm_ctx, data); 419 break; 420 case WLAN_CM_SM_EV_CONNECT_SUCCESS: 421 cm_connect_complete(cm_ctx, data); 422 break; 423 case WLAN_CM_SM_EV_DISCONNECT_REQ: 424 status = cm_add_disconnect_req_to_list(cm_ctx, data); 425 if (QDF_IS_STATUS_ERROR(status)) { 426 /* if fail to add req return failure */ 427 event_handled = false; 428 break; 429 } 430 cm_sm_transition_to(cm_ctx, WLAN_CM_S_DISCONNECTING); 431 cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_DISCONNECT_START, 432 data_len, data); 433 break; 434 case WLAN_CM_SM_EV_REASSOC_DONE: 435 cm_reassoc_complete(cm_ctx, data); 436 break; 437 default: 438 event_handled = 439 cm_handle_roam_connected_event(cm_ctx, event, 440 data_len, data); 441 break; 442 } 443 return event_handled; 444 } 445 446 /** 447 * cm_state_disconnecting_entry() - Entry API for disconnecting state for 448 * connection mgr 449 * @ctx: connection manager ctx 450 * 451 * API to perform operations on moving to disconnecting state 452 * 453 * Return: void 454 */ 455 static void cm_state_disconnecting_entry(void *ctx) 456 { 457 struct cnx_mgr *cm_ctx = ctx; 458 459 cm_sm_state_update(cm_ctx, WLAN_CM_S_DISCONNECTING, WLAN_CM_SS_IDLE); 460 } 461 462 /** 463 * cm_state_disconnecting_exit() - Exit API for disconnecting state for 464 * connection mgr 465 * @ctx: connection manager ctx 466 * 467 * API to perform operations on exiting from disconnecting state 468 * 469 * Return: void 470 */ 471 static void cm_state_disconnecting_exit(void *ctx) 472 { 473 } 474 475 /** 476 * cm_state_disconnecting_event() - Disconnecting State event handler for 477 * connection mgr 478 * @ctx: connection manager ctx 479 * @event: event 480 * @data_len: length of @data 481 * @data: event data 482 * 483 * API to handle events in Disconnecting state 484 * 485 * Return: bool 486 */ 487 static bool cm_state_disconnecting_event(void *ctx, uint16_t event, 488 uint16_t data_len, void *data) 489 { 490 struct cnx_mgr *cm_ctx = ctx; 491 bool event_handled = true; 492 QDF_STATUS status; 493 494 switch (event) { 495 case WLAN_CM_SM_EV_CONNECT_REQ: 496 status = cm_handle_connect_req_in_non_init_state(cm_ctx, data, 497 WLAN_CM_S_DISCONNECTING); 498 if (QDF_IS_STATUS_ERROR(status)) { 499 event_handled = false; 500 break; 501 } 502 cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTING); 503 cm_sm_deliver_event_sync(cm_ctx, 504 WLAN_CM_SM_EV_CONNECT_START, 505 data_len, data); 506 break; 507 case WLAN_CM_SM_EV_DISCONNECT_START: 508 cm_disconnect_start(cm_ctx, data); 509 break; 510 case WLAN_CM_SM_EV_DISCONNECT_ACTIVE: 511 cm_disconnect_active(cm_ctx, data); 512 break; 513 case WLAN_CM_SM_EV_DISCONNECT_DONE: 514 cm_sm_transition_to(cm_ctx, WLAN_CM_S_INIT); 515 cm_sm_deliver_event_sync(cm_ctx, event, data_len, data); 516 break; 517 case WLAN_CM_SM_EV_DISCONNECT_REQ: 518 status = cm_handle_discon_req_in_non_connected_state(cm_ctx, 519 data, WLAN_CM_S_DISCONNECTING); 520 if (QDF_IS_STATUS_ERROR(status)) { 521 event_handled = false; 522 break; 523 } 524 cm_sm_deliver_event_sync(cm_ctx, 525 WLAN_CM_SM_EV_DISCONNECT_START, 526 data_len, data); 527 break; 528 case WLAN_CM_SM_EV_RSO_STOP_RSP: 529 cm_disconnect_continue_after_rso_stop(cm_ctx->vdev, data); 530 break; 531 default: 532 event_handled = false; 533 break; 534 } 535 536 return event_handled; 537 } 538 539 /** 540 * cm_subst_join_pending_entry() - Entry API for join pending sub-state for 541 * connection mgr 542 * @ctx: connection manager ctx 543 * 544 * API to perform operations on moving to join pending sub-state 545 * 546 * Return: void 547 */ 548 static void cm_subst_join_pending_entry(void *ctx) 549 { 550 struct cnx_mgr *cm_ctx = ctx; 551 552 if (cm_get_state(cm_ctx) != WLAN_CM_S_CONNECTING) 553 QDF_BUG(0); 554 555 cm_set_substate(cm_ctx, WLAN_CM_SS_JOIN_PENDING); 556 } 557 558 /** 559 * cm_subst_join_pending_exit() - Exit API for join pending sub-state for 560 * connection mgr 561 * @ctx: connection manager ctx 562 * 563 * API to perform operations on exiting from join pending sub-state 564 * 565 * Return: void 566 */ 567 static void cm_subst_join_pending_exit(void *ctx) 568 { 569 } 570 571 /** 572 * cm_subst_join_pending_event() - Join pending sub-state event handler for 573 * connection mgr 574 * @ctx: connection manager ctx 575 * @event: event 576 * @data_len: length of @data 577 * @data: event data 578 * 579 * API to handle events in Join pending sub-state 580 * 581 * Return: bool 582 */ 583 static bool cm_subst_join_pending_event(void *ctx, uint16_t event, 584 uint16_t data_len, void *data) 585 { 586 struct cnx_mgr *cm_ctx = ctx; 587 bool event_handled = true; 588 QDF_STATUS status = QDF_STATUS_SUCCESS; 589 struct wlan_cm_connect_resp *resp; 590 struct cm_req *cm_req; 591 592 switch (event) { 593 case WLAN_CM_SM_EV_CONNECT_REQ: 594 status = 595 cm_handle_connect_req_in_non_init_state(cm_ctx, data, 596 WLAN_CM_SS_JOIN_PENDING); 597 if (QDF_IS_STATUS_ERROR(status)) { 598 event_handled = false; 599 break; 600 } 601 cm_sm_deliver_event_sync(cm_ctx, 602 WLAN_CM_SM_EV_CONNECT_START, 603 data_len, data); 604 break; 605 case WLAN_CM_SM_EV_CONNECT_START: 606 cm_connect_start(cm_ctx, data); 607 break; 608 case WLAN_CM_SM_EV_CONNECT_ACTIVE: 609 /* check if cm id is valid for the current req */ 610 if (!cm_check_cmid_match_list_head(cm_ctx, data)) { 611 event_handled = false; 612 break; 613 } 614 cm_sm_transition_to(cm_ctx, WLAN_CM_SS_JOIN_ACTIVE); 615 cm_sm_deliver_event_sync(cm_ctx, event, data_len, data); 616 break; 617 case WLAN_CM_SM_EV_HW_MODE_SUCCESS: 618 case WLAN_CM_SM_EV_HW_MODE_FAILURE: 619 case WLAN_CM_SM_EV_BEARER_SWITCH_COMPLETE: 620 /* check if cm id is valid for the current req */ 621 if (!cm_check_cmid_match_list_head(cm_ctx, data)) { 622 event_handled = false; 623 break; 624 } 625 cm_ser_connect_after_mode_change_resp(cm_ctx, data, event); 626 break; 627 case WLAN_CM_SM_EV_SCAN: 628 cm_sm_transition_to(cm_ctx, WLAN_CM_SS_SCAN); 629 cm_sm_deliver_event_sync(cm_ctx, event, data_len, data); 630 break; 631 case WLAN_CM_SM_EV_SCAN_FAILURE: 632 status = QDF_STATUS_E_FAILURE; 633 /* Fall through after setting status failure */ 634 fallthrough; 635 case WLAN_CM_SM_EV_SCAN_SUCCESS: 636 cm_connect_scan_resp(cm_ctx, data, status); 637 break; 638 case WLAN_CM_SM_EV_CONNECT_FAILURE: 639 /* check if connect resp cm id is valid for the current req */ 640 if (!cm_connect_resp_cmid_match_list_head(cm_ctx, data)) { 641 event_handled = false; 642 break; 643 } 644 /* 645 * On connect req failure (before serialization), if there is a 646 * pending disconnect req then move to disconnecting state and 647 * wait for disconnect to complete before moving to INIT state. 648 * Else directly transition to INIT state. 649 * 650 * On disconnect completion or a new connect/disconnect req in 651 * disconnnecting state, the failed connect req will be flushed. 652 * This will ensure SM moves to INIT state after completion of 653 * all operation. 654 */ 655 if (cm_ctx->disconnect_count) { 656 resp = data; 657 658 mlme_debug(CM_PREFIX_FMT "disconnect_count %d", 659 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 660 resp->cm_id), 661 cm_ctx->disconnect_count); 662 cm_req = cm_get_req_by_cm_id(cm_ctx, resp->cm_id); 663 if (cm_req) 664 cm_req->failed_req = true; 665 cm_sm_transition_to(cm_ctx, WLAN_CM_S_DISCONNECTING); 666 break; 667 } 668 cm_sm_transition_to(cm_ctx, WLAN_CM_S_INIT); 669 cm_sm_deliver_event_sync(cm_ctx, event, data_len, data); 670 break; 671 case WLAN_CM_SM_EV_DISCONNECT_ACTIVE: 672 cm_disconnect_active(cm_ctx, data); 673 break; 674 case WLAN_CM_SM_EV_DISCONNECT_DONE: 675 cm_disconnect_complete(cm_ctx, data); 676 break; 677 case WLAN_CM_SM_EV_DISCONNECT_REQ: 678 status = cm_handle_discon_req_in_non_connected_state(cm_ctx, 679 data, WLAN_CM_SS_JOIN_PENDING); 680 if (QDF_IS_STATUS_ERROR(status)) { 681 event_handled = false; 682 break; 683 } 684 cm_sm_transition_to(cm_ctx, WLAN_CM_S_DISCONNECTING); 685 cm_sm_deliver_event_sync(cm_ctx, 686 WLAN_CM_SM_EV_DISCONNECT_START, 687 data_len, data); 688 break; 689 case WLAN_CM_SM_EV_RSO_STOP_RSP: 690 cm_disconnect_continue_after_rso_stop(cm_ctx->vdev, data); 691 break; 692 default: 693 event_handled = false; 694 break; 695 } 696 697 return event_handled; 698 } 699 700 /** 701 * cm_subst_scan_entry() - Entry API for scan sub-state for 702 * connection mgr 703 * @ctx: connection manager ctx 704 * 705 * API to perform operations on moving to scan sub-state 706 * 707 * Return: void 708 */ 709 static void cm_subst_scan_entry(void *ctx) 710 { 711 struct cnx_mgr *cm_ctx = ctx; 712 713 if (cm_get_state(cm_ctx) != WLAN_CM_S_CONNECTING) 714 QDF_BUG(0); 715 716 cm_set_substate(cm_ctx, WLAN_CM_SS_SCAN); 717 } 718 719 /** 720 * cm_subst_scan_exit() - Exit API for scan sub-state for 721 * connection mgr 722 * @ctx: connection manager ctx 723 * 724 * API to perform operations on exiting from scan sub-state 725 * 726 * Return: void 727 */ 728 static void cm_subst_scan_exit(void *ctx) 729 { 730 } 731 732 /** 733 * cm_subst_scan_event() - Scan sub-state event handler for 734 * connection mgr 735 * @ctx: connection manager ctx 736 * @event: event 737 * @data_len: length of @data 738 * @data: event data 739 * 740 * API to handle events in scan sub-state 741 * 742 * Return: bool 743 */ 744 static bool cm_subst_scan_event(void *ctx, uint16_t event, 745 uint16_t data_len, void *data) 746 { 747 struct cnx_mgr *cm_ctx = ctx; 748 bool event_handled = true; 749 QDF_STATUS status; 750 751 switch (event) { 752 case WLAN_CM_SM_EV_CONNECT_REQ: 753 status = cm_handle_connect_req_in_non_init_state(cm_ctx, data, 754 WLAN_CM_SS_SCAN); 755 if (QDF_IS_STATUS_ERROR(status)) { 756 event_handled = false; 757 break; 758 } 759 cm_sm_transition_to(cm_ctx, WLAN_CM_SS_JOIN_PENDING); 760 cm_sm_deliver_event_sync(cm_ctx, 761 WLAN_CM_SM_EV_CONNECT_START, 762 data_len, data); 763 break; 764 case WLAN_CM_SM_EV_SCAN: 765 cm_connect_scan_start(cm_ctx, data); 766 break; 767 case WLAN_CM_SM_EV_SCAN_SUCCESS: 768 case WLAN_CM_SM_EV_SCAN_FAILURE: 769 /* check if scan id is valid for the current req */ 770 if (!cm_check_scanid_match_list_head(cm_ctx, data)) { 771 event_handled = false; 772 break; 773 } 774 cm_sm_transition_to(cm_ctx, WLAN_CM_SS_JOIN_PENDING); 775 cm_sm_deliver_event_sync(cm_ctx, event, data_len, data); 776 break; 777 case WLAN_CM_SM_EV_DISCONNECT_ACTIVE: 778 cm_disconnect_active(cm_ctx, data); 779 break; 780 case WLAN_CM_SM_EV_DISCONNECT_DONE: 781 cm_disconnect_complete(cm_ctx, data); 782 break; 783 case WLAN_CM_SM_EV_DISCONNECT_REQ: 784 status = cm_handle_discon_req_in_non_connected_state(cm_ctx, 785 data, WLAN_CM_SS_SCAN); 786 if (QDF_IS_STATUS_ERROR(status)) { 787 event_handled = false; 788 break; 789 } 790 cm_sm_transition_to(cm_ctx, WLAN_CM_S_DISCONNECTING); 791 cm_sm_deliver_event_sync(cm_ctx, 792 WLAN_CM_SM_EV_DISCONNECT_START, 793 data_len, data); 794 break; 795 case WLAN_CM_SM_EV_RSO_STOP_RSP: 796 cm_disconnect_continue_after_rso_stop(cm_ctx->vdev, data); 797 break; 798 default: 799 event_handled = false; 800 break; 801 } 802 803 return event_handled; 804 } 805 806 /** 807 * cm_subst_join_active_entry() - Entry API for join active sub-state for 808 * connection mgr 809 * @ctx: connection manager ctx 810 * 811 * API to perform operations on moving to join active sub-state 812 * 813 * Return: void 814 */ 815 static void cm_subst_join_active_entry(void *ctx) 816 { 817 struct cnx_mgr *cm_ctx = ctx; 818 819 if (cm_get_state(cm_ctx) != WLAN_CM_S_CONNECTING) 820 QDF_BUG(0); 821 822 cm_set_substate(cm_ctx, WLAN_CM_SS_JOIN_ACTIVE); 823 } 824 825 /** 826 * cm_subst_join_active_exit() - Exit API for join active sub-state for 827 * connection mgr 828 * @ctx: connection manager ctx 829 * 830 * API to perform operations on exiting from join active sub-state 831 * 832 * Return: void 833 */ 834 static void cm_subst_join_active_exit(void *ctx) 835 { 836 } 837 838 /** 839 * cm_subst_join_active_event() - Join active sub-state event handler for 840 * connection mgr 841 * @ctx: connection manager ctx 842 * @event: event 843 * @data_len: length of @data 844 * @data: event data 845 * 846 * API to handle events in join active sub-state 847 * 848 * Return: bool 849 */ 850 static bool cm_subst_join_active_event(void *ctx, uint16_t event, 851 uint16_t data_len, void *data) 852 { 853 struct cnx_mgr *cm_ctx = ctx; 854 bool event_handled = true; 855 QDF_STATUS status; 856 857 switch (event) { 858 case WLAN_CM_SM_EV_CONNECT_REQ: 859 status = cm_handle_connect_req_in_non_init_state(cm_ctx, data, 860 WLAN_CM_SS_JOIN_ACTIVE); 861 if (QDF_IS_STATUS_ERROR(status)) { 862 event_handled = false; 863 break; 864 } 865 cm_sm_transition_to(cm_ctx, WLAN_CM_SS_JOIN_PENDING); 866 cm_sm_deliver_event_sync(cm_ctx, 867 WLAN_CM_SM_EV_CONNECT_START, 868 data_len, data); 869 break; 870 case WLAN_CM_SM_EV_CONNECT_ACTIVE: 871 cm_connect_active(cm_ctx, data); 872 break; 873 case WLAN_CM_SM_EV_CONNECT_SUCCESS: 874 /* check if connect resp cm id is valid for the current req */ 875 if (!cm_connect_resp_cmid_match_list_head(cm_ctx, data)) { 876 event_handled = false; 877 break; 878 } 879 cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED); 880 cm_sm_deliver_event_sync(cm_ctx, event, data_len, data); 881 break; 882 case WLAN_CM_SM_EV_CONNECT_GET_NEXT_CANDIDATE: 883 /* check if connect resp cm id is valid for the current req */ 884 if (!cm_connect_resp_cmid_match_list_head(cm_ctx, data)) { 885 event_handled = false; 886 break; 887 } 888 cm_try_next_candidate(cm_ctx, data); 889 break; 890 case WLAN_CM_SM_EV_CONNECT_FAILURE: 891 /* check if connect resp cm id is valid for the current req */ 892 if (!cm_connect_resp_cmid_match_list_head(cm_ctx, data)) { 893 event_handled = false; 894 break; 895 } 896 cm_sm_transition_to(cm_ctx, WLAN_CM_S_INIT); 897 cm_sm_deliver_event_sync(cm_ctx, event, data_len, data); 898 break; 899 case WLAN_CM_SM_EV_BSS_SELECT_IND_SUCCESS: 900 /* check if cm id is valid for the current req */ 901 if (!cm_check_cmid_match_list_head(cm_ctx, data)) { 902 event_handled = false; 903 break; 904 } 905 cm_peer_create_on_bss_select_ind_resp(cm_ctx, data); 906 break; 907 case WLAN_CM_SM_EV_BSS_CREATE_PEER_SUCCESS: 908 /* check if cm id is valid for the current req */ 909 if (!cm_check_cmid_match_list_head(cm_ctx, data)) { 910 event_handled = false; 911 break; 912 } 913 cm_resume_connect_after_peer_create(cm_ctx, data); 914 break; 915 case WLAN_CM_SM_EV_DISCONNECT_REQ: 916 status = cm_handle_discon_req_in_non_connected_state(cm_ctx, 917 data, WLAN_CM_SS_JOIN_ACTIVE); 918 if (QDF_IS_STATUS_ERROR(status)) { 919 event_handled = false; 920 break; 921 } 922 cm_sm_transition_to(cm_ctx, WLAN_CM_S_DISCONNECTING); 923 cm_sm_deliver_event_sync(cm_ctx, 924 WLAN_CM_SM_EV_DISCONNECT_START, 925 data_len, data); 926 break; 927 default: 928 event_handled = false; 929 break; 930 } 931 932 return event_handled; 933 } 934 935 #ifdef CONN_MGR_ADV_FEATURE 936 /** 937 * cm_subst_idle_due_to_link_switch_entry() - Entry API for idle due to 938 * link switch substate for connection manager. 939 * @ctx: Connection manager context 940 * 941 * API to perform entry operations to this substate. 942 */ 943 static void cm_subst_idle_due_to_link_switch_entry(void *ctx) 944 { 945 struct cnx_mgr *cm_ctx = ctx; 946 947 if (cm_get_state(cm_ctx) != WLAN_CM_S_INIT) 948 QDF_BUG(0); 949 950 cm_set_substate(cm_ctx, WLAN_CM_SS_IDLE_DUE_TO_LINK_SWITCH); 951 } 952 953 /** 954 * cm_subst_idle_due_to_link_switch_exit() - Exit API from idle due to 955 * link switch substate for connection manager. 956 * @ctx: Connection manager context 957 * 958 * API to perform exit operations before leaving from this substate. 959 */ 960 static inline void cm_subst_idle_due_to_link_switch_exit(void *ctx) 961 { 962 } 963 964 /** 965 * cm_subst_idle_due_to_link_switch_event() - Event handler API for idle 966 * due to link switch substate for connection manager. 967 * @ctx: connection manager ctx 968 * @event: event 969 * @data_len: length of @data 970 * @data: event data 971 * 972 * API to handle events in IDLE_DUE_TO_LINK_SWITCH substate. 973 * Return true if the event is handled or else return false. 974 * 975 * Return: bool 976 */ 977 static bool cm_subst_idle_due_to_link_switch_event(void *ctx, uint16_t event, 978 uint16_t data_len, 979 void *data) 980 { 981 struct cnx_mgr *cm_ctx = ctx; 982 bool event_handled = true; 983 QDF_STATUS status; 984 enum wlan_cm_sm_state cm_state = WLAN_CM_SS_IDLE_DUE_TO_LINK_SWITCH; 985 986 switch (event) { 987 case WLAN_CM_SM_EV_CONNECT_REQ: 988 /* 989 * If the connect request is due to link switch then 990 * move the state to INIT to handle usual connect request. 991 * Connect request due to link switch are only allowed in 992 * INIT-IDLE and INIT-IDLE_DUE_TO_LINK_SWITCH states in all 993 * other states the connect request will be rejected. 994 * 995 * As VDEV is in INIT state due to link switch and if connect 996 * request is received from other than link switch, then 997 * forcefully move VDEV to CONNECTED state, so the event follows 998 * pre-link switch handling path. 999 */ 1000 if (cm_is_link_switch_connect_req(data)) 1001 cm_sm_transition_to(cm_ctx, WLAN_CM_S_INIT); 1002 else 1003 cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED); 1004 1005 status = cm_sm_deliver_event_sync(cm_ctx, event, data_len, 1006 data); 1007 if (QDF_IS_STATUS_ERROR(status)) 1008 event_handled = false; 1009 break; 1010 case WLAN_CM_SM_EV_DISCONNECT_REQ: 1011 status = cm_handle_discon_req_in_non_connected_state(cm_ctx, 1012 data, 1013 cm_state); 1014 /* 1015 * To handle the case where disconnect request is due to 1016 * link switch, return error so that link switch will abort. 1017 */ 1018 if (QDF_IS_STATUS_ERROR(status)) { 1019 event_handled = false; 1020 break; 1021 } 1022 /* 1023 * If disconnect request for non-connected state is success, 1024 * then forcefully move VDEV to disconnecting state and start 1025 * the disconnect sequence. 1026 */ 1027 cm_sm_transition_to(cm_ctx, WLAN_CM_S_DISCONNECTING); 1028 status = cm_sm_deliver_event_sync(cm_ctx, 1029 WLAN_CM_SM_EV_DISCONNECT_START, 1030 data_len, data); 1031 if (QDF_IS_STATUS_ERROR(status)) 1032 event_handled = false; 1033 1034 break; 1035 case WLAN_CM_SM_EV_ROAM_SYNC: 1036 /* 1037 * If link switch fails on assoc VDEV and FW roams to new AP 1038 * then the ROAM_SYNC event will be dropped as ROAM_SYNC in 1039 * INIT state is only allowed for link VDEV. Hence move the VDEV 1040 * state to CONNECTED state to handle this event. 1041 */ 1042 cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED); 1043 status = cm_sm_deliver_event_sync(cm_ctx, event, data_len, 1044 data); 1045 if (QDF_IS_STATUS_ERROR(status)) { 1046 cm_sm_transition_to(cm_ctx, WLAN_CM_S_INIT); 1047 event_handled = false; 1048 } 1049 break; 1050 default: 1051 /* Handle all other events in INIT state. */ 1052 cm_sm_transition_to(cm_ctx, WLAN_CM_S_INIT); 1053 status = cm_sm_deliver_event_sync(cm_ctx, event, data_len, 1054 data); 1055 if (QDF_IS_STATUS_ERROR(status)) 1056 event_handled = false; 1057 break; 1058 } 1059 1060 return event_handled; 1061 } 1062 #else 1063 static inline void cm_subst_idle_due_to_link_switch_entry(void *ctx) 1064 { 1065 } 1066 1067 static inline void cm_subst_idle_due_to_link_switch_exit(void *ctx) 1068 { 1069 } 1070 1071 static inline bool 1072 cm_subst_idle_due_to_link_switch_event(void *ctx, uint16_t event, 1073 uint16_t data_len, void *data) 1074 { 1075 return false; 1076 } 1077 #endif 1078 1079 struct wlan_sm_state_info cm_sm_info[] = { 1080 { 1081 (uint8_t)WLAN_CM_S_INIT, 1082 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1083 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1084 true, 1085 "INIT", 1086 cm_state_init_entry, 1087 cm_state_init_exit, 1088 cm_state_init_event 1089 }, 1090 { 1091 (uint8_t)WLAN_CM_S_CONNECTING, 1092 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1093 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1094 true, 1095 "CONNECTING", 1096 cm_state_connecting_entry, 1097 cm_state_connecting_exit, 1098 cm_state_connecting_event 1099 }, 1100 { 1101 (uint8_t)WLAN_CM_S_CONNECTED, 1102 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1103 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1104 true, 1105 "CONNECTED", 1106 cm_state_connected_entry, 1107 cm_state_connected_exit, 1108 cm_state_connected_event 1109 }, 1110 { 1111 (uint8_t)WLAN_CM_S_DISCONNECTING, 1112 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1113 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1114 true, 1115 "DISCONNECTING", 1116 cm_state_disconnecting_entry, 1117 cm_state_disconnecting_exit, 1118 cm_state_disconnecting_event 1119 }, 1120 { 1121 (uint8_t)WLAN_CM_S_ROAMING, 1122 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1123 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1124 true, 1125 "ROAMING", 1126 cm_state_roaming_entry, 1127 cm_state_roaming_exit, 1128 cm_state_roaming_event 1129 }, 1130 { 1131 (uint8_t)WLAN_CM_S_MAX, 1132 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1133 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1134 false, 1135 "INVALID", 1136 NULL, 1137 NULL, 1138 NULL 1139 }, 1140 { 1141 (uint8_t)WLAN_CM_SS_IDLE, 1142 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1143 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1144 false, 1145 "IDLE", 1146 NULL, 1147 NULL, 1148 NULL 1149 }, 1150 { 1151 (uint8_t)WLAN_CM_SS_JOIN_PENDING, 1152 (uint8_t)WLAN_CM_S_CONNECTING, 1153 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1154 false, 1155 "JOIN_PENDING", 1156 cm_subst_join_pending_entry, 1157 cm_subst_join_pending_exit, 1158 cm_subst_join_pending_event 1159 }, 1160 { 1161 (uint8_t)WLAN_CM_SS_SCAN, 1162 (uint8_t)WLAN_CM_S_CONNECTING, 1163 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1164 false, 1165 "SCAN", 1166 cm_subst_scan_entry, 1167 cm_subst_scan_exit, 1168 cm_subst_scan_event 1169 }, 1170 { 1171 (uint8_t)WLAN_CM_SS_JOIN_ACTIVE, 1172 (uint8_t)WLAN_CM_S_CONNECTING, 1173 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1174 false, 1175 "JOIN_ACTIVE", 1176 cm_subst_join_active_entry, 1177 cm_subst_join_active_exit, 1178 cm_subst_join_active_event 1179 }, 1180 { 1181 (uint8_t)WLAN_CM_SS_PREAUTH, 1182 (uint8_t)WLAN_CM_S_ROAMING, 1183 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1184 false, 1185 "PREAUTH", 1186 cm_subst_preauth_entry, 1187 cm_subst_preauth_exit, 1188 cm_subst_preauth_event 1189 }, 1190 { 1191 (uint8_t)WLAN_CM_SS_REASSOC, 1192 (uint8_t)WLAN_CM_S_ROAMING, 1193 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1194 false, 1195 "REASSOC", 1196 cm_subst_reassoc_entry, 1197 cm_subst_reassoc_exit, 1198 cm_subst_reassoc_event 1199 }, 1200 { 1201 (uint8_t)WLAN_CM_SS_ROAM_STARTED, 1202 (uint8_t)WLAN_CM_S_ROAMING, 1203 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1204 false, 1205 "ROAM_START", 1206 cm_subst_roam_start_entry, 1207 cm_subst_roam_start_exit, 1208 cm_subst_roam_start_event 1209 }, 1210 { 1211 (uint8_t)WLAN_CM_SS_ROAM_SYNC, 1212 (uint8_t)WLAN_CM_S_ROAMING, 1213 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1214 false, 1215 "ROAM_SYNC", 1216 cm_subst_roam_sync_entry, 1217 cm_subst_roam_sync_exit, 1218 cm_subst_roam_sync_event 1219 }, 1220 { 1221 (uint8_t)WLAN_CM_SS_IDLE_DUE_TO_LINK_SWITCH, 1222 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1223 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1224 false, 1225 "IDLE_DUE_TO_LINK_SWITCH", 1226 cm_subst_idle_due_to_link_switch_entry, 1227 cm_subst_idle_due_to_link_switch_exit, 1228 cm_subst_idle_due_to_link_switch_event 1229 }, 1230 { 1231 (uint8_t)WLAN_CM_SS_MAX, 1232 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1233 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 1234 false, 1235 "INVALID", 1236 NULL, 1237 NULL, 1238 NULL 1239 }, 1240 }; 1241 1242 static const char *cm_sm_event_names[] = { 1243 "EV_CONNECT_REQ", 1244 "EV_SCAN", 1245 "EV_SCAN_SUCCESS", 1246 "EV_SCAN_FAILURE", 1247 "EV_HW_MODE_SUCCESS", 1248 "EV_HW_MODE_FAILURE", 1249 "EV_CONNECT_START", 1250 "EV_CONNECT_ACTIVE", 1251 "EV_CONNECT_SUCCESS", 1252 "EV_BSS_SELECT_IND_SUCCESS", 1253 "EV_BSS_CREATE_PEER_SUCCESS", 1254 "EV_CONNECT_GET_NXT_CANDIDATE", 1255 "EV_CONNECT_FAILURE", 1256 "EV_DISCONNECT_REQ", 1257 "EV_DISCONNECT_START", 1258 "EV_DISCONNECT_ACTIVE", 1259 "EV_DISCONNECT_DONE", 1260 "EV_ROAM_START", 1261 "EV_ROAM_SYNC", 1262 "EV_ROAM_INVOKE_FAIL", 1263 "EV_ROAM_HO_FAIL", 1264 "EV_PREAUTH_DONE", 1265 "EV_GET_NEXT_PREAUTH_AP", 1266 "EV_PREAUTH_FAIL", 1267 "EV_START_REASSOC", 1268 "EV_REASSOC_ACTIVE", 1269 "EV_REASSOC_DONE", 1270 "EV_REASSOC_FAILURE", 1271 "EV_ROAM_COMPLETE", 1272 "EV_ROAM_REQ", 1273 "EV_ROAM_INVOKE", 1274 "EV_ROAM_ABORT", 1275 "EV_ROAM_DONE", 1276 "EV_PREAUTH_ACTIVE", 1277 "EV_PREAUTH_RESP", 1278 "EV_REASSOC_TIMER", 1279 "EV_HO_ROAM_DISCONNECT_DONE", 1280 "EV_RSO_STOP_RSP", 1281 "EV_BEARER_SWITCH_COMPLETE", 1282 }; 1283 1284 enum wlan_cm_sm_state cm_get_state(struct cnx_mgr *cm_ctx) 1285 { 1286 enum QDF_OPMODE op_mode; 1287 1288 if (!cm_ctx || !cm_ctx->vdev) 1289 return WLAN_CM_S_MAX; 1290 1291 op_mode = wlan_vdev_mlme_get_opmode(cm_ctx->vdev); 1292 1293 if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE) 1294 return WLAN_CM_S_MAX; 1295 1296 return cm_ctx->sm.cm_state; 1297 } 1298 1299 enum wlan_cm_sm_state cm_get_sub_state(struct cnx_mgr *cm_ctx) 1300 { 1301 enum QDF_OPMODE op_mode; 1302 1303 if (!cm_ctx || !cm_ctx->vdev) 1304 return WLAN_CM_SS_MAX; 1305 1306 op_mode = wlan_vdev_mlme_get_opmode(cm_ctx->vdev); 1307 1308 if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE) 1309 return WLAN_CM_SS_MAX; 1310 1311 return cm_ctx->sm.cm_substate; 1312 } 1313 1314 static void cm_sm_print_state_event(struct cnx_mgr *cm_ctx, 1315 enum wlan_cm_sm_evt event) 1316 { 1317 enum wlan_cm_sm_state state; 1318 enum wlan_cm_sm_state substate; 1319 1320 state = cm_get_state(cm_ctx); 1321 substate = cm_get_sub_state(cm_ctx); 1322 1323 mlme_nofl_debug("[%s]%s - %s, %s", cm_ctx->sm.sm_hdl->name, 1324 cm_sm_info[state].name, cm_sm_info[substate].name, 1325 cm_sm_event_names[event]); 1326 } 1327 1328 static void cm_sm_print_state(struct cnx_mgr *cm_ctx) 1329 { 1330 enum wlan_cm_sm_state state; 1331 enum wlan_cm_sm_state substate; 1332 1333 state = cm_get_state(cm_ctx); 1334 substate = cm_get_sub_state(cm_ctx); 1335 1336 mlme_nofl_debug("[%s]%s - %s", cm_ctx->sm.sm_hdl->name, 1337 cm_sm_info[state].name, cm_sm_info[substate].name); 1338 } 1339 1340 QDF_STATUS cm_sm_deliver_event(struct wlan_objmgr_vdev *vdev, 1341 enum wlan_cm_sm_evt event, 1342 uint16_t data_len, void *data) 1343 { 1344 QDF_STATUS status; 1345 enum wlan_cm_sm_state state_entry, state_exit; 1346 enum wlan_cm_sm_state substate_entry, substate_exit; 1347 enum QDF_OPMODE op_mode = wlan_vdev_mlme_get_opmode(vdev); 1348 struct cnx_mgr *cm_ctx; 1349 1350 if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE) { 1351 mlme_err("vdev %d Invalid mode %d", 1352 wlan_vdev_get_id(vdev), op_mode); 1353 return QDF_STATUS_E_NOSUPPORT; 1354 } 1355 1356 cm_ctx = cm_get_cm_ctx(vdev); 1357 if (!cm_ctx) 1358 return QDF_STATUS_E_FAILURE; 1359 1360 cm_lock_acquire(cm_ctx); 1361 1362 /* store entry state and sub state for prints */ 1363 state_entry = cm_get_state(cm_ctx); 1364 substate_entry = cm_get_sub_state(cm_ctx); 1365 cm_sm_print_state_event(cm_ctx, event); 1366 1367 status = cm_sm_deliver_event_sync(cm_ctx, event, data_len, data); 1368 /* Take exit state, exit substate for prints */ 1369 state_exit = cm_get_state(cm_ctx); 1370 substate_exit = cm_get_sub_state(cm_ctx); 1371 /* If no state and substate change, don't print */ 1372 if (!((state_entry == state_exit) && (substate_entry == substate_exit))) 1373 cm_sm_print_state(cm_ctx); 1374 cm_lock_release(cm_ctx); 1375 1376 return status; 1377 } 1378 1379 QDF_STATUS cm_sm_create(struct cnx_mgr *cm_ctx) 1380 { 1381 struct wlan_sm *sm; 1382 uint8_t name[WLAN_SM_ENGINE_MAX_NAME]; 1383 1384 qdf_scnprintf(name, sizeof(name), "CM-PS_%d-VD_%d", 1385 wlan_psoc_get_id(wlan_vdev_get_psoc(cm_ctx->vdev)), 1386 wlan_vdev_get_id(cm_ctx->vdev)); 1387 sm = wlan_sm_create(name, cm_ctx, 1388 WLAN_CM_S_INIT, 1389 cm_sm_info, 1390 QDF_ARRAY_SIZE(cm_sm_info), 1391 cm_sm_event_names, 1392 QDF_ARRAY_SIZE(cm_sm_event_names)); 1393 if (!sm) { 1394 mlme_err("vdev %d CM State Machine allocation failed", 1395 wlan_vdev_get_id(cm_ctx->vdev)); 1396 return QDF_STATUS_E_NOMEM; 1397 } 1398 cm_ctx->sm.sm_hdl = sm; 1399 1400 cm_lock_create(cm_ctx); 1401 1402 return QDF_STATUS_SUCCESS; 1403 } 1404 1405 QDF_STATUS cm_sm_destroy(struct cnx_mgr *cm_ctx) 1406 { 1407 cm_lock_destroy(cm_ctx); 1408 wlan_sm_delete(cm_ctx->sm.sm_hdl); 1409 1410 return QDF_STATUS_SUCCESS; 1411 } 1412 1413 #ifdef SM_ENG_HIST_ENABLE 1414 void cm_sm_history_print(struct wlan_objmgr_vdev *vdev) 1415 { 1416 struct cnx_mgr *cm_ctx; 1417 1418 cm_ctx = cm_get_cm_ctx(vdev); 1419 if (!cm_ctx) { 1420 mlme_err("cm_ctx is NULL"); 1421 return; 1422 } 1423 1424 return wlan_sm_print_history(cm_ctx->sm.sm_hdl); 1425 } 1426 #endif 1427