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