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