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