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