1 /* 2 * Copyright (c) 2012-2015, 2020-2021, The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-2023 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 util apis of connection manager 20 */ 21 22 #include "wlan_cm_main_api.h" 23 #include "wlan_scan_api.h" 24 #include "wlan_cm_public_struct.h" 25 #include "wlan_serialization_api.h" 26 #include "wlan_cm_bss_score_param.h" 27 #ifdef WLAN_POLICY_MGR_ENABLE 28 #include <wlan_policy_mgr_api.h> 29 #endif 30 #include "wlan_cm_roam.h" 31 #include <qdf_platform.h> 32 #include <wlan_mlo_mgr_link_switch.h> 33 34 static uint32_t cm_get_prefix_for_cm_id(enum wlan_cm_source source) { 35 switch (source) { 36 case CM_OSIF_CONNECT: 37 case CM_OSIF_CFG_CONNECT: 38 case CM_MLO_LINK_VDEV_CONNECT: 39 case CM_MLO_LINK_SWITCH_CONNECT: 40 return CONNECT_REQ_PREFIX; 41 case CM_ROAMING_HOST: 42 case CM_ROAMING_FW: 43 case CM_ROAMING_NUD_FAILURE: 44 case CM_ROAMING_LINK_REMOVAL: 45 case CM_ROAMING_USER: 46 return ROAM_REQ_PREFIX; 47 default: 48 return DISCONNECT_REQ_PREFIX; 49 } 50 } 51 52 wlan_cm_id cm_get_cm_id(struct cnx_mgr *cm_ctx, enum wlan_cm_source source) 53 { 54 wlan_cm_id cm_id; 55 uint32_t prefix; 56 uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev); 57 58 prefix = cm_get_prefix_for_cm_id(source); 59 60 cm_id = qdf_atomic_inc_return(&cm_ctx->global_cmd_id); 61 cm_id = (cm_id & CM_ID_MASK); 62 cm_id = CM_ID_SET_VDEV_ID(cm_id, vdev_id); 63 cm_id = (cm_id | prefix); 64 if (source == CM_MLO_LINK_SWITCH_DISCONNECT || 65 source == CM_MLO_LINK_SWITCH_CONNECT) 66 cm_id |= CM_ID_LSWITCH_BIT; 67 68 return cm_id; 69 } 70 71 struct cnx_mgr *cm_get_cm_ctx_fl(struct wlan_objmgr_vdev *vdev, 72 const char *func, uint32_t line) 73 { 74 struct vdev_mlme_obj *vdev_mlme; 75 struct cnx_mgr *cm_ctx = NULL; 76 77 if (!vdev) { 78 mlme_rl_nofl_err("%s:%u: vdev is NULL", func, line); 79 return NULL; 80 } 81 82 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); 83 if (vdev_mlme) 84 cm_ctx = vdev_mlme->cnx_mgr_ctx; 85 86 if (!cm_ctx) 87 mlme_nofl_err("%s:%u: vdev %d cm_ctx is NULL", func, line, 88 wlan_vdev_get_id(vdev)); 89 90 return cm_ctx; 91 } 92 93 cm_ext_t *cm_get_ext_hdl_fl(struct wlan_objmgr_vdev *vdev, 94 const char *func, uint32_t line) 95 { 96 struct cnx_mgr *cm_ctx; 97 cm_ext_t *ext_ctx = NULL; 98 99 cm_ctx = cm_get_cm_ctx_fl(vdev, func, line); 100 if (cm_ctx) 101 ext_ctx = cm_ctx->ext_cm_ptr; 102 103 if (!ext_ctx) 104 mlme_nofl_err("%s:%u: vdev %d cm ext ctx is NULL", func, line, 105 wlan_vdev_get_id(vdev)); 106 return ext_ctx; 107 } 108 109 void cm_reset_active_cm_id(struct wlan_objmgr_vdev *vdev, wlan_cm_id cm_id) 110 { 111 struct cnx_mgr *cm_ctx; 112 113 cm_ctx = cm_get_cm_ctx(vdev); 114 if (!cm_ctx) 115 return; 116 117 /* Reset active cm id if cm id match */ 118 if (cm_ctx->active_cm_id == cm_id) 119 cm_ctx->active_cm_id = CM_ID_INVALID; 120 } 121 122 123 #ifdef WLAN_CM_USE_SPINLOCK 124 /** 125 * cm_req_lock_acquire - acquire CM SM mutex/spinlock 126 * @cm_ctx: connection manager ctx 127 * 128 * acquire CM SM mutex/spinlock 129 * 130 * return: void 131 */ 132 inline void cm_req_lock_acquire(struct cnx_mgr *cm_ctx) 133 { 134 qdf_spinlock_acquire(&cm_ctx->cm_req_lock); 135 } 136 137 /** 138 * cm_req_lock_release - release CM SM mutex/spinlock 139 * @cm_ctx: connection manager ctx 140 * 141 * release CM SM mutex/spinlock 142 * 143 * return: void 144 */ 145 inline void cm_req_lock_release(struct cnx_mgr *cm_ctx) 146 { 147 qdf_spinlock_release(&cm_ctx->cm_req_lock); 148 } 149 150 QDF_STATUS cm_activate_cmd_req_flush_cb(struct scheduler_msg *msg) 151 { 152 struct wlan_serialization_command *cmd = msg->bodyptr; 153 154 if (!cmd || !cmd->vdev) { 155 mlme_err("Null input cmd:%pK", cmd); 156 return QDF_STATUS_E_INVAL; 157 } 158 159 wlan_objmgr_vdev_release_ref(cmd->vdev, WLAN_MLME_CM_ID); 160 return QDF_STATUS_SUCCESS; 161 } 162 163 #else 164 inline void cm_req_lock_acquire(struct cnx_mgr *cm_ctx) 165 { 166 qdf_mutex_acquire(&cm_ctx->cm_req_lock); 167 } 168 169 inline void cm_req_lock_release(struct cnx_mgr *cm_ctx) 170 { 171 qdf_mutex_release(&cm_ctx->cm_req_lock); 172 } 173 #endif /* WLAN_CM_USE_SPINLOCK */ 174 175 #ifdef CRYPTO_SET_KEY_CONVERGED 176 QDF_STATUS cm_set_key(struct cnx_mgr *cm_ctx, bool unicast, 177 uint8_t key_idx, struct qdf_mac_addr *bssid) 178 { 179 enum wlan_crypto_cipher_type cipher; 180 struct wlan_crypto_key *crypto_key; 181 uint8_t wep_key_idx = 0; 182 183 cipher = wlan_crypto_get_cipher(cm_ctx->vdev, unicast, key_idx); 184 if (IS_WEP_CIPHER(cipher)) { 185 wep_key_idx = wlan_crypto_get_default_key_idx(cm_ctx->vdev, 186 false); 187 crypto_key = wlan_crypto_get_key(cm_ctx->vdev, wep_key_idx); 188 qdf_mem_copy(crypto_key->macaddr, bssid->bytes, 189 QDF_MAC_ADDR_SIZE); 190 } else { 191 crypto_key = wlan_crypto_get_key(cm_ctx->vdev, key_idx); 192 } 193 194 return wlan_crypto_set_key_req(cm_ctx->vdev, crypto_key, (unicast ? 195 WLAN_CRYPTO_KEY_TYPE_UNICAST : 196 WLAN_CRYPTO_KEY_TYPE_GROUP)); 197 } 198 #endif 199 200 #ifdef CONN_MGR_ADV_FEATURE 201 void cm_store_wep_key(struct cnx_mgr *cm_ctx, 202 struct wlan_cm_connect_crypto_info *crypto, 203 wlan_cm_id cm_id) 204 { 205 struct wlan_crypto_key *crypto_key = NULL; 206 QDF_STATUS status; 207 enum wlan_crypto_cipher_type cipher_type; 208 struct wlan_cm_wep_key_params *wep_keys; 209 210 if (!(crypto->ciphers_pairwise & (1 << WLAN_CRYPTO_CIPHER_WEP_40 | 211 1 << WLAN_CRYPTO_CIPHER_WEP_104))) 212 return; 213 214 if (crypto->ciphers_pairwise & 1 << WLAN_CRYPTO_CIPHER_WEP_40) 215 cipher_type = WLAN_CRYPTO_CIPHER_WEP_40; 216 else 217 cipher_type = WLAN_CRYPTO_CIPHER_WEP_104; 218 219 wep_keys = &crypto->wep_keys; 220 status = wlan_crypto_validate_key_params(cipher_type, 221 wep_keys->key_idx, 222 wep_keys->key_len, 223 wep_keys->seq_len); 224 if (QDF_IS_STATUS_ERROR(status)) { 225 mlme_err(CM_PREFIX_FMT "Invalid key params", 226 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id)); 227 return; 228 } 229 230 crypto_key = wlan_crypto_get_key(cm_ctx->vdev, wep_keys->key_idx); 231 if (!crypto_key) { 232 crypto_key = qdf_mem_malloc(sizeof(*crypto_key)); 233 if (!crypto_key) 234 return; 235 236 status = wlan_crypto_save_key(cm_ctx->vdev, wep_keys->key_idx, 237 crypto_key); 238 if (QDF_IS_STATUS_ERROR(status)) { 239 mlme_err(CM_PREFIX_FMT "Failed to save key", 240 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 241 cm_id)); 242 qdf_mem_free(crypto_key); 243 return; 244 } 245 } 246 qdf_mem_zero(crypto_key, sizeof(*crypto_key)); 247 crypto_key->cipher_type = cipher_type; 248 crypto_key->keylen = wep_keys->key_len; 249 crypto_key->keyix = wep_keys->key_idx; 250 qdf_mem_copy(&crypto_key->keyval[0], wep_keys->key, wep_keys->key_len); 251 qdf_mem_copy(&crypto_key->keyrsc[0], wep_keys->seq, wep_keys->seq_len); 252 mlme_debug(CM_PREFIX_FMT "cipher_type %d key_len %d, seq_len %d", 253 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id), 254 crypto_key->cipher_type, wep_keys->key_len, 255 wep_keys->seq_len); 256 } 257 258 void cm_trigger_panic_on_cmd_timeout(struct wlan_objmgr_vdev *vdev) 259 { 260 struct wlan_objmgr_psoc *psoc; 261 262 psoc = wlan_vdev_get_psoc(vdev); 263 if (!psoc) 264 return; 265 266 if (qdf_is_recovering() || qdf_is_fw_down()) 267 return; 268 269 qdf_trigger_self_recovery(psoc, QDF_ACTIVE_LIST_TIMEOUT); 270 } 271 272 #else 273 void cm_trigger_panic_on_cmd_timeout(struct wlan_objmgr_vdev *vdev) 274 { 275 struct vdev_mlme_obj *vdev_mlme = NULL; 276 struct wlan_sm *vdev_sm = NULL; 277 278 vdev_mlme = wlan_objmgr_vdev_get_comp_private_obj( 279 vdev, 280 WLAN_UMAC_COMP_MLME); 281 if (!vdev_mlme) { 282 mlme_err("VDEV MLME is null"); 283 goto error; 284 } 285 286 vdev_sm = vdev_mlme->sm_hdl; 287 if (!vdev_sm) { 288 mlme_err("VDEV SM is null"); 289 goto error; 290 } 291 292 wlan_sm_print_history(vdev_sm); 293 cm_sm_history_print(vdev); 294 error: 295 QDF_ASSERT(0); 296 } 297 #endif 298 299 #ifdef WLAN_FEATURE_FILS_SK 300 void cm_store_fils_key(struct cnx_mgr *cm_ctx, bool unicast, 301 uint8_t key_id, uint16_t key_length, 302 uint8_t *key, struct qdf_mac_addr *bssid, 303 wlan_cm_id cm_id) 304 { 305 struct wlan_crypto_key *crypto_key = NULL; 306 QDF_STATUS status; 307 uint8_t i; 308 int32_t cipher; 309 enum wlan_crypto_cipher_type cipher_type = WLAN_CRYPTO_CIPHER_NONE; 310 311 if (unicast) 312 cipher = wlan_crypto_get_param(cm_ctx->vdev, 313 WLAN_CRYPTO_PARAM_UCAST_CIPHER); 314 else 315 cipher = wlan_crypto_get_param(cm_ctx->vdev, 316 WLAN_CRYPTO_PARAM_MCAST_CIPHER); 317 318 for (i = 0; i <= WLAN_CRYPTO_CIPHER_MAX; i++) { 319 if (QDF_HAS_PARAM(cipher, i)) { 320 cipher_type = i; 321 break; 322 } 323 } 324 crypto_key = wlan_crypto_get_key(cm_ctx->vdev, key_id); 325 if (!crypto_key) { 326 crypto_key = qdf_mem_malloc(sizeof(*crypto_key)); 327 if (!crypto_key) 328 return; 329 status = wlan_crypto_save_key(cm_ctx->vdev, key_id, crypto_key); 330 if (QDF_IS_STATUS_ERROR(status)) { 331 mlme_err(CM_PREFIX_FMT "Failed to save key", 332 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 333 cm_id)); 334 qdf_mem_free(crypto_key); 335 return; 336 } 337 } 338 qdf_mem_zero(crypto_key, sizeof(*crypto_key)); 339 crypto_key->cipher_type = cipher_type; 340 crypto_key->keylen = key_length; 341 crypto_key->keyix = key_id; 342 qdf_mem_copy(&crypto_key->keyval[0], key, key_length); 343 qdf_mem_copy(crypto_key->macaddr, bssid->bytes, QDF_MAC_ADDR_SIZE); 344 mlme_debug(CM_PREFIX_FMT "cipher_type %d key_len %d, key_id %d mac:" QDF_MAC_ADDR_FMT, 345 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id), 346 crypto_key->cipher_type, crypto_key->keylen, 347 crypto_key->keyix, QDF_MAC_ADDR_REF(crypto_key->macaddr)); 348 } 349 static void cm_set_fils_connection_from_req(struct wlan_cm_connect_req *req, 350 struct wlan_cm_connect_resp *resp) 351 { 352 resp->is_fils_connection = req->fils_info.is_fils_connection; 353 } 354 #else 355 static inline 356 void cm_set_fils_connection_from_req(struct wlan_cm_connect_req *req, 357 struct wlan_cm_connect_resp *resp) 358 {} 359 #endif 360 361 bool cm_check_cmid_match_list_head(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id) 362 { 363 qdf_list_node_t *cur_node = NULL; 364 struct cm_req *cm_req; 365 bool match = false; 366 wlan_cm_id head_cm_id = 0; 367 368 if (!cm_id) 369 return false; 370 371 cm_req_lock_acquire(cm_ctx); 372 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 373 if (!cur_node) 374 goto exit; 375 376 cm_req = qdf_container_of(cur_node, struct cm_req, node); 377 head_cm_id = cm_req->cm_id; 378 if (head_cm_id == *cm_id) 379 match = true; 380 381 exit: 382 cm_req_lock_release(cm_ctx); 383 if (!match) 384 mlme_info("head_cm_id 0x%x didn't match the given cm_id 0x%x", 385 head_cm_id, *cm_id); 386 387 return match; 388 } 389 390 bool cm_check_scanid_match_list_head(struct cnx_mgr *cm_ctx, 391 wlan_scan_id *scan_id) 392 { 393 qdf_list_node_t *cur_node = NULL; 394 struct cm_req *cm_req; 395 bool match = false; 396 wlan_cm_id head_scan_id = 0; 397 uint32_t prefix = 0; 398 399 if (!scan_id) 400 return false; 401 402 cm_req_lock_acquire(cm_ctx); 403 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 404 if (!cur_node) 405 goto exit; 406 407 cm_req = qdf_container_of(cur_node, struct cm_req, node); 408 prefix = CM_ID_GET_PREFIX(cm_req->cm_id); 409 /* Check only if head is connect req */ 410 if (prefix != CONNECT_REQ_PREFIX) 411 goto exit; 412 head_scan_id = cm_req->connect_req.scan_id; 413 if (head_scan_id == *scan_id) 414 match = true; 415 416 exit: 417 cm_req_lock_release(cm_ctx); 418 if (!match) 419 mlme_info("head_scan_id 0x%x didn't match the given scan_id 0x%x prefix 0x%x", 420 head_scan_id, *scan_id, prefix); 421 422 return match; 423 } 424 425 struct cm_req *cm_get_req_by_cm_id_fl(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id, 426 const char *func, uint32_t line) 427 { 428 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 429 struct cm_req * cm_req; 430 431 cm_req_lock_acquire(cm_ctx); 432 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 433 while (cur_node) { 434 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 435 cm_req = qdf_container_of(cur_node, struct cm_req, node); 436 437 if (cm_req->cm_id == cm_id) { 438 cm_req_lock_release(cm_ctx); 439 return cm_req; 440 } 441 442 cur_node = next_node; 443 next_node = NULL; 444 } 445 cm_req_lock_release(cm_ctx); 446 447 mlme_nofl_info("%s:%u: cm req not found for cm id 0x%x", func, 448 line, cm_id); 449 450 return NULL; 451 } 452 453 #ifdef WLAN_FEATURE_11BE_MLO 454 void 455 cm_connect_resp_fill_mld_addr_from_candidate(struct wlan_objmgr_vdev *vdev, 456 struct scan_cache_entry *entry, 457 struct wlan_cm_connect_resp *resp) 458 { 459 struct qdf_mac_addr *mld_addr; 460 461 if (!entry || !vdev || !wlan_vdev_mlme_is_mlo_vdev(vdev)) 462 return; 463 464 mld_addr = util_scan_entry_mldaddr(entry); 465 if (!mld_addr) 466 return; 467 468 qdf_copy_macaddr(&resp->mld_addr, mld_addr); 469 } 470 471 void 472 cm_connect_resp_fill_mld_addr_from_cm_id(struct wlan_objmgr_vdev *vdev, 473 wlan_cm_id cm_id, 474 struct wlan_cm_connect_resp *rsp) 475 { 476 struct cm_req *cm_req; 477 struct cnx_mgr *cm_ctx; 478 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 479 struct scan_cache_entry *entry; 480 481 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) 482 return; 483 484 cm_ctx = cm_get_cm_ctx(vdev); 485 if (!cm_ctx) 486 return; 487 488 cm_req_lock_acquire(cm_ctx); 489 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 490 while (cur_node) { 491 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 492 cm_req = qdf_container_of(cur_node, struct cm_req, node); 493 494 if (cm_req->cm_id != cm_id) { 495 cur_node = next_node; 496 next_node = NULL; 497 continue; 498 } 499 500 if (!cm_req->connect_req.cur_candidate || 501 !cm_req->connect_req.cur_candidate->entry) 502 break; 503 504 entry = cm_req->connect_req.cur_candidate->entry; 505 cm_connect_resp_fill_mld_addr_from_candidate(vdev, entry, rsp); 506 break; 507 } 508 cm_req_lock_release(cm_ctx); 509 } 510 511 static void 512 cm_connect_resp_fill_mld_addr_from_scan_db(struct wlan_objmgr_vdev *vdev, 513 struct qdf_mac_addr *bssid, 514 struct wlan_cm_connect_resp *resp) 515 { 516 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) 517 return; 518 519 wlan_scan_get_mld_addr_by_link_addr(wlan_vdev_get_pdev(vdev), bssid, 520 &resp->mld_addr); 521 } 522 #else 523 static inline void 524 cm_connect_resp_fill_mld_addr_from_scan_db(struct wlan_objmgr_vdev *vdev, 525 struct qdf_mac_addr *bssid, 526 struct wlan_cm_connect_resp *resp) 527 { 528 } 529 #endif 530 531 /** 532 * cm_fill_connect_resp_from_req() - Fill connect resp from connect request 533 * @vdev: VDEV objmgr pointer 534 * @resp: cm connect response 535 * @cm_req: cm request 536 * 537 * Context: Can be called from APIs holding cm request list lock 538 * 539 * Return: void 540 */ 541 static void 542 cm_fill_connect_resp_from_req(struct wlan_objmgr_vdev *vdev, 543 struct wlan_cm_connect_resp *resp, 544 struct cm_req *cm_req) 545 { 546 struct scan_cache_node *candidate; 547 struct wlan_cm_connect_req *req; 548 549 req = &cm_req->connect_req.req; 550 candidate = cm_req->connect_req.cur_candidate; 551 if (candidate) { 552 qdf_copy_macaddr(&resp->bssid, &candidate->entry->bssid); 553 cm_connect_resp_fill_mld_addr_from_candidate(vdev, 554 candidate->entry, 555 resp); 556 } else if (!qdf_is_macaddr_zero(&req->bssid)) { 557 qdf_copy_macaddr(&resp->bssid, &req->bssid); 558 cm_connect_resp_fill_mld_addr_from_scan_db(vdev, &req->bssid, 559 resp); 560 } else { 561 qdf_copy_macaddr(&resp->bssid, &req->bssid_hint); 562 cm_connect_resp_fill_mld_addr_from_scan_db(vdev, &req->bssid, 563 resp); 564 } 565 566 if (candidate) 567 resp->freq = candidate->entry->channel.chan_freq; 568 else if (req->chan_freq) 569 resp->freq = req->chan_freq; 570 else 571 resp->freq = req->chan_freq_hint; 572 573 resp->ssid = req->ssid; 574 resp->is_wps_connection = req->is_wps_connection; 575 resp->is_osen_connection = req->is_osen_connection; 576 cm_set_fils_connection_from_req(req, resp); 577 } 578 579 /** 580 * cm_handle_connect_flush() - Fill fail connect resp from req and indicate 581 * same to osif 582 * @cm_ctx: connection manager context 583 * @cm_req: cm request 584 * 585 * Context: Can be called from APIs holding cm request list lock 586 * 587 * Return: void 588 */ 589 static void 590 cm_handle_connect_flush(struct cnx_mgr *cm_ctx, struct cm_req *cm_req) 591 { 592 struct wlan_cm_connect_resp *resp; 593 594 resp = qdf_mem_malloc(sizeof(*resp)); 595 if (!resp) 596 return; 597 598 resp->connect_status = QDF_STATUS_E_FAILURE; 599 resp->cm_id = cm_req->cm_id; 600 resp->vdev_id = wlan_vdev_get_id(cm_ctx->vdev); 601 if (cm_req->failed_req) 602 resp->reason = CM_GENERIC_FAILURE; 603 else 604 resp->reason = CM_ABORT_DUE_TO_NEW_REQ_RECVD; 605 606 /* Get bssid and ssid and freq for the cm id from the req list */ 607 cm_fill_connect_resp_from_req(cm_ctx->vdev, resp, cm_req); 608 609 cm_notify_connect_complete(cm_ctx, resp, 0); 610 611 /* For link switch connect request, notify MLO mgr */ 612 if (cm_is_link_switch_connect_resp(resp)) { 613 cm_reset_active_cm_id(cm_ctx->vdev, resp->cm_id); 614 mlo_mgr_link_switch_connect_done(cm_ctx->vdev, 615 resp->connect_status); 616 } 617 618 qdf_mem_free(resp); 619 } 620 621 /** 622 * cm_handle_disconnect_flush() - Fill disconnect resp from req and indicate 623 * same to osif 624 * @cm_ctx: connection manager context 625 * @cm_req: cm request 626 * 627 * Context: Can be called from APIs holding cm request list lock 628 * 629 * Return: void 630 */ 631 static void 632 cm_handle_disconnect_flush(struct cnx_mgr *cm_ctx, struct cm_req *cm_req) 633 { 634 struct wlan_cm_discon_rsp resp; 635 636 qdf_mem_zero(&resp, sizeof(resp)); 637 resp.req.cm_id = cm_req->cm_id; 638 resp.req.req = cm_req->discon_req.req; 639 /* 640 * Indicate to OSIF to inform kernel if not already done and this is 641 * the latest disconnect req received. If this is not the latest, it 642 * will be dropped in OSIF as src and cm_id will not match. A flushed 643 * disconnect can be last of this was received when previous disconnect 644 * was already in serialization active queue and thus wasn't flushed. 645 */ 646 mlme_cm_osif_disconnect_complete(cm_ctx->vdev, &resp); 647 648 if (cm_is_link_switch_disconnect_resp(&resp)) { 649 cm_reset_active_cm_id(cm_ctx->vdev, resp.req.cm_id); 650 mlo_mgr_link_switch_disconnect_done(cm_ctx->vdev, 651 QDF_STATUS_E_ABORTED, 652 true); 653 } 654 } 655 656 void cm_remove_cmd_from_serialization(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id) 657 { 658 struct wlan_serialization_queued_cmd_info cmd_info; 659 uint32_t prefix = CM_ID_GET_PREFIX(cm_id); 660 661 qdf_mem_zero(&cmd_info, sizeof(cmd_info)); 662 cmd_info.cmd_id = cm_id; 663 cmd_info.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD; 664 665 if (prefix == CONNECT_REQ_PREFIX) { 666 cmd_info.cmd_type = WLAN_SER_CMD_VDEV_CONNECT; 667 } else if (prefix == ROAM_REQ_PREFIX) { 668 /* 669 * Try removing PREAUTH command when in preauth state else 670 * try remove ROAM command 671 */ 672 if (cm_ctx->preauth_in_progress) 673 cmd_info.cmd_type = WLAN_SER_CMD_PERFORM_PRE_AUTH; 674 else 675 cmd_info.cmd_type = WLAN_SER_CMD_VDEV_ROAM; 676 cm_ctx->preauth_in_progress = false; 677 } else if (prefix == DISCONNECT_REQ_PREFIX) { 678 cmd_info.cmd_type = WLAN_SER_CMD_VDEV_DISCONNECT; 679 } else { 680 mlme_err(CM_PREFIX_FMT "Invalid prefix %x", 681 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id), 682 prefix); 683 return; 684 } 685 686 cmd_info.vdev = cm_ctx->vdev; 687 688 if (cm_id == cm_ctx->active_cm_id) { 689 mlme_debug(CM_PREFIX_FMT "Remove cmd type %d from active", 690 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id), 691 cmd_info.cmd_type); 692 cmd_info.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE; 693 /* 694 * Active command id is reset during memory release, but a new 695 * command will become active before memory release of 696 * serialization command, and if it try to check the active 697 * cm_id(using cm_get_active_req_type) it will be valid (), so 698 * reset the cm id for active command before calling release 699 * active command. 700 * One example: For ML vdevs, disconnect on Assoc vdev can get 701 * activated before release memory of link vdev command which 702 * reset active CM id, and thus during RSO stop can lead to 703 * assumption that link vdev disconnect is active when it is not. 704 */ 705 cm_reset_active_cm_id(cm_ctx->vdev, cm_id); 706 wlan_serialization_remove_cmd(&cmd_info); 707 } else { 708 mlme_debug(CM_PREFIX_FMT "Remove cmd type %d from pending", 709 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id), 710 cmd_info.cmd_type); 711 cmd_info.queue_type = WLAN_SERIALIZATION_PENDING_QUEUE; 712 wlan_serialization_cancel_request(&cmd_info); 713 } 714 } 715 716 void 717 cm_flush_pending_request(struct cnx_mgr *cm_ctx, uint32_t prefix, 718 bool only_failed_req) 719 { 720 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 721 struct cm_req *cm_req; 722 uint32_t req_prefix; 723 bool roam_offload = false; 724 725 if (cm_roam_offload_enabled(wlan_vdev_get_psoc(cm_ctx->vdev)) && 726 prefix == ROAM_REQ_PREFIX) 727 roam_offload = true; 728 729 cm_req_lock_acquire(cm_ctx); 730 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 731 while (cur_node) { 732 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 733 cm_req = qdf_container_of(cur_node, struct cm_req, node); 734 735 req_prefix = CM_ID_GET_PREFIX(cm_req->cm_id); 736 737 /* 738 * Only remove requests matching the flush prefix and 739 * the pending req for non roam offload(LFR3) commands 740 * (roam command is dummy in FW roam/LFR3 so active 741 * command can be removed) 742 */ 743 if (req_prefix != prefix || 744 (!roam_offload && cm_req->cm_id == cm_ctx->active_cm_id)) 745 goto next; 746 747 /* If only_failed_req is set flush only failed req */ 748 if (only_failed_req && !cm_req->failed_req) 749 goto next; 750 751 if (req_prefix == CONNECT_REQ_PREFIX) { 752 cm_handle_connect_flush(cm_ctx, cm_req); 753 cm_ctx->connect_count--; 754 cm_free_connect_req_mem(&cm_req->connect_req); 755 } else if (req_prefix == ROAM_REQ_PREFIX) { 756 cm_free_roam_req_mem(&cm_req->roam_req); 757 } else if (req_prefix == DISCONNECT_REQ_PREFIX) { 758 cm_handle_disconnect_flush(cm_ctx, cm_req); 759 cm_ctx->disconnect_count--; 760 } else { 761 mlme_err(CM_PREFIX_FMT "Invalid prefix %x", 762 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 763 cm_req->cm_id), prefix); 764 } 765 766 cm_req_history_del(cm_ctx, cm_req, CM_REQ_DEL_FLUSH); 767 mlme_debug(CM_PREFIX_FMT, 768 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 769 cm_req->cm_id)); 770 cm_remove_cmd_from_serialization(cm_ctx, cm_req->cm_id); 771 qdf_list_remove_node(&cm_ctx->req_list, &cm_req->node); 772 qdf_mem_free(cm_req); 773 next: 774 cur_node = next_node; 775 next_node = NULL; 776 } 777 778 cm_req_lock_release(cm_ctx); 779 } 780 781 QDF_STATUS 782 cm_fill_bss_info_in_connect_rsp_by_cm_id(struct cnx_mgr *cm_ctx, 783 wlan_cm_id cm_id, 784 struct wlan_cm_connect_resp *resp) 785 { 786 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 787 struct cm_req *cm_req; 788 uint32_t prefix = CM_ID_GET_PREFIX(cm_id); 789 790 if (prefix != CONNECT_REQ_PREFIX) 791 return QDF_STATUS_E_INVAL; 792 793 cm_req_lock_acquire(cm_ctx); 794 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 795 while (cur_node) { 796 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 797 cm_req = qdf_container_of(cur_node, struct cm_req, node); 798 799 if (cm_req->cm_id == cm_id) { 800 cm_fill_connect_resp_from_req(cm_ctx->vdev, 801 resp, cm_req); 802 cm_req_lock_release(cm_ctx); 803 return QDF_STATUS_SUCCESS; 804 } 805 806 cur_node = next_node; 807 next_node = NULL; 808 } 809 cm_req_lock_release(cm_ctx); 810 811 return QDF_STATUS_E_FAILURE; 812 } 813 814 #if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD) 815 bool cm_is_cm_id_current_candidate_single_pmk(struct cnx_mgr *cm_ctx, 816 wlan_cm_id cm_id) 817 { 818 struct wlan_objmgr_psoc *psoc; 819 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 820 struct cm_req *cm_req; 821 uint32_t prefix = CM_ID_GET_PREFIX(cm_id); 822 int32_t akm; 823 struct scan_cache_node *candidate; 824 bool is_single_pmk = false; 825 826 psoc = wlan_vdev_get_psoc(cm_ctx->vdev); 827 if (!psoc) { 828 mlme_err(CM_PREFIX_FMT "Failed to find psoc", 829 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 830 cm_id)); 831 return is_single_pmk; 832 } 833 834 if (prefix != CONNECT_REQ_PREFIX) 835 return is_single_pmk; 836 837 akm = wlan_crypto_get_param(cm_ctx->vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); 838 if (!QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE)) 839 return is_single_pmk; 840 841 cm_req_lock_acquire(cm_ctx); 842 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 843 while (cur_node) { 844 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 845 cm_req = qdf_container_of(cur_node, struct cm_req, node); 846 847 if (cm_req->cm_id == cm_id) { 848 candidate = cm_req->connect_req.cur_candidate; 849 if (candidate && 850 util_scan_entry_single_pmk(psoc, candidate->entry)) 851 is_single_pmk = true; 852 break; 853 } 854 855 cur_node = next_node; 856 next_node = NULL; 857 } 858 cm_req_lock_release(cm_ctx); 859 860 return is_single_pmk; 861 } 862 #endif 863 864 QDF_STATUS cm_add_req_to_list_and_indicate_osif(struct cnx_mgr *cm_ctx, 865 struct cm_req *cm_req, 866 enum wlan_cm_source source) 867 { 868 uint32_t prefix = CM_ID_GET_PREFIX(cm_req->cm_id); 869 870 cm_req_lock_acquire(cm_ctx); 871 if (qdf_list_size(&cm_ctx->req_list) >= CM_MAX_REQ) { 872 cm_req_lock_release(cm_ctx); 873 mlme_err(CM_PREFIX_FMT "List full size %d", 874 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 875 cm_req->cm_id), 876 qdf_list_size(&cm_ctx->req_list)); 877 return QDF_STATUS_E_FAILURE; 878 } 879 880 qdf_list_insert_front(&cm_ctx->req_list, &cm_req->node); 881 if (prefix == CONNECT_REQ_PREFIX) 882 cm_ctx->connect_count++; 883 else if (prefix == DISCONNECT_REQ_PREFIX) 884 cm_ctx->disconnect_count++; 885 886 cm_req_history_add(cm_ctx, cm_req); 887 cm_req_lock_release(cm_ctx); 888 mlme_debug(CM_PREFIX_FMT, 889 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 890 cm_req->cm_id)); 891 892 mlme_cm_osif_update_id_and_src(cm_ctx->vdev, source, cm_req->cm_id); 893 894 return QDF_STATUS_SUCCESS; 895 } 896 897 static void cm_zero_and_free_memory(uint8_t *ptr, uint32_t len) 898 { 899 if (!ptr) 900 return; 901 902 qdf_mem_zero(ptr, len); 903 qdf_mem_free(ptr); 904 } 905 906 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 907 /** 908 * cm_free_roaming_info() - Function to free all params in roaming info 909 * @connect_rsp: pointer to connect response 910 * 911 * Function to free up all the memory in connect response 912 * 913 * Return: void 914 */ 915 static 916 void cm_free_roaming_info(struct wlan_cm_connect_resp *connect_rsp) 917 { 918 cm_zero_and_free_memory((uint8_t *)connect_rsp->roaming_info, 919 sizeof(*connect_rsp->roaming_info)); 920 } 921 #else 922 static inline 923 void cm_free_roaming_info(struct wlan_cm_connect_resp *connect_rsp) 924 { 925 } 926 #endif 927 928 #ifdef WLAN_FEATURE_FILS_SK 929 /** 930 * cm_free_fils_ie() - function to free all params in fils ie 931 * @connect_ie: ptr to connect ies 932 * 933 * Function to free up all the memory in fils ies response. 934 * 935 * Return: void 936 */ 937 static 938 void cm_free_fils_ie(struct wlan_connect_rsp_ies *connect_ie) 939 { 940 if (!connect_ie->fils_ie) 941 return; 942 943 if (connect_ie->fils_ie->fils_pmk) 944 cm_zero_and_free_memory(connect_ie->fils_ie->fils_pmk, 945 connect_ie->fils_ie->fils_pmk_len); 946 947 cm_zero_and_free_memory((uint8_t *)connect_ie->fils_ie, 948 sizeof(*connect_ie->fils_ie)); 949 } 950 #else 951 static inline 952 void cm_free_fils_ie(struct wlan_connect_rsp_ies *connect_ie) 953 { 954 } 955 #endif 956 957 /** 958 * cm_free_connect_ies() - Function to free all params in coonect ies 959 * @connect_ie: ptr to connect ies 960 * 961 * Function to free up all the memory in connect ies response 962 * 963 * Return: void 964 */ 965 static 966 void cm_free_connect_ies(struct wlan_connect_rsp_ies *connect_ie) 967 { 968 cm_zero_and_free_memory(connect_ie->assoc_req.ptr, 969 connect_ie->assoc_req.len); 970 connect_ie->assoc_req.len = 0; 971 972 cm_zero_and_free_memory(connect_ie->bcn_probe_rsp.ptr, 973 connect_ie->bcn_probe_rsp.len); 974 connect_ie->bcn_probe_rsp.len = 0; 975 976 cm_zero_and_free_memory(connect_ie->link_bcn_probe_rsp.ptr, 977 connect_ie->link_bcn_probe_rsp.len); 978 connect_ie->link_bcn_probe_rsp.len = 0; 979 980 cm_zero_and_free_memory(connect_ie->assoc_rsp.ptr, 981 connect_ie->assoc_rsp.len); 982 connect_ie->assoc_rsp.len = 0; 983 } 984 985 void cm_free_connect_rsp_ies(struct wlan_cm_connect_resp *connect_rsp) 986 { 987 cm_free_connect_ies(&connect_rsp->connect_ies); 988 cm_free_fils_ie(&connect_rsp->connect_ies); 989 cm_free_roaming_info(connect_rsp); 990 } 991 992 static void cm_free_connect_req_ies(struct wlan_cm_connect_req *req) 993 { 994 cm_zero_and_free_memory(req->assoc_ie.ptr, req->assoc_ie.len); 995 req->assoc_ie.ptr = NULL; 996 cm_zero_and_free_memory(req->scan_ie.ptr, req->scan_ie.len); 997 req->scan_ie.ptr = NULL; 998 } 999 1000 void cm_free_wep_key_params(struct wlan_cm_connect_req *req) 1001 { 1002 cm_zero_and_free_memory(req->crypto.wep_keys.key, 1003 req->crypto.wep_keys.key_len); 1004 req->crypto.wep_keys.key = NULL; 1005 cm_zero_and_free_memory(req->crypto.wep_keys.seq, 1006 req->crypto.wep_keys.seq_len); 1007 req->crypto.wep_keys.seq = NULL; 1008 } 1009 1010 void cm_free_connect_req_param(struct wlan_cm_connect_req *req) 1011 { 1012 cm_free_connect_req_ies(req); 1013 cm_free_wep_key_params(req); 1014 } 1015 1016 void cm_free_connect_req(struct wlan_cm_connect_req *req) 1017 { 1018 cm_free_connect_req_param(req); 1019 cm_zero_and_free_memory((uint8_t *)req, sizeof(*req)); 1020 } 1021 1022 void cm_free_connect_rsp(struct wlan_cm_connect_resp *connect_rsp) 1023 { 1024 cm_free_connect_rsp_ies(connect_rsp); 1025 cm_zero_and_free_memory((uint8_t *)connect_rsp, sizeof(*connect_rsp)); 1026 } 1027 1028 #ifdef CONN_MGR_ADV_FEATURE 1029 /** 1030 * cm_free_first_connect_rsp() - Function to free all params in connect rsp 1031 * @req: pointer to connect req struct 1032 * 1033 * Function to free up all the memory in connect rsp. 1034 * 1035 * Return: void 1036 */ 1037 static 1038 void cm_free_first_connect_rsp(struct cm_connect_req *req) 1039 { 1040 struct wlan_cm_connect_resp *connect_rsp = req->first_candidate_rsp; 1041 1042 if (!connect_rsp) 1043 return; 1044 1045 cm_free_connect_rsp(connect_rsp); 1046 } 1047 #else 1048 static inline 1049 void cm_free_first_connect_rsp(struct cm_connect_req *req) 1050 { 1051 } 1052 #endif /* CONN_MGR_ADV_FEATURE */ 1053 1054 void cm_free_connect_req_mem(struct cm_connect_req *connect_req) 1055 { 1056 struct wlan_cm_connect_req *req; 1057 1058 req = &connect_req->req; 1059 1060 if (connect_req->candidate_list) 1061 wlan_scan_purge_results(connect_req->candidate_list); 1062 1063 cm_free_connect_req_param(req); 1064 1065 cm_free_first_connect_rsp(connect_req); 1066 1067 qdf_mem_zero(connect_req, sizeof(*connect_req)); 1068 } 1069 1070 QDF_STATUS 1071 cm_delete_req_from_list(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id) 1072 { 1073 uint32_t prefix = CM_ID_GET_PREFIX(cm_id); 1074 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 1075 struct cm_req *cm_req = NULL; 1076 1077 cm_req_lock_acquire(cm_ctx); 1078 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 1079 while (cur_node) { 1080 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 1081 1082 cm_req = qdf_container_of(cur_node, struct cm_req, node); 1083 if (cm_req->cm_id == cm_id) 1084 break; 1085 1086 cur_node = next_node; 1087 next_node = NULL; 1088 cm_req = NULL; 1089 } 1090 1091 if (!cm_req) { 1092 cm_req_lock_release(cm_ctx); 1093 mlme_err(CM_PREFIX_FMT " req not found", 1094 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id)); 1095 return QDF_STATUS_E_FAILURE; 1096 } 1097 1098 qdf_list_remove_node(&cm_ctx->req_list, &cm_req->node); 1099 if (prefix == CONNECT_REQ_PREFIX) { 1100 cm_ctx->connect_count--; 1101 cm_free_connect_req_mem(&cm_req->connect_req); 1102 } else if (prefix == ROAM_REQ_PREFIX) { 1103 cm_free_roam_req_mem(&cm_req->roam_req); 1104 } else if (prefix == DISCONNECT_REQ_PREFIX) { 1105 cm_ctx->disconnect_count--; 1106 } else { 1107 mlme_err(CM_PREFIX_FMT "Invalid prefix %x", 1108 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 1109 cm_req->cm_id), prefix); 1110 } 1111 1112 if (cm_id == cm_ctx->active_cm_id) 1113 cm_req_history_del(cm_ctx, cm_req, CM_REQ_DEL_ACTIVE); 1114 else 1115 cm_req_history_del(cm_ctx, cm_req, CM_REQ_DEL_PENDING); 1116 1117 mlme_debug(CM_PREFIX_FMT, 1118 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 1119 cm_req->cm_id)); 1120 1121 qdf_mem_free(cm_req); 1122 cm_req_lock_release(cm_ctx); 1123 1124 return QDF_STATUS_SUCCESS; 1125 } 1126 1127 void cm_remove_cmd(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id_to_remove) 1128 { 1129 struct wlan_objmgr_psoc *psoc; 1130 QDF_STATUS status; 1131 wlan_cm_id cm_id; 1132 1133 if (!cm_id_to_remove) { 1134 mlme_err("cm_id_to_remove is null"); 1135 return; 1136 } 1137 1138 /* 1139 * store local value as cm_delete_req_from_list may free the 1140 * cm_id_to_remove pointer 1141 */ 1142 cm_id = *cm_id_to_remove; 1143 /* return if zero or invalid cm_id */ 1144 if (!cm_id || cm_id == CM_ID_INVALID) { 1145 mlme_debug(CM_PREFIX_FMT " Invalid cm_id", 1146 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 1147 cm_id)); 1148 return; 1149 } 1150 1151 psoc = wlan_vdev_get_psoc(cm_ctx->vdev); 1152 if (!psoc) { 1153 mlme_err(CM_PREFIX_FMT "Failed to find psoc", 1154 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id)); 1155 return; 1156 } 1157 1158 status = cm_delete_req_from_list(cm_ctx, cm_id); 1159 if (QDF_IS_STATUS_ERROR(status)) 1160 return; 1161 1162 if (cm_is_link_switch_cmd(cm_id)) { 1163 mlme_debug("Skip cmd remove for link switch connect/disconnect"); 1164 return; 1165 } 1166 1167 cm_remove_cmd_from_serialization(cm_ctx, cm_id); 1168 } 1169 1170 void cm_vdev_scan_cancel(struct wlan_objmgr_pdev *pdev, 1171 struct wlan_objmgr_vdev *vdev) 1172 { 1173 struct scan_cancel_request *req; 1174 QDF_STATUS status; 1175 1176 req = qdf_mem_malloc(sizeof(*req)); 1177 if (!req) 1178 return; 1179 1180 req->vdev = vdev; 1181 req->cancel_req.scan_id = INVAL_SCAN_ID; 1182 req->cancel_req.vdev_id = wlan_vdev_get_id(vdev); 1183 req->cancel_req.pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); 1184 req->cancel_req.req_type = WLAN_SCAN_CANCEL_VDEV_ALL; 1185 1186 status = wlan_scan_cancel(req); 1187 /* In success/failure case wlan_scan_cancel free the req memory */ 1188 if (QDF_IS_STATUS_ERROR(status)) 1189 mlme_err("vdev %d cancel scan request failed", 1190 wlan_vdev_get_id(vdev)); 1191 } 1192 1193 void cm_set_max_connect_attempts(struct wlan_objmgr_vdev *vdev, 1194 uint8_t max_connect_attempts) 1195 { 1196 struct cnx_mgr *cm_ctx; 1197 1198 cm_ctx = cm_get_cm_ctx(vdev); 1199 if (!cm_ctx) 1200 return; 1201 1202 cm_ctx->max_connect_attempts = 1203 QDF_MIN(max_connect_attempts, CM_MAX_CONNECT_ATTEMPTS); 1204 mlme_debug("vdev %d max connect attempts set to %d, requested %d", 1205 wlan_vdev_get_id(vdev), 1206 cm_ctx->max_connect_attempts, max_connect_attempts); 1207 } 1208 1209 void cm_set_max_connect_timeout(struct wlan_objmgr_vdev *vdev, 1210 uint32_t max_connect_timeout) 1211 { 1212 struct cnx_mgr *cm_ctx; 1213 1214 cm_ctx = cm_get_cm_ctx(vdev); 1215 if (!cm_ctx) 1216 return; 1217 1218 cm_ctx->connect_timeout = max_connect_timeout; 1219 } 1220 1221 QDF_STATUS 1222 cm_fill_disconnect_resp_from_cm_id(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id, 1223 struct wlan_cm_discon_rsp *resp) 1224 { 1225 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 1226 struct cm_req *cm_req; 1227 uint32_t prefix = CM_ID_GET_PREFIX(cm_id); 1228 1229 if (prefix != DISCONNECT_REQ_PREFIX) 1230 return QDF_STATUS_E_INVAL; 1231 1232 cm_req_lock_acquire(cm_ctx); 1233 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 1234 while (cur_node) { 1235 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 1236 cm_req = qdf_container_of(cur_node, struct cm_req, node); 1237 1238 if (cm_req->cm_id == cm_id) { 1239 resp->req.cm_id = cm_id; 1240 resp->req.req = cm_req->discon_req.req; 1241 cm_req_lock_release(cm_ctx); 1242 return QDF_STATUS_SUCCESS; 1243 } 1244 1245 cur_node = next_node; 1246 next_node = NULL; 1247 } 1248 cm_req_lock_release(cm_ctx); 1249 1250 return QDF_STATUS_E_FAILURE; 1251 } 1252 1253 void cm_inform_bcn_probe(struct cnx_mgr *cm_ctx, uint8_t *bcn_probe, 1254 uint32_t len, qdf_freq_t freq, int32_t rssi, 1255 wlan_cm_id cm_id) 1256 { 1257 qdf_nbuf_t buf; 1258 struct wlan_objmgr_pdev *pdev; 1259 uint8_t *data, i, vdev_id; 1260 struct mgmt_rx_event_params rx_param = {0}; 1261 struct wlan_frame_hdr *hdr; 1262 enum mgmt_frame_type frm_type = MGMT_BEACON; 1263 1264 vdev_id = wlan_vdev_get_id(cm_ctx->vdev); 1265 if (!bcn_probe || !len || (len < sizeof(*hdr))) { 1266 mlme_err(CM_PREFIX_FMT "bcn_probe is null or invalid len %d", 1267 CM_PREFIX_REF(vdev_id, cm_id), len); 1268 return; 1269 } 1270 1271 pdev = wlan_vdev_get_pdev(cm_ctx->vdev); 1272 if (!pdev) { 1273 mlme_err(CM_PREFIX_FMT "Failed to find pdev", 1274 CM_PREFIX_REF(vdev_id, cm_id)); 1275 return; 1276 } 1277 1278 hdr = (struct wlan_frame_hdr *)bcn_probe; 1279 if ((hdr->i_fc[0] & QDF_IEEE80211_FC0_SUBTYPE_MASK) == 1280 MGMT_SUBTYPE_PROBE_RESP) 1281 frm_type = MGMT_PROBE_RESP; 1282 1283 rx_param.pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); 1284 rx_param.chan_freq = freq; 1285 rx_param.rssi = rssi; 1286 1287 /* Set all per chain rssi as invalid */ 1288 for (i = 0; i < WLAN_MGMT_TXRX_HOST_MAX_ANTENNA; i++) 1289 rx_param.rssi_ctl[i] = WLAN_INVALID_PER_CHAIN_RSSI; 1290 1291 buf = qdf_nbuf_alloc(NULL, qdf_roundup(len, 4), 0, 4, false); 1292 if (!buf) 1293 return; 1294 1295 qdf_nbuf_put_tail(buf, len); 1296 qdf_nbuf_set_protocol(buf, ETH_P_CONTROL); 1297 1298 data = qdf_nbuf_data(buf); 1299 qdf_mem_copy(data, bcn_probe, len); 1300 /* buf will be freed by scan module in error or success case */ 1301 wlan_scan_process_bcn_probe_rx_sync(wlan_pdev_get_psoc(pdev), buf, 1302 &rx_param, frm_type); 1303 } 1304 1305 bool cm_is_vdev_connecting(struct wlan_objmgr_vdev *vdev) 1306 { 1307 struct cnx_mgr *cm_ctx; 1308 enum wlan_cm_sm_state state; 1309 1310 cm_ctx = cm_get_cm_ctx(vdev); 1311 if (!cm_ctx) 1312 return false; 1313 1314 state = cm_get_state(cm_ctx); 1315 1316 if (state == WLAN_CM_S_CONNECTING) 1317 return true; 1318 1319 return false; 1320 } 1321 1322 bool cm_is_vdev_connected(struct wlan_objmgr_vdev *vdev) 1323 { 1324 struct cnx_mgr *cm_ctx; 1325 enum wlan_cm_sm_state state; 1326 1327 cm_ctx = cm_get_cm_ctx(vdev); 1328 if (!cm_ctx) 1329 return false; 1330 1331 state = cm_get_state(cm_ctx); 1332 1333 if (state == WLAN_CM_S_CONNECTED) 1334 return true; 1335 1336 return false; 1337 } 1338 1339 bool cm_is_vdev_active(struct wlan_objmgr_vdev *vdev) 1340 { 1341 struct cnx_mgr *cm_ctx; 1342 enum wlan_cm_sm_state state; 1343 1344 cm_ctx = cm_get_cm_ctx(vdev); 1345 if (!cm_ctx) 1346 return false; 1347 1348 state = cm_get_state(cm_ctx); 1349 1350 if (state == WLAN_CM_S_CONNECTED || state == WLAN_CM_S_ROAMING) 1351 return true; 1352 1353 return false; 1354 } 1355 1356 bool cm_is_vdev_disconnecting(struct wlan_objmgr_vdev *vdev) 1357 { 1358 struct cnx_mgr *cm_ctx; 1359 enum wlan_cm_sm_state state; 1360 1361 cm_ctx = cm_get_cm_ctx(vdev); 1362 if (!cm_ctx) 1363 return false; 1364 1365 state = cm_get_state(cm_ctx); 1366 1367 if (state == WLAN_CM_S_DISCONNECTING) 1368 return true; 1369 1370 return false; 1371 } 1372 1373 bool cm_is_vdev_disconnected(struct wlan_objmgr_vdev *vdev) 1374 { 1375 struct cnx_mgr *cm_ctx; 1376 enum wlan_cm_sm_state state; 1377 1378 cm_ctx = cm_get_cm_ctx(vdev); 1379 if (!cm_ctx) 1380 return true; 1381 1382 state = cm_get_state(cm_ctx); 1383 1384 if (state == WLAN_CM_S_INIT) 1385 return true; 1386 1387 return false; 1388 } 1389 1390 #ifdef CONN_MGR_ADV_FEATURE 1391 bool cm_is_vdev_idle_due_to_link_switch(struct wlan_objmgr_vdev *vdev) 1392 { 1393 struct cnx_mgr *cm_ctx; 1394 enum wlan_cm_sm_state state; 1395 enum wlan_cm_sm_state sub_state; 1396 1397 cm_ctx = cm_get_cm_ctx(vdev); 1398 if (!cm_ctx) 1399 return false; 1400 1401 state = cm_get_state(cm_ctx); 1402 sub_state = cm_get_sub_state(cm_ctx); 1403 1404 if (state == WLAN_CM_S_INIT && 1405 sub_state == WLAN_CM_SS_IDLE_DUE_TO_LINK_SWITCH) 1406 return true; 1407 1408 return false; 1409 } 1410 #endif 1411 1412 bool cm_is_vdev_roaming(struct wlan_objmgr_vdev *vdev) 1413 { 1414 struct cnx_mgr *cm_ctx; 1415 enum wlan_cm_sm_state state; 1416 1417 cm_ctx = cm_get_cm_ctx(vdev); 1418 if (!cm_ctx) 1419 return false; 1420 1421 state = cm_get_state(cm_ctx); 1422 1423 if (state == WLAN_CM_S_ROAMING) 1424 return true; 1425 1426 return false; 1427 } 1428 1429 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 1430 bool cm_is_vdev_roam_started(struct wlan_objmgr_vdev *vdev) 1431 { 1432 struct cnx_mgr *cm_ctx; 1433 enum wlan_cm_sm_state state; 1434 enum wlan_cm_sm_state sub_state; 1435 1436 cm_ctx = cm_get_cm_ctx(vdev); 1437 if (!cm_ctx) 1438 return false; 1439 1440 state = cm_get_state(cm_ctx); 1441 sub_state = cm_get_sub_state(cm_ctx); 1442 if (state == WLAN_CM_S_ROAMING && sub_state == WLAN_CM_SS_ROAM_STARTED) 1443 return true; 1444 1445 return false; 1446 } 1447 1448 bool cm_is_vdev_roam_sync_inprogress(struct wlan_objmgr_vdev *vdev) 1449 { 1450 struct cnx_mgr *cm_ctx; 1451 enum wlan_cm_sm_state state; 1452 enum wlan_cm_sm_state sub_state; 1453 1454 cm_ctx = cm_get_cm_ctx(vdev); 1455 if (!cm_ctx) 1456 return false; 1457 1458 state = cm_get_state(cm_ctx); 1459 sub_state = cm_get_sub_state(cm_ctx); 1460 if (state == WLAN_CM_S_ROAMING && sub_state == WLAN_CM_SS_ROAM_SYNC) 1461 return true; 1462 1463 return false; 1464 } 1465 #endif 1466 1467 #ifdef WLAN_FEATURE_HOST_ROAM 1468 bool cm_is_vdev_roam_preauth_state(struct wlan_objmgr_vdev *vdev) 1469 { 1470 struct cnx_mgr *cm_ctx; 1471 enum wlan_cm_sm_state state; 1472 enum wlan_cm_sm_state sub_state; 1473 1474 cm_ctx = cm_get_cm_ctx(vdev); 1475 if (!cm_ctx) 1476 return false; 1477 1478 state = cm_get_state(cm_ctx); 1479 sub_state = cm_get_sub_state(cm_ctx); 1480 if (state == WLAN_CM_S_ROAMING && sub_state == WLAN_CM_SS_PREAUTH) 1481 return true; 1482 1483 return false; 1484 } 1485 1486 bool cm_is_vdev_roam_reassoc_state(struct wlan_objmgr_vdev *vdev) 1487 { 1488 struct cnx_mgr *cm_ctx; 1489 enum wlan_cm_sm_state state; 1490 enum wlan_cm_sm_state sub_state; 1491 1492 cm_ctx = cm_get_cm_ctx(vdev); 1493 if (!cm_ctx) 1494 return false; 1495 1496 state = cm_get_state(cm_ctx); 1497 sub_state = cm_get_sub_state(cm_ctx); 1498 if (state == WLAN_CM_S_ROAMING && sub_state == WLAN_CM_SS_REASSOC) 1499 return true; 1500 1501 return false; 1502 } 1503 #endif 1504 1505 enum wlan_cm_active_request_type 1506 cm_get_active_req_type(struct wlan_objmgr_vdev *vdev) 1507 { 1508 struct cnx_mgr *cm_ctx; 1509 wlan_cm_id cm_id; 1510 uint32_t active_req_prefix = 0; 1511 1512 cm_ctx = cm_get_cm_ctx(vdev); 1513 if (!cm_ctx) 1514 return CM_NONE; 1515 1516 cm_id = cm_ctx->active_cm_id; 1517 1518 if (cm_id != CM_ID_INVALID) 1519 active_req_prefix = CM_ID_GET_PREFIX(cm_id); 1520 1521 if (active_req_prefix == CONNECT_REQ_PREFIX) 1522 return CM_CONNECT_ACTIVE; 1523 else if (active_req_prefix == DISCONNECT_REQ_PREFIX) 1524 return CM_DISCONNECT_ACTIVE; 1525 else if (active_req_prefix == ROAM_REQ_PREFIX) 1526 return CM_ROAM_ACTIVE; 1527 else 1528 return CM_NONE; 1529 } 1530 1531 #ifdef WLAN_FEATURE_11BE_MLO 1532 static inline 1533 void cm_fill_ml_partner_info(struct wlan_cm_connect_req *req, 1534 struct wlan_cm_vdev_connect_req *connect_req) 1535 { 1536 if (req->ml_parnter_info.num_partner_links) 1537 qdf_mem_copy(&connect_req->ml_parnter_info, 1538 &req->ml_parnter_info, 1539 sizeof(struct mlo_partner_info)); 1540 } 1541 #else 1542 static inline 1543 void cm_fill_ml_partner_info(struct wlan_cm_connect_req *req, 1544 struct wlan_cm_vdev_connect_req *connect_req) 1545 { 1546 } 1547 #endif 1548 1549 bool cm_find_bss_from_candidate_list(qdf_list_t *candidate_list, 1550 struct qdf_mac_addr *bssid, 1551 struct scan_cache_node **entry_found) 1552 { 1553 struct scan_cache_node *scan_entry; 1554 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 1555 struct qdf_mac_addr *bssid2; 1556 1557 if (qdf_is_macaddr_zero(bssid) || 1558 qdf_is_macaddr_broadcast(bssid)) 1559 return false; 1560 1561 if (qdf_list_peek_front(candidate_list, &cur_node) != 1562 QDF_STATUS_SUCCESS) { 1563 mlme_err("failed to peer front of candidate_list"); 1564 return false; 1565 } 1566 1567 while (cur_node) { 1568 qdf_list_peek_next(candidate_list, cur_node, &next_node); 1569 1570 scan_entry = qdf_container_of(cur_node, struct scan_cache_node, 1571 node); 1572 bssid2 = &scan_entry->entry->bssid; 1573 if (qdf_is_macaddr_zero(bssid2)) 1574 goto next; 1575 1576 if (qdf_is_macaddr_equal(bssid, bssid2)) { 1577 if (entry_found) 1578 *entry_found = scan_entry; 1579 return true; 1580 } 1581 next: 1582 cur_node = next_node; 1583 next_node = NULL; 1584 } 1585 1586 return false; 1587 } 1588 1589 bool cm_is_connect_req_reassoc(struct wlan_cm_connect_req *req) 1590 { 1591 if (!qdf_is_macaddr_zero(&req->prev_bssid) && 1592 (!qdf_is_macaddr_zero(&req->bssid) || 1593 !qdf_is_macaddr_zero(&req->bssid_hint)) && 1594 (req->chan_freq || req->chan_freq_hint)) 1595 return true; 1596 1597 return false; 1598 } 1599 1600 bool cm_is_first_candidate_connect_attempt(struct wlan_objmgr_vdev *vdev) 1601 { 1602 struct cnx_mgr *cm_ctx; 1603 struct cm_req *cm_req; 1604 bool status = false; 1605 1606 cm_ctx = cm_get_cm_ctx(vdev); 1607 if (!cm_ctx) 1608 return status; 1609 1610 cm_req_lock_acquire(cm_ctx); 1611 cm_req = cm_get_req_by_cm_id(cm_ctx, cm_ctx->active_cm_id); 1612 if (!cm_req) 1613 goto out; 1614 1615 if (cm_req->connect_req.cur_candidate_retries || 1616 cm_req->connect_req.connect_attempts > 1) 1617 goto out; 1618 1619 status = true; 1620 1621 out: 1622 cm_req_lock_release(cm_ctx); 1623 return status; 1624 } 1625 1626 QDF_STATUS 1627 cm_get_active_connect_req_param(struct wlan_objmgr_vdev *vdev, 1628 struct wlan_cm_connect_req *req) 1629 { 1630 struct cnx_mgr *cm_ctx; 1631 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 1632 struct cm_req *cm_req = NULL; 1633 QDF_STATUS status = QDF_STATUS_E_FAILURE; 1634 uint32_t cm_id_prefix; 1635 1636 cm_ctx = cm_get_cm_ctx(vdev); 1637 if (!cm_ctx) 1638 return QDF_STATUS_E_FAILURE; 1639 1640 cm_req_lock_acquire(cm_ctx); 1641 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 1642 while (cur_node) { 1643 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 1644 1645 cm_req = qdf_container_of(cur_node, struct cm_req, node); 1646 cm_id_prefix = CM_ID_GET_PREFIX((cm_req->cm_id)); 1647 1648 if (cm_req->cm_id != cm_ctx->active_cm_id || 1649 cm_id_prefix != CONNECT_REQ_PREFIX) { 1650 cur_node = next_node; 1651 next_node = NULL; 1652 continue; 1653 } 1654 1655 *req = cm_req->connect_req.req; 1656 qdf_mem_zero(&req->assoc_ie, sizeof(struct element_info)); 1657 qdf_mem_zero(&req->scan_ie, sizeof(struct element_info)); 1658 status = QDF_STATUS_SUCCESS; 1659 break; 1660 } 1661 1662 cm_req_lock_release(cm_ctx); 1663 return status; 1664 } 1665 1666 bool cm_get_active_connect_req(struct wlan_objmgr_vdev *vdev, 1667 struct wlan_cm_vdev_connect_req *req) 1668 { 1669 struct cnx_mgr *cm_ctx; 1670 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 1671 struct cm_req *cm_req = NULL; 1672 bool status = false; 1673 uint32_t cm_id_prefix; 1674 1675 cm_ctx = cm_get_cm_ctx(vdev); 1676 if (!cm_ctx) 1677 return status; 1678 1679 cm_req_lock_acquire(cm_ctx); 1680 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 1681 while (cur_node) { 1682 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 1683 1684 cm_req = qdf_container_of(cur_node, struct cm_req, node); 1685 cm_id_prefix = CM_ID_GET_PREFIX((cm_req->cm_id)); 1686 1687 if (cm_req->cm_id == cm_ctx->active_cm_id && 1688 cm_id_prefix == CONNECT_REQ_PREFIX) { 1689 req->vdev_id = wlan_vdev_get_id(vdev); 1690 req->cm_id = cm_req->connect_req.cm_id; 1691 req->bss = cm_req->connect_req.cur_candidate; 1692 req->is_wps_connection = 1693 cm_req->connect_req.req.is_wps_connection; 1694 req->is_osen_connection = 1695 cm_req->connect_req.req.is_osen_connection; 1696 req->is_non_assoc_link = cm_req->connect_req.req.is_non_assoc_link; 1697 cm_fill_ml_partner_info(&cm_req->connect_req.req, req); 1698 status = true; 1699 cm_req_lock_release(cm_ctx); 1700 return status; 1701 } 1702 1703 cur_node = next_node; 1704 next_node = NULL; 1705 } 1706 cm_req_lock_release(cm_ctx); 1707 1708 return status; 1709 } 1710 1711 bool cm_get_active_disconnect_req(struct wlan_objmgr_vdev *vdev, 1712 struct wlan_cm_vdev_discon_req *req) 1713 { 1714 struct cnx_mgr *cm_ctx; 1715 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 1716 struct cm_req *cm_req = NULL; 1717 bool status = false; 1718 uint32_t cm_id_prefix; 1719 1720 cm_ctx = cm_get_cm_ctx(vdev); 1721 if (!cm_ctx) 1722 return status; 1723 1724 cm_req_lock_acquire(cm_ctx); 1725 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 1726 while (cur_node) { 1727 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 1728 1729 cm_req = qdf_container_of(cur_node, struct cm_req, node); 1730 cm_id_prefix = CM_ID_GET_PREFIX((cm_req->cm_id)); 1731 1732 if (cm_req->cm_id == cm_ctx->active_cm_id && 1733 cm_id_prefix == DISCONNECT_REQ_PREFIX) { 1734 req->cm_id = cm_req->cm_id; 1735 req->req.vdev_id = wlan_vdev_get_id(vdev); 1736 req->req.source = cm_req->discon_req.req.source; 1737 req->req.reason_code = 1738 cm_req->discon_req.req.reason_code; 1739 req->req.bssid = cm_req->discon_req.req.bssid; 1740 req->req.is_no_disassoc_disconnect = 1741 cm_req->discon_req.req.is_no_disassoc_disconnect; 1742 status = true; 1743 cm_req_lock_release(cm_ctx); 1744 return status; 1745 } 1746 1747 cur_node = next_node; 1748 next_node = NULL; 1749 } 1750 cm_req_lock_release(cm_ctx); 1751 1752 return status; 1753 } 1754 1755 struct cm_req *cm_get_req_by_scan_id(struct cnx_mgr *cm_ctx, 1756 wlan_scan_id scan_id) 1757 { 1758 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 1759 struct cm_req *cm_req; 1760 1761 cm_req_lock_acquire(cm_ctx); 1762 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 1763 while (cur_node) { 1764 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 1765 cm_req = qdf_container_of(cur_node, struct cm_req, node); 1766 1767 if (cm_req->connect_req.scan_id == scan_id) { 1768 cm_req_lock_release(cm_ctx); 1769 return cm_req; 1770 } 1771 1772 cur_node = next_node; 1773 next_node = NULL; 1774 } 1775 cm_req_lock_release(cm_ctx); 1776 1777 return NULL; 1778 } 1779 1780 wlan_cm_id cm_get_cm_id_by_scan_id(struct cnx_mgr *cm_ctx, 1781 wlan_scan_id scan_id) 1782 { 1783 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 1784 struct cm_req *cm_req; 1785 1786 cm_req_lock_acquire(cm_ctx); 1787 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 1788 while (cur_node) { 1789 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 1790 cm_req = qdf_container_of(cur_node, struct cm_req, node); 1791 1792 if (cm_req->connect_req.scan_id == scan_id) { 1793 cm_req_lock_release(cm_ctx); 1794 return cm_req->cm_id; 1795 } 1796 1797 cur_node = next_node; 1798 next_node = NULL; 1799 } 1800 cm_req_lock_release(cm_ctx); 1801 1802 return CM_ID_INVALID; 1803 } 1804 1805 QDF_STATUS cm_get_rnr(struct wlan_objmgr_vdev *vdev, wlan_cm_id cm_id, 1806 struct reduced_neighbor_report *rnr) 1807 { 1808 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 1809 struct cm_req *cm_req; 1810 uint32_t prefix = CM_ID_GET_PREFIX(cm_id); 1811 struct cnx_mgr *cm_ctx; 1812 1813 if (prefix != CONNECT_REQ_PREFIX) 1814 return QDF_STATUS_E_INVAL; 1815 1816 cm_ctx = cm_get_cm_ctx(vdev); 1817 if (!cm_ctx) 1818 return QDF_STATUS_E_INVAL; 1819 1820 cm_req_lock_acquire(cm_ctx); 1821 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 1822 while (cur_node) { 1823 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 1824 cm_req = qdf_container_of(cur_node, struct cm_req, node); 1825 1826 if (cm_req->cm_id == cm_id) { 1827 if (!cm_req->connect_req.cur_candidate || 1828 !cm_req->connect_req.cur_candidate->entry) 1829 break; 1830 1831 qdf_mem_copy(rnr, 1832 &cm_req->connect_req.cur_candidate->entry->rnr, 1833 sizeof(*rnr)); 1834 cm_req_lock_release(cm_ctx); 1835 return QDF_STATUS_SUCCESS; 1836 } 1837 1838 cur_node = next_node; 1839 next_node = NULL; 1840 } 1841 cm_req_lock_release(cm_ctx); 1842 1843 return QDF_STATUS_E_FAILURE; 1844 } 1845 1846 #ifdef WLAN_POLICY_MGR_ENABLE 1847 static void 1848 cm_get_pcl_chan_weigtage_for_sta(struct wlan_objmgr_pdev *pdev, 1849 struct pcl_freq_weight_list *pcl_lst, 1850 struct wlan_objmgr_vdev *vdev) 1851 { 1852 uint32_t num_entries = 0; 1853 uint8_t vdev_id; 1854 QDF_STATUS status; 1855 1856 if (!pcl_lst || !vdev) 1857 return; 1858 1859 vdev_id = wlan_vdev_get_id(vdev); 1860 1861 status = policy_mgr_get_pcl(wlan_pdev_get_psoc(pdev), 1862 PM_STA_MODE, 1863 pcl_lst->pcl_freq_list, 1864 &num_entries, 1865 pcl_lst->pcl_weight_list, 1866 NUM_CHANNELS, vdev_id); 1867 if (QDF_IS_STATUS_ERROR(status)) 1868 return; 1869 pcl_lst->num_of_pcl_channels = num_entries; 1870 } 1871 1872 void cm_calculate_scores(struct cnx_mgr *cm_ctx, 1873 struct wlan_objmgr_pdev *pdev, 1874 struct scan_filter *filter, qdf_list_t *list) 1875 { 1876 struct pcl_freq_weight_list *pcl_lst = NULL; 1877 1878 if (!filter->num_of_bssid) { 1879 pcl_lst = qdf_mem_malloc(sizeof(*pcl_lst)); 1880 cm_get_pcl_chan_weigtage_for_sta(pdev, pcl_lst, cm_ctx->vdev); 1881 if (pcl_lst && !pcl_lst->num_of_pcl_channels) { 1882 qdf_mem_free(pcl_lst); 1883 pcl_lst = NULL; 1884 } 1885 } 1886 wlan_cm_calculate_bss_score(pdev, pcl_lst, list, &filter->bssid_hint, 1887 (struct qdf_mac_addr *) 1888 wlan_vdev_mlme_get_macaddr(cm_ctx->vdev)); 1889 if (pcl_lst) 1890 qdf_mem_free(pcl_lst); 1891 } 1892 #else 1893 inline 1894 void cm_calculate_scores(struct cnx_mgr *cm_ctx, 1895 struct wlan_objmgr_pdev *pdev, 1896 struct scan_filter *filter, qdf_list_t *list) 1897 { 1898 wlan_cm_calculate_bss_score(pdev, NULL, list, &filter->bssid_hint, 1899 NULL); 1900 1901 /* 1902 * Custom sorting if enabled 1903 */ 1904 if (cm_ctx && cm_ctx->cm_candidate_list_custom_sort) 1905 cm_ctx->cm_candidate_list_custom_sort(cm_ctx->vdev, list); 1906 } 1907 #endif 1908 1909 #ifdef SM_ENG_HIST_ENABLE 1910 static const char *cm_id_to_string(wlan_cm_id cm_id) 1911 { 1912 uint32_t prefix = CM_ID_GET_PREFIX(cm_id); 1913 1914 switch (prefix) { 1915 case CONNECT_REQ_PREFIX: 1916 return "CONNECT"; 1917 case DISCONNECT_REQ_PREFIX: 1918 return "DISCONNECT"; 1919 case ROAM_REQ_PREFIX: 1920 return "ROAM"; 1921 default: 1922 return "INVALID"; 1923 } 1924 } 1925 1926 void cm_req_history_add(struct cnx_mgr *cm_ctx, 1927 struct cm_req *cm_req) 1928 { 1929 struct cm_req_history *history = &cm_ctx->req_history; 1930 struct cm_req_history_info *data; 1931 1932 qdf_spin_lock_bh(&history->cm_req_hist_lock); 1933 data = &history->data[history->index]; 1934 history->index++; 1935 history->index %= CM_REQ_HISTORY_SIZE; 1936 1937 qdf_mem_zero(data, sizeof(*data)); 1938 data->cm_id = cm_req->cm_id; 1939 data->add_time = qdf_get_log_timestamp(); 1940 data->add_cm_state = cm_get_state(cm_ctx); 1941 qdf_spin_unlock_bh(&history->cm_req_hist_lock); 1942 } 1943 1944 void cm_req_history_del(struct cnx_mgr *cm_ctx, 1945 struct cm_req *cm_req, 1946 enum cm_req_del_type del_type) 1947 { 1948 uint8_t i, idx; 1949 struct cm_req_history_info *data; 1950 struct cm_req_history *history = &cm_ctx->req_history; 1951 1952 qdf_spin_lock_bh(&history->cm_req_hist_lock); 1953 for (i = 0; i < CM_REQ_HISTORY_SIZE; i++) { 1954 if (history->index < i) 1955 idx = CM_REQ_HISTORY_SIZE + history->index - i; 1956 else 1957 idx = history->index - i; 1958 1959 data = &history->data[idx]; 1960 if (data->cm_id == cm_req->cm_id) { 1961 data->del_time = qdf_get_log_timestamp(); 1962 data->del_cm_state = cm_get_state(cm_ctx); 1963 data->del_type = del_type; 1964 break; 1965 } 1966 1967 if (!data->cm_id) 1968 break; 1969 } 1970 qdf_spin_unlock_bh(&history->cm_req_hist_lock); 1971 } 1972 1973 void cm_req_history_init(struct cnx_mgr *cm_ctx) 1974 { 1975 qdf_mem_zero(&cm_ctx->req_history, sizeof(struct cm_req_history)); 1976 qdf_spinlock_create(&cm_ctx->req_history.cm_req_hist_lock); 1977 } 1978 1979 void cm_req_history_deinit(struct cnx_mgr *cm_ctx) 1980 { 1981 qdf_spinlock_destroy(&cm_ctx->req_history.cm_req_hist_lock); 1982 } 1983 1984 static inline void cm_req_history_print_entry(uint16_t idx, 1985 struct cm_req_history_info *data) 1986 { 1987 if (!data->cm_id) 1988 return; 1989 1990 mlme_nofl_err(" |%6u | 0x%016llx | 0x%016llx |%12s | 0x%08x |%15s |%15s |%8u", 1991 idx, data->add_time, data->del_time, 1992 cm_id_to_string(data->cm_id), data->cm_id, 1993 cm_sm_info[data->add_cm_state].name, 1994 cm_sm_info[data->del_cm_state].name, 1995 data->del_type); 1996 } 1997 1998 void cm_req_history_print(struct cnx_mgr *cm_ctx) 1999 { 2000 struct cm_req_history *history = &cm_ctx->req_history; 2001 uint8_t i, idx; 2002 2003 mlme_nofl_err("CM Request history is as below"); 2004 mlme_nofl_err("|%6s |%19s |%19s |%12s |%11s |%15s |%15s |%8s", 2005 "Index", "Add Time", "Del Time", "Req type", 2006 "Cm Id", "Add State", "Del State", "Del Type"); 2007 2008 qdf_spin_lock_bh(&history->cm_req_hist_lock); 2009 for (i = 0; i < CM_REQ_HISTORY_SIZE; i++) { 2010 idx = (history->index + i) % CM_REQ_HISTORY_SIZE; 2011 cm_req_history_print_entry(idx, &history->data[idx]); 2012 } 2013 qdf_spin_unlock_bh(&history->cm_req_hist_lock); 2014 } 2015 #endif 2016 2017 #ifndef CONN_MGR_ADV_FEATURE 2018 void cm_set_candidate_advance_filter_cb( 2019 struct wlan_objmgr_vdev *vdev, 2020 void (*filter_fun)(struct wlan_objmgr_vdev *vdev, 2021 struct scan_filter *filter)) 2022 { 2023 struct cnx_mgr *cm_ctx; 2024 2025 cm_ctx = cm_get_cm_ctx(vdev); 2026 if (!cm_ctx) 2027 return; 2028 2029 cm_ctx->cm_candidate_advance_filter = filter_fun; 2030 } 2031 2032 void cm_set_candidate_custom_sort_cb( 2033 struct wlan_objmgr_vdev *vdev, 2034 void (*sort_fun)(struct wlan_objmgr_vdev *vdev, 2035 qdf_list_t *list)) 2036 { 2037 struct cnx_mgr *cm_ctx; 2038 2039 cm_ctx = cm_get_cm_ctx(vdev); 2040 if (!cm_ctx) 2041 return; 2042 2043 cm_ctx->cm_candidate_list_custom_sort = sort_fun; 2044 } 2045 #endif 2046 2047 #ifdef CONN_MGR_ADV_FEATURE 2048 #define CM_MIN_CANDIDATE_NUM 1 2049 2050 /** 2051 * cm_fill_connect_ies_from_rsp() - fill connect ies from response structure 2052 * @first_cand_rsp: first candidate connect failure response 2053 * @rsp: connect response 2054 * 2055 * This API fills roaming info for first candidate failure response from the 2056 * provided response. 2057 * 2058 * Return: void 2059 */ 2060 static 2061 void cm_fill_connect_ies_from_rsp(struct wlan_cm_connect_resp *first_cand_rsp, 2062 struct wlan_cm_connect_resp *rsp) 2063 { 2064 struct wlan_connect_rsp_ies *connect_ies; 2065 2066 connect_ies = &first_cand_rsp->connect_ies; 2067 2068 connect_ies->bcn_probe_rsp.ptr = NULL; 2069 connect_ies->link_bcn_probe_rsp.ptr = NULL; 2070 connect_ies->assoc_req.ptr = NULL; 2071 connect_ies->assoc_rsp.ptr = NULL; 2072 2073 /* Beacon/Probe Rsp frame */ 2074 if (rsp->connect_ies.bcn_probe_rsp.ptr && 2075 rsp->connect_ies.bcn_probe_rsp.len) { 2076 connect_ies->bcn_probe_rsp.ptr = 2077 qdf_mem_malloc(rsp->connect_ies.bcn_probe_rsp.len); 2078 if (connect_ies->bcn_probe_rsp.ptr) 2079 qdf_mem_copy(connect_ies->bcn_probe_rsp.ptr, 2080 rsp->connect_ies.bcn_probe_rsp.ptr, 2081 rsp->connect_ies.bcn_probe_rsp.len); 2082 else 2083 connect_ies->bcn_probe_rsp.len = 0; 2084 } 2085 2086 /* Link Beacon/Probe Rsp frame */ 2087 if (rsp->connect_ies.link_bcn_probe_rsp.ptr && 2088 rsp->connect_ies.link_bcn_probe_rsp.len) { 2089 connect_ies->link_bcn_probe_rsp.ptr = 2090 qdf_mem_malloc(rsp->connect_ies.link_bcn_probe_rsp.len); 2091 if (connect_ies->link_bcn_probe_rsp.ptr) 2092 qdf_mem_copy(connect_ies->link_bcn_probe_rsp.ptr, 2093 rsp->connect_ies.link_bcn_probe_rsp.ptr, 2094 rsp->connect_ies.link_bcn_probe_rsp.len); 2095 else 2096 connect_ies->link_bcn_probe_rsp.len = 0; 2097 } 2098 2099 /* Assoc Req IE data */ 2100 if (rsp->connect_ies.assoc_req.ptr && 2101 rsp->connect_ies.assoc_req.len) { 2102 connect_ies->assoc_req.ptr = 2103 qdf_mem_malloc(rsp->connect_ies.assoc_req.len); 2104 if (connect_ies->assoc_req.ptr) 2105 qdf_mem_copy(connect_ies->assoc_req.ptr, 2106 rsp->connect_ies.assoc_req.ptr, 2107 rsp->connect_ies.assoc_req.len); 2108 else 2109 connect_ies->assoc_req.len = 0; 2110 } 2111 2112 /* Assoc Rsp IE data */ 2113 if (rsp->connect_ies.assoc_rsp.ptr && 2114 rsp->connect_ies.assoc_rsp.len) { 2115 connect_ies->assoc_rsp.ptr = 2116 qdf_mem_malloc(rsp->connect_ies.assoc_rsp.len); 2117 if (connect_ies->assoc_rsp.ptr) 2118 qdf_mem_copy(connect_ies->assoc_rsp.ptr, 2119 rsp->connect_ies.assoc_rsp.ptr, 2120 rsp->connect_ies.assoc_rsp.len); 2121 else 2122 connect_ies->assoc_rsp.len = 0; 2123 } 2124 } 2125 2126 /** 2127 * cm_copy_rsp_from_rsp() - copy response from other response 2128 * @destination_rsp: destination connect response 2129 * @source_rsp: source connect response 2130 * 2131 * This API copies source response to destination response. 2132 * 2133 * Return: void 2134 */ 2135 static 2136 void cm_copy_rsp_from_rsp(struct wlan_cm_connect_resp *destination_rsp, 2137 struct wlan_cm_connect_resp *source_rsp) 2138 { 2139 *destination_rsp = *source_rsp; 2140 cm_fill_connect_ies_from_rsp(destination_rsp, source_rsp); 2141 } 2142 2143 void cm_store_first_candidate_rsp(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id, 2144 struct wlan_cm_connect_resp *resp) 2145 { 2146 struct wlan_cm_connect_resp *first_candid_rsp; 2147 uint8_t num_candidates; 2148 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 2149 struct cm_req *cm_req; 2150 uint32_t prefix = CM_ID_GET_PREFIX(cm_id); 2151 2152 if (prefix != CONNECT_REQ_PREFIX) 2153 return; 2154 2155 cm_req_lock_acquire(cm_ctx); 2156 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 2157 while (cur_node) { 2158 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 2159 cm_req = qdf_container_of(cur_node, struct cm_req, node); 2160 2161 if (cm_req->cm_id == cm_id) { 2162 /* 2163 * Do not cache response if first candidate response is 2164 * already stored. "first_candidate_rsp" pointer is 2165 * freed once connect request is completed and freed. 2166 */ 2167 if (cm_req->connect_req.first_candidate_rsp) 2168 break; 2169 2170 /* only cached for more than one candidate */ 2171 num_candidates = qdf_list_size( 2172 cm_req->connect_req.candidate_list); 2173 if (num_candidates <= CM_MIN_CANDIDATE_NUM) 2174 break; 2175 2176 first_candid_rsp = qdf_mem_malloc( 2177 sizeof(*first_candid_rsp)); 2178 if (!first_candid_rsp) 2179 break; 2180 2181 cm_copy_rsp_from_rsp(first_candid_rsp, resp); 2182 cm_req->connect_req.first_candidate_rsp = 2183 first_candid_rsp; 2184 mlme_debug(CM_PREFIX_FMT " " QDF_MAC_ADDR_FMT " with reason %d", 2185 CM_PREFIX_REF(first_candid_rsp->vdev_id, 2186 cm_id), 2187 QDF_MAC_ADDR_REF(first_candid_rsp->bssid.bytes), 2188 first_candid_rsp->reason); 2189 break; 2190 } 2191 2192 cur_node = next_node; 2193 next_node = NULL; 2194 } 2195 2196 cm_req_lock_release(cm_ctx); 2197 } 2198 2199 QDF_STATUS 2200 cm_get_first_candidate_rsp(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id, 2201 struct wlan_cm_connect_resp *first_candid_rsp) 2202 { 2203 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 2204 struct cm_req *cm_req; 2205 uint32_t prefix = CM_ID_GET_PREFIX(cm_id); 2206 2207 if (prefix != CONNECT_REQ_PREFIX) 2208 return QDF_STATUS_E_INVAL; 2209 2210 cm_req_lock_acquire(cm_ctx); 2211 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 2212 while (cur_node) { 2213 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 2214 cm_req = qdf_container_of(cur_node, struct cm_req, node); 2215 2216 if (cm_req->cm_id == cm_id) { 2217 if (!cm_req->connect_req.first_candidate_rsp) 2218 break; 2219 2220 cm_copy_rsp_from_rsp(first_candid_rsp, 2221 cm_req->connect_req.first_candidate_rsp); 2222 2223 mlme_debug(CM_PREFIX_FMT " " QDF_MAC_ADDR_FMT "with reason %d", 2224 CM_PREFIX_REF(first_candid_rsp->vdev_id, 2225 cm_id), 2226 QDF_MAC_ADDR_REF(first_candid_rsp->bssid.bytes), 2227 first_candid_rsp->reason); 2228 2229 cm_req_lock_release(cm_ctx); 2230 return QDF_STATUS_SUCCESS; 2231 } 2232 2233 cur_node = next_node; 2234 next_node = NULL; 2235 } 2236 2237 cm_req_lock_release(cm_ctx); 2238 return QDF_STATUS_E_FAILURE; 2239 } 2240 2241 void cm_store_n_send_failed_candidate(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id) 2242 { 2243 struct wlan_cm_connect_resp resp = {0}; 2244 2245 cm_fill_failure_resp_from_cm_id(cm_ctx, &resp, cm_id, 2246 CM_VALID_CANDIDATE_CHECK_FAIL); 2247 cm_store_first_candidate_rsp(cm_ctx, cm_id, &resp); 2248 mlme_cm_osif_failed_candidate_ind(cm_ctx->vdev, &resp); 2249 } 2250 #endif /* CONN_MGR_ADV_FEATURE */ 2251