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 false); 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_is_connect_req_reassoc(struct wlan_cm_connect_req *req) 1260 { 1261 if (!qdf_is_macaddr_zero(&req->prev_bssid) && 1262 (!qdf_is_macaddr_zero(&req->bssid) || 1263 !qdf_is_macaddr_zero(&req->bssid_hint)) && 1264 (req->chan_freq || req->chan_freq_hint)) 1265 return true; 1266 1267 return false; 1268 } 1269 1270 bool cm_get_active_connect_req(struct wlan_objmgr_vdev *vdev, 1271 struct wlan_cm_vdev_connect_req *req) 1272 { 1273 struct cnx_mgr *cm_ctx; 1274 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 1275 struct cm_req *cm_req = NULL; 1276 bool status = false; 1277 uint32_t cm_id_prefix; 1278 1279 cm_ctx = cm_get_cm_ctx(vdev); 1280 if (!cm_ctx) 1281 return status; 1282 1283 cm_req_lock_acquire(cm_ctx); 1284 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 1285 while (cur_node) { 1286 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 1287 1288 cm_req = qdf_container_of(cur_node, struct cm_req, node); 1289 cm_id_prefix = CM_ID_GET_PREFIX((cm_req->cm_id)); 1290 1291 if (cm_req->cm_id == cm_ctx->active_cm_id && 1292 cm_id_prefix == CONNECT_REQ_PREFIX) { 1293 req->vdev_id = wlan_vdev_get_id(vdev); 1294 req->cm_id = cm_req->connect_req.cm_id; 1295 req->bss = cm_req->connect_req.cur_candidate; 1296 req->is_wps_connection = 1297 cm_req->connect_req.req.is_wps_connection; 1298 req->is_osen_connection = 1299 cm_req->connect_req.req.is_osen_connection; 1300 req->is_non_assoc_link = cm_req->connect_req.req.is_non_assoc_link; 1301 cm_fill_ml_partner_info(&cm_req->connect_req.req, req); 1302 status = true; 1303 cm_req_lock_release(cm_ctx); 1304 return status; 1305 } 1306 1307 cur_node = next_node; 1308 next_node = NULL; 1309 } 1310 cm_req_lock_release(cm_ctx); 1311 1312 return status; 1313 } 1314 1315 bool cm_get_active_disconnect_req(struct wlan_objmgr_vdev *vdev, 1316 struct wlan_cm_vdev_discon_req *req) 1317 { 1318 struct cnx_mgr *cm_ctx; 1319 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 1320 struct cm_req *cm_req = NULL; 1321 bool status = false; 1322 uint32_t cm_id_prefix; 1323 1324 cm_ctx = cm_get_cm_ctx(vdev); 1325 if (!cm_ctx) 1326 return status; 1327 1328 cm_req_lock_acquire(cm_ctx); 1329 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 1330 while (cur_node) { 1331 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 1332 1333 cm_req = qdf_container_of(cur_node, struct cm_req, node); 1334 cm_id_prefix = CM_ID_GET_PREFIX((cm_req->cm_id)); 1335 1336 if (cm_req->cm_id == cm_ctx->active_cm_id && 1337 cm_id_prefix == DISCONNECT_REQ_PREFIX) { 1338 req->cm_id = cm_req->cm_id; 1339 req->req.vdev_id = wlan_vdev_get_id(vdev); 1340 req->req.source = cm_req->discon_req.req.source; 1341 req->req.reason_code = 1342 cm_req->discon_req.req.reason_code; 1343 req->req.bssid = cm_req->discon_req.req.bssid; 1344 req->req.is_no_disassoc_disconnect = 1345 cm_req->discon_req.req.is_no_disassoc_disconnect; 1346 status = true; 1347 cm_req_lock_release(cm_ctx); 1348 return status; 1349 } 1350 1351 cur_node = next_node; 1352 next_node = NULL; 1353 } 1354 cm_req_lock_release(cm_ctx); 1355 1356 return status; 1357 } 1358 1359 struct cm_req *cm_get_req_by_scan_id(struct cnx_mgr *cm_ctx, 1360 wlan_scan_id scan_id) 1361 { 1362 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 1363 struct cm_req *cm_req; 1364 1365 cm_req_lock_acquire(cm_ctx); 1366 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 1367 while (cur_node) { 1368 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 1369 cm_req = qdf_container_of(cur_node, struct cm_req, node); 1370 1371 if (cm_req->connect_req.scan_id == scan_id) { 1372 cm_req_lock_release(cm_ctx); 1373 return cm_req; 1374 } 1375 1376 cur_node = next_node; 1377 next_node = NULL; 1378 } 1379 cm_req_lock_release(cm_ctx); 1380 1381 return NULL; 1382 } 1383 1384 wlan_cm_id cm_get_cm_id_by_scan_id(struct cnx_mgr *cm_ctx, 1385 wlan_scan_id scan_id) 1386 { 1387 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 1388 struct cm_req *cm_req; 1389 1390 cm_req_lock_acquire(cm_ctx); 1391 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 1392 while (cur_node) { 1393 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 1394 cm_req = qdf_container_of(cur_node, struct cm_req, node); 1395 1396 if (cm_req->connect_req.scan_id == scan_id) { 1397 cm_req_lock_release(cm_ctx); 1398 return cm_req->cm_id; 1399 } 1400 1401 cur_node = next_node; 1402 next_node = NULL; 1403 } 1404 cm_req_lock_release(cm_ctx); 1405 1406 return CM_ID_INVALID; 1407 } 1408 1409 #ifdef WLAN_POLICY_MGR_ENABLE 1410 static void 1411 cm_get_pcl_chan_weigtage_for_sta(struct wlan_objmgr_pdev *pdev, 1412 struct pcl_freq_weight_list *pcl_lst) 1413 { 1414 enum QDF_OPMODE opmode = QDF_STA_MODE; 1415 enum policy_mgr_con_mode pm_mode; 1416 uint32_t num_entries = 0; 1417 QDF_STATUS status; 1418 1419 if (!pcl_lst) 1420 return; 1421 1422 if (policy_mgr_map_concurrency_mode(&opmode, &pm_mode)) { 1423 status = policy_mgr_get_pcl(wlan_pdev_get_psoc(pdev), pm_mode, 1424 pcl_lst->pcl_freq_list, 1425 &num_entries, 1426 pcl_lst->pcl_weight_list, 1427 NUM_CHANNELS); 1428 if (QDF_IS_STATUS_ERROR(status)) 1429 return; 1430 pcl_lst->num_of_pcl_channels = num_entries; 1431 } 1432 } 1433 1434 void cm_calculate_scores(struct cnx_mgr *cm_ctx, 1435 struct wlan_objmgr_pdev *pdev, 1436 struct scan_filter *filter, qdf_list_t *list) 1437 { 1438 struct pcl_freq_weight_list *pcl_lst = NULL; 1439 1440 if (!filter->num_of_bssid) { 1441 pcl_lst = qdf_mem_malloc(sizeof(*pcl_lst)); 1442 cm_get_pcl_chan_weigtage_for_sta(pdev, pcl_lst); 1443 if (pcl_lst && !pcl_lst->num_of_pcl_channels) { 1444 qdf_mem_free(pcl_lst); 1445 pcl_lst = NULL; 1446 } 1447 } 1448 wlan_cm_calculate_bss_score(pdev, pcl_lst, list, &filter->bssid_hint); 1449 if (pcl_lst) 1450 qdf_mem_free(pcl_lst); 1451 } 1452 #else 1453 inline 1454 void cm_calculate_scores(struct cnx_mgr *cm_ctx, 1455 struct wlan_objmgr_pdev *pdev, 1456 struct scan_filter *filter, qdf_list_t *list) 1457 { 1458 wlan_cm_calculate_bss_score(pdev, NULL, list, &filter->bssid_hint); 1459 1460 /* 1461 * Custom sorting if enabled 1462 */ 1463 if (cm_ctx && cm_ctx->cm_candidate_list_custom_sort) 1464 cm_ctx->cm_candidate_list_custom_sort(cm_ctx->vdev, list); 1465 } 1466 #endif 1467 1468 #ifdef SM_ENG_HIST_ENABLE 1469 static const char *cm_id_to_string(wlan_cm_id cm_id) 1470 { 1471 uint32_t prefix = CM_ID_GET_PREFIX(cm_id); 1472 1473 switch (prefix) { 1474 case CONNECT_REQ_PREFIX: 1475 return "CONNECT"; 1476 case DISCONNECT_REQ_PREFIX: 1477 return "DISCONNECT"; 1478 case ROAM_REQ_PREFIX: 1479 return "ROAM"; 1480 default: 1481 return "INVALID"; 1482 } 1483 } 1484 1485 void cm_req_history_add(struct cnx_mgr *cm_ctx, 1486 struct cm_req *cm_req) 1487 { 1488 struct cm_req_history *history = &cm_ctx->req_history; 1489 struct cm_req_history_info *data; 1490 1491 qdf_spin_lock_bh(&history->cm_req_hist_lock); 1492 data = &history->data[history->index]; 1493 history->index++; 1494 history->index %= CM_REQ_HISTORY_SIZE; 1495 1496 qdf_mem_zero(data, sizeof(*data)); 1497 data->cm_id = cm_req->cm_id; 1498 data->add_time = qdf_get_log_timestamp(); 1499 data->add_cm_state = cm_get_state(cm_ctx); 1500 qdf_spin_unlock_bh(&history->cm_req_hist_lock); 1501 } 1502 1503 void cm_req_history_del(struct cnx_mgr *cm_ctx, 1504 struct cm_req *cm_req, 1505 enum cm_req_del_type del_type) 1506 { 1507 uint8_t i, idx; 1508 struct cm_req_history_info *data; 1509 struct cm_req_history *history = &cm_ctx->req_history; 1510 1511 qdf_spin_lock_bh(&history->cm_req_hist_lock); 1512 for (i = 0; i < CM_REQ_HISTORY_SIZE; i++) { 1513 if (history->index < i) 1514 idx = CM_REQ_HISTORY_SIZE + history->index - i; 1515 else 1516 idx = history->index - i; 1517 1518 data = &history->data[idx]; 1519 if (data->cm_id == cm_req->cm_id) { 1520 data->del_time = qdf_get_log_timestamp(); 1521 data->del_cm_state = cm_get_state(cm_ctx); 1522 data->del_type = del_type; 1523 break; 1524 } 1525 1526 if (!data->cm_id) 1527 break; 1528 } 1529 qdf_spin_unlock_bh(&history->cm_req_hist_lock); 1530 } 1531 1532 void cm_req_history_init(struct cnx_mgr *cm_ctx) 1533 { 1534 qdf_spinlock_create(&cm_ctx->req_history.cm_req_hist_lock); 1535 qdf_mem_zero(&cm_ctx->req_history, sizeof(struct cm_req_history)); 1536 } 1537 1538 void cm_req_history_deinit(struct cnx_mgr *cm_ctx) 1539 { 1540 qdf_spinlock_destroy(&cm_ctx->req_history.cm_req_hist_lock); 1541 } 1542 1543 static inline void cm_req_history_print_entry(uint16_t idx, 1544 struct cm_req_history_info *data) 1545 { 1546 if (!data->cm_id) 1547 return; 1548 1549 mlme_nofl_err(" |%6u | 0x%016llx | 0x%016llx |%12s | 0x%08x |%15s |%15s |%8u", 1550 idx, data->add_time, data->del_time, 1551 cm_id_to_string(data->cm_id), data->cm_id, 1552 cm_sm_info[data->add_cm_state].name, 1553 cm_sm_info[data->del_cm_state].name, 1554 data->del_type); 1555 } 1556 1557 void cm_req_history_print(struct cnx_mgr *cm_ctx) 1558 { 1559 struct cm_req_history *history = &cm_ctx->req_history; 1560 uint8_t i, idx; 1561 1562 mlme_nofl_err("CM Request history is as below"); 1563 mlme_nofl_err("|%6s |%19s |%19s |%12s |%11s |%15s |%15s |%8s", 1564 "Index", "Add Time", "Del Time", "Req type", 1565 "Cm Id", "Add State", "Del State", "Del Type"); 1566 1567 qdf_spin_lock_bh(&history->cm_req_hist_lock); 1568 for (i = 0; i < CM_REQ_HISTORY_SIZE; i++) { 1569 idx = (history->index + i) % CM_REQ_HISTORY_SIZE; 1570 cm_req_history_print_entry(idx, &history->data[idx]); 1571 } 1572 qdf_spin_unlock_bh(&history->cm_req_hist_lock); 1573 } 1574 #endif 1575 1576 #ifndef CONN_MGR_ADV_FEATURE 1577 void cm_set_candidate_advance_filter_cb( 1578 struct wlan_objmgr_vdev *vdev, 1579 void (*filter_fun)(struct wlan_objmgr_vdev *vdev, 1580 struct scan_filter *filter)) 1581 { 1582 struct cnx_mgr *cm_ctx; 1583 1584 cm_ctx = cm_get_cm_ctx(vdev); 1585 if (!cm_ctx) 1586 return; 1587 1588 cm_ctx->cm_candidate_advance_filter = filter_fun; 1589 } 1590 1591 void cm_set_candidate_custom_sort_cb( 1592 struct wlan_objmgr_vdev *vdev, 1593 void (*sort_fun)(struct wlan_objmgr_vdev *vdev, 1594 qdf_list_t *list)) 1595 { 1596 struct cnx_mgr *cm_ctx; 1597 1598 cm_ctx = cm_get_cm_ctx(vdev); 1599 if (!cm_ctx) 1600 return; 1601 1602 cm_ctx->cm_candidate_list_custom_sort = sort_fun; 1603 } 1604 #endif 1605