1 /* 2 * Copyright (c) 2012-2015, 2020-2021, The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /** 19 * DOC: 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 return CONNECT_REQ_PREFIX; 38 case CM_ROAMING_HOST: 39 case CM_ROAMING_FW: 40 case CM_ROAMING_NUD_FAILURE: 41 return ROAM_REQ_PREFIX; 42 default: 43 return DISCONNECT_REQ_PREFIX; 44 } 45 } 46 47 wlan_cm_id cm_get_cm_id(struct cnx_mgr *cm_ctx, enum wlan_cm_source source) 48 { 49 wlan_cm_id cmd_id; 50 uint32_t prefix; 51 52 prefix = cm_get_prefix_for_cm_id(source); 53 54 cmd_id = qdf_atomic_inc_return(&cm_ctx->global_cmd_id); 55 cmd_id = (cmd_id & CM_ID_MASK); 56 cmd_id = (cmd_id | prefix); 57 58 return cmd_id; 59 } 60 61 struct cnx_mgr *cm_get_cm_ctx_fl(struct wlan_objmgr_vdev *vdev, 62 const char *func, uint32_t line) 63 { 64 struct vdev_mlme_obj *vdev_mlme; 65 struct cnx_mgr *cm_ctx = NULL; 66 67 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); 68 if (vdev_mlme) 69 cm_ctx = vdev_mlme->cnx_mgr_ctx; 70 71 if (!cm_ctx) 72 mlme_nofl_err("%s:%u: vdev %d cm_ctx is NULL", func, line, 73 wlan_vdev_get_id(vdev)); 74 75 return cm_ctx; 76 } 77 78 cm_ext_t *cm_get_ext_hdl_fl(struct wlan_objmgr_vdev *vdev, 79 const char *func, uint32_t line) 80 { 81 struct cnx_mgr *cm_ctx; 82 cm_ext_t *ext_ctx = NULL; 83 84 cm_ctx = cm_get_cm_ctx_fl(vdev, func, line); 85 if (cm_ctx) 86 ext_ctx = cm_ctx->ext_cm_ptr; 87 88 if (!ext_ctx) 89 mlme_nofl_err("%s:%u: vdev %d cm ext ctx is NULL", func, line, 90 wlan_vdev_get_id(vdev)); 91 return ext_ctx; 92 } 93 94 void cm_reset_active_cm_id(struct wlan_objmgr_vdev *vdev, wlan_cm_id cm_id) 95 { 96 struct cnx_mgr *cm_ctx; 97 98 cm_ctx = cm_get_cm_ctx(vdev); 99 if (!cm_ctx) 100 return; 101 102 /* Reset active cm id if cm id match */ 103 if (cm_ctx->active_cm_id == cm_id) 104 cm_ctx->active_cm_id = CM_ID_INVALID; 105 } 106 107 108 #ifdef WLAN_CM_USE_SPINLOCK 109 /** 110 * cm_req_lock_acquire - acquire CM SM mutex/spinlock 111 * @cm_ctx: connection manager ctx 112 * 113 * acquire CM SM mutex/spinlock 114 * 115 * return: void 116 */ 117 inline void cm_req_lock_acquire(struct cnx_mgr *cm_ctx) 118 { 119 qdf_spinlock_acquire(&cm_ctx->cm_req_lock); 120 } 121 122 /** 123 * cm_req_lock_release - release CM SM mutex/spinlock 124 * @cm_ctx: connection manager ctx 125 * 126 * release CM SM mutex/spinlock 127 * 128 * return: void 129 */ 130 inline void cm_req_lock_release(struct cnx_mgr *cm_ctx) 131 { 132 qdf_spinlock_release(&cm_ctx->cm_req_lock); 133 } 134 135 QDF_STATUS cm_activate_cmd_req_flush_cb(struct scheduler_msg *msg) 136 { 137 struct wlan_serialization_command *cmd = msg->bodyptr; 138 139 if (!cmd || !cmd->vdev) { 140 mlme_err("Null input cmd:%pK", cmd); 141 return QDF_STATUS_E_INVAL; 142 } 143 144 wlan_objmgr_vdev_release_ref(cmd->vdev, WLAN_MLME_CM_ID); 145 return QDF_STATUS_SUCCESS; 146 } 147 148 #else 149 inline void cm_req_lock_acquire(struct cnx_mgr *cm_ctx) 150 { 151 qdf_mutex_acquire(&cm_ctx->cm_req_lock); 152 } 153 154 inline void cm_req_lock_release(struct cnx_mgr *cm_ctx) 155 { 156 qdf_mutex_release(&cm_ctx->cm_req_lock); 157 } 158 #endif /* WLAN_CM_USE_SPINLOCK */ 159 160 #ifdef CRYPTO_SET_KEY_CONVERGED 161 QDF_STATUS cm_set_key(struct cnx_mgr *cm_ctx, bool unicast, 162 uint8_t key_idx, struct qdf_mac_addr *bssid) 163 { 164 enum wlan_crypto_cipher_type cipher; 165 struct wlan_crypto_key *crypto_key; 166 uint8_t wep_key_idx = 0; 167 168 cipher = wlan_crypto_get_cipher(cm_ctx->vdev, unicast, key_idx); 169 if (IS_WEP_CIPHER(cipher)) { 170 wep_key_idx = wlan_crypto_get_default_key_idx(cm_ctx->vdev, 171 !unicast); 172 crypto_key = wlan_crypto_get_key(cm_ctx->vdev, wep_key_idx); 173 qdf_mem_copy(crypto_key->macaddr, bssid->bytes, 174 QDF_MAC_ADDR_SIZE); 175 } else { 176 crypto_key = wlan_crypto_get_key(cm_ctx->vdev, key_idx); 177 } 178 179 return wlan_crypto_set_key_req(cm_ctx->vdev, crypto_key, (unicast ? 180 WLAN_CRYPTO_KEY_TYPE_UNICAST : 181 WLAN_CRYPTO_KEY_TYPE_GROUP)); 182 } 183 #endif 184 185 #ifdef CONN_MGR_ADV_FEATURE 186 void cm_store_wep_key(struct cnx_mgr *cm_ctx, 187 struct wlan_cm_connect_crypto_info *crypto, 188 wlan_cm_id cm_id) 189 { 190 struct wlan_crypto_key *crypto_key = NULL; 191 QDF_STATUS status; 192 enum wlan_crypto_cipher_type cipher_type; 193 struct wlan_cm_wep_key_params *wep_keys; 194 195 if (!(crypto->ciphers_pairwise & (1 << WLAN_CRYPTO_CIPHER_WEP_40 | 196 1 << WLAN_CRYPTO_CIPHER_WEP_104))) 197 return; 198 199 if (crypto->ciphers_pairwise & 1 << WLAN_CRYPTO_CIPHER_WEP_40) 200 cipher_type = WLAN_CRYPTO_CIPHER_WEP_40; 201 else 202 cipher_type = WLAN_CRYPTO_CIPHER_WEP_104; 203 204 wep_keys = &crypto->wep_keys; 205 status = wlan_crypto_validate_key_params(cipher_type, 206 wep_keys->key_idx, 207 wep_keys->key_len, 208 wep_keys->seq_len); 209 if (QDF_IS_STATUS_ERROR(status)) { 210 mlme_err(CM_PREFIX_FMT "Invalid key params", 211 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id)); 212 return; 213 } 214 215 crypto_key = wlan_crypto_get_key(cm_ctx->vdev, wep_keys->key_idx); 216 if (!crypto_key) { 217 crypto_key = qdf_mem_malloc(sizeof(*crypto_key)); 218 if (!crypto_key) 219 return; 220 221 status = wlan_crypto_save_key(cm_ctx->vdev, wep_keys->key_idx, 222 crypto_key); 223 if (QDF_IS_STATUS_ERROR(status)) { 224 mlme_err(CM_PREFIX_FMT "Failed to save key", 225 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 226 cm_id)); 227 qdf_mem_free(crypto_key); 228 return; 229 } 230 } 231 qdf_mem_zero(crypto_key, sizeof(*crypto_key)); 232 crypto_key->cipher_type = cipher_type; 233 crypto_key->keylen = wep_keys->key_len; 234 crypto_key->keyix = wep_keys->key_idx; 235 qdf_mem_copy(&crypto_key->keyval[0], wep_keys->key, wep_keys->key_len); 236 qdf_mem_copy(&crypto_key->keyrsc[0], wep_keys->seq, wep_keys->seq_len); 237 mlme_debug(CM_PREFIX_FMT "cipher_type %d key_len %d, seq_len %d", 238 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id), 239 crypto_key->cipher_type, wep_keys->key_len, 240 wep_keys->seq_len); 241 } 242 243 void cm_trigger_panic_on_cmd_timeout(struct wlan_objmgr_vdev *vdev) 244 { 245 struct wlan_objmgr_psoc *psoc; 246 247 psoc = wlan_vdev_get_psoc(vdev); 248 if (!psoc) 249 return; 250 251 if (qdf_is_recovering() || qdf_is_fw_down()) 252 return; 253 254 qdf_trigger_self_recovery(psoc, QDF_ACTIVE_LIST_TIMEOUT); 255 } 256 257 #else 258 void cm_trigger_panic_on_cmd_timeout(struct wlan_objmgr_vdev *vdev) 259 { 260 struct vdev_mlme_obj *vdev_mlme = NULL; 261 struct wlan_sm *vdev_sm = NULL; 262 263 vdev_mlme = wlan_objmgr_vdev_get_comp_private_obj( 264 vdev, 265 WLAN_UMAC_COMP_MLME); 266 if (!vdev_mlme) { 267 mlme_err("VDEV MLME is null"); 268 goto error; 269 } 270 271 vdev_sm = vdev_mlme->sm_hdl; 272 if (!vdev_sm) { 273 mlme_err("VDEV SM is null"); 274 goto error; 275 } 276 277 wlan_sm_print_history(vdev_sm); 278 cm_sm_history_print(vdev); 279 error: 280 QDF_ASSERT(0); 281 } 282 #endif 283 284 #ifdef WLAN_FEATURE_FILS_SK 285 void cm_store_fils_key(struct cnx_mgr *cm_ctx, bool unicast, 286 uint8_t key_id, uint16_t key_length, 287 uint8_t *key, struct qdf_mac_addr *bssid, 288 wlan_cm_id cm_id) 289 { 290 struct wlan_crypto_key *crypto_key = NULL; 291 QDF_STATUS status; 292 uint8_t i; 293 int32_t cipher; 294 enum wlan_crypto_cipher_type cipher_type = WLAN_CRYPTO_CIPHER_NONE; 295 296 if (unicast) 297 cipher = wlan_crypto_get_param(cm_ctx->vdev, 298 WLAN_CRYPTO_PARAM_UCAST_CIPHER); 299 else 300 cipher = wlan_crypto_get_param(cm_ctx->vdev, 301 WLAN_CRYPTO_PARAM_MCAST_CIPHER); 302 303 for (i = 0; i <= WLAN_CRYPTO_CIPHER_MAX; i++) { 304 if (QDF_HAS_PARAM(cipher, i)) { 305 cipher_type = i; 306 break; 307 } 308 } 309 crypto_key = wlan_crypto_get_key(cm_ctx->vdev, key_id); 310 if (!crypto_key) { 311 crypto_key = qdf_mem_malloc(sizeof(*crypto_key)); 312 if (!crypto_key) 313 return; 314 status = wlan_crypto_save_key(cm_ctx->vdev, key_id, crypto_key); 315 if (QDF_IS_STATUS_ERROR(status)) { 316 mlme_err(CM_PREFIX_FMT "Failed to save key", 317 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 318 cm_id)); 319 qdf_mem_free(crypto_key); 320 return; 321 } 322 } 323 qdf_mem_zero(crypto_key, sizeof(*crypto_key)); 324 crypto_key->cipher_type = cipher_type; 325 crypto_key->keylen = key_length; 326 crypto_key->keyix = key_id; 327 qdf_mem_copy(&crypto_key->keyval[0], key, key_length); 328 qdf_mem_copy(crypto_key->macaddr, bssid->bytes, QDF_MAC_ADDR_SIZE); 329 mlme_debug(CM_PREFIX_FMT "cipher_type %d key_len %d, key_id %d mac:" QDF_MAC_ADDR_FMT, 330 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id), 331 crypto_key->cipher_type, crypto_key->keylen, 332 crypto_key->keyix, QDF_MAC_ADDR_REF(crypto_key->macaddr)); 333 } 334 static void cm_set_fils_connection_from_req(struct wlan_cm_connect_req *req, 335 struct wlan_cm_connect_resp *resp) 336 { 337 resp->is_fils_connection = req->fils_info.is_fils_connection; 338 } 339 #else 340 static inline 341 void cm_set_fils_connection_from_req(struct wlan_cm_connect_req *req, 342 struct wlan_cm_connect_resp *resp) 343 {} 344 #endif 345 346 bool cm_check_cmid_match_list_head(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id) 347 { 348 qdf_list_node_t *cur_node = NULL; 349 struct cm_req *cm_req; 350 bool match = false; 351 wlan_cm_id head_cm_id = 0; 352 353 if (!cm_id) 354 return false; 355 356 cm_req_lock_acquire(cm_ctx); 357 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 358 if (!cur_node) 359 goto exit; 360 361 cm_req = qdf_container_of(cur_node, struct cm_req, node); 362 head_cm_id = cm_req->cm_id; 363 if (head_cm_id == *cm_id) 364 match = true; 365 366 exit: 367 cm_req_lock_release(cm_ctx); 368 if (!match) 369 mlme_info("head_cm_id 0x%x didn't match the given cm_id 0x%x", 370 head_cm_id, *cm_id); 371 372 return match; 373 } 374 375 bool cm_check_scanid_match_list_head(struct cnx_mgr *cm_ctx, 376 wlan_scan_id *scan_id) 377 { 378 qdf_list_node_t *cur_node = NULL; 379 struct cm_req *cm_req; 380 bool match = false; 381 wlan_cm_id head_scan_id = 0; 382 uint32_t prefix = 0; 383 384 if (!scan_id) 385 return false; 386 387 cm_req_lock_acquire(cm_ctx); 388 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 389 if (!cur_node) 390 goto exit; 391 392 cm_req = qdf_container_of(cur_node, struct cm_req, node); 393 prefix = CM_ID_GET_PREFIX(cm_req->cm_id); 394 /* Check only if head is connect req */ 395 if (prefix != CONNECT_REQ_PREFIX) 396 goto exit; 397 head_scan_id = cm_req->connect_req.scan_id; 398 if (head_scan_id == *scan_id) 399 match = true; 400 401 exit: 402 cm_req_lock_release(cm_ctx); 403 if (!match) 404 mlme_info("head_scan_id 0x%x didn't match the given scan_id 0x%x prefix 0x%x", 405 head_scan_id, *scan_id, prefix); 406 407 return match; 408 } 409 410 struct cm_req *cm_get_req_by_cm_id_fl(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id, 411 const char *func, uint32_t line) 412 { 413 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 414 struct cm_req * cm_req; 415 416 cm_req_lock_acquire(cm_ctx); 417 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 418 while (cur_node) { 419 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 420 cm_req = qdf_container_of(cur_node, struct cm_req, node); 421 422 if (cm_req->cm_id == cm_id) { 423 cm_req_lock_release(cm_ctx); 424 return cm_req; 425 } 426 427 cur_node = next_node; 428 next_node = NULL; 429 } 430 cm_req_lock_release(cm_ctx); 431 432 mlme_nofl_info("%s:%u: cm req not found for cm id 0x%x", func, 433 line, cm_id); 434 435 return NULL; 436 } 437 438 /** 439 * cm_fill_connect_resp_from_req() - Fill connect resp from connect request 440 * @resp: cm connect response 441 * @cm_req: cm request 442 * 443 * Context: Can be called from APIs holding cm request list lock 444 * 445 * Return: void 446 */ 447 static void 448 cm_fill_connect_resp_from_req(struct wlan_cm_connect_resp *resp, 449 struct cm_req *cm_req) 450 { 451 struct scan_cache_node *candidate; 452 struct wlan_cm_connect_req *req; 453 454 req = &cm_req->connect_req.req; 455 candidate = cm_req->connect_req.cur_candidate; 456 if (candidate) 457 qdf_copy_macaddr(&resp->bssid, &candidate->entry->bssid); 458 else if (!qdf_is_macaddr_zero(&req->bssid)) 459 qdf_copy_macaddr(&resp->bssid, &req->bssid); 460 else 461 qdf_copy_macaddr(&resp->bssid, &req->bssid_hint); 462 463 if (candidate) 464 resp->freq = candidate->entry->channel.chan_freq; 465 else 466 resp->freq = req->chan_freq; 467 468 resp->ssid = req->ssid; 469 resp->is_wps_connection = req->is_wps_connection; 470 resp->is_osen_connection = req->is_osen_connection; 471 cm_set_fils_connection_from_req(req, resp); 472 } 473 474 /** 475 * cm_handle_connect_flush() - Fill fail connect resp from req and indicate 476 * same to osif 477 * @cm_ctx: connection manager context 478 * @cm_req: cm request 479 * 480 * Context: Can be called from APIs holding cm request list lock 481 * 482 * Return: void 483 */ 484 static void 485 cm_handle_connect_flush(struct cnx_mgr *cm_ctx, struct cm_req *cm_req) 486 { 487 struct wlan_cm_connect_resp *resp; 488 489 resp = qdf_mem_malloc(sizeof(*resp)); 490 if (!resp) 491 return; 492 493 resp->connect_status = QDF_STATUS_E_FAILURE; 494 resp->cm_id = cm_req->cm_id; 495 resp->vdev_id = wlan_vdev_get_id(cm_ctx->vdev); 496 if (cm_req->failed_req) 497 resp->reason = CM_GENERIC_FAILURE; 498 else 499 resp->reason = CM_ABORT_DUE_TO_NEW_REQ_RECVD; 500 501 /* Get bssid and ssid and freq for the cm id from the req list */ 502 cm_fill_connect_resp_from_req(resp, cm_req); 503 504 cm_notify_connect_complete(cm_ctx, resp); 505 qdf_mem_free(resp); 506 } 507 508 /** 509 * cm_handle_disconnect_flush() - Fill disconnect resp from req and indicate 510 * same to osif 511 * @cm_ctx: connection manager context 512 * @cm_req: cm request 513 * 514 * Context: Can be called from APIs holding cm request list lock 515 * 516 * Return: void 517 */ 518 static void 519 cm_handle_disconnect_flush(struct cnx_mgr *cm_ctx, struct cm_req *cm_req) 520 { 521 struct wlan_cm_discon_rsp resp; 522 523 qdf_mem_zero(&resp, sizeof(resp)); 524 resp.req.cm_id = cm_req->cm_id; 525 resp.req.req = cm_req->discon_req.req; 526 /* 527 * Indicate to OSIF to inform kernel if not already done and this is 528 * the latest disconnect req received. If this is not the latest, it 529 * will be dropped in OSIF as src and cm_id will not match. A flushed 530 * disconnect can be last of this was received when previous disconnect 531 * was already in serialization active queue and thus wasn't flushed. 532 */ 533 mlme_cm_osif_disconnect_complete(cm_ctx->vdev, &resp); 534 } 535 536 void cm_remove_cmd_from_serialization(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id) 537 { 538 struct wlan_serialization_queued_cmd_info cmd_info; 539 uint32_t prefix = CM_ID_GET_PREFIX(cm_id); 540 541 qdf_mem_zero(&cmd_info, sizeof(cmd_info)); 542 cmd_info.cmd_id = cm_id; 543 cmd_info.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD; 544 545 if (prefix == CONNECT_REQ_PREFIX) { 546 cmd_info.cmd_type = WLAN_SER_CMD_VDEV_CONNECT; 547 } else if (prefix == ROAM_REQ_PREFIX) { 548 /* 549 * Try removing PREAUTH command when in preauth state else 550 * try remove ROAM command 551 */ 552 if (cm_ctx->preauth_in_progress) 553 cmd_info.cmd_type = WLAN_SER_CMD_PERFORM_PRE_AUTH; 554 else 555 cmd_info.cmd_type = WLAN_SER_CMD_VDEV_ROAM; 556 cm_ctx->preauth_in_progress = false; 557 } else if (prefix == DISCONNECT_REQ_PREFIX) { 558 cmd_info.cmd_type = WLAN_SER_CMD_VDEV_DISCONNECT; 559 } else { 560 mlme_err(CM_PREFIX_FMT "Invalid prefix %x", 561 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id), 562 prefix); 563 return; 564 } 565 566 cmd_info.vdev = cm_ctx->vdev; 567 568 if (cm_id == cm_ctx->active_cm_id) { 569 mlme_debug(CM_PREFIX_FMT "Remove cmd type %d from active", 570 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id), 571 cmd_info.cmd_type); 572 cmd_info.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE; 573 wlan_serialization_remove_cmd(&cmd_info); 574 } else { 575 mlme_debug(CM_PREFIX_FMT "Remove cmd type %d from pending", 576 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id), 577 cmd_info.cmd_type); 578 cmd_info.queue_type = WLAN_SERIALIZATION_PENDING_QUEUE; 579 wlan_serialization_cancel_request(&cmd_info); 580 } 581 } 582 583 void 584 cm_flush_pending_request(struct cnx_mgr *cm_ctx, uint32_t prefix, 585 bool only_failed_req) 586 { 587 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 588 struct cm_req *cm_req; 589 uint32_t req_prefix; 590 bool roam_offload = false; 591 592 if (cm_roam_offload_enabled(wlan_vdev_get_psoc(cm_ctx->vdev)) && 593 prefix == ROAM_REQ_PREFIX) 594 roam_offload = true; 595 596 cm_req_lock_acquire(cm_ctx); 597 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 598 while (cur_node) { 599 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 600 cm_req = qdf_container_of(cur_node, struct cm_req, node); 601 602 req_prefix = CM_ID_GET_PREFIX(cm_req->cm_id); 603 604 /* 605 * Only remove requests matching the flush prefix and 606 * the pending req for non roam offload(LFR3) commands 607 * (roam command is dummy in FW roam/LFR3 so active 608 * command can be removed) 609 */ 610 if (req_prefix != prefix || 611 (!roam_offload && cm_req->cm_id == cm_ctx->active_cm_id)) 612 goto next; 613 614 /* If only_failed_req is set flush only failed req */ 615 if (only_failed_req && !cm_req->failed_req) 616 goto next; 617 618 if (req_prefix == CONNECT_REQ_PREFIX) { 619 cm_handle_connect_flush(cm_ctx, cm_req); 620 cm_ctx->connect_count--; 621 cm_free_connect_req_mem(&cm_req->connect_req); 622 } else if (req_prefix == ROAM_REQ_PREFIX) { 623 cm_free_roam_req_mem(&cm_req->roam_req); 624 } else if (req_prefix == DISCONNECT_REQ_PREFIX) { 625 cm_handle_disconnect_flush(cm_ctx, cm_req); 626 cm_ctx->disconnect_count--; 627 } else { 628 mlme_err(CM_PREFIX_FMT "Invalid prefix %x", 629 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 630 cm_req->cm_id), prefix); 631 } 632 633 cm_req_history_del(cm_ctx, cm_req, CM_REQ_DEL_FLUSH); 634 mlme_debug(CM_PREFIX_FMT, 635 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 636 cm_req->cm_id)); 637 cm_remove_cmd_from_serialization(cm_ctx, cm_req->cm_id); 638 qdf_list_remove_node(&cm_ctx->req_list, &cm_req->node); 639 qdf_mem_free(cm_req); 640 next: 641 cur_node = next_node; 642 next_node = NULL; 643 } 644 645 cm_req_lock_release(cm_ctx); 646 } 647 648 QDF_STATUS 649 cm_fill_bss_info_in_connect_rsp_by_cm_id(struct cnx_mgr *cm_ctx, 650 wlan_cm_id cm_id, 651 struct wlan_cm_connect_resp *resp) 652 { 653 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 654 struct cm_req *cm_req; 655 uint32_t prefix = CM_ID_GET_PREFIX(cm_id); 656 657 if (prefix != CONNECT_REQ_PREFIX) 658 return QDF_STATUS_E_INVAL; 659 660 cm_req_lock_acquire(cm_ctx); 661 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 662 while (cur_node) { 663 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 664 cm_req = qdf_container_of(cur_node, struct cm_req, node); 665 666 if (cm_req->cm_id == cm_id) { 667 cm_fill_connect_resp_from_req(resp, cm_req); 668 cm_req_lock_release(cm_ctx); 669 return QDF_STATUS_SUCCESS; 670 } 671 672 cur_node = next_node; 673 next_node = NULL; 674 } 675 cm_req_lock_release(cm_ctx); 676 677 return QDF_STATUS_E_FAILURE; 678 } 679 680 #if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD) 681 bool cm_is_cm_id_current_candidate_single_pmk(struct cnx_mgr *cm_ctx, 682 wlan_cm_id cm_id) 683 { 684 struct wlan_objmgr_psoc *psoc; 685 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 686 struct cm_req *cm_req; 687 uint32_t prefix = CM_ID_GET_PREFIX(cm_id); 688 int32_t akm; 689 struct scan_cache_node *candidate; 690 bool is_single_pmk = false; 691 692 psoc = wlan_vdev_get_psoc(cm_ctx->vdev); 693 if (!psoc) { 694 mlme_err(CM_PREFIX_FMT "Failed to find psoc", 695 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 696 cm_id)); 697 return is_single_pmk; 698 } 699 700 if (prefix != CONNECT_REQ_PREFIX) 701 return is_single_pmk; 702 703 akm = wlan_crypto_get_param(cm_ctx->vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); 704 if (!QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE)) 705 return is_single_pmk; 706 707 cm_req_lock_acquire(cm_ctx); 708 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 709 while (cur_node) { 710 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 711 cm_req = qdf_container_of(cur_node, struct cm_req, node); 712 713 if (cm_req->cm_id == cm_id) { 714 candidate = cm_req->connect_req.cur_candidate; 715 if (candidate && 716 util_scan_entry_single_pmk(psoc, candidate->entry)) 717 is_single_pmk = true; 718 break; 719 } 720 721 cur_node = next_node; 722 next_node = NULL; 723 } 724 cm_req_lock_release(cm_ctx); 725 726 return is_single_pmk; 727 } 728 #endif 729 730 QDF_STATUS cm_add_req_to_list_and_indicate_osif(struct cnx_mgr *cm_ctx, 731 struct cm_req *cm_req, 732 enum wlan_cm_source source) 733 { 734 uint32_t prefix = CM_ID_GET_PREFIX(cm_req->cm_id); 735 736 cm_req_lock_acquire(cm_ctx); 737 if (qdf_list_size(&cm_ctx->req_list) >= CM_MAX_REQ) { 738 cm_req_lock_release(cm_ctx); 739 mlme_err(CM_PREFIX_FMT "List full size %d", 740 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 741 cm_req->cm_id), 742 qdf_list_size(&cm_ctx->req_list)); 743 return QDF_STATUS_E_FAILURE; 744 } 745 746 qdf_list_insert_front(&cm_ctx->req_list, &cm_req->node); 747 if (prefix == CONNECT_REQ_PREFIX) 748 cm_ctx->connect_count++; 749 else if (prefix == DISCONNECT_REQ_PREFIX) 750 cm_ctx->disconnect_count++; 751 752 cm_req_history_add(cm_ctx, cm_req); 753 cm_req_lock_release(cm_ctx); 754 mlme_debug(CM_PREFIX_FMT, 755 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 756 cm_req->cm_id)); 757 758 mlme_cm_osif_update_id_and_src(cm_ctx->vdev, source, cm_req->cm_id); 759 760 return QDF_STATUS_SUCCESS; 761 } 762 763 static void cm_zero_and_free_memory(uint8_t *ptr, uint32_t len) 764 { 765 if (!ptr) 766 return; 767 768 qdf_mem_zero(ptr, len); 769 qdf_mem_free(ptr); 770 } 771 772 void cm_free_connect_req_mem(struct cm_connect_req *connect_req) 773 { 774 struct wlan_cm_connect_req *req; 775 776 req = &connect_req->req; 777 778 if (connect_req->candidate_list) 779 wlan_scan_purge_results(connect_req->candidate_list); 780 781 cm_zero_and_free_memory(req->assoc_ie.ptr, req->assoc_ie.len); 782 cm_zero_and_free_memory(req->scan_ie.ptr, req->scan_ie.len); 783 784 cm_zero_and_free_memory(req->crypto.wep_keys.key, 785 req->crypto.wep_keys.key_len); 786 cm_zero_and_free_memory(req->crypto.wep_keys.seq, 787 req->crypto.wep_keys.seq_len); 788 789 qdf_mem_zero(connect_req, sizeof(*connect_req)); 790 } 791 792 QDF_STATUS 793 cm_delete_req_from_list(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id) 794 { 795 uint32_t prefix = CM_ID_GET_PREFIX(cm_id); 796 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 797 struct cm_req *cm_req = NULL; 798 799 cm_req_lock_acquire(cm_ctx); 800 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 801 while (cur_node) { 802 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 803 804 cm_req = qdf_container_of(cur_node, struct cm_req, node); 805 if (cm_req->cm_id == cm_id) 806 break; 807 808 cur_node = next_node; 809 next_node = NULL; 810 cm_req = NULL; 811 } 812 813 if (!cm_req) { 814 cm_req_lock_release(cm_ctx); 815 mlme_err(CM_PREFIX_FMT " req not found", 816 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id)); 817 return QDF_STATUS_E_FAILURE; 818 } 819 820 qdf_list_remove_node(&cm_ctx->req_list, &cm_req->node); 821 if (prefix == CONNECT_REQ_PREFIX) { 822 cm_ctx->connect_count--; 823 cm_free_connect_req_mem(&cm_req->connect_req); 824 } else if (prefix == ROAM_REQ_PREFIX) { 825 cm_free_roam_req_mem(&cm_req->roam_req); 826 } else if (prefix == DISCONNECT_REQ_PREFIX) { 827 cm_ctx->disconnect_count--; 828 } else { 829 mlme_err(CM_PREFIX_FMT "Invalid prefix %x", 830 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 831 cm_req->cm_id), prefix); 832 } 833 834 if (cm_id == cm_ctx->active_cm_id) 835 cm_req_history_del(cm_ctx, cm_req, CM_REQ_DEL_ACTIVE); 836 else 837 cm_req_history_del(cm_ctx, cm_req, CM_REQ_DEL_PENDING); 838 839 mlme_debug(CM_PREFIX_FMT, 840 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 841 cm_req->cm_id)); 842 843 qdf_mem_free(cm_req); 844 cm_req_lock_release(cm_ctx); 845 846 return QDF_STATUS_SUCCESS; 847 } 848 849 void cm_remove_cmd(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id_to_remove) 850 { 851 struct wlan_objmgr_psoc *psoc; 852 QDF_STATUS status; 853 wlan_cm_id cm_id; 854 855 if (!cm_id_to_remove) { 856 mlme_err("cm_id_to_remove is null"); 857 return; 858 } 859 860 /* 861 * store local value as cm_delete_req_from_list may free the 862 * cm_id_to_remove pointer 863 */ 864 cm_id = *cm_id_to_remove; 865 /* return if zero or invalid cm_id */ 866 if (!cm_id || cm_id == CM_ID_INVALID) { 867 mlme_debug(CM_PREFIX_FMT " Invalid cm_id", 868 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 869 cm_id)); 870 return; 871 } 872 873 psoc = wlan_vdev_get_psoc(cm_ctx->vdev); 874 if (!psoc) { 875 mlme_err(CM_PREFIX_FMT "Failed to find psoc", 876 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id)); 877 return; 878 } 879 880 status = cm_delete_req_from_list(cm_ctx, cm_id); 881 if (QDF_IS_STATUS_ERROR(status)) 882 return; 883 884 cm_remove_cmd_from_serialization(cm_ctx, cm_id); 885 } 886 887 void cm_vdev_scan_cancel(struct wlan_objmgr_pdev *pdev, 888 struct wlan_objmgr_vdev *vdev) 889 { 890 struct scan_cancel_request *req; 891 QDF_STATUS status; 892 893 req = qdf_mem_malloc(sizeof(*req)); 894 if (!req) 895 return; 896 897 req->vdev = vdev; 898 req->cancel_req.scan_id = INVAL_SCAN_ID; 899 req->cancel_req.vdev_id = wlan_vdev_get_id(vdev); 900 req->cancel_req.pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); 901 req->cancel_req.req_type = WLAN_SCAN_CANCEL_VDEV_ALL; 902 903 status = wlan_scan_cancel(req); 904 /* In success/failure case wlan_scan_cancel free the req memory */ 905 if (QDF_IS_STATUS_ERROR(status)) 906 mlme_err("vdev %d cancel scan request failed", 907 wlan_vdev_get_id(vdev)); 908 } 909 910 void cm_set_max_connect_attempts(struct wlan_objmgr_vdev *vdev, 911 uint8_t max_connect_attempts) 912 { 913 struct cnx_mgr *cm_ctx; 914 915 cm_ctx = cm_get_cm_ctx(vdev); 916 if (!cm_ctx) 917 return; 918 919 cm_ctx->max_connect_attempts = 920 QDF_MIN(max_connect_attempts, CM_MAX_CONNECT_ATTEMPTS); 921 mlme_debug("vdev %d max connect attempts set to %d, requested %d", 922 wlan_vdev_get_id(vdev), 923 cm_ctx->max_connect_attempts, max_connect_attempts); 924 } 925 926 void cm_set_max_connect_timeout(struct wlan_objmgr_vdev *vdev, 927 uint32_t max_connect_timeout) 928 { 929 struct cnx_mgr *cm_ctx; 930 931 cm_ctx = cm_get_cm_ctx(vdev); 932 if (!cm_ctx) 933 return; 934 935 cm_ctx->connect_timeout = max_connect_timeout; 936 } 937 938 QDF_STATUS 939 cm_fill_disconnect_resp_from_cm_id(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id, 940 struct wlan_cm_discon_rsp *resp) 941 { 942 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 943 struct cm_req *cm_req; 944 uint32_t prefix = CM_ID_GET_PREFIX(cm_id); 945 946 if (prefix != DISCONNECT_REQ_PREFIX) 947 return QDF_STATUS_E_INVAL; 948 949 cm_req_lock_acquire(cm_ctx); 950 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 951 while (cur_node) { 952 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 953 cm_req = qdf_container_of(cur_node, struct cm_req, node); 954 955 if (cm_req->cm_id == cm_id) { 956 resp->req.cm_id = cm_id; 957 resp->req.req = cm_req->discon_req.req; 958 cm_req_lock_release(cm_ctx); 959 return QDF_STATUS_SUCCESS; 960 } 961 962 cur_node = next_node; 963 next_node = NULL; 964 } 965 cm_req_lock_release(cm_ctx); 966 967 return QDF_STATUS_E_FAILURE; 968 } 969 970 void cm_inform_bcn_probe(struct cnx_mgr *cm_ctx, uint8_t *bcn_probe, 971 uint32_t len, qdf_freq_t freq, int32_t rssi, 972 wlan_cm_id cm_id) 973 { 974 qdf_nbuf_t buf; 975 struct wlan_objmgr_pdev *pdev; 976 uint8_t *data, i, vdev_id; 977 struct mgmt_rx_event_params rx_param = {0}; 978 struct wlan_frame_hdr *hdr; 979 enum mgmt_frame_type frm_type = MGMT_BEACON; 980 981 vdev_id = wlan_vdev_get_id(cm_ctx->vdev); 982 if (!bcn_probe || !len || (len < sizeof(*hdr))) { 983 mlme_err(CM_PREFIX_FMT "bcn_probe is null or invalid len %d", 984 CM_PREFIX_REF(vdev_id, cm_id), len); 985 return; 986 } 987 988 pdev = wlan_vdev_get_pdev(cm_ctx->vdev); 989 if (!pdev) { 990 mlme_err(CM_PREFIX_FMT "Failed to find pdev", 991 CM_PREFIX_REF(vdev_id, cm_id)); 992 return; 993 } 994 995 hdr = (struct wlan_frame_hdr *)bcn_probe; 996 if ((hdr->i_fc[0] & QDF_IEEE80211_FC0_SUBTYPE_MASK) == 997 MGMT_SUBTYPE_PROBE_RESP) 998 frm_type = MGMT_PROBE_RESP; 999 1000 rx_param.pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); 1001 rx_param.chan_freq = freq; 1002 rx_param.rssi = rssi; 1003 1004 /* Set all per chain rssi as invalid */ 1005 for (i = 0; i < WLAN_MGMT_TXRX_HOST_MAX_ANTENNA; i++) 1006 rx_param.rssi_ctl[i] = WLAN_INVALID_PER_CHAIN_RSSI; 1007 1008 buf = qdf_nbuf_alloc(NULL, qdf_roundup(len, 4), 0, 4, false); 1009 if (!buf) 1010 return; 1011 1012 qdf_nbuf_put_tail(buf, len); 1013 qdf_nbuf_set_protocol(buf, ETH_P_CONTROL); 1014 1015 data = qdf_nbuf_data(buf); 1016 qdf_mem_copy(data, bcn_probe, len); 1017 /* buf will be freed by scan module in error or success case */ 1018 wlan_scan_process_bcn_probe_rx_sync(wlan_pdev_get_psoc(pdev), buf, 1019 &rx_param, frm_type); 1020 } 1021 1022 bool cm_is_vdev_connecting(struct wlan_objmgr_vdev *vdev) 1023 { 1024 struct cnx_mgr *cm_ctx; 1025 enum wlan_cm_sm_state state; 1026 1027 cm_ctx = cm_get_cm_ctx(vdev); 1028 if (!cm_ctx) 1029 return false; 1030 1031 state = cm_get_state(cm_ctx); 1032 1033 if (state == WLAN_CM_S_CONNECTING) 1034 return true; 1035 1036 return false; 1037 } 1038 1039 bool cm_is_vdev_connected(struct wlan_objmgr_vdev *vdev) 1040 { 1041 struct cnx_mgr *cm_ctx; 1042 enum wlan_cm_sm_state state; 1043 1044 cm_ctx = cm_get_cm_ctx(vdev); 1045 if (!cm_ctx) 1046 return false; 1047 1048 state = cm_get_state(cm_ctx); 1049 1050 if (state == WLAN_CM_S_CONNECTED) 1051 return true; 1052 1053 return false; 1054 } 1055 1056 bool cm_is_vdev_active(struct wlan_objmgr_vdev *vdev) 1057 { 1058 struct cnx_mgr *cm_ctx; 1059 enum wlan_cm_sm_state state; 1060 1061 cm_ctx = cm_get_cm_ctx(vdev); 1062 if (!cm_ctx) 1063 return false; 1064 1065 state = cm_get_state(cm_ctx); 1066 1067 if (state == WLAN_CM_S_CONNECTED || state == WLAN_CM_S_ROAMING) 1068 return true; 1069 1070 return false; 1071 } 1072 1073 bool cm_is_vdev_disconnecting(struct wlan_objmgr_vdev *vdev) 1074 { 1075 struct cnx_mgr *cm_ctx; 1076 enum wlan_cm_sm_state state; 1077 1078 cm_ctx = cm_get_cm_ctx(vdev); 1079 if (!cm_ctx) 1080 return false; 1081 1082 state = cm_get_state(cm_ctx); 1083 1084 if (state == WLAN_CM_S_DISCONNECTING) 1085 return true; 1086 1087 return false; 1088 } 1089 1090 bool cm_is_vdev_disconnected(struct wlan_objmgr_vdev *vdev) 1091 { 1092 struct cnx_mgr *cm_ctx; 1093 enum wlan_cm_sm_state state; 1094 1095 cm_ctx = cm_get_cm_ctx(vdev); 1096 if (!cm_ctx) 1097 return true; 1098 1099 state = cm_get_state(cm_ctx); 1100 1101 if (state == WLAN_CM_S_INIT) 1102 return true; 1103 1104 return false; 1105 } 1106 1107 bool cm_is_vdev_roaming(struct wlan_objmgr_vdev *vdev) 1108 { 1109 struct cnx_mgr *cm_ctx; 1110 enum wlan_cm_sm_state state; 1111 1112 cm_ctx = cm_get_cm_ctx(vdev); 1113 if (!cm_ctx) 1114 return false; 1115 1116 state = cm_get_state(cm_ctx); 1117 1118 if (state == WLAN_CM_S_ROAMING) 1119 return true; 1120 1121 return false; 1122 } 1123 1124 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 1125 bool cm_is_vdev_roam_started(struct wlan_objmgr_vdev *vdev) 1126 { 1127 struct cnx_mgr *cm_ctx; 1128 enum wlan_cm_sm_state state; 1129 enum wlan_cm_sm_state sub_state; 1130 1131 cm_ctx = cm_get_cm_ctx(vdev); 1132 if (!cm_ctx) 1133 return false; 1134 1135 state = cm_get_state(cm_ctx); 1136 sub_state = cm_get_sub_state(cm_ctx); 1137 if (state == WLAN_CM_S_ROAMING && sub_state == WLAN_CM_SS_ROAM_STARTED) 1138 return true; 1139 1140 return false; 1141 } 1142 1143 bool cm_is_vdev_roam_sync_inprogress(struct wlan_objmgr_vdev *vdev) 1144 { 1145 struct cnx_mgr *cm_ctx; 1146 enum wlan_cm_sm_state state; 1147 enum wlan_cm_sm_state sub_state; 1148 1149 cm_ctx = cm_get_cm_ctx(vdev); 1150 if (!cm_ctx) 1151 return false; 1152 1153 state = cm_get_state(cm_ctx); 1154 sub_state = cm_get_sub_state(cm_ctx); 1155 if (state == WLAN_CM_S_ROAMING && sub_state == WLAN_CM_SS_ROAM_SYNC) 1156 return true; 1157 1158 return false; 1159 } 1160 #endif 1161 1162 #ifdef WLAN_FEATURE_HOST_ROAM 1163 bool cm_is_vdev_roam_preauth_state(struct wlan_objmgr_vdev *vdev) 1164 { 1165 struct cnx_mgr *cm_ctx; 1166 enum wlan_cm_sm_state state; 1167 enum wlan_cm_sm_state sub_state; 1168 1169 cm_ctx = cm_get_cm_ctx(vdev); 1170 if (!cm_ctx) 1171 return false; 1172 1173 state = cm_get_state(cm_ctx); 1174 sub_state = cm_get_sub_state(cm_ctx); 1175 if (state == WLAN_CM_S_ROAMING && sub_state == WLAN_CM_SS_PREAUTH) 1176 return true; 1177 1178 return false; 1179 } 1180 1181 bool cm_is_vdev_roam_reassoc_state(struct wlan_objmgr_vdev *vdev) 1182 { 1183 struct cnx_mgr *cm_ctx; 1184 enum wlan_cm_sm_state state; 1185 enum wlan_cm_sm_state sub_state; 1186 1187 cm_ctx = cm_get_cm_ctx(vdev); 1188 if (!cm_ctx) 1189 return false; 1190 1191 state = cm_get_state(cm_ctx); 1192 sub_state = cm_get_sub_state(cm_ctx); 1193 if (state == WLAN_CM_S_ROAMING && sub_state == WLAN_CM_SS_REASSOC) 1194 return true; 1195 1196 return false; 1197 } 1198 #endif 1199 1200 enum wlan_cm_active_request_type 1201 cm_get_active_req_type(struct wlan_objmgr_vdev *vdev) 1202 { 1203 struct cnx_mgr *cm_ctx; 1204 wlan_cm_id cm_id; 1205 uint32_t active_req_prefix = 0; 1206 1207 cm_ctx = cm_get_cm_ctx(vdev); 1208 if (!cm_ctx) 1209 return CM_NONE; 1210 1211 cm_id = cm_ctx->active_cm_id; 1212 1213 if (cm_id != CM_ID_INVALID) 1214 active_req_prefix = CM_ID_GET_PREFIX(cm_id); 1215 1216 if (active_req_prefix == CONNECT_REQ_PREFIX) 1217 return CM_CONNECT_ACTIVE; 1218 else if (active_req_prefix == DISCONNECT_REQ_PREFIX) 1219 return CM_DISCONNECT_ACTIVE; 1220 else if (active_req_prefix == ROAM_REQ_PREFIX) 1221 return CM_ROAM_ACTIVE; 1222 else 1223 return CM_NONE; 1224 } 1225 1226 #ifdef WLAN_FEATURE_11BE_MLO 1227 static inline 1228 void cm_fill_ml_partner_info(struct wlan_cm_connect_req *req, 1229 struct wlan_cm_vdev_connect_req *connect_req) 1230 { 1231 if (req->ml_parnter_info.num_partner_links) 1232 qdf_mem_copy(&connect_req->ml_parnter_info, 1233 &req->ml_parnter_info, 1234 sizeof(struct mlo_partner_info)); 1235 } 1236 #else 1237 static inline 1238 void cm_fill_ml_partner_info(struct wlan_cm_connect_req *req, 1239 struct wlan_cm_vdev_connect_req *connect_req) 1240 { 1241 } 1242 #endif 1243 1244 bool cm_get_active_connect_req(struct wlan_objmgr_vdev *vdev, 1245 struct wlan_cm_vdev_connect_req *req) 1246 { 1247 struct cnx_mgr *cm_ctx; 1248 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 1249 struct cm_req *cm_req = NULL; 1250 bool status = false; 1251 uint32_t cm_id_prefix; 1252 1253 cm_ctx = cm_get_cm_ctx(vdev); 1254 if (!cm_ctx) 1255 return status; 1256 1257 cm_req_lock_acquire(cm_ctx); 1258 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 1259 while (cur_node) { 1260 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 1261 1262 cm_req = qdf_container_of(cur_node, struct cm_req, node); 1263 cm_id_prefix = CM_ID_GET_PREFIX((cm_req->cm_id)); 1264 1265 if (cm_req->cm_id == cm_ctx->active_cm_id && 1266 cm_id_prefix == CONNECT_REQ_PREFIX) { 1267 req->vdev_id = wlan_vdev_get_id(vdev); 1268 req->cm_id = cm_req->connect_req.cm_id; 1269 req->bss = cm_req->connect_req.cur_candidate; 1270 req->is_wps_connection = 1271 cm_req->connect_req.req.is_wps_connection; 1272 req->is_osen_connection = 1273 cm_req->connect_req.req.is_osen_connection; 1274 req->is_non_assoc_link = cm_req->connect_req.req.is_non_assoc_link; 1275 cm_fill_ml_partner_info(&cm_req->connect_req.req, req); 1276 status = true; 1277 cm_req_lock_release(cm_ctx); 1278 return status; 1279 } 1280 1281 cur_node = next_node; 1282 next_node = NULL; 1283 } 1284 cm_req_lock_release(cm_ctx); 1285 1286 return status; 1287 } 1288 1289 bool cm_get_active_disconnect_req(struct wlan_objmgr_vdev *vdev, 1290 struct wlan_cm_vdev_discon_req *req) 1291 { 1292 struct cnx_mgr *cm_ctx; 1293 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 1294 struct cm_req *cm_req = NULL; 1295 bool status = false; 1296 uint32_t cm_id_prefix; 1297 1298 cm_ctx = cm_get_cm_ctx(vdev); 1299 if (!cm_ctx) 1300 return status; 1301 1302 cm_req_lock_acquire(cm_ctx); 1303 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 1304 while (cur_node) { 1305 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 1306 1307 cm_req = qdf_container_of(cur_node, struct cm_req, node); 1308 cm_id_prefix = CM_ID_GET_PREFIX((cm_req->cm_id)); 1309 1310 if (cm_req->cm_id == cm_ctx->active_cm_id && 1311 cm_id_prefix == DISCONNECT_REQ_PREFIX) { 1312 req->cm_id = cm_req->cm_id; 1313 req->req.vdev_id = wlan_vdev_get_id(vdev); 1314 req->req.source = cm_req->discon_req.req.source; 1315 req->req.reason_code = 1316 cm_req->discon_req.req.reason_code; 1317 req->req.bssid = cm_req->discon_req.req.bssid; 1318 req->req.is_no_disassoc_disconnect = 1319 cm_req->discon_req.req.is_no_disassoc_disconnect; 1320 status = true; 1321 cm_req_lock_release(cm_ctx); 1322 return status; 1323 } 1324 1325 cur_node = next_node; 1326 next_node = NULL; 1327 } 1328 cm_req_lock_release(cm_ctx); 1329 1330 return status; 1331 } 1332 1333 struct cm_req *cm_get_req_by_scan_id(struct cnx_mgr *cm_ctx, 1334 wlan_scan_id scan_id) 1335 { 1336 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 1337 struct cm_req *cm_req; 1338 1339 cm_req_lock_acquire(cm_ctx); 1340 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 1341 while (cur_node) { 1342 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 1343 cm_req = qdf_container_of(cur_node, struct cm_req, node); 1344 1345 if (cm_req->connect_req.scan_id == scan_id) { 1346 cm_req_lock_release(cm_ctx); 1347 return cm_req; 1348 } 1349 1350 cur_node = next_node; 1351 next_node = NULL; 1352 } 1353 cm_req_lock_release(cm_ctx); 1354 1355 return NULL; 1356 } 1357 1358 wlan_cm_id cm_get_cm_id_by_scan_id(struct cnx_mgr *cm_ctx, 1359 wlan_scan_id scan_id) 1360 { 1361 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 1362 struct cm_req *cm_req; 1363 1364 cm_req_lock_acquire(cm_ctx); 1365 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 1366 while (cur_node) { 1367 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 1368 cm_req = qdf_container_of(cur_node, struct cm_req, node); 1369 1370 if (cm_req->connect_req.scan_id == scan_id) { 1371 cm_req_lock_release(cm_ctx); 1372 return cm_req->cm_id; 1373 } 1374 1375 cur_node = next_node; 1376 next_node = NULL; 1377 } 1378 cm_req_lock_release(cm_ctx); 1379 1380 return CM_ID_INVALID; 1381 } 1382 1383 #ifdef WLAN_POLICY_MGR_ENABLE 1384 static void 1385 cm_get_pcl_chan_weigtage_for_sta(struct wlan_objmgr_pdev *pdev, 1386 struct pcl_freq_weight_list *pcl_lst) 1387 { 1388 enum QDF_OPMODE opmode = QDF_STA_MODE; 1389 enum policy_mgr_con_mode pm_mode; 1390 uint32_t num_entries = 0; 1391 QDF_STATUS status; 1392 1393 if (!pcl_lst) 1394 return; 1395 1396 if (policy_mgr_map_concurrency_mode(&opmode, &pm_mode)) { 1397 status = policy_mgr_get_pcl(wlan_pdev_get_psoc(pdev), pm_mode, 1398 pcl_lst->pcl_freq_list, 1399 &num_entries, 1400 pcl_lst->pcl_weight_list, 1401 NUM_CHANNELS); 1402 if (QDF_IS_STATUS_ERROR(status)) 1403 return; 1404 pcl_lst->num_of_pcl_channels = num_entries; 1405 } 1406 } 1407 1408 void cm_calculate_scores(struct cnx_mgr *cm_ctx, 1409 struct wlan_objmgr_pdev *pdev, 1410 struct scan_filter *filter, qdf_list_t *list) 1411 { 1412 struct pcl_freq_weight_list *pcl_lst = NULL; 1413 1414 if (!filter->num_of_bssid) { 1415 pcl_lst = qdf_mem_malloc(sizeof(*pcl_lst)); 1416 cm_get_pcl_chan_weigtage_for_sta(pdev, pcl_lst); 1417 if (pcl_lst && !pcl_lst->num_of_pcl_channels) { 1418 qdf_mem_free(pcl_lst); 1419 pcl_lst = NULL; 1420 } 1421 } 1422 wlan_cm_calculate_bss_score(pdev, pcl_lst, list, &filter->bssid_hint); 1423 if (pcl_lst) 1424 qdf_mem_free(pcl_lst); 1425 } 1426 #else 1427 inline 1428 void cm_calculate_scores(struct cnx_mgr *cm_ctx, 1429 struct wlan_objmgr_pdev *pdev, 1430 struct scan_filter *filter, qdf_list_t *list) 1431 { 1432 wlan_cm_calculate_bss_score(pdev, NULL, list, &filter->bssid_hint); 1433 1434 /* 1435 * Custom sorting if enabled 1436 */ 1437 if (cm_ctx && cm_ctx->cm_candidate_list_custom_sort) 1438 cm_ctx->cm_candidate_list_custom_sort(cm_ctx->vdev, list); 1439 } 1440 #endif 1441 1442 #ifdef SM_ENG_HIST_ENABLE 1443 static const char *cm_id_to_string(wlan_cm_id cm_id) 1444 { 1445 uint32_t prefix = CM_ID_GET_PREFIX(cm_id); 1446 1447 switch (prefix) { 1448 case CONNECT_REQ_PREFIX: 1449 return "CONNECT"; 1450 case DISCONNECT_REQ_PREFIX: 1451 return "DISCONNECT"; 1452 case ROAM_REQ_PREFIX: 1453 return "ROAM"; 1454 default: 1455 return "INVALID"; 1456 } 1457 } 1458 1459 void cm_req_history_add(struct cnx_mgr *cm_ctx, 1460 struct cm_req *cm_req) 1461 { 1462 struct cm_req_history *history = &cm_ctx->req_history; 1463 struct cm_req_history_info *data; 1464 1465 qdf_spin_lock_bh(&history->cm_req_hist_lock); 1466 data = &history->data[history->index]; 1467 history->index++; 1468 history->index %= CM_REQ_HISTORY_SIZE; 1469 1470 qdf_mem_zero(data, sizeof(*data)); 1471 data->cm_id = cm_req->cm_id; 1472 data->add_time = qdf_get_log_timestamp(); 1473 data->add_cm_state = cm_get_state(cm_ctx); 1474 qdf_spin_unlock_bh(&history->cm_req_hist_lock); 1475 } 1476 1477 void cm_req_history_del(struct cnx_mgr *cm_ctx, 1478 struct cm_req *cm_req, 1479 enum cm_req_del_type del_type) 1480 { 1481 uint8_t i, idx; 1482 struct cm_req_history_info *data; 1483 struct cm_req_history *history = &cm_ctx->req_history; 1484 1485 qdf_spin_lock_bh(&history->cm_req_hist_lock); 1486 for (i = 0; i < CM_REQ_HISTORY_SIZE; i++) { 1487 if (history->index < i) 1488 idx = CM_REQ_HISTORY_SIZE + history->index - i; 1489 else 1490 idx = history->index - i; 1491 1492 data = &history->data[idx]; 1493 if (data->cm_id == cm_req->cm_id) { 1494 data->del_time = qdf_get_log_timestamp(); 1495 data->del_cm_state = cm_get_state(cm_ctx); 1496 data->del_type = del_type; 1497 break; 1498 } 1499 1500 if (!data->cm_id) 1501 break; 1502 } 1503 qdf_spin_unlock_bh(&history->cm_req_hist_lock); 1504 } 1505 1506 void cm_req_history_init(struct cnx_mgr *cm_ctx) 1507 { 1508 qdf_spinlock_create(&cm_ctx->req_history.cm_req_hist_lock); 1509 qdf_mem_zero(&cm_ctx->req_history, sizeof(struct cm_req_history)); 1510 } 1511 1512 void cm_req_history_deinit(struct cnx_mgr *cm_ctx) 1513 { 1514 qdf_spinlock_destroy(&cm_ctx->req_history.cm_req_hist_lock); 1515 } 1516 1517 static inline void cm_req_history_print_entry(uint16_t idx, 1518 struct cm_req_history_info *data) 1519 { 1520 if (!data->cm_id) 1521 return; 1522 1523 mlme_nofl_err(" |%6u | 0x%016llx | 0x%016llx |%12s | 0x%08x |%15s |%15s |%8u", 1524 idx, data->add_time, data->del_time, 1525 cm_id_to_string(data->cm_id), data->cm_id, 1526 cm_sm_info[data->add_cm_state].name, 1527 cm_sm_info[data->del_cm_state].name, 1528 data->del_type); 1529 } 1530 1531 void cm_req_history_print(struct cnx_mgr *cm_ctx) 1532 { 1533 struct cm_req_history *history = &cm_ctx->req_history; 1534 uint8_t i, idx; 1535 1536 mlme_nofl_err("CM Request history is as below"); 1537 mlme_nofl_err("|%6s |%19s |%19s |%12s |%11s |%15s |%15s |%8s", 1538 "Index", "Add Time", "Del Time", "Req type", 1539 "Cm Id", "Add State", "Del State", "Del Type"); 1540 1541 qdf_spin_lock_bh(&history->cm_req_hist_lock); 1542 for (i = 0; i < CM_REQ_HISTORY_SIZE; i++) { 1543 idx = (history->index + i) % CM_REQ_HISTORY_SIZE; 1544 cm_req_history_print_entry(idx, &history->data[idx]); 1545 } 1546 qdf_spin_unlock_bh(&history->cm_req_hist_lock); 1547 } 1548 #endif 1549 1550 #ifndef CONN_MGR_ADV_FEATURE 1551 void cm_set_candidate_advance_filter_cb( 1552 struct wlan_objmgr_vdev *vdev, 1553 void (*filter_fun)(struct wlan_objmgr_vdev *vdev, 1554 struct scan_filter *filter)) 1555 { 1556 struct cnx_mgr *cm_ctx; 1557 1558 cm_ctx = cm_get_cm_ctx(vdev); 1559 if (!cm_ctx) 1560 return; 1561 1562 cm_ctx->cm_candidate_advance_filter = filter_fun; 1563 } 1564 1565 void cm_set_candidate_custom_sort_cb( 1566 struct wlan_objmgr_vdev *vdev, 1567 void (*sort_fun)(struct wlan_objmgr_vdev *vdev, 1568 qdf_list_t *list)) 1569 { 1570 struct cnx_mgr *cm_ctx; 1571 1572 cm_ctx = cm_get_cm_ctx(vdev); 1573 if (!cm_ctx) 1574 return; 1575 1576 cm_ctx->cm_candidate_list_custom_sort = sort_fun; 1577 } 1578 #endif 1579