1 /* 2 * Copyright (c) 2012-2015, 2020, The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 /** 18 * DOC: Implements general SM framework for connection manager 19 */ 20 21 #include "wlan_cm_main_api.h" 22 #include "wlan_cm_sm.h" 23 #include "wlan_cm_roam_sm.h" 24 25 void cm_set_state(struct cnx_mgr *cm_ctx, enum wlan_cm_sm_state state) 26 { 27 if (state < WLAN_CM_S_MAX) 28 cm_ctx->sm.cm_state = state; 29 else 30 mlme_err("vdev %d mlme state (%d) is invalid", 31 wlan_vdev_get_id(cm_ctx->vdev), state); 32 } 33 34 void cm_set_substate(struct cnx_mgr *cm_ctx, enum wlan_cm_sm_state substate) 35 { 36 if ((substate > WLAN_CM_S_MAX) && (substate < WLAN_CM_SS_MAX)) 37 cm_ctx->sm.cm_substate = substate; 38 else 39 mlme_err("vdev %d mlme sub state (%d) is invalid", 40 wlan_vdev_get_id(cm_ctx->vdev), substate); 41 } 42 43 void cm_sm_state_update(struct cnx_mgr *cm_ctx, 44 enum wlan_cm_sm_state state, 45 enum wlan_cm_sm_state substate) 46 { 47 if (!cm_ctx) { 48 mlme_err("vdev %d cm_ctx is NULL", 49 wlan_vdev_get_id(cm_ctx->vdev)); 50 return; 51 } 52 53 cm_set_state(cm_ctx, state); 54 cm_set_substate(cm_ctx, substate); 55 } 56 57 /** 58 * cm_state_init_entry() - Entry API for init state for connection mgr 59 * @ctx: connection manager ctx 60 * 61 * API to perform operations on moving to init state 62 * 63 * Return: void 64 */ 65 static void cm_state_init_entry(void *ctx) 66 { 67 struct cnx_mgr *cm_ctx = ctx; 68 69 cm_sm_state_update(cm_ctx, WLAN_CM_S_INIT, WLAN_CM_SS_IDLE); 70 } 71 72 /** 73 * cm_state_init_exit() - Exit API for init state for connection mgr 74 * @ctx: connection manager ctx 75 * 76 * API to perform operations on exiting from init state 77 * 78 * Return: void 79 */ 80 static void cm_state_init_exit(void *ctx) 81 { 82 } 83 84 /** 85 * cm_state_init_event() - Init State event handler for connection mgr 86 * @ctx: connection manager ctx 87 * 88 * API to handle events in INIT state 89 * 90 * Return: bool 91 */ 92 static bool cm_state_init_event(void *ctx, uint16_t event, 93 uint16_t data_len, void *data) 94 { 95 struct cnx_mgr *cm_ctx = ctx; 96 bool event_handled; 97 QDF_STATUS status; 98 struct cm_disconnect_req *req; 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 event_handled = true; 112 break; 113 case WLAN_CM_SM_EV_CONNECT_FAILURE: 114 cm_connect_complete(cm_ctx, data); 115 event_handled = true; 116 break; 117 case WLAN_CM_SM_EV_DISCONNECT_DONE: 118 cm_disconnect_complete(cm_ctx, data); 119 event_handled = true; 120 break; 121 case WLAN_CM_SM_EV_DISCONNECT_REQ: 122 status = cm_add_disconnect_req_to_list(cm_ctx, data); 123 if (QDF_IS_STATUS_ERROR(status)) { 124 /* if fail to add req return failure */ 125 event_handled = false; 126 break; 127 } 128 129 req = data; 130 cm_send_disconnect_resp(cm_ctx, req->cm_id); 131 event_handled = true; 132 break; 133 default: 134 event_handled = false; 135 break; 136 } 137 138 return event_handled; 139 } 140 141 /** 142 * cm_state_connecting_entry() - Entry API for connecting state for 143 * connection mgr 144 * @ctx: connection manager ctx 145 * 146 * API to perform operations on moving to connecting state 147 * 148 * Return: void 149 */ 150 static void cm_state_connecting_entry(void *ctx) 151 { 152 struct cnx_mgr *cm_ctx = ctx; 153 154 cm_sm_state_update(cm_ctx, WLAN_CM_S_CONNECTING, WLAN_CM_SS_IDLE); 155 } 156 157 /** 158 * cm_state_connecting_exit() - Exit API for connecting state for 159 * connection mgr 160 * @ctx: connection manager ctx 161 * 162 * API to perform operations on exiting from connecting state 163 * 164 * Return: void 165 */ 166 static void cm_state_connecting_exit(void *ctx) 167 { 168 } 169 170 /** 171 * cm_state_connecting_event() - Connecting State event handler for 172 * connection mgr 173 * @ctx: connection manager ctx 174 * 175 * API to handle events in CONNECTING state 176 * 177 * Return: bool 178 */ 179 static bool cm_state_connecting_event(void *ctx, uint16_t event, 180 uint16_t data_len, void *data) 181 { 182 struct cnx_mgr *cm_ctx = ctx; 183 bool event_handled; 184 185 switch (event) { 186 case WLAN_CM_SM_EV_CONNECT_START: 187 cm_sm_transition_to(cm_ctx, WLAN_CM_SS_JOIN_PENDING); 188 cm_sm_deliver_event_sync(cm_ctx, event, data_len, data); 189 event_handled = true; 190 break; 191 default: 192 event_handled = false; 193 break; 194 } 195 196 return event_handled; 197 } 198 199 /** 200 * cm_state_connected_entry() - Entry API for connected state for 201 * connection mgr 202 * @ctx: connection manager ctx 203 * 204 * API to perform operations on moving to connected state 205 * 206 * Return: void 207 */ 208 static void cm_state_connected_entry(void *ctx) 209 { 210 struct cnx_mgr *cm_ctx = ctx; 211 212 cm_sm_state_update(cm_ctx, WLAN_CM_S_CONNECTED, WLAN_CM_SS_IDLE); 213 } 214 215 /** 216 * cm_state_connected_exit() - Exit API for connected state for 217 * connection mgr 218 * @ctx: connection manager ctx 219 * 220 * API to perform operations on exiting from connected state 221 * 222 * Return: void 223 */ 224 static void cm_state_connected_exit(void *ctx) 225 { 226 } 227 228 /** 229 * cm_state_connected_event() - Connected State event handler for 230 * connection mgr 231 * @ctx: connection manager ctx 232 * 233 * API to handle events in CONNECTED state 234 * 235 * Return: bool 236 */ 237 static bool cm_state_connected_event(void *ctx, uint16_t event, 238 uint16_t data_len, void *data) 239 { 240 struct cnx_mgr *cm_ctx = ctx; 241 bool event_handled; 242 QDF_STATUS status; 243 244 switch (event) { 245 case WLAN_CM_SM_EV_CONNECT_REQ: 246 status = cm_handle_connect_req_in_non_init_state(cm_ctx, data, 247 WLAN_CM_S_CONNECTED); 248 if (QDF_IS_STATUS_ERROR(status)) { 249 event_handled = false; 250 break; 251 } 252 cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTING); 253 cm_sm_deliver_event_sync(cm_ctx, 254 WLAN_CM_SM_EV_CONNECT_START, 255 data_len, data); 256 event_handled = true; 257 break; 258 case WLAN_CM_SM_EV_DISCONNECT_ACTIVE: 259 cm_disconnect_active(cm_ctx, data); 260 event_handled = true; 261 break; 262 case WLAN_CM_SM_EV_CONNECT_SUCCESS: 263 cm_connect_complete(cm_ctx, data); 264 event_handled = true; 265 break; 266 case WLAN_CM_SM_EV_DISCONNECT_REQ: 267 status = cm_add_disconnect_req_to_list(cm_ctx, data); 268 if (QDF_IS_STATUS_ERROR(status)) { 269 /* if fail to add req return failure */ 270 event_handled = false; 271 break; 272 } 273 cm_sm_transition_to(cm_ctx, WLAN_CM_S_DISCONNECTING); 274 cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_DISCONNECT_START, 275 data_len, data); 276 event_handled = true; 277 break; 278 default: 279 event_handled = false; 280 break; 281 } 282 283 return event_handled; 284 } 285 286 /** 287 * cm_state_disconnecting_entry() - Entry API for disconnecting state for 288 * connection mgr 289 * @ctx: connection manager ctx 290 * 291 * API to perform operations on moving to disconnecting state 292 * 293 * Return: void 294 */ 295 static void cm_state_disconnecting_entry(void *ctx) 296 { 297 struct cnx_mgr *cm_ctx = ctx; 298 299 cm_sm_state_update(cm_ctx, WLAN_CM_S_DISCONNECTING, WLAN_CM_SS_IDLE); 300 } 301 302 /** 303 * cm_state_disconnecting_exit() - Exit API for disconnecting state for 304 * connection mgr 305 * @ctx: connection manager ctx 306 * 307 * API to perform operations on exiting from disconnecting state 308 * 309 * Return: void 310 */ 311 static void cm_state_disconnecting_exit(void *ctx) 312 { 313 } 314 315 /** 316 * cm_state_connected_event() - Disconnecting State event handler for 317 * connection mgr 318 * @ctx: connection manager ctx 319 * 320 * API to handle events in Disconnecting state 321 * 322 * Return: bool 323 */ 324 static bool cm_state_disconnecting_event(void *ctx, uint16_t event, 325 uint16_t data_len, void *data) 326 { 327 struct cnx_mgr *cm_ctx = ctx; 328 bool event_handled; 329 QDF_STATUS status; 330 331 switch (event) { 332 case WLAN_CM_SM_EV_CONNECT_REQ: 333 status = cm_handle_connect_req_in_non_init_state(cm_ctx, data, 334 WLAN_CM_S_DISCONNECTING); 335 if (QDF_IS_STATUS_ERROR(status)) { 336 event_handled = false; 337 break; 338 } 339 cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTING); 340 cm_sm_deliver_event_sync(cm_ctx, 341 WLAN_CM_SM_EV_CONNECT_START, 342 data_len, data); 343 event_handled = true; 344 break; 345 case WLAN_CM_SM_EV_DISCONNECT_START: 346 cm_disconnect_start(cm_ctx, data); 347 event_handled = true; 348 break; 349 case WLAN_CM_SM_EV_DISCONNECT_ACTIVE: 350 cm_disconnect_active(cm_ctx, data); 351 event_handled = true; 352 break; 353 case WLAN_CM_SM_EV_DISCONNECT_DONE: 354 cm_sm_transition_to(cm_ctx, WLAN_CM_S_INIT); 355 cm_sm_deliver_event_sync(cm_ctx, event, data_len, data); 356 event_handled = true; 357 break; 358 case WLAN_CM_SM_EV_DISCONNECT_REQ: 359 status = cm_handle_discon_req_in_non_connected_state(cm_ctx, 360 data, WLAN_CM_S_DISCONNECTING); 361 if (QDF_IS_STATUS_ERROR(status)) { 362 event_handled = false; 363 break; 364 } 365 cm_sm_deliver_event_sync(cm_ctx, 366 WLAN_CM_SM_EV_DISCONNECT_START, 367 data_len, data); 368 event_handled = true; 369 break; 370 default: 371 event_handled = false; 372 break; 373 } 374 375 return event_handled; 376 } 377 378 /** 379 * cm_subst_join_pending_entry() - Entry API for join pending sub-state for 380 * connection mgr 381 * @ctx: connection manager ctx 382 * 383 * API to perform operations on moving to join pending sub-state 384 * 385 * Return: void 386 */ 387 static void cm_subst_join_pending_entry(void *ctx) 388 { 389 struct cnx_mgr *cm_ctx = ctx; 390 391 if (cm_get_state(cm_ctx) != WLAN_CM_S_CONNECTING) 392 QDF_BUG(0); 393 394 cm_set_substate(cm_ctx, WLAN_CM_SS_JOIN_PENDING); 395 } 396 397 /** 398 * cm_subst_join_pending_exit() - Exit API for join pending sub-state for 399 * connection mgr 400 * @ctx: connection manager ctx 401 * 402 * API to perform operations on exiting from join pending sub-state 403 * 404 * Return: void 405 */ 406 static void cm_subst_join_pending_exit(void *ctx) 407 { 408 } 409 410 /** 411 * cm_subst_join_pending_event() - Join pending sub-state event handler for 412 * connection mgr 413 * @ctx: connection manager ctx 414 * 415 * API to handle events in Join pending sub-state 416 * 417 * Return: bool 418 */ 419 static bool cm_subst_join_pending_event(void *ctx, uint16_t event, 420 uint16_t data_len, void *data) 421 { 422 struct cnx_mgr *cm_ctx = ctx; 423 bool event_handled; 424 QDF_STATUS status = QDF_STATUS_SUCCESS; 425 struct wlan_cm_connect_resp *resp; 426 struct cm_req *cm_req; 427 428 switch (event) { 429 case WLAN_CM_SM_EV_CONNECT_REQ: 430 status = 431 cm_handle_connect_req_in_non_init_state(cm_ctx, data, 432 WLAN_CM_SS_JOIN_PENDING); 433 if (QDF_IS_STATUS_ERROR(status)) { 434 event_handled = false; 435 break; 436 } 437 cm_sm_deliver_event_sync(cm_ctx, 438 WLAN_CM_SM_EV_CONNECT_START, 439 data_len, data); 440 event_handled = true; 441 break; 442 case WLAN_CM_SM_EV_CONNECT_START: 443 cm_connect_start(cm_ctx, data); 444 event_handled = true; 445 break; 446 case WLAN_CM_SM_EV_CONNECT_ACTIVE: 447 /* check if cm id is valid for the current req */ 448 if (!cm_check_cmid_match_list_head(cm_ctx, data)) { 449 event_handled = false; 450 break; 451 } 452 cm_sm_transition_to(cm_ctx, WLAN_CM_SS_JOIN_ACTIVE); 453 cm_sm_deliver_event_sync(cm_ctx, event, data_len, data); 454 event_handled = true; 455 break; 456 case WLAN_CM_SM_EV_HW_MODE_SUCCESS: 457 case WLAN_CM_SM_EV_HW_MODE_FAILURE: 458 /* check if cm id is valid for the current req */ 459 if (!cm_check_cmid_match_list_head(cm_ctx, data)) { 460 event_handled = false; 461 break; 462 } 463 cm_handle_hw_mode_change(cm_ctx, data, event); 464 event_handled = true; 465 break; 466 case WLAN_CM_SM_EV_SCAN: 467 cm_sm_transition_to(cm_ctx, WLAN_CM_SS_SCAN); 468 cm_sm_deliver_event_sync(cm_ctx, event, data_len, data); 469 event_handled = true; 470 break; 471 case WLAN_CM_SM_EV_SCAN_FAILURE: 472 status = QDF_STATUS_E_FAILURE; 473 /* Fall through after setting status failure */ 474 /* fallthrough */ 475 case WLAN_CM_SM_EV_SCAN_SUCCESS: 476 cm_connect_scan_resp(cm_ctx, data, status); 477 event_handled = true; 478 break; 479 case WLAN_CM_SM_EV_CONNECT_FAILURE: 480 /* check if connect resp cm id is valid for the current req */ 481 if (!cm_connect_resp_cmid_match_list_head(cm_ctx, data)) { 482 event_handled = false; 483 break; 484 } 485 /* 486 * On connect req failure (before serialization), if there is a 487 * pending disconnect req then move to disconnecting state and 488 * wait for disconnect to complete before moving to INIT state. 489 * Else directly transition to INIT state. 490 * 491 * On disconnect completion or a new connect/disconnect req in 492 * disconnnecting state, the failed connect req will be flushed. 493 * This will ensure SM moves to INIT state after completion of 494 * all operation. 495 */ 496 if (cm_ctx->disconnect_count) { 497 resp = data; 498 499 mlme_debug(CM_PREFIX_FMT "disconnect_count %d", 500 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 501 resp->cm_id), 502 cm_ctx->disconnect_count); 503 cm_req = cm_get_req_by_cm_id(cm_ctx, resp->cm_id); 504 cm_req->failed_req = true; 505 cm_sm_transition_to(cm_ctx, WLAN_CM_S_DISCONNECTING); 506 event_handled = true; 507 break; 508 } 509 cm_sm_transition_to(cm_ctx, WLAN_CM_S_INIT); 510 cm_sm_deliver_event_sync(cm_ctx, event, data_len, data); 511 event_handled = true; 512 break; 513 case WLAN_CM_SM_EV_DISCONNECT_ACTIVE: 514 cm_disconnect_active(cm_ctx, data); 515 event_handled = true; 516 break; 517 case WLAN_CM_SM_EV_DISCONNECT_DONE: 518 cm_disconnect_complete(cm_ctx, data); 519 event_handled = true; 520 break; 521 case WLAN_CM_SM_EV_DISCONNECT_REQ: 522 status = cm_handle_discon_req_in_non_connected_state(cm_ctx, 523 data, WLAN_CM_SS_JOIN_PENDING); 524 if (QDF_IS_STATUS_ERROR(status)) { 525 event_handled = false; 526 break; 527 } 528 cm_sm_transition_to(cm_ctx, WLAN_CM_S_DISCONNECTING); 529 cm_sm_deliver_event_sync(cm_ctx, 530 WLAN_CM_SM_EV_DISCONNECT_START, 531 data_len, data); 532 event_handled = true; 533 break; 534 default: 535 event_handled = false; 536 break; 537 } 538 539 return event_handled; 540 } 541 542 /** 543 * cm_subst_scan_entry() - Entry API for scan sub-state for 544 * connection mgr 545 * @ctx: connection manager ctx 546 * 547 * API to perform operations on moving to scan sub-state 548 * 549 * Return: void 550 */ 551 static void cm_subst_scan_entry(void *ctx) 552 { 553 struct cnx_mgr *cm_ctx = ctx; 554 555 if (cm_get_state(cm_ctx) != WLAN_CM_S_CONNECTING) 556 QDF_BUG(0); 557 558 cm_set_substate(cm_ctx, WLAN_CM_SS_SCAN); 559 } 560 561 /** 562 * cm_subst_scan_exit() - Exit API for scan sub-state for 563 * connection mgr 564 * @ctx: connection manager ctx 565 * 566 * API to perform operations on exiting from scan sub-state 567 * 568 * Return: void 569 */ 570 static void cm_subst_scan_exit(void *ctx) 571 { 572 } 573 574 /** 575 * cm_subst_scan_event() - Scan sub-state event handler for 576 * connection mgr 577 * @ctx: connection manager ctx 578 * 579 * API to handle events in scan sub-state 580 * 581 * Return: bool 582 */ 583 static bool cm_subst_scan_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; 588 QDF_STATUS status; 589 590 switch (event) { 591 case WLAN_CM_SM_EV_CONNECT_REQ: 592 status = cm_handle_connect_req_in_non_init_state(cm_ctx, data, 593 WLAN_CM_SS_SCAN); 594 if (QDF_IS_STATUS_ERROR(status)) { 595 event_handled = false; 596 break; 597 } 598 cm_sm_transition_to(cm_ctx, WLAN_CM_SS_JOIN_PENDING); 599 cm_sm_deliver_event_sync(cm_ctx, 600 WLAN_CM_SM_EV_CONNECT_START, 601 data_len, data); 602 event_handled = true; 603 break; 604 case WLAN_CM_SM_EV_SCAN: 605 cm_connect_scan_start(cm_ctx, data); 606 event_handled = true; 607 break; 608 case WLAN_CM_SM_EV_SCAN_SUCCESS: 609 case WLAN_CM_SM_EV_SCAN_FAILURE: 610 /* check if scan id is valid for the current req */ 611 if (!cm_check_scanid_match_list_head(cm_ctx, data)) { 612 event_handled = false; 613 break; 614 } 615 cm_sm_transition_to(cm_ctx, WLAN_CM_SS_JOIN_PENDING); 616 cm_sm_deliver_event_sync(cm_ctx, event, data_len, data); 617 event_handled = true; 618 break; 619 case WLAN_CM_SM_EV_DISCONNECT_ACTIVE: 620 cm_disconnect_active(cm_ctx, data); 621 event_handled = true; 622 break; 623 case WLAN_CM_SM_EV_DISCONNECT_DONE: 624 cm_disconnect_complete(cm_ctx, data); 625 event_handled = true; 626 break; 627 case WLAN_CM_SM_EV_DISCONNECT_REQ: 628 status = cm_handle_discon_req_in_non_connected_state(cm_ctx, 629 data, WLAN_CM_SS_SCAN); 630 if (QDF_IS_STATUS_ERROR(status)) { 631 event_handled = false; 632 break; 633 } 634 cm_sm_transition_to(cm_ctx, WLAN_CM_S_DISCONNECTING); 635 cm_sm_deliver_event_sync(cm_ctx, 636 WLAN_CM_SM_EV_DISCONNECT_START, 637 data_len, data); 638 event_handled = true; 639 break; 640 default: 641 event_handled = false; 642 break; 643 } 644 645 return event_handled; 646 } 647 648 /** 649 * cm_subst_join_active_entry() - Entry API for join active sub-state for 650 * connection mgr 651 * @ctx: connection manager ctx 652 * 653 * API to perform operations on moving to join active sub-state 654 * 655 * Return: void 656 */ 657 static void cm_subst_join_active_entry(void *ctx) 658 { 659 struct cnx_mgr *cm_ctx = ctx; 660 661 if (cm_get_state(cm_ctx) != WLAN_CM_S_CONNECTING) 662 QDF_BUG(0); 663 664 cm_set_substate(cm_ctx, WLAN_CM_SS_JOIN_ACTIVE); 665 } 666 667 /** 668 * cm_subst_join_active_exit() - Exit API for join active sub-state for 669 * connection mgr 670 * @ctx: connection manager ctx 671 * 672 * API to perform operations on exiting from join active sub-state 673 * 674 * Return: void 675 */ 676 static void cm_subst_join_active_exit(void *ctx) 677 { 678 } 679 680 /** 681 * cm_subst_join_active_event() - Join active sub-state event handler for 682 * connection mgr 683 * @ctx: connection manager ctx 684 * 685 * API to handle events in join active sub-state 686 * 687 * Return: bool 688 */ 689 static bool cm_subst_join_active_event(void *ctx, uint16_t event, 690 uint16_t data_len, void *data) 691 { 692 struct cnx_mgr *cm_ctx = ctx; 693 bool event_handled; 694 QDF_STATUS status; 695 696 switch (event) { 697 case WLAN_CM_SM_EV_CONNECT_REQ: 698 status = cm_handle_connect_req_in_non_init_state(cm_ctx, data, 699 WLAN_CM_SS_JOIN_ACTIVE); 700 if (QDF_IS_STATUS_ERROR(status)) { 701 event_handled = false; 702 break; 703 } 704 cm_sm_transition_to(cm_ctx, WLAN_CM_SS_JOIN_PENDING); 705 cm_sm_deliver_event_sync(cm_ctx, 706 WLAN_CM_SM_EV_CONNECT_START, 707 data_len, data); 708 event_handled = true; 709 break; 710 case WLAN_CM_SM_EV_CONNECT_ACTIVE: 711 cm_connect_active(cm_ctx, data); 712 event_handled = true; 713 break; 714 case WLAN_CM_SM_EV_CONNECT_SUCCESS: 715 /* check if connect resp cm id is valid for the current req */ 716 if (!cm_connect_resp_cmid_match_list_head(cm_ctx, data)) { 717 event_handled = false; 718 break; 719 } 720 cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED); 721 cm_sm_deliver_event_sync(cm_ctx, event, data_len, data); 722 event_handled = true; 723 break; 724 case WLAN_CM_SM_EV_CONNECT_GET_NEXT_CANDIDATE: 725 /* check if connect resp cm id is valid for the current req */ 726 if (!cm_connect_resp_cmid_match_list_head(cm_ctx, data)) { 727 event_handled = false; 728 break; 729 } 730 cm_try_next_candidate(cm_ctx, data); 731 event_handled = true; 732 break; 733 case WLAN_CM_SM_EV_CONNECT_FAILURE: 734 /* check if connect resp cm id is valid for the current req */ 735 if (!cm_connect_resp_cmid_match_list_head(cm_ctx, data)) { 736 event_handled = false; 737 break; 738 } 739 cm_sm_transition_to(cm_ctx, WLAN_CM_S_INIT); 740 cm_sm_deliver_event_sync(cm_ctx, event, data_len, data); 741 event_handled = true; 742 break; 743 case WLAN_CM_SM_EV_BSS_SELECT_IND_SUCCESS: 744 /* check if cm id is valid for the current req */ 745 if (!cm_check_cmid_match_list_head(cm_ctx, data)) { 746 event_handled = false; 747 break; 748 } 749 cm_peer_create_on_bss_select_ind_resp(cm_ctx, data); 750 event_handled = true; 751 break; 752 case WLAN_CM_SM_EV_BSS_CREATE_PEER_SUCCESS: 753 /* check if cm id is valid for the current req */ 754 if (!cm_check_cmid_match_list_head(cm_ctx, data)) { 755 event_handled = false; 756 break; 757 } 758 cm_resume_connect_after_peer_create(cm_ctx, data); 759 event_handled = true; 760 break; 761 case WLAN_CM_SM_EV_DISCONNECT_REQ: 762 status = cm_handle_discon_req_in_non_connected_state(cm_ctx, 763 data, WLAN_CM_SS_JOIN_ACTIVE); 764 if (QDF_IS_STATUS_ERROR(status)) { 765 event_handled = false; 766 break; 767 } 768 cm_sm_transition_to(cm_ctx, WLAN_CM_S_DISCONNECTING); 769 cm_sm_deliver_event_sync(cm_ctx, 770 WLAN_CM_SM_EV_DISCONNECT_START, 771 data_len, data); 772 event_handled = true; 773 break; 774 default: 775 event_handled = false; 776 break; 777 } 778 779 return event_handled; 780 } 781 782 struct wlan_sm_state_info cm_sm_info[] = { 783 { 784 (uint8_t)WLAN_CM_S_INIT, 785 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 786 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 787 true, 788 "INIT", 789 cm_state_init_entry, 790 cm_state_init_exit, 791 cm_state_init_event 792 }, 793 { 794 (uint8_t)WLAN_CM_S_CONNECTING, 795 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 796 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 797 true, 798 "CONNECTING", 799 cm_state_connecting_entry, 800 cm_state_connecting_exit, 801 cm_state_connecting_event 802 }, 803 { 804 (uint8_t)WLAN_CM_S_CONNECTED, 805 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 806 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 807 true, 808 "CONNECTED", 809 cm_state_connected_entry, 810 cm_state_connected_exit, 811 cm_state_connected_event 812 }, 813 { 814 (uint8_t)WLAN_CM_S_DISCONNECTING, 815 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 816 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 817 true, 818 "DISCONNECTING", 819 cm_state_disconnecting_entry, 820 cm_state_disconnecting_exit, 821 cm_state_disconnecting_event 822 }, 823 { 824 (uint8_t)WLAN_CM_S_ROAMING, 825 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 826 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 827 true, 828 "ROAMING", 829 cm_state_roaming_entry, 830 cm_state_roaming_exit, 831 cm_state_roaming_event 832 }, 833 { 834 (uint8_t)WLAN_CM_S_MAX, 835 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 836 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 837 false, 838 "INVALID", 839 NULL, 840 NULL, 841 NULL 842 }, 843 { 844 (uint8_t)WLAN_CM_SS_IDLE, 845 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 846 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 847 false, 848 "IDLE", 849 NULL, 850 NULL, 851 NULL 852 }, 853 { 854 (uint8_t)WLAN_CM_SS_JOIN_PENDING, 855 (uint8_t)WLAN_CM_S_CONNECTING, 856 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 857 false, 858 "JOIN_PENDING", 859 cm_subst_join_pending_entry, 860 cm_subst_join_pending_exit, 861 cm_subst_join_pending_event 862 }, 863 { 864 (uint8_t)WLAN_CM_SS_SCAN, 865 (uint8_t)WLAN_CM_S_CONNECTING, 866 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 867 false, 868 "SCAN", 869 cm_subst_scan_entry, 870 cm_subst_scan_exit, 871 cm_subst_scan_event 872 }, 873 { 874 (uint8_t)WLAN_CM_SS_JOIN_ACTIVE, 875 (uint8_t)WLAN_CM_S_CONNECTING, 876 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 877 false, 878 "JOIN_ACTIVE", 879 cm_subst_join_active_entry, 880 cm_subst_join_active_exit, 881 cm_subst_join_active_event 882 }, 883 { 884 (uint8_t)WLAN_CM_SS_PREAUTH, 885 (uint8_t)WLAN_CM_S_ROAMING, 886 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 887 false, 888 "PREAUTH", 889 cm_subst_preauth_entry, 890 cm_subst_preauth_exit, 891 cm_subst_preauth_event 892 }, 893 { 894 (uint8_t)WLAN_CM_SS_REASSOC, 895 (uint8_t)WLAN_CM_S_ROAMING, 896 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 897 false, 898 "REASSOC", 899 cm_subst_reassoc_entry, 900 cm_subst_reassoc_exit, 901 cm_subst_reassoc_event 902 }, 903 { 904 (uint8_t)WLAN_CM_SS_ROAM_STARTED, 905 (uint8_t)WLAN_CM_S_ROAMING, 906 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 907 false, 908 "ROAM_START", 909 cm_subst_roam_start_entry, 910 cm_subst_roam_start_exit, 911 cm_subst_roam_start_event 912 }, 913 { 914 (uint8_t)WLAN_CM_SS_ROAM_SYNC, 915 (uint8_t)WLAN_CM_S_ROAMING, 916 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 917 false, 918 "ROAM_SYNC", 919 cm_subst_roam_sync_entry, 920 cm_subst_roam_sync_exit, 921 cm_subst_roam_sync_event 922 }, 923 { 924 (uint8_t)WLAN_CM_SS_MAX, 925 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 926 (uint8_t)WLAN_SM_ENGINE_STATE_NONE, 927 false, 928 "INVALID", 929 NULL, 930 NULL, 931 NULL 932 }, 933 }; 934 935 static const char *cm_sm_event_names[] = { 936 "EV_CONNECT_REQ", 937 "EV_SCAN", 938 "EV_SCAN_SUCCESS", 939 "EV_SCAN_FAILURE", 940 "EV_HW_MODE_SUCCESS", 941 "EV_HW_MODE_FAILURE", 942 "EV_CONNECT_START", 943 "EV_CONNECT_ACTIVE", 944 "EV_CONNECT_SUCCESS", 945 "EV_BSS_SELECT_IND_SUCCESS", 946 "EV_BSS_CREATE_PEER_SUCCESS", 947 "EV_CONNECT_GET_NXT_CANDIDATE", 948 "EV_CONNECT_FAILURE", 949 "EV_DISCONNECT_REQ", 950 "EV_DISCONNECT_START", 951 "EV_DISCONNECT_ACTIVE", 952 "EV_DISCONNECT_DONE", 953 "EV_ROAM_START", 954 "EV_ROAM_SYNC", 955 "EV_ROAM_INVOKE_FAIL", 956 "EV_ROAM_HO_FAIL", 957 "EV_PREAUTH_DONE", 958 "EV_GET_NEXT_PREAUTH_AP", 959 "EV_PREAUTH_FAIL", 960 "EV_START_REASSOC", 961 "EV_REASSOC_DONE", 962 "EV_REASSOC_FAILURE", 963 "EV_ROAM_COMPLETE", 964 }; 965 966 enum wlan_cm_sm_state cm_get_state(struct cnx_mgr *cm_ctx) 967 { 968 enum QDF_OPMODE op_mode; 969 970 if (!cm_ctx || !cm_ctx->vdev) 971 return WLAN_CM_S_MAX; 972 973 op_mode = wlan_vdev_mlme_get_opmode(cm_ctx->vdev); 974 975 if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE) 976 return WLAN_CM_S_MAX; 977 978 return cm_ctx->sm.cm_state; 979 } 980 981 enum wlan_cm_sm_state cm_get_sub_state(struct cnx_mgr *cm_ctx) 982 { 983 enum QDF_OPMODE op_mode; 984 985 if (!cm_ctx || !cm_ctx->vdev) 986 return WLAN_CM_SS_MAX; 987 988 op_mode = wlan_vdev_mlme_get_opmode(cm_ctx->vdev); 989 990 if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE) 991 return WLAN_CM_SS_MAX; 992 993 return cm_ctx->sm.cm_substate; 994 } 995 996 static void cm_sm_print_state_event(struct cnx_mgr *cm_ctx, 997 enum wlan_cm_sm_evt event) 998 { 999 enum wlan_cm_sm_state state; 1000 enum wlan_cm_sm_state substate; 1001 1002 state = cm_get_state(cm_ctx); 1003 substate = cm_get_sub_state(cm_ctx); 1004 1005 mlme_nofl_debug("[%s]%s - %s, %s", cm_ctx->sm.sm_hdl->name, 1006 cm_sm_info[state].name, cm_sm_info[substate].name, 1007 cm_sm_event_names[event]); 1008 } 1009 1010 static void cm_sm_print_state(struct cnx_mgr *cm_ctx) 1011 { 1012 enum wlan_cm_sm_state state; 1013 enum wlan_cm_sm_state substate; 1014 1015 state = cm_get_state(cm_ctx); 1016 substate = cm_get_sub_state(cm_ctx); 1017 1018 mlme_nofl_debug("[%s]%s - %s", cm_ctx->sm.sm_hdl->name, 1019 cm_sm_info[state].name, cm_sm_info[substate].name); 1020 } 1021 1022 QDF_STATUS cm_sm_deliver_event(struct wlan_objmgr_vdev *vdev, 1023 enum wlan_cm_sm_evt event, 1024 uint16_t data_len, void *data) 1025 { 1026 QDF_STATUS status; 1027 enum wlan_cm_sm_state state_entry, state_exit; 1028 enum wlan_cm_sm_state substate_entry, substate_exit; 1029 enum QDF_OPMODE op_mode = wlan_vdev_mlme_get_opmode(vdev); 1030 struct cnx_mgr *cm_ctx; 1031 1032 if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE) { 1033 mlme_err("vdev %d Invalid mode %d", 1034 wlan_vdev_get_id(vdev), op_mode); 1035 return QDF_STATUS_E_NOSUPPORT; 1036 } 1037 1038 cm_ctx = cm_get_cm_ctx(vdev); 1039 if (!cm_ctx) 1040 return QDF_STATUS_E_FAILURE; 1041 1042 cm_lock_acquire(cm_ctx); 1043 1044 /* store entry state and sub state for prints */ 1045 state_entry = cm_get_state(cm_ctx); 1046 substate_entry = cm_get_sub_state(cm_ctx); 1047 cm_sm_print_state_event(cm_ctx, event); 1048 1049 status = cm_sm_deliver_event_sync(cm_ctx, event, data_len, data); 1050 /* Take exit state, exit substate for prints */ 1051 state_exit = cm_get_state(cm_ctx); 1052 substate_exit = cm_get_sub_state(cm_ctx); 1053 /* If no state and substate change, don't print */ 1054 if (!((state_entry == state_exit) && (substate_entry == substate_exit))) 1055 cm_sm_print_state(cm_ctx); 1056 cm_lock_release(cm_ctx); 1057 1058 return status; 1059 } 1060 1061 QDF_STATUS cm_sm_create(struct cnx_mgr *cm_ctx) 1062 { 1063 struct wlan_sm *sm; 1064 uint8_t name[WLAN_SM_ENGINE_MAX_NAME]; 1065 1066 qdf_scnprintf(name, sizeof(name), "CM-VDEV-%d", 1067 wlan_vdev_get_id(cm_ctx->vdev)); 1068 sm = wlan_sm_create(name, cm_ctx, 1069 WLAN_CM_S_INIT, 1070 cm_sm_info, 1071 QDF_ARRAY_SIZE(cm_sm_info), 1072 cm_sm_event_names, 1073 QDF_ARRAY_SIZE(cm_sm_event_names)); 1074 if (!sm) { 1075 mlme_err("vdev %d CM State Machine allocation failed", 1076 wlan_vdev_get_id(cm_ctx->vdev)); 1077 return QDF_STATUS_E_NOMEM; 1078 } 1079 cm_ctx->sm.sm_hdl = sm; 1080 1081 cm_lock_create(cm_ctx); 1082 1083 return QDF_STATUS_SUCCESS; 1084 } 1085 1086 QDF_STATUS cm_sm_destroy(struct cnx_mgr *cm_ctx) 1087 { 1088 cm_lock_destroy(cm_ctx); 1089 wlan_sm_delete(cm_ctx->sm.sm_hdl); 1090 1091 return QDF_STATUS_SUCCESS; 1092 } 1093 1094 #ifdef SM_ENG_HIST_ENABLE 1095 void cm_sm_history_print(struct wlan_objmgr_vdev *vdev) 1096 { 1097 struct cnx_mgr *cm_ctx; 1098 1099 cm_ctx = cm_get_cm_ctx(vdev); 1100 if (!cm_ctx) { 1101 mlme_err("cm_ctx is NULL"); 1102 return; 1103 } 1104 1105 return wlan_sm_print_history(cm_ctx->sm.sm_hdl); 1106 } 1107 #endif 1108