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