1 /* 2 * Copyright (c) 2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 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: wlan_cm_host_roam_preauth.c 20 * 21 * Implements general roam pre-auth functionality for connection manager 22 */ 23 24 #include "wlan_cm_vdev_api.h" 25 #include "wni_api.h" 26 #include <wlan_cm_api.h> 27 #include "wlan_cm_roam_api.h" 28 #include "wlan_cm_roam_public_struct.h" 29 #include "wlan_cm_public_struct.h" 30 #include "wlan_mlme_vdev_mgr_interface.h" 31 #include "connection_mgr/core/src/wlan_cm_roam.h" 32 #include "connection_mgr/core/src/wlan_cm_sm.h" 33 #include "connection_mgr/core/src/wlan_cm_main_api.h" 34 35 #define MAX_NUM_PREAUTH_RETRIES 3 36 #define CM_PREAUTH_TIMEOUT 10000 37 #define REASSOC_TIMER_DURATION 60 38 39 static QDF_STATUS cm_get_valid_preauth_candidate(struct cm_roam_req *cm_req) 40 { 41 qdf_list_t *candidate_list; 42 qdf_list_node_t *cur_node = NULL; 43 struct scan_cache_node *prev_candidate; 44 bool new_candidate = false; 45 uint8_t vdev_id = cm_req->req.vdev_id; 46 47 candidate_list = cm_req->candidate_list; 48 if (!candidate_list || !qdf_list_size(candidate_list)) { 49 mlme_info(CM_PREFIX_FMT "no valid candidate found", 50 CM_PREFIX_REF(vdev_id, cm_req->cm_id)); 51 return QDF_STATUS_E_EMPTY; 52 } 53 54 prev_candidate = cm_req->cur_candidate; 55 if (!prev_candidate) { 56 qdf_list_peek_front(candidate_list, &cur_node); 57 new_candidate = true; 58 } else if (cm_req->num_preauth_retry >= MAX_NUM_PREAUTH_RETRIES) { 59 qdf_list_peek_next(candidate_list, &prev_candidate->node, 60 &cur_node); 61 new_candidate = true; 62 } 63 64 if (new_candidate) { 65 if (!cur_node) { 66 mlme_debug(CM_PREFIX_FMT "All candidates tried", 67 CM_PREFIX_REF(vdev_id, cm_req->cm_id)); 68 return QDF_STATUS_E_FAILURE; 69 } 70 cm_req->num_preauth_retry = 0; 71 cm_req->cur_candidate = qdf_container_of(cur_node, 72 struct scan_cache_node, 73 node); 74 } 75 76 cm_req->num_preauth_retry++; 77 78 mlme_debug(CM_PREFIX_FMT "Try preauth attempt no. %d for " QDF_MAC_ADDR_FMT, 79 CM_PREFIX_REF(vdev_id, cm_req->cm_id), 80 cm_req->num_preauth_retry, 81 QDF_MAC_ADDR_REF(cm_req->cur_candidate->entry->bssid.bytes)); 82 83 return QDF_STATUS_SUCCESS; 84 } 85 86 void cm_preauth_fail(struct cnx_mgr *cm_ctx, 87 struct wlan_cm_preauth_fail *preauth_fail_rsp) 88 { 89 struct cm_req *cm_req; 90 wlan_cm_id cm_id; 91 92 cm_id = preauth_fail_rsp->cm_id; 93 cm_req = cm_get_req_by_cm_id(cm_ctx, cm_id); 94 /* 95 * If the entry is not present in the list, it must have been cleared 96 * already. 97 */ 98 if (!cm_req) 99 return; 100 101 if (cm_get_state(cm_ctx) == WLAN_CM_S_CONNECTED) 102 cm_mlme_roam_preauth_fail(cm_ctx->vdev, &cm_req->roam_req.req, 103 preauth_fail_rsp->reason); 104 105 mlme_debug(CM_PREFIX_FMT, 106 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id)); 107 108 if (cm_req->roam_req.req.source == CM_ROAMING_HOST && 109 cm_get_state(cm_ctx) == WLAN_CM_S_CONNECTED) 110 wlan_cm_disconnect(cm_ctx->vdev, CM_ROAM_DISCONNECT, 111 REASON_USER_TRIGGERED_ROAM_FAILURE, NULL); 112 113 cm_remove_cmd(cm_ctx, &cm_id); 114 } 115 116 static void 117 cm_preauth_handle_event_post_fail(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id) 118 { 119 struct wlan_cm_preauth_fail preauth_fail_rsp; 120 121 preauth_fail_rsp.cm_id = cm_id; 122 preauth_fail_rsp.reason = CM_ABORT_DUE_TO_NEW_REQ_RECVD; 123 124 cm_preauth_fail(cm_ctx, &preauth_fail_rsp); 125 } 126 127 static QDF_STATUS 128 cm_preauth_cmd_timeout(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id) 129 { 130 QDF_STATUS status; 131 struct wlan_cm_preauth_fail preauth_fail_rsp; 132 133 preauth_fail_rsp.cm_id = cm_id; 134 preauth_fail_rsp.reason = CM_SER_TIMEOUT; 135 136 status = cm_sm_deliver_event( 137 cm_ctx->vdev, WLAN_CM_SM_EV_PREAUTH_FAIL, 138 sizeof(struct wlan_cm_preauth_fail), &preauth_fail_rsp); 139 if (QDF_IS_STATUS_ERROR(status)) 140 cm_preauth_handle_event_post_fail(cm_ctx, cm_id); 141 142 return status; 143 } 144 145 static QDF_STATUS 146 cm_ser_preauth_cb(struct wlan_serialization_command *cmd, 147 enum wlan_serialization_cb_reason reason) 148 { 149 QDF_STATUS status = QDF_STATUS_SUCCESS; 150 struct wlan_objmgr_vdev *vdev; 151 struct cnx_mgr *cm_ctx; 152 153 if (!cmd) { 154 mlme_err("cmd is NULL, reason: %d", reason); 155 QDF_ASSERT(0); 156 return QDF_STATUS_E_NULL_VALUE; 157 } 158 159 vdev = cmd->vdev; 160 cm_ctx = cm_get_cm_ctx(vdev); 161 if (!cm_ctx) 162 return QDF_STATUS_E_NULL_VALUE; 163 164 switch (reason) { 165 case WLAN_SER_CB_ACTIVATE_CMD: 166 if (cmd->activation_reason == SER_PENDING_TO_ACTIVE) 167 status = cm_sm_deliver_event( 168 vdev, WLAN_CM_SM_EV_PREAUTH_ACTIVE, 169 sizeof(wlan_cm_id), &cmd->cmd_id); 170 else 171 status = cm_sm_deliver_event_sync( 172 cm_ctx, WLAN_CM_SM_EV_PREAUTH_ACTIVE, 173 sizeof(wlan_cm_id), &cmd->cmd_id); 174 if (QDF_IS_STATUS_SUCCESS(status)) 175 break; 176 /* 177 * Handle failure if posting fails, i.e. the SM state has 178 * changed or head cm_id doesn't match the active cm_id. 179 * connect active should be handled only in JOIN_PENDING. If 180 * new command has been received connect activation should be 181 * aborted from here with connect req cleanup. 182 */ 183 cm_preauth_handle_event_post_fail(cm_ctx, cmd->cmd_id); 184 break; 185 case WLAN_SER_CB_CANCEL_CMD: 186 /* command removed from pending list. */ 187 break; 188 case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT: 189 mlme_err(CM_PREFIX_FMT "Active command timeout", 190 CM_PREFIX_REF(wlan_vdev_get_id(vdev), cmd->cmd_id)); 191 QDF_ASSERT(0); 192 193 cm_preauth_cmd_timeout(cm_ctx, cmd->cmd_id); 194 break; 195 case WLAN_SER_CB_RELEASE_MEM_CMD: 196 cm_reset_active_cm_id(vdev, cmd->cmd_id); 197 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); 198 break; 199 default: 200 QDF_ASSERT(0); 201 status = QDF_STATUS_E_INVAL; 202 break; 203 } 204 205 return status; 206 } 207 208 static QDF_STATUS cm_ser_preauth_req(struct cnx_mgr *cm_ctx, 209 struct cm_req *cm_req) 210 { 211 struct wlan_serialization_command cmd = {0, }; 212 enum wlan_serialization_status ser_cmd_status; 213 QDF_STATUS status; 214 uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev); 215 216 status = wlan_objmgr_vdev_try_get_ref(cm_ctx->vdev, WLAN_MLME_CM_ID); 217 if (QDF_IS_STATUS_ERROR(status)) { 218 mlme_err(CM_PREFIX_FMT "unable to get reference", 219 CM_PREFIX_REF(vdev_id, cm_req->cm_id)); 220 return status; 221 } 222 223 cmd.cmd_type = WLAN_SER_CMD_PERFORM_PRE_AUTH; 224 cmd.cmd_id = cm_req->cm_id; 225 cmd.cmd_cb = cm_ser_preauth_cb; 226 cmd.source = WLAN_UMAC_COMP_MLME; 227 cmd.is_high_priority = false; 228 cmd.cmd_timeout_duration = CM_PREAUTH_TIMEOUT; 229 cmd.vdev = cm_ctx->vdev; 230 cmd.is_blocking = true; 231 232 ser_cmd_status = wlan_serialization_request(&cmd); 233 switch (ser_cmd_status) { 234 case WLAN_SER_CMD_PENDING: 235 /* command moved to pending list.Do nothing */ 236 break; 237 case WLAN_SER_CMD_ACTIVE: 238 /* command moved to active list. Do nothing */ 239 break; 240 default: 241 mlme_err(CM_PREFIX_FMT "ser cmd status %d", 242 CM_PREFIX_REF(vdev_id, cm_req->cm_id), ser_cmd_status); 243 wlan_objmgr_vdev_release_ref(cm_ctx->vdev, WLAN_MLME_CM_ID); 244 245 return QDF_STATUS_E_FAILURE; 246 } 247 248 return QDF_STATUS_SUCCESS; 249 } 250 251 QDF_STATUS 252 cm_send_preauth_start_fail(struct cnx_mgr *cm_ctx, 253 wlan_cm_id cm_id, 254 enum wlan_cm_connect_fail_reason reason) 255 { 256 QDF_STATUS status; 257 struct wlan_cm_preauth_fail preauth_fail_rsp; 258 259 preauth_fail_rsp.cm_id = cm_id; 260 preauth_fail_rsp.reason = reason; 261 262 status = cm_sm_deliver_event_sync( 263 cm_ctx, WLAN_CM_SM_EV_PREAUTH_FAIL, 264 sizeof(struct wlan_cm_preauth_fail), &preauth_fail_rsp); 265 if (QDF_IS_STATUS_ERROR(status)) 266 cm_preauth_handle_event_post_fail(cm_ctx, cm_id); 267 268 return status; 269 } 270 271 static void cm_flush_invalid_preauth_ap(struct cnx_mgr *cm_ctx, 272 struct cm_roam_req *roam_req) 273 { 274 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 275 qdf_list_t *candidate_list; 276 struct scan_cache_node *scan_node = NULL; 277 struct qdf_mac_addr connected_bssid; 278 bool is_valid; 279 uint8_t vdev_id = roam_req->req.vdev_id; 280 struct wlan_objmgr_psoc *psoc; 281 uint8_t enable_mcc_mode = false; 282 qdf_freq_t conc_freq, bss_freq; 283 284 /* 285 * Only When entering first time (ie cur_candidate is NULL), 286 * flush invalid APs from the list and if list is not NULL. 287 */ 288 if (roam_req->cur_candidate || !roam_req->candidate_list) 289 return; 290 291 psoc = wlan_vdev_get_psoc(cm_ctx->vdev); 292 if (!psoc) 293 return; 294 295 wlan_mlme_get_mcc_feature(psoc, &enable_mcc_mode); 296 297 wlan_vdev_get_bss_peer_mac(cm_ctx->vdev, &connected_bssid); 298 299 candidate_list = roam_req->candidate_list; 300 301 qdf_list_peek_front(candidate_list, &cur_node); 302 303 while (cur_node) { 304 is_valid = true; 305 qdf_list_peek_next(candidate_list, cur_node, &next_node); 306 scan_node = qdf_container_of(cur_node, struct scan_cache_node, 307 node); 308 bss_freq = scan_node->entry->channel.chan_freq; 309 if (qdf_is_macaddr_equal(&connected_bssid, 310 &scan_node->entry->bssid)) { 311 mlme_debug(CM_PREFIX_FMT "Remove connected AP " QDF_MAC_ADDR_FMT " from list", 312 CM_PREFIX_REF(vdev_id, roam_req->cm_id), 313 QDF_MAC_ADDR_REF(connected_bssid.bytes)); 314 is_valid = false; 315 } 316 317 /* 318 * Continue if MCC is disabled in INI and if AP 319 * will create MCC 320 */ 321 if (policy_mgr_concurrent_open_sessions_running(psoc) && 322 !enable_mcc_mode) { 323 conc_freq = wlan_get_conc_freq(); 324 if (conc_freq && (conc_freq != bss_freq)) { 325 mlme_info(CM_PREFIX_FMT "Remove AP " QDF_MAC_ADDR_FMT ", MCC not supported. freq %d conc_freq %d", 326 CM_PREFIX_REF(vdev_id, roam_req->cm_id), 327 QDF_MAC_ADDR_REF(connected_bssid.bytes), 328 bss_freq, conc_freq); 329 is_valid = false; 330 } 331 } 332 333 if (!is_valid) { 334 qdf_list_remove_node(candidate_list, cur_node); 335 util_scan_free_cache_entry(scan_node->entry); 336 qdf_mem_free(scan_node); 337 } 338 339 cur_node = next_node; 340 next_node = NULL; 341 } 342 } 343 344 QDF_STATUS cm_host_roam_preauth_start(struct cnx_mgr *cm_ctx, 345 struct cm_req *cm_req) 346 { 347 QDF_STATUS status; 348 349 cm_flush_invalid_preauth_ap(cm_ctx, &cm_req->roam_req); 350 351 status = cm_get_valid_preauth_candidate(&cm_req->roam_req); 352 if (QDF_IS_STATUS_ERROR(status)) 353 return status; 354 355 return cm_ser_preauth_req(cm_ctx, cm_req); 356 } 357 358 void cm_free_preauth_req(struct wlan_preauth_req *preauth_req) 359 { 360 if (!preauth_req) 361 return; 362 363 util_scan_free_cache_entry(preauth_req->entry); 364 preauth_req->entry = NULL; 365 qdf_mem_free(preauth_req); 366 } 367 368 static QDF_STATUS cm_flush_preauth_req(struct scheduler_msg *msg) 369 { 370 struct wlan_preauth_req *preauth_req; 371 372 if (!msg || !msg->bodyptr) { 373 mlme_err("msg or msg->bodyptr is NULL"); 374 return QDF_STATUS_E_INVAL; 375 } 376 377 preauth_req = msg->bodyptr; 378 cm_free_preauth_req(preauth_req); 379 380 return QDF_STATUS_SUCCESS; 381 } 382 383 static QDF_STATUS 384 cm_issue_preauth_req(struct cnx_mgr *cm_ctx, struct cm_roam_req *roam_req) 385 { 386 struct wlan_preauth_req *preauth_req; 387 struct scheduler_msg msg; 388 QDF_STATUS status; 389 390 qdf_mem_zero(&msg, sizeof(msg)); 391 preauth_req = qdf_mem_malloc(sizeof(*preauth_req)); 392 if (!preauth_req) 393 return QDF_STATUS_E_NOMEM; 394 395 preauth_req->vdev_id = wlan_vdev_get_id(cm_ctx->vdev); 396 preauth_req->entry = 397 util_scan_copy_cache_entry(roam_req->cur_candidate->entry); 398 399 if (!preauth_req->entry) { 400 qdf_mem_free(preauth_req); 401 return QDF_STATUS_E_NOMEM; 402 } 403 404 msg.bodyptr = preauth_req; 405 msg.type = CM_PREAUTH_REQ; 406 msg.flush_callback = cm_flush_preauth_req; 407 408 status = scheduler_post_message(QDF_MODULE_ID_MLME, 409 QDF_MODULE_ID_PE, 410 QDF_MODULE_ID_PE, &msg); 411 if (QDF_IS_STATUS_ERROR(status)) { 412 mlme_err(CM_PREFIX_FMT "msg post fail", 413 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 414 roam_req->cm_id)); 415 cm_free_preauth_req(preauth_req); 416 } 417 418 return status; 419 } 420 421 QDF_STATUS cm_preauth_active(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id) 422 { 423 struct cm_req *cm_req; 424 struct cm_roam_req *roam_req; 425 QDF_STATUS status; 426 427 cm_req = cm_get_req_by_cm_id(cm_ctx, *cm_id); 428 if (!cm_req) 429 return QDF_STATUS_E_INVAL; 430 431 cm_ctx->active_cm_id = *cm_id; 432 roam_req = &cm_req->roam_req; 433 434 status = cm_issue_preauth_req(cm_ctx, roam_req); 435 if (QDF_IS_STATUS_ERROR(status)) 436 cm_send_preauth_start_fail(cm_ctx, *cm_id, CM_GENERIC_FAILURE); 437 438 return status; 439 } 440 441 #ifdef FEATURE_WLAN_ESE 442 static void cm_update_cckmtsf(uint32_t *timestamp0, uint32_t *timestamp1, 443 uint64_t *incr) 444 { 445 uint64_t timestamp64 = ((uint64_t)*timestamp1 << 32) | (*timestamp0); 446 447 timestamp64 = (uint64_t)(timestamp64 + (*incr)); 448 *timestamp0 = (uint32_t)(timestamp64 & 0xffffffff); 449 *timestamp1 = (uint32_t)((timestamp64 >> 32) & 0xffffffff); 450 } 451 452 /** 453 * cm_roam_read_tsf() - read TSF 454 * @cm_ctx: connection manager context 455 * @rsp: preauth response 456 * 457 * This function reads the TSF and also add the time elapsed since last 458 * beacon or probe response reception from the hand off AP to arrive at 459 * the latest TSF value. 460 * 461 * Return: none 462 */ 463 static void cm_roam_read_tsf(struct cnx_mgr *cm_ctx, 464 struct wlan_preauth_rsp *rsp) 465 { 466 struct cm_req *cm_req; 467 struct scan_cache_entry *scan_entry; 468 uint64_t timer_diff = 0; 469 470 cm_req = cm_get_req_by_cm_id(cm_ctx, rsp->cm_id); 471 if (!cm_req) 472 return; 473 if (!cm_req->roam_req.cur_candidate || 474 !cm_req->roam_req.cur_candidate->entry) 475 return; 476 477 scan_entry = cm_req->roam_req.cur_candidate->entry; 478 qdf_mem_copy(rsp->timestamp, scan_entry->tsf_info.data, 8); 479 480 /* Get the time diff in nano seconds */ 481 timer_diff = qdf_get_monotonic_boottime_ns() - scan_entry->boottime_ns; 482 /* Convert msec to micro sec timer */ 483 timer_diff = do_div(timer_diff, SYSTEM_TIME_NSEC_TO_USEC); 484 /* Update the TSF with the difference in system time */ 485 cm_update_cckmtsf(&rsp->timestamp[0], &rsp->timestamp[1], 486 &timer_diff); 487 } 488 #else 489 static inline void cm_roam_read_tsf(struct cnx_mgr *cm_ctx, 490 struct wlan_preauth_rsp *rsp) 491 {} 492 #endif 493 494 #define MD_IE_ID 54 495 496 void cm_reassoc_timer_callback(void *context) 497 { 498 QDF_STATUS status; 499 struct reassoc_timer_ctx *ctx = context; 500 struct cnx_mgr *cm_ctx; 501 struct wlan_objmgr_vdev *vdev; 502 wlan_cm_id cm_id = ctx->cm_id; 503 uint8_t vdev_id = ctx->vdev_id; 504 505 vdev = wlan_objmgr_get_vdev_by_id_from_pdev(ctx->pdev, vdev_id, 506 WLAN_MLME_CM_ID); 507 if (!vdev) { 508 mlme_err(CM_PREFIX_FMT "vdev object is NULL", 509 CM_PREFIX_REF(vdev_id, cm_id)); 510 return; 511 } 512 513 cm_ctx = cm_get_cm_ctx(vdev); 514 if (!cm_ctx) 515 goto rel_ref; 516 517 status = cm_sm_deliver_event(vdev, WLAN_CM_SM_EV_REASSOC_TIMER, 518 sizeof(wlan_cm_id), &cm_id); 519 520 if (QDF_IS_STATUS_ERROR(status)) 521 cm_preauth_handle_event_post_fail(cm_ctx, cm_id); 522 523 rel_ref: 524 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); 525 } 526 527 void cm_preauth_success(struct cnx_mgr *cm_ctx, struct wlan_preauth_rsp *rsp) 528 { 529 QDF_STATUS status; 530 struct mlme_legacy_priv *mlme_priv; 531 struct rso_config *rso_cfg; 532 struct wlan_objmgr_pdev *pdev; 533 struct wlan_objmgr_vdev *vdev; 534 uint8_t vdev_id = rsp->vdev_id; 535 wlan_cm_id cm_id = rsp->cm_id; 536 struct cm_roam_values_copy config; 537 bool is_11r; 538 539 vdev = cm_ctx->vdev; 540 pdev = wlan_vdev_get_pdev(vdev); 541 if (!pdev || !rsp->psoc) { 542 mlme_err(CM_PREFIX_FMT "pdev or psoc is NULL", 543 CM_PREFIX_REF(vdev_id, cm_id)); 544 goto err; 545 } 546 547 mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); 548 if (!mlme_priv) { 549 mlme_err(CM_PREFIX_FMT "vdev ext priv is NULL", 550 CM_PREFIX_REF(vdev_id, cm_id)); 551 goto err; 552 } 553 554 rso_cfg = wlan_cm_get_rso_config(vdev); 555 if (!rso_cfg) { 556 mlme_err(CM_PREFIX_FMT "rso_cfg is NULL", 557 CM_PREFIX_REF(vdev_id, cm_id)); 558 goto err; 559 } 560 561 mlme_err(CM_PREFIX_FMT "Preauth success with " QDF_MAC_ADDR_FMT, 562 CM_PREFIX_REF(vdev_id, rsp->cm_id), 563 QDF_MAC_ADDR_REF(rsp->pre_auth_bssid.bytes)); 564 565 cm_csr_preauth_done(vdev); 566 567 qdf_mem_copy(rsp->ric_ies, 568 mlme_priv->connect_info.ft_info.ric_ies, 569 mlme_priv->connect_info.ft_info.ric_ies_length); 570 rsp->ric_ies_length = mlme_priv->connect_info.ft_info.ric_ies_length; 571 572 mlme_priv->connect_info.ft_info.ft_state = FT_REASSOC_REQ_WAIT; 573 574 /* start reassoc timer */ 575 rso_cfg->ctx.pdev = pdev; 576 rso_cfg->ctx.vdev_id = vdev_id; 577 rso_cfg->ctx.cm_id = cm_id; 578 579 status = qdf_mc_timer_start(&rso_cfg->reassoc_timer, 580 REASSOC_TIMER_DURATION); 581 if (QDF_IS_STATUS_ERROR(status)) { 582 mlme_err(CM_PREFIX_FMT "start reassoc timer failed, status %d", 583 CM_PREFIX_REF(vdev_id, cm_id), status); 584 goto err; 585 } 586 587 wlan_cm_roam_cfg_get_value(rsp->psoc, vdev_id, IS_11R_CONNECTION, 588 &config); 589 is_11r = config.bool_value; 590 if (is_11r) 591 mlme_cm_osif_ft_preauth_complete(vdev, rsp); 592 593 if (wlan_cm_get_ese_assoc(pdev, vdev_id)) { 594 cm_roam_read_tsf(cm_ctx, rsp); 595 mlme_cm_osif_cckm_preauth_complete(vdev, rsp); 596 } 597 598 if (cm_is_fast_roam_enabled(rsp->psoc) && 599 cm_is_rsn_or_8021x_sha256_auth_type(vdev)) 600 mlme_cm_osif_pmksa_candidate_notify(vdev, &rsp->pre_auth_bssid, 601 1, false); 602 603 mlme_priv->connect_info.ft_info.add_mdie = false; 604 if (!(is_11r && cm_is_open_mode(vdev))) 605 return; 606 607 qdf_mem_zero(mlme_priv->connect_info.ft_info.reassoc_ft_ie, 608 MAX_FTIE_SIZE); 609 mlme_priv->connect_info.ft_info.reassoc_ie_len = 0; 610 611 if (wlan_get_ie_ptr_from_eid(MD_IE_ID, rsp->ft_ie, rsp->ft_ie_length)) 612 mlme_priv->connect_info.ft_info.add_mdie = true; 613 614 if (!mlme_priv->connect_info.ft_info.ric_ies_length) 615 return; 616 617 /* Copy the RIC IEs to reassoc IEs */ 618 qdf_mem_copy(mlme_priv->connect_info.ft_info.reassoc_ft_ie, 619 mlme_priv->connect_info.ft_info.ric_ies, 620 mlme_priv->connect_info.ft_info.ric_ies_length); 621 mlme_priv->connect_info.ft_info.reassoc_ie_len = 622 mlme_priv->connect_info.ft_info.ric_ies_length; 623 mlme_priv->connect_info.ft_info.add_mdie = true; 624 return; 625 626 err: 627 rsp->status = QDF_STATUS_E_ABORTED; 628 status = cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_PREAUTH_RESP, 629 sizeof(*rsp), rsp); 630 if (QDF_IS_STATUS_ERROR(status)) 631 cm_preauth_handle_event_post_fail(cm_ctx, cm_id); 632 } 633 634 static QDF_STATUS 635 cm_hanlde_preauth_failure(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id) 636 { 637 QDF_STATUS status; 638 struct wlan_cm_preauth_fail preauth_fail_rsp; 639 640 preauth_fail_rsp.cm_id = cm_id; 641 preauth_fail_rsp.reason = CM_GENERIC_FAILURE; 642 643 status = cm_sm_deliver_event_sync( 644 cm_ctx, WLAN_CM_SM_EV_PREAUTH_FAIL, 645 sizeof(struct wlan_cm_preauth_fail), &preauth_fail_rsp); 646 if (QDF_IS_STATUS_ERROR(status)) 647 cm_preauth_handle_event_post_fail(cm_ctx, cm_id); 648 649 return status; 650 } 651 652 void cm_preauth_done_resp(struct cnx_mgr *cm_ctx, struct wlan_preauth_rsp *rsp) 653 { 654 QDF_STATUS status; 655 struct cm_req *cm_req; 656 wlan_cm_id cm_id = rsp->cm_id; 657 658 if (QDF_IS_STATUS_ERROR(rsp->status)) { 659 cm_req = cm_get_req_by_cm_id(cm_ctx, cm_id); 660 if (!cm_req) 661 return; 662 mlme_info(CM_PREFIX_FMT "Preauth attempt no. %d failed for " QDF_MAC_ADDR_FMT, 663 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id), 664 cm_req->roam_req.num_preauth_retry, 665 QDF_MAC_ADDR_REF(rsp->pre_auth_bssid.bytes)); 666 667 /* retry again with same or new candidate */ 668 status = cm_host_roam_preauth_start(cm_ctx, cm_req); 669 if (QDF_IS_STATUS_ERROR(status)) 670 cm_hanlde_preauth_failure(cm_ctx, cm_id); 671 } else { 672 status = cm_sm_deliver_event_sync(cm_ctx, 673 WLAN_CM_SM_EV_PREAUTH_DONE, 674 sizeof(*rsp), rsp); 675 if (QDF_IS_STATUS_ERROR(status)) 676 cm_preauth_handle_event_post_fail(cm_ctx, cm_id); 677 } 678 } 679 680 /** 681 * cm_remove_preauth_cmd_from_serialization() - Remove preauth cmd 682 * from serialization 683 * @cm_ctx: connection manager context 684 * @cm_id: cm id of roam req 685 * 686 * Return: void 687 */ 688 static void cm_remove_preauth_cmd_from_serialization(struct cnx_mgr *cm_ctx, 689 wlan_cm_id cm_id) 690 { 691 struct wlan_serialization_queued_cmd_info cmd_info; 692 693 qdf_mem_zero(&cmd_info, sizeof(cmd_info)); 694 cmd_info.vdev = cm_ctx->vdev; 695 cmd_info.cmd_id = cm_id; 696 cmd_info.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD; 697 cmd_info.cmd_type = WLAN_SER_CMD_PERFORM_PRE_AUTH; 698 699 mlme_debug(CM_PREFIX_FMT "Remove cmd type %d from active", 700 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id), 701 cmd_info.cmd_type); 702 cmd_info.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE; 703 wlan_serialization_remove_cmd(&cmd_info); 704 } 705 706 static QDF_STATUS cm_preauth_rsp(struct wlan_objmgr_vdev *vdev, 707 struct wlan_preauth_rsp *rsp) 708 { 709 QDF_STATUS status; 710 struct cnx_mgr *cm_ctx; 711 wlan_cm_id cm_id; 712 uint32_t prefix; 713 714 cm_ctx = cm_get_cm_ctx(vdev); 715 if (!cm_ctx) 716 return QDF_STATUS_E_NULL_VALUE; 717 718 cm_id = cm_ctx->active_cm_id; 719 prefix = CM_ID_GET_PREFIX(cm_id); 720 721 if (prefix != ROAM_REQ_PREFIX) { 722 mlme_err(CM_PREFIX_FMT "active req is not roam req", 723 CM_PREFIX_REF(wlan_vdev_get_id(vdev), cm_id)); 724 return QDF_STATUS_E_INVAL; 725 } 726 rsp->cm_id = cm_id; 727 728 mlme_debug(CM_PREFIX_FMT "preauth resp status %d for " QDF_MAC_ADDR_FMT, 729 CM_PREFIX_REF(wlan_vdev_get_id(vdev), cm_id), 730 rsp->status, QDF_MAC_ADDR_REF(rsp->pre_auth_bssid.bytes)); 731 732 cm_remove_preauth_cmd_from_serialization(cm_ctx, cm_id); 733 734 status = cm_sm_deliver_event(vdev, WLAN_CM_SM_EV_PREAUTH_RESP, 735 sizeof(*rsp), rsp); 736 if (QDF_IS_STATUS_ERROR(status)) 737 cm_preauth_handle_event_post_fail(cm_ctx, cm_id); 738 739 return status; 740 } 741 742 QDF_STATUS cm_handle_preauth_rsp(struct scheduler_msg *msg) 743 { 744 QDF_STATUS status = QDF_STATUS_SUCCESS; 745 struct wlan_preauth_rsp *rsp = NULL; 746 struct wlan_objmgr_vdev *vdev; 747 748 if (!msg || !msg->bodyptr) { 749 status = QDF_STATUS_E_FAILURE; 750 goto end; 751 } 752 753 rsp = (struct wlan_preauth_rsp *)msg->bodyptr; 754 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(rsp->psoc, rsp->vdev_id, 755 WLAN_MLME_CM_ID); 756 if (!vdev) { 757 mlme_err("vdev_id: %d : vdev not found, status %d", 758 rsp->vdev_id, rsp->status); 759 status = QDF_STATUS_E_INVAL; 760 goto end; 761 } 762 763 status = cm_preauth_rsp(vdev, rsp); 764 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); 765 end: 766 if (rsp) 767 qdf_mem_free(rsp); 768 769 return status; 770 } 771