1 /* 2 * Copyright (c) 2012-2015,2020-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2022 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 roaming sm 20 */ 21 22 #include "wlan_cm_main.h" 23 #include "wlan_cm_roam_sm.h" 24 #include "wlan_cm_sm.h" 25 #include "wlan_cm_main_api.h" 26 #include "wlan_cm_roam.h" 27 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 28 #include "wlan_mlo_mgr_roam.h" 29 #endif 30 31 #if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) 32 void cm_state_roaming_entry(void *ctx) 33 { 34 struct cnx_mgr *cm_ctx = ctx; 35 36 cm_sm_state_update(cm_ctx, WLAN_CM_S_ROAMING, WLAN_CM_SS_IDLE); 37 } 38 39 void cm_state_roaming_exit(void *ctx) 40 { 41 } 42 43 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 44 static 45 bool cm_handle_fw_roaming_event(struct cnx_mgr *cm_ctx, uint16_t event, 46 uint16_t data_len, void *data) 47 { 48 bool event_handled = true; 49 QDF_STATUS status; 50 51 switch (event) { 52 case WLAN_CM_SM_EV_ROAM_INVOKE: 53 status = cm_add_fw_roam_cmd_to_list_n_ser(cm_ctx, data); 54 if (QDF_IS_STATUS_ERROR(status)) { 55 event_handled = false; 56 break; 57 } 58 cm_sm_transition_to(cm_ctx, WLAN_CM_SS_ROAM_STARTED); 59 cm_sm_deliver_event_sync(cm_ctx, 60 WLAN_CM_SM_EV_ROAM_INVOKE, 61 data_len, data); 62 break; 63 case WLAN_CM_SM_EV_ROAM_START: 64 status = cm_add_fw_roam_cmd_to_list_n_ser(cm_ctx, data); 65 if (QDF_IS_STATUS_ERROR(status)) { 66 event_handled = false; 67 break; 68 } 69 cm_sm_transition_to(cm_ctx, WLAN_CM_SS_ROAM_STARTED); 70 cm_sm_deliver_event_sync(cm_ctx, 71 WLAN_CM_SM_EV_ROAM_START, 72 0, NULL); 73 break; 74 case WLAN_CM_SM_EV_ROAM_ABORT: 75 cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED); 76 cm_sm_deliver_event_sync(cm_ctx, event, 77 data_len, data); 78 break; 79 case WLAN_CM_SM_EV_ROAM_SYNC: 80 cm_sm_transition_to(cm_ctx, WLAN_CM_SS_ROAM_SYNC); 81 cm_sm_deliver_event_sync(cm_ctx, event, 82 data_len, data); 83 break; 84 default: 85 event_handled = false; 86 break; 87 } 88 89 return event_handled; 90 } 91 #else 92 static inline 93 bool cm_handle_fw_roaming_event(struct cnx_mgr *cm_ctx, uint16_t event, 94 uint16_t data_len, void *data) 95 { 96 return false; 97 } 98 #endif 99 100 bool cm_state_roaming_event(void *ctx, uint16_t event, 101 uint16_t data_len, void *data) 102 { 103 struct cnx_mgr *cm_ctx = ctx; 104 bool event_handled = true; 105 struct wlan_objmgr_psoc *psoc; 106 107 switch (event) { 108 case WLAN_CM_SM_EV_ROAM_REQ: 109 psoc = wlan_vdev_get_psoc(cm_ctx->vdev); 110 if (!psoc) { 111 event_handled = false; 112 break; 113 } 114 if (cm_roam_offload_enabled(psoc)) { 115 cm_sm_deliver_event_sync(cm_ctx, 116 WLAN_CM_SM_EV_ROAM_INVOKE, 117 data_len, data); 118 } else { 119 cm_add_roam_req_to_list(cm_ctx, data); 120 cm_sm_transition_to(cm_ctx, WLAN_CM_SS_PREAUTH); 121 cm_sm_deliver_event_sync(cm_ctx, 122 WLAN_CM_SM_EV_ROAM_START, 123 data_len, data); 124 } 125 break; 126 default: 127 event_handled = cm_handle_fw_roaming_event(cm_ctx, event, 128 data_len, data); 129 break; 130 } 131 132 return event_handled; 133 } 134 135 static bool cm_handle_connect_disconnect_in_roam(struct cnx_mgr *cm_ctx, 136 uint16_t event, 137 uint16_t data_len, void *data) 138 { 139 QDF_STATUS status; 140 141 switch (event) { 142 case WLAN_CM_SM_EV_CONNECT_REQ: 143 status = cm_handle_connect_req_in_non_init_state(cm_ctx, data, 144 WLAN_CM_S_ROAMING); 145 if (QDF_IS_STATUS_ERROR(status)) 146 return false; 147 cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTING); 148 cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_CONNECT_START, 149 data_len, data); 150 break; 151 case WLAN_CM_SM_EV_DISCONNECT_REQ: 152 status = cm_handle_discon_req_in_non_connected_state(cm_ctx, 153 data, WLAN_CM_S_ROAMING); 154 if (QDF_IS_STATUS_ERROR(status)) 155 return false; 156 cm_sm_transition_to(cm_ctx, WLAN_CM_S_DISCONNECTING); 157 cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_DISCONNECT_START, 158 data_len, data); 159 break; 160 case WLAN_CM_SM_EV_DISCONNECT_ACTIVE: 161 cm_disconnect_active(cm_ctx, data); 162 break; 163 default: 164 return false; 165 break; 166 } 167 168 return true; 169 } 170 #endif 171 172 #ifdef WLAN_FEATURE_HOST_ROAM 173 void cm_subst_preauth_entry(void *ctx) 174 { 175 struct cnx_mgr *cm_ctx = ctx; 176 177 if (cm_get_state(cm_ctx) != WLAN_CM_S_ROAMING) 178 QDF_BUG(0); 179 180 cm_set_substate(cm_ctx, WLAN_CM_SS_PREAUTH); 181 /* set preauth to true when we enter preauth state */ 182 cm_ctx->preauth_in_progress = true; 183 } 184 185 void cm_subst_preauth_exit(void *ctx) 186 { 187 } 188 189 #ifdef WLAN_FEATURE_PREAUTH_ENABLE 190 static bool 191 cm_handle_preauth_event(struct cnx_mgr *cm_ctx, uint16_t event, 192 uint16_t data_len, void *data) 193 { 194 bool event_handled = true; 195 196 switch (event) { 197 case WLAN_CM_SM_EV_PREAUTH_ACTIVE: 198 if (!cm_check_cmid_match_list_head(cm_ctx, data)) { 199 event_handled = false; 200 break; 201 } 202 cm_preauth_active(cm_ctx, data); 203 break; 204 case WLAN_CM_SM_EV_PREAUTH_RESP: 205 cm_preauth_done_resp(cm_ctx, data); 206 break; 207 case WLAN_CM_SM_EV_PREAUTH_DONE: 208 cm_sm_transition_to(cm_ctx, WLAN_CM_SS_REASSOC); 209 cm_preauth_success(cm_ctx, data); 210 break; 211 case WLAN_CM_SM_EV_PREAUTH_FAIL: 212 cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED); 213 cm_preauth_fail(cm_ctx, data); 214 break; 215 default: 216 event_handled = false; 217 } 218 219 return event_handled; 220 } 221 #else 222 static inline bool 223 cm_handle_preauth_event(struct cnx_mgr *cm_ctx, uint16_t event, 224 uint16_t data_len, void *data) 225 { 226 return false; 227 } 228 #endif 229 230 bool cm_subst_preauth_event(void *ctx, uint16_t event, 231 uint16_t data_len, void *data) 232 { 233 struct cnx_mgr *cm_ctx = ctx; 234 bool event_handled = true; 235 236 switch (event) { 237 case WLAN_CM_SM_EV_CONNECT_REQ: 238 case WLAN_CM_SM_EV_DISCONNECT_REQ: 239 case WLAN_CM_SM_EV_DISCONNECT_ACTIVE: 240 event_handled = 241 cm_handle_connect_disconnect_in_roam(cm_ctx, event, 242 data_len, data); 243 break; 244 case WLAN_CM_SM_EV_ROAM_START: 245 cm_host_roam_start_req(cm_ctx, data); 246 break; 247 case WLAN_CM_SM_EV_START_REASSOC: 248 cm_sm_transition_to(cm_ctx, WLAN_CM_SS_REASSOC); 249 cm_sm_deliver_event_sync(cm_ctx, event, data_len, data); 250 break; 251 case WLAN_CM_SM_EV_REASSOC_FAILURE: 252 cm_reassoc_complete(cm_ctx, data); 253 break; 254 default: 255 event_handled = cm_handle_preauth_event(cm_ctx, event, 256 data_len, data); 257 break; 258 } 259 260 return event_handled; 261 } 262 263 void cm_subst_reassoc_entry(void *ctx) 264 { 265 struct cnx_mgr *cm_ctx = ctx; 266 267 if (cm_get_state(cm_ctx) != WLAN_CM_S_ROAMING) 268 QDF_BUG(0); 269 270 cm_set_substate(cm_ctx, WLAN_CM_SS_REASSOC); 271 /* set preauth to false as soon as we move to reassoc state */ 272 cm_ctx->preauth_in_progress = false; 273 } 274 275 void cm_subst_reassoc_exit(void *ctx) 276 { 277 } 278 279 #ifdef WLAN_FEATURE_PREAUTH_ENABLE 280 static bool 281 cm_handle_reassoc_event(struct cnx_mgr *cm_ctx, uint16_t event, 282 uint16_t data_len, void *data) 283 { 284 bool event_handled = true; 285 QDF_STATUS status; 286 287 switch (event) { 288 case WLAN_CM_SM_EV_REASSOC_TIMER: 289 status = cm_handle_reassoc_timer(cm_ctx, data); 290 if (QDF_IS_STATUS_ERROR(status)) 291 event_handled = false; 292 break; 293 default: 294 event_handled = false; 295 } 296 297 return event_handled; 298 } 299 #else 300 static inline bool 301 cm_handle_reassoc_event(struct cnx_mgr *cm_ctx, uint16_t event, 302 uint16_t data_len, void *data) 303 { 304 return false; 305 } 306 #endif 307 308 bool cm_subst_reassoc_event(void *ctx, uint16_t event, 309 uint16_t data_len, void *data) 310 { 311 struct cnx_mgr *cm_ctx = ctx; 312 bool event_handled = true; 313 314 switch (event) { 315 case WLAN_CM_SM_EV_CONNECT_REQ: 316 case WLAN_CM_SM_EV_DISCONNECT_REQ: 317 case WLAN_CM_SM_EV_DISCONNECT_ACTIVE: 318 event_handled = 319 cm_handle_connect_disconnect_in_roam(cm_ctx, event, 320 data_len, data); 321 break; 322 case WLAN_CM_SM_EV_START_REASSOC: 323 cm_reassoc_start(cm_ctx, data); 324 break; 325 case WLAN_CM_SM_EV_REASSOC_ACTIVE: 326 if (!cm_check_cmid_match_list_head(cm_ctx, data)) { 327 event_handled = false; 328 break; 329 } 330 cm_reassoc_active(cm_ctx, data); 331 break; 332 case WLAN_CM_SM_EV_HO_ROAM_DISCONNECT_DONE: 333 cm_reassoc_disconnect_complete(cm_ctx, data); 334 break; 335 case WLAN_CM_SM_EV_BSS_CREATE_PEER_SUCCESS: 336 if (!cm_check_cmid_match_list_head(cm_ctx, data)) { 337 event_handled = false; 338 break; 339 } 340 cm_resume_reassoc_after_peer_create(cm_ctx, data); 341 break; 342 case WLAN_CM_SM_EV_REASSOC_DONE: 343 if (!cm_roam_resp_cmid_match_list_head(cm_ctx, data)) { 344 event_handled = false; 345 break; 346 } 347 cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED); 348 cm_sm_deliver_event_sync(cm_ctx, event, data_len, data); 349 break; 350 case WLAN_CM_SM_EV_REASSOC_FAILURE: 351 cm_reassoc_complete(cm_ctx, data); 352 break; 353 case WLAN_CM_SM_EV_HW_MODE_SUCCESS: 354 case WLAN_CM_SM_EV_HW_MODE_FAILURE: 355 /* check if cm id is valid for the current req */ 356 if (!cm_check_cmid_match_list_head(cm_ctx, data)) { 357 event_handled = false; 358 break; 359 } 360 cm_handle_reassoc_hw_mode_change(cm_ctx, data, event); 361 break; 362 default: 363 event_handled = cm_handle_reassoc_event(cm_ctx, event, 364 data_len, data); 365 break; 366 } 367 368 return event_handled; 369 } 370 371 #endif /* WLAN_FEATURE_HOST_ROAM */ 372 373 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 374 void cm_subst_roam_start_entry(void *ctx) 375 { 376 struct cnx_mgr *cm_ctx = ctx; 377 378 if (cm_get_state(cm_ctx) != WLAN_CM_S_ROAMING) 379 QDF_BUG(0); 380 381 cm_set_substate(cm_ctx, WLAN_CM_SS_ROAM_STARTED); 382 } 383 384 void cm_subst_roam_start_exit(void *ctx) 385 { 386 } 387 388 bool cm_subst_roam_start_event(void *ctx, uint16_t event, 389 uint16_t data_len, void *data) 390 { 391 bool event_handled = true; 392 struct cnx_mgr *cm_ctx = ctx; 393 394 switch (event) { 395 case WLAN_CM_SM_EV_CONNECT_REQ: 396 case WLAN_CM_SM_EV_DISCONNECT_REQ: 397 case WLAN_CM_SM_EV_DISCONNECT_ACTIVE: 398 event_handled = 399 cm_handle_connect_disconnect_in_roam(cm_ctx, event, 400 data_len, data); 401 break; 402 case WLAN_CM_SM_EV_ROAM_START: 403 cm_fw_roam_start(ctx); 404 break; 405 case WLAN_CM_SM_EV_ROAM_INVOKE: 406 cm_send_roam_invoke_req(cm_ctx, data); 407 break; 408 case WLAN_CM_SM_EV_ROAM_ABORT: 409 case WLAN_CM_SM_EV_ROAM_INVOKE_FAIL: 410 case WLAN_CM_SM_EV_ROAM_HO_FAIL: 411 cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED); 412 cm_sm_deliver_event_sync(cm_ctx, event, 413 data_len, data); 414 break; 415 case WLAN_CM_SM_EV_ROAM_SYNC: 416 cm_sm_transition_to(cm_ctx, WLAN_CM_SS_ROAM_SYNC); 417 cm_sm_deliver_event_sync(cm_ctx, event, 418 data_len, data); 419 break; 420 default: 421 event_handled = false; 422 break; 423 } 424 425 return event_handled; 426 } 427 428 void cm_subst_roam_sync_entry(void *ctx) 429 { 430 struct cnx_mgr *cm_ctx = ctx; 431 432 if (cm_get_state(cm_ctx) != WLAN_CM_S_ROAMING) 433 QDF_BUG(0); 434 435 cm_set_substate(cm_ctx, WLAN_CM_SS_ROAM_SYNC); 436 } 437 438 void cm_subst_roam_sync_exit(void *ctx) 439 { 440 } 441 442 bool cm_subst_roam_sync_event(void *ctx, uint16_t event, 443 uint16_t data_len, void *data) 444 { 445 bool event_handled = true; 446 struct cnx_mgr *cm_ctx = ctx; 447 448 switch (event) { 449 case WLAN_CM_SM_EV_CONNECT_REQ: 450 case WLAN_CM_SM_EV_DISCONNECT_REQ: 451 case WLAN_CM_SM_EV_DISCONNECT_ACTIVE: 452 event_handled = 453 cm_handle_connect_disconnect_in_roam(cm_ctx, event, 454 data_len, data); 455 break; 456 case WLAN_CM_SM_EV_ROAM_SYNC: 457 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 458 mlo_cm_roam_sync_cb(cm_ctx->vdev, data, data_len); 459 #endif 460 cm_fw_send_vdev_roam_event(cm_ctx, data_len, data); 461 break; 462 case WLAN_CM_SM_EV_ROAM_DONE: 463 cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED); 464 cm_sm_deliver_event_sync(cm_ctx, event, 465 data_len, data); 466 break; 467 case WLAN_CM_SM_EV_ROAM_ABORT: 468 case WLAN_CM_SM_EV_ROAM_HO_FAIL: 469 cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED); 470 cm_sm_deliver_event_sync(cm_ctx, event, 471 data_len, data); 472 break; 473 default: 474 event_handled = false; 475 break; 476 } 477 478 return event_handled; 479 } 480 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */ 481