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