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