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 default: 156 return false; 157 break; 158 } 159 160 return true; 161 } 162 163 #ifdef WLAN_FEATURE_HOST_ROAM 164 void cm_subst_preauth_entry(void *ctx) 165 { 166 struct cnx_mgr *cm_ctx = ctx; 167 168 if (cm_get_state(cm_ctx) != WLAN_CM_S_ROAMING) 169 QDF_BUG(0); 170 171 cm_set_substate(cm_ctx, WLAN_CM_SS_PREAUTH); 172 /* set preauth to true when we enter preauth state */ 173 cm_ctx->preauth_in_progress = true; 174 } 175 176 void cm_subst_preauth_exit(void *ctx) 177 { 178 } 179 180 #ifdef WLAN_FEATURE_PREAUTH_ENABLE 181 static bool 182 cm_handle_preauth_event(struct cnx_mgr *cm_ctx, uint16_t event, 183 uint16_t data_len, void *data) 184 { 185 bool event_handled = true; 186 187 switch (event) { 188 case WLAN_CM_SM_EV_PREAUTH_ACTIVE: 189 if (!cm_check_cmid_match_list_head(cm_ctx, data)) { 190 event_handled = false; 191 break; 192 } 193 cm_preauth_active(cm_ctx, data); 194 break; 195 case WLAN_CM_SM_EV_PREAUTH_RESP: 196 cm_preauth_done_resp(cm_ctx, data); 197 break; 198 case WLAN_CM_SM_EV_PREAUTH_DONE: 199 cm_sm_transition_to(cm_ctx, WLAN_CM_SS_REASSOC); 200 cm_preauth_success(cm_ctx, data); 201 break; 202 case WLAN_CM_SM_EV_PREAUTH_FAIL: 203 cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED); 204 cm_preauth_fail(cm_ctx, data); 205 break; 206 default: 207 event_handled = false; 208 } 209 210 return event_handled; 211 } 212 #else 213 static inline bool 214 cm_handle_preauth_event(struct cnx_mgr *cm_ctx, uint16_t event, 215 uint16_t data_len, void *data) 216 { 217 return false; 218 } 219 #endif 220 221 bool cm_subst_preauth_event(void *ctx, uint16_t event, 222 uint16_t data_len, void *data) 223 { 224 struct cnx_mgr *cm_ctx = ctx; 225 bool event_handled = true; 226 227 switch (event) { 228 case WLAN_CM_SM_EV_CONNECT_REQ: 229 case WLAN_CM_SM_EV_DISCONNECT_REQ: 230 event_handled = 231 cm_handle_connect_disconnect_in_roam(cm_ctx, event, 232 data_len, data); 233 break; 234 case WLAN_CM_SM_EV_ROAM_START: 235 cm_host_roam_start_req(cm_ctx, data); 236 break; 237 case WLAN_CM_SM_EV_START_REASSOC: 238 cm_sm_transition_to(cm_ctx, WLAN_CM_SS_REASSOC); 239 cm_sm_deliver_event_sync(cm_ctx, event, data_len, data); 240 break; 241 case WLAN_CM_SM_EV_REASSOC_FAILURE: 242 cm_reassoc_complete(cm_ctx, data); 243 break; 244 default: 245 event_handled = cm_handle_preauth_event(cm_ctx, event, 246 data_len, data); 247 break; 248 } 249 250 return event_handled; 251 } 252 253 void cm_subst_reassoc_entry(void *ctx) 254 { 255 struct cnx_mgr *cm_ctx = ctx; 256 257 if (cm_get_state(cm_ctx) != WLAN_CM_S_ROAMING) 258 QDF_BUG(0); 259 260 cm_set_substate(cm_ctx, WLAN_CM_SS_REASSOC); 261 /* set preauth to false as soon as we move to reassoc state */ 262 cm_ctx->preauth_in_progress = false; 263 } 264 265 void cm_subst_reassoc_exit(void *ctx) 266 { 267 } 268 269 #ifdef WLAN_FEATURE_PREAUTH_ENABLE 270 static bool 271 cm_handle_reassoc_event(struct cnx_mgr *cm_ctx, uint16_t event, 272 uint16_t data_len, void *data) 273 { 274 bool event_handled = true; 275 QDF_STATUS status; 276 277 switch (event) { 278 case WLAN_CM_SM_EV_REASSOC_TIMER: 279 status = cm_handle_reassoc_timer(cm_ctx, data); 280 if (QDF_IS_STATUS_ERROR(status)) 281 event_handled = false; 282 break; 283 default: 284 event_handled = false; 285 } 286 287 return event_handled; 288 } 289 #else 290 static inline bool 291 cm_handle_reassoc_event(struct cnx_mgr *cm_ctx, uint16_t event, 292 uint16_t data_len, void *data) 293 { 294 return false; 295 } 296 #endif 297 298 bool cm_subst_reassoc_event(void *ctx, uint16_t event, 299 uint16_t data_len, void *data) 300 { 301 struct cnx_mgr *cm_ctx = ctx; 302 bool event_handled = true; 303 304 switch (event) { 305 case WLAN_CM_SM_EV_CONNECT_REQ: 306 case WLAN_CM_SM_EV_DISCONNECT_REQ: 307 event_handled = 308 cm_handle_connect_disconnect_in_roam(cm_ctx, event, 309 data_len, data); 310 break; 311 case WLAN_CM_SM_EV_START_REASSOC: 312 cm_reassoc_start(cm_ctx, data); 313 break; 314 case WLAN_CM_SM_EV_REASSOC_ACTIVE: 315 if (!cm_check_cmid_match_list_head(cm_ctx, data)) { 316 event_handled = false; 317 break; 318 } 319 cm_reassoc_active(cm_ctx, data); 320 break; 321 case WLAN_CM_SM_EV_DISCONNECT_DONE: 322 cm_reassoc_disconnect_complete(cm_ctx, data); 323 break; 324 case WLAN_CM_SM_EV_BSS_CREATE_PEER_SUCCESS: 325 if (!cm_check_cmid_match_list_head(cm_ctx, data)) { 326 event_handled = false; 327 break; 328 } 329 cm_resume_reassoc_after_peer_create(cm_ctx, data); 330 break; 331 case WLAN_CM_SM_EV_REASSOC_DONE: 332 if (!cm_roam_resp_cmid_match_list_head(cm_ctx, data)) { 333 event_handled = false; 334 break; 335 } 336 cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED); 337 cm_sm_deliver_event_sync(cm_ctx, event, data_len, data); 338 break; 339 case WLAN_CM_SM_EV_REASSOC_FAILURE: 340 cm_reassoc_complete(cm_ctx, data); 341 break; 342 case WLAN_CM_SM_EV_HW_MODE_SUCCESS: 343 case WLAN_CM_SM_EV_HW_MODE_FAILURE: 344 /* check if cm id is valid for the current req */ 345 if (!cm_check_cmid_match_list_head(cm_ctx, data)) { 346 event_handled = false; 347 break; 348 } 349 cm_handle_reassoc_hw_mode_change(cm_ctx, data, event); 350 break; 351 default: 352 event_handled = cm_handle_reassoc_event(cm_ctx, event, 353 data_len, data); 354 break; 355 } 356 357 return event_handled; 358 } 359 360 #endif /* WLAN_FEATURE_HOST_ROAM */ 361 362 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 363 void cm_subst_roam_start_entry(void *ctx) 364 { 365 struct cnx_mgr *cm_ctx = ctx; 366 367 if (cm_get_state(cm_ctx) != WLAN_CM_S_ROAMING) 368 QDF_BUG(0); 369 370 cm_set_substate(cm_ctx, WLAN_CM_SS_ROAM_STARTED); 371 } 372 373 void cm_subst_roam_start_exit(void *ctx) 374 { 375 } 376 377 bool cm_subst_roam_start_event(void *ctx, uint16_t event, 378 uint16_t data_len, void *data) 379 { 380 bool event_handled = true; 381 struct cnx_mgr *cm_ctx = ctx; 382 383 switch (event) { 384 case WLAN_CM_SM_EV_CONNECT_REQ: 385 case WLAN_CM_SM_EV_DISCONNECT_REQ: 386 event_handled = 387 cm_handle_connect_disconnect_in_roam(cm_ctx, event, 388 data_len, data); 389 break; 390 case WLAN_CM_SM_EV_ROAM_START: 391 cm_fw_roam_start(ctx); 392 break; 393 case WLAN_CM_SM_EV_ROAM_INVOKE: 394 cm_send_roam_invoke_req(cm_ctx, data); 395 break; 396 case WLAN_CM_SM_EV_ROAM_ABORT: 397 case WLAN_CM_SM_EV_ROAM_INVOKE_FAIL: 398 case WLAN_CM_SM_EV_ROAM_HO_FAIL: 399 cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED); 400 cm_sm_deliver_event_sync(cm_ctx, event, 401 data_len, data); 402 break; 403 case WLAN_CM_SM_EV_ROAM_SYNC: 404 cm_sm_transition_to(cm_ctx, WLAN_CM_SS_ROAM_SYNC); 405 cm_sm_deliver_event_sync(cm_ctx, event, 406 data_len, data); 407 break; 408 default: 409 event_handled = false; 410 break; 411 } 412 413 return event_handled; 414 } 415 416 void cm_subst_roam_sync_entry(void *ctx) 417 { 418 struct cnx_mgr *cm_ctx = ctx; 419 420 if (cm_get_state(cm_ctx) != WLAN_CM_S_ROAMING) 421 QDF_BUG(0); 422 423 cm_set_substate(cm_ctx, WLAN_CM_SS_ROAM_SYNC); 424 } 425 426 void cm_subst_roam_sync_exit(void *ctx) 427 { 428 } 429 430 bool cm_subst_roam_sync_event(void *ctx, uint16_t event, 431 uint16_t data_len, void *data) 432 { 433 bool event_handled = true; 434 struct cnx_mgr *cm_ctx = ctx; 435 436 switch (event) { 437 case WLAN_CM_SM_EV_CONNECT_REQ: 438 case WLAN_CM_SM_EV_DISCONNECT_REQ: 439 event_handled = 440 cm_handle_connect_disconnect_in_roam(cm_ctx, event, 441 data_len, data); 442 break; 443 case WLAN_CM_SM_EV_ROAM_SYNC: 444 cm_fw_send_vdev_roam_event(cm_ctx, data_len, data); 445 break; 446 case WLAN_CM_SM_EV_ROAM_DONE: 447 cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED); 448 cm_sm_deliver_event_sync(cm_ctx, event, 449 data_len, data); 450 break; 451 case WLAN_CM_SM_EV_ROAM_ABORT: 452 case WLAN_CM_SM_EV_ROAM_HO_FAIL: 453 cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED); 454 cm_sm_deliver_event_sync(cm_ctx, event, 455 data_len, data); 456 break; 457 default: 458 event_handled = false; 459 break; 460 } 461 462 return event_handled; 463 } 464 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */ 465