1 /* 2 * Copyright (c) 2012-2015, 2020, 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 26 static uint32_t cm_get_prefix_for_cm_id(enum wlan_cm_source source) { 27 switch (source) { 28 case CM_OSIF_CONNECT: 29 case CM_ROAMING: 30 return CONNECT_REQ_PREFIX; 31 default: 32 return DISCONNECT_REQ_PREFIX; 33 } 34 } 35 36 wlan_cm_id cm_get_cm_id(struct cnx_mgr *cm_ctx, enum wlan_cm_source source) 37 { 38 wlan_cm_id cmd_id; 39 uint32_t prefix; 40 41 prefix = cm_get_prefix_for_cm_id(source); 42 43 cmd_id = qdf_atomic_inc_return(&cm_ctx->global_cmd_id); 44 cmd_id = (cmd_id & CM_ID_MASK); 45 cmd_id = (cmd_id | prefix); 46 47 return cmd_id; 48 } 49 50 struct cnx_mgr *cm_get_cm_ctx_fl(struct wlan_objmgr_vdev *vdev, 51 const char *func, uint32_t line) 52 { 53 struct vdev_mlme_obj *vdev_mlme; 54 struct cnx_mgr *cm_ctx = NULL; 55 56 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); 57 if (vdev_mlme) 58 cm_ctx = vdev_mlme->cnx_mgr_ctx; 59 60 if (!cm_ctx) 61 mlme_nofl_err("%s:%u: vdev %d cm_ctx is NULL", func, line, 62 wlan_vdev_get_id(vdev)); 63 64 return cm_ctx; 65 } 66 67 void cm_reset_active_cm_id(struct wlan_objmgr_vdev *vdev, wlan_cm_id cm_id) 68 { 69 struct cnx_mgr *cm_ctx; 70 71 cm_ctx = cm_get_cm_ctx(vdev); 72 if (!cm_ctx) 73 return; 74 75 /* Reset active cm id if cm id match */ 76 if (cm_ctx->active_cm_id == cm_id) 77 cm_ctx->active_cm_id = CM_ID_INVALID; 78 } 79 80 81 #ifdef WLAN_CM_USE_SPINLOCK 82 /** 83 * cm_req_lock_acquire - acquire CM SM mutex/spinlock 84 * @cm_ctx: connection manager ctx 85 * 86 * acquire CM SM mutex/spinlock 87 * 88 * return: void 89 */ 90 static inline void cm_req_lock_acquire(struct cnx_mgr *cm_ctx) 91 { 92 qdf_spinlock_acquire(&cm_ctx->cm_req_lock); 93 } 94 95 /** 96 * cm_req_lock_release - release CM SM mutex/spinlock 97 * @cm_ctx: connection manager ctx 98 * 99 * release CM SM mutex/spinlock 100 * 101 * return: void 102 */ 103 static inline void cm_req_lock_release(struct cnx_mgr *cm_ctx) 104 { 105 qdf_spinlock_release(&cm_ctx->cm_req_lock); 106 } 107 #else 108 static inline void cm_req_lock_acquire(struct cnx_mgr *cm_ctx) 109 { 110 qdf_mutex_acquire(&cm_ctx->cm_req_lock); 111 } 112 113 static inline void cm_req_lock_release(struct cnx_mgr *cm_ctx) 114 { 115 qdf_mutex_release(&cm_ctx->cm_req_lock); 116 } 117 #endif /* WLAN_CM_USE_SPINLOCK */ 118 119 #ifdef CRYPTO_SET_KEY_CONVERGED 120 QDF_STATUS cm_set_key(struct cnx_mgr *cm_ctx, bool unicast, 121 uint8_t key_idx, struct qdf_mac_addr *bssid) 122 { 123 enum wlan_crypto_cipher_type cipher; 124 struct wlan_crypto_key *crypto_key; 125 uint8_t wep_key_idx = 0; 126 127 cipher = wlan_crypto_get_cipher(cm_ctx->vdev, unicast, key_idx); 128 if (IS_WEP_CIPHER(cipher)) { 129 wep_key_idx = wlan_crypto_get_default_key_idx(cm_ctx->vdev, 130 !unicast); 131 crypto_key = wlan_crypto_get_key(cm_ctx->vdev, wep_key_idx); 132 qdf_mem_copy(crypto_key->macaddr, bssid->bytes, 133 QDF_MAC_ADDR_SIZE); 134 } else { 135 crypto_key = wlan_crypto_get_key(cm_ctx->vdev, key_idx); 136 } 137 138 return wlan_crypto_set_key_req(cm_ctx->vdev, crypto_key, (unicast ? 139 WLAN_CRYPTO_KEY_TYPE_UNICAST : 140 WLAN_CRYPTO_KEY_TYPE_GROUP)); 141 } 142 #endif 143 144 #ifdef CONN_MGR_ADV_FEATURE 145 void cm_store_wep_key(struct cnx_mgr *cm_ctx, 146 struct wlan_cm_connect_crypto_info *crypto, 147 wlan_cm_id cm_id) 148 { 149 struct wlan_crypto_key *crypto_key = NULL; 150 QDF_STATUS status; 151 enum wlan_crypto_cipher_type cipher_type; 152 struct wlan_cm_wep_key_params *wep_keys; 153 154 if (!(crypto->ciphers_pairwise & (1 << WLAN_CRYPTO_CIPHER_WEP_40 | 155 1 << WLAN_CRYPTO_CIPHER_WEP_104))) 156 return; 157 158 if (crypto->ciphers_pairwise & 1 << WLAN_CRYPTO_CIPHER_WEP_40) 159 cipher_type = WLAN_CRYPTO_CIPHER_WEP_40; 160 else 161 cipher_type = WLAN_CRYPTO_CIPHER_WEP_104; 162 163 wep_keys = &crypto->wep_keys; 164 status = wlan_crypto_validate_key_params(cipher_type, 165 wep_keys->key_idx, 166 wep_keys->key_len, 167 wep_keys->seq_len); 168 if (QDF_IS_STATUS_ERROR(status)) { 169 mlme_err(CM_PREFIX_FMT "Invalid key params", 170 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id)); 171 return; 172 } 173 174 crypto_key = wlan_crypto_get_key(cm_ctx->vdev, wep_keys->key_idx); 175 if (!crypto_key) { 176 crypto_key = qdf_mem_malloc(sizeof(*crypto_key)); 177 if (!crypto_key) 178 return; 179 180 status = wlan_crypto_save_key(cm_ctx->vdev, wep_keys->key_idx, 181 crypto_key); 182 if (QDF_IS_STATUS_ERROR(status)) { 183 mlme_err(CM_PREFIX_FMT "Failed to save key", 184 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 185 cm_id)); 186 qdf_mem_free(crypto_key); 187 return; 188 } 189 } 190 qdf_mem_zero(crypto_key, sizeof(*crypto_key)); 191 crypto_key->cipher_type = cipher_type; 192 crypto_key->keylen = wep_keys->key_len; 193 crypto_key->keyix = wep_keys->key_idx; 194 qdf_mem_copy(&crypto_key->keyval[0], wep_keys->key, wep_keys->key_len); 195 qdf_mem_copy(&crypto_key->keyrsc[0], wep_keys->seq, wep_keys->seq_len); 196 mlme_debug(CM_PREFIX_FMT "cipher_type %d key_len %d, seq_len %d", 197 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id), 198 crypto_key->cipher_type, wep_keys->key_len, 199 wep_keys->seq_len); 200 } 201 #endif 202 203 #ifdef WLAN_FEATURE_FILS_SK 204 void cm_store_fils_key(struct cnx_mgr *cm_ctx, bool unicast, 205 uint8_t key_id, uint16_t key_length, 206 uint8_t *key, struct qdf_mac_addr *bssid, 207 wlan_cm_id cm_id) 208 { 209 struct wlan_crypto_key *crypto_key = NULL; 210 QDF_STATUS status; 211 uint8_t i; 212 int32_t cipher; 213 enum wlan_crypto_cipher_type cipher_type = WLAN_CRYPTO_CIPHER_NONE; 214 215 if (unicast) 216 cipher = wlan_crypto_get_param(cm_ctx->vdev, 217 WLAN_CRYPTO_PARAM_UCAST_CIPHER); 218 else 219 cipher = wlan_crypto_get_param(cm_ctx->vdev, 220 WLAN_CRYPTO_PARAM_MCAST_CIPHER); 221 222 for (i = 0; i <= WLAN_CRYPTO_CIPHER_MAX; i++) { 223 if (QDF_HAS_PARAM(cipher, i)) { 224 cipher_type = i; 225 break; 226 } 227 } 228 crypto_key = wlan_crypto_get_key(cm_ctx->vdev, key_id); 229 if (!crypto_key) { 230 crypto_key = qdf_mem_malloc(sizeof(*crypto_key)); 231 if (!crypto_key) 232 return; 233 status = wlan_crypto_save_key(cm_ctx->vdev, key_id, crypto_key); 234 if (QDF_IS_STATUS_ERROR(status)) { 235 mlme_err(CM_PREFIX_FMT "Failed to save key", 236 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 237 cm_id)); 238 qdf_mem_free(crypto_key); 239 return; 240 } 241 } 242 qdf_mem_zero(crypto_key, sizeof(*crypto_key)); 243 crypto_key->cipher_type = cipher_type; 244 crypto_key->keylen = key_length; 245 crypto_key->keyix = key_id; 246 qdf_mem_copy(&crypto_key->keyval[0], key, key_length); 247 qdf_mem_copy(crypto_key->macaddr, bssid->bytes, QDF_MAC_ADDR_SIZE); 248 mlme_debug(CM_PREFIX_FMT "cipher_type %d key_len %d, key_id %d mac:" QDF_MAC_ADDR_FMT, 249 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id), 250 crypto_key->cipher_type, crypto_key->keylen, 251 crypto_key->keyix, QDF_MAC_ADDR_REF(crypto_key->macaddr)); 252 } 253 #endif 254 255 bool cm_check_cmid_match_list_head(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id) 256 { 257 qdf_list_node_t *cur_node = NULL; 258 struct cm_req *cm_req; 259 bool match = false; 260 wlan_cm_id head_cm_id = 0; 261 262 if (!cm_id) 263 return false; 264 265 cm_req_lock_acquire(cm_ctx); 266 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 267 if (!cur_node) 268 goto exit; 269 270 cm_req = qdf_container_of(cur_node, struct cm_req, node); 271 head_cm_id = cm_req->cm_id; 272 if (head_cm_id == *cm_id) 273 match = true; 274 275 exit: 276 cm_req_lock_release(cm_ctx); 277 if (!match) 278 mlme_info("head_cm_id 0x%x didn't match the given cm_id 0x%x", 279 head_cm_id, *cm_id); 280 281 return match; 282 } 283 284 bool cm_check_scanid_match_list_head(struct cnx_mgr *cm_ctx, 285 wlan_scan_id *scan_id) 286 { 287 qdf_list_node_t *cur_node = NULL; 288 struct cm_req *cm_req; 289 bool match = false; 290 wlan_cm_id head_scan_id = 0; 291 uint32_t prefix = 0; 292 293 if (!scan_id) 294 return false; 295 296 cm_req_lock_acquire(cm_ctx); 297 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 298 if (!cur_node) 299 goto exit; 300 301 cm_req = qdf_container_of(cur_node, struct cm_req, node); 302 prefix = CM_ID_GET_PREFIX(cm_req->cm_id); 303 /* Check only if head is connect req */ 304 if (prefix != CONNECT_REQ_PREFIX) 305 goto exit; 306 head_scan_id = cm_req->connect_req.scan_id; 307 if (head_scan_id == *scan_id) 308 match = true; 309 310 exit: 311 cm_req_lock_release(cm_ctx); 312 if (!match) 313 mlme_info("head_scan_id 0x%x didn't match the given scan_id 0x%x prefix 0x%x", 314 head_scan_id, *scan_id, prefix); 315 316 return match; 317 } 318 319 struct cm_req *cm_get_req_by_cm_id_fl(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id, 320 const char *func, uint32_t line) 321 { 322 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 323 struct cm_req * cm_req; 324 325 cm_req_lock_acquire(cm_ctx); 326 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 327 while (cur_node) { 328 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 329 cm_req = qdf_container_of(cur_node, struct cm_req, node); 330 331 if (cm_req->cm_id == cm_id) { 332 cm_req_lock_release(cm_ctx); 333 return cm_req; 334 } 335 336 cur_node = next_node; 337 next_node = NULL; 338 } 339 cm_req_lock_release(cm_ctx); 340 341 mlme_nofl_info("%s:%u: cm req not found for cm id 0x%x", func, 342 line, cm_id); 343 344 return NULL; 345 } 346 347 /** 348 * cm_fill_connect_resp_from_req() - Fill connect resp from connect request 349 * @resp: cm connect response 350 * @cm_req: cm request 351 * 352 * Context: Can be called from APIs holding cm request list lock 353 * 354 * Return: void 355 */ 356 static void 357 cm_fill_connect_resp_from_req(struct wlan_cm_connect_resp *resp, 358 struct cm_req *cm_req) 359 { 360 struct scan_cache_node *candidate; 361 struct wlan_cm_connect_req *req; 362 363 req = &cm_req->connect_req.req; 364 candidate = cm_req->connect_req.cur_candidate; 365 if (candidate) 366 qdf_copy_macaddr(&resp->bssid, &candidate->entry->bssid); 367 else if (!qdf_is_macaddr_zero(&req->bssid)) 368 qdf_copy_macaddr(&resp->bssid, &req->bssid); 369 else 370 qdf_copy_macaddr(&resp->bssid, &req->bssid_hint); 371 372 if (candidate) 373 resp->freq = candidate->entry->channel.chan_freq; 374 else 375 resp->freq = req->chan_freq; 376 377 resp->ssid = req->ssid; 378 } 379 380 /** 381 * cm_handle_connect_flush() - Fill fail connect resp from req and indicate 382 * same to osif 383 * @cm_ctx: connection manager context 384 * @cm_req: cm request 385 * 386 * Context: Can be called from APIs holding cm request list lock 387 * 388 * Return: void 389 */ 390 static void 391 cm_handle_connect_flush(struct cnx_mgr *cm_ctx, struct cm_req *cm_req) 392 { 393 struct wlan_cm_connect_resp *resp; 394 395 resp = qdf_mem_malloc(sizeof(*resp)); 396 if (!resp) 397 return; 398 399 resp->connect_status = QDF_STATUS_E_FAILURE; 400 resp->cm_id = cm_req->cm_id; 401 resp->vdev_id = wlan_vdev_get_id(cm_ctx->vdev); 402 resp->reason = CM_ABORT_DUE_TO_NEW_REQ_RECVD; 403 404 /* Get bssid and ssid and freq for the cm id from the req list */ 405 cm_fill_connect_resp_from_req(resp, cm_req); 406 407 mlme_cm_osif_connect_complete(cm_ctx->vdev, resp); 408 qdf_mem_free(resp); 409 } 410 411 /** 412 * cm_handle_disconnect_flush() - Fill disconnect resp from req and indicate 413 * same to osif 414 * @cm_ctx: connection manager context 415 * @cm_req: cm request 416 * 417 * Context: Can be called from APIs holding cm request list lock 418 * 419 * Return: void 420 */ 421 static void 422 cm_handle_disconnect_flush(struct cnx_mgr *cm_ctx, struct cm_req *cm_req) 423 { 424 struct wlan_cm_discon_rsp resp; 425 426 qdf_mem_zero(&resp, sizeof(resp)); 427 resp.req.cm_id = cm_req->cm_id; 428 resp.req.req = cm_req->discon_req.req; 429 430 mlme_cm_osif_disconnect_complete(cm_ctx->vdev, &resp); 431 } 432 433 static void cm_remove_cmd_from_serialization(struct cnx_mgr *cm_ctx, 434 wlan_cm_id cm_id) 435 { 436 struct wlan_serialization_queued_cmd_info cmd_info; 437 uint32_t prefix = CM_ID_GET_PREFIX(cm_id); 438 439 qdf_mem_zero(&cmd_info, sizeof(cmd_info)); 440 cmd_info.cmd_id = cm_id; 441 cmd_info.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD; 442 443 if (prefix == CONNECT_REQ_PREFIX) 444 cmd_info.cmd_type = WLAN_SER_CMD_VDEV_CONNECT; 445 else 446 cmd_info.cmd_type = WLAN_SER_CMD_VDEV_DISCONNECT; 447 448 cmd_info.vdev = cm_ctx->vdev; 449 450 if (cm_id == cm_ctx->active_cm_id) { 451 mlme_debug(CM_PREFIX_FMT "Remove from active", 452 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 453 cm_id)); 454 cmd_info.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE; 455 wlan_serialization_remove_cmd(&cmd_info); 456 } else { 457 mlme_debug(CM_PREFIX_FMT "Remove from pending", 458 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 459 cm_id)); 460 cmd_info.queue_type = WLAN_SERIALIZATION_PENDING_QUEUE; 461 wlan_serialization_cancel_request(&cmd_info); 462 } 463 } 464 465 void 466 cm_flush_pending_request(struct cnx_mgr *cm_ctx, uint32_t prefix, 467 bool only_failed_req) 468 { 469 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 470 struct cm_req *cm_req; 471 uint32_t req_prefix; 472 473 cm_req_lock_acquire(cm_ctx); 474 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 475 while (cur_node) { 476 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 477 cm_req = qdf_container_of(cur_node, struct cm_req, node); 478 479 req_prefix = CM_ID_GET_PREFIX(cm_req->cm_id); 480 481 /* Only remove the pending requests matching the flush prefix */ 482 if (req_prefix != prefix || 483 cm_req->cm_id == cm_ctx->active_cm_id) 484 goto next; 485 486 /* If only_failed_req is set flush only failed req */ 487 if (only_failed_req && !cm_req->failed_req) 488 goto next; 489 490 if (req_prefix == CONNECT_REQ_PREFIX) { 491 cm_handle_connect_flush(cm_ctx, cm_req); 492 cm_ctx->connect_count--; 493 cm_free_connect_req_mem(&cm_req->connect_req); 494 } else { 495 cm_handle_disconnect_flush(cm_ctx, cm_req); 496 cm_ctx->disconnect_count--; 497 } 498 mlme_debug(CM_PREFIX_FMT, 499 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 500 cm_req->cm_id)); 501 cm_remove_cmd_from_serialization(cm_ctx, cm_req->cm_id); 502 qdf_list_remove_node(&cm_ctx->req_list, &cm_req->node); 503 qdf_mem_free(cm_req); 504 next: 505 cur_node = next_node; 506 next_node = NULL; 507 } 508 509 cm_req_lock_release(cm_ctx); 510 } 511 512 QDF_STATUS 513 cm_fill_bss_info_in_connect_rsp_by_cm_id(struct cnx_mgr *cm_ctx, 514 wlan_cm_id cm_id, 515 struct wlan_cm_connect_resp *resp) 516 { 517 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 518 struct cm_req *cm_req; 519 uint32_t prefix = CM_ID_GET_PREFIX(cm_id); 520 521 if (prefix != CONNECT_REQ_PREFIX) 522 return QDF_STATUS_E_INVAL; 523 524 cm_req_lock_acquire(cm_ctx); 525 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 526 while (cur_node) { 527 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 528 cm_req = qdf_container_of(cur_node, struct cm_req, node); 529 530 if (cm_req->cm_id == cm_id) { 531 cm_fill_connect_resp_from_req(resp, cm_req); 532 cm_req_lock_release(cm_ctx); 533 return QDF_STATUS_SUCCESS; 534 } 535 536 cur_node = next_node; 537 next_node = NULL; 538 } 539 cm_req_lock_release(cm_ctx); 540 541 return QDF_STATUS_E_FAILURE; 542 } 543 544 #if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD) 545 bool cm_is_cm_id_current_candidate_single_pmk(struct cnx_mgr *cm_ctx, 546 wlan_cm_id cm_id) 547 { 548 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 549 struct cm_req *cm_req; 550 uint32_t prefix = CM_ID_GET_PREFIX(cm_id); 551 struct scan_cache_node *candidate; 552 bool is_single_pmk = false; 553 554 if (prefix != CONNECT_REQ_PREFIX) 555 return is_single_pmk; 556 557 cm_req_lock_acquire(cm_ctx); 558 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 559 while (cur_node) { 560 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 561 cm_req = qdf_container_of(cur_node, struct cm_req, node); 562 563 if (cm_req->cm_id == cm_id) { 564 candidate = cm_req->connect_req.cur_candidate; 565 if (candidate && 566 util_scan_entry_single_pmk(candidate->entry)) 567 is_single_pmk = true; 568 break; 569 } 570 571 cur_node = next_node; 572 next_node = NULL; 573 } 574 cm_req_lock_release(cm_ctx); 575 576 return is_single_pmk; 577 } 578 #endif 579 580 QDF_STATUS cm_add_req_to_list_and_indicate_osif(struct cnx_mgr *cm_ctx, 581 struct cm_req *cm_req, 582 enum wlan_cm_source source) 583 { 584 uint32_t prefix = CM_ID_GET_PREFIX(cm_req->cm_id); 585 586 cm_req_lock_acquire(cm_ctx); 587 if (qdf_list_size(&cm_ctx->req_list) >= CM_MAX_REQ) { 588 cm_req_lock_release(cm_ctx); 589 mlme_err(CM_PREFIX_FMT "List full size %d", 590 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 591 cm_req->cm_id), 592 qdf_list_size(&cm_ctx->req_list)); 593 return QDF_STATUS_E_FAILURE; 594 } 595 596 qdf_list_insert_front(&cm_ctx->req_list, &cm_req->node); 597 if (prefix == CONNECT_REQ_PREFIX) 598 cm_ctx->connect_count++; 599 else 600 cm_ctx->disconnect_count++; 601 cm_req_lock_release(cm_ctx); 602 mlme_debug(CM_PREFIX_FMT, 603 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 604 cm_req->cm_id)); 605 606 mlme_cm_osif_update_id_and_src(cm_ctx->vdev, source, cm_req->cm_id); 607 608 return QDF_STATUS_SUCCESS; 609 } 610 611 static void cm_zero_and_free_memory(uint8_t *ptr, uint32_t len) 612 { 613 if (!ptr) 614 return; 615 616 qdf_mem_zero(ptr, len); 617 qdf_mem_free(ptr); 618 } 619 620 void cm_free_connect_req_mem(struct cm_connect_req *connect_req) 621 { 622 struct wlan_cm_connect_req *req; 623 624 req = &connect_req->req; 625 626 if (connect_req->candidate_list) 627 wlan_scan_purge_results(connect_req->candidate_list); 628 629 cm_zero_and_free_memory(req->assoc_ie.ptr, req->assoc_ie.len); 630 cm_zero_and_free_memory(req->scan_ie.ptr, req->scan_ie.len); 631 632 cm_zero_and_free_memory(req->crypto.wep_keys.key, 633 req->crypto.wep_keys.key_len); 634 cm_zero_and_free_memory(req->crypto.wep_keys.seq, 635 req->crypto.wep_keys.seq_len); 636 637 qdf_mem_zero(connect_req, sizeof(*connect_req)); 638 } 639 640 QDF_STATUS 641 cm_delete_req_from_list(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id) 642 { 643 uint32_t prefix = CM_ID_GET_PREFIX(cm_id); 644 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 645 struct cm_req *cm_req = NULL; 646 647 cm_req_lock_acquire(cm_ctx); 648 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 649 while (cur_node) { 650 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 651 652 cm_req = qdf_container_of(cur_node, struct cm_req, node); 653 if (cm_req->cm_id == cm_id) 654 break; 655 656 cur_node = next_node; 657 next_node = NULL; 658 cm_req = NULL; 659 } 660 661 if (!cm_req) { 662 cm_req_lock_release(cm_ctx); 663 mlme_err(CM_PREFIX_FMT " req not found", 664 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id)); 665 return QDF_STATUS_E_FAILURE; 666 } 667 668 qdf_list_remove_node(&cm_ctx->req_list, &cm_req->node); 669 if (prefix == CONNECT_REQ_PREFIX) { 670 cm_ctx->connect_count--; 671 cm_free_connect_req_mem(&cm_req->connect_req); 672 } else { 673 cm_ctx->disconnect_count--; 674 } 675 mlme_debug(CM_PREFIX_FMT, 676 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), 677 cm_req->cm_id)); 678 679 qdf_mem_free(cm_req); 680 cm_req_lock_release(cm_ctx); 681 682 return QDF_STATUS_SUCCESS; 683 } 684 685 void cm_remove_cmd(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id) 686 { 687 struct wlan_objmgr_psoc *psoc; 688 QDF_STATUS status; 689 690 psoc = wlan_vdev_get_psoc(cm_ctx->vdev); 691 if (!psoc) { 692 mlme_err(CM_PREFIX_FMT "Failed to find psoc", 693 CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id)); 694 return; 695 } 696 697 status = cm_delete_req_from_list(cm_ctx, cm_id); 698 if (QDF_IS_STATUS_ERROR(status)) 699 return; 700 701 cm_remove_cmd_from_serialization(cm_ctx, cm_id); 702 } 703 704 void cm_vdev_scan_cancel(struct wlan_objmgr_pdev *pdev, 705 struct wlan_objmgr_vdev *vdev) 706 { 707 struct scan_cancel_request *req; 708 QDF_STATUS status; 709 710 req = qdf_mem_malloc(sizeof(*req)); 711 if (!req) 712 return; 713 714 req->vdev = vdev; 715 req->cancel_req.scan_id = INVAL_SCAN_ID; 716 req->cancel_req.vdev_id = wlan_vdev_get_id(vdev); 717 req->cancel_req.pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); 718 req->cancel_req.req_type = WLAN_SCAN_CANCEL_VDEV_ALL; 719 720 status = wlan_scan_cancel(req); 721 /* In success/failure case wlan_scan_cancel free the req memory */ 722 if (QDF_IS_STATUS_ERROR(status)) 723 mlme_err("vdev %d cancel scan request failed", 724 wlan_vdev_get_id(vdev)); 725 } 726 727 void cm_set_max_connect_attempts(struct wlan_objmgr_vdev *vdev, 728 uint8_t max_connect_attempts) 729 { 730 struct cnx_mgr *cm_ctx; 731 732 cm_ctx = cm_get_cm_ctx(vdev); 733 if (!cm_ctx) 734 return; 735 736 cm_ctx->max_connect_attempts = 737 QDF_MIN(max_connect_attempts, CM_MAX_CONNECT_ATTEMPTS); 738 mlme_debug("vdev %d max connect attempts set to %d, requested %d", 739 wlan_vdev_get_id(vdev), 740 cm_ctx->max_connect_attempts, max_connect_attempts); 741 } 742 743 QDF_STATUS 744 cm_fill_disconnect_resp_from_cm_id(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id, 745 struct wlan_cm_discon_rsp *resp) 746 { 747 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 748 struct cm_req *cm_req; 749 uint32_t prefix = CM_ID_GET_PREFIX(cm_id); 750 751 if (prefix != DISCONNECT_REQ_PREFIX) 752 return QDF_STATUS_E_INVAL; 753 754 cm_req_lock_acquire(cm_ctx); 755 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 756 while (cur_node) { 757 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 758 cm_req = qdf_container_of(cur_node, struct cm_req, node); 759 760 if (cm_req->cm_id == cm_id) { 761 resp->req.cm_id = cm_id; 762 resp->req.req = cm_req->discon_req.req; 763 cm_req_lock_release(cm_ctx); 764 return QDF_STATUS_SUCCESS; 765 } 766 767 cur_node = next_node; 768 next_node = NULL; 769 } 770 cm_req_lock_release(cm_ctx); 771 772 return QDF_STATUS_E_FAILURE; 773 } 774 775 void cm_inform_bcn_probe(struct cnx_mgr *cm_ctx, uint8_t *bcn_probe, 776 uint32_t len, qdf_freq_t freq, int32_t rssi, 777 wlan_cm_id cm_id) 778 { 779 qdf_nbuf_t buf; 780 struct wlan_objmgr_pdev *pdev; 781 uint8_t *data, i, vdev_id; 782 struct mgmt_rx_event_params rx_param = {0}; 783 struct wlan_frame_hdr *hdr; 784 enum mgmt_frame_type frm_type = MGMT_BEACON; 785 786 vdev_id = wlan_vdev_get_id(cm_ctx->vdev); 787 if (!bcn_probe || !len || (len < sizeof(*hdr))) { 788 mlme_err(CM_PREFIX_FMT "bcn_probe is null or invalid len %d", 789 CM_PREFIX_REF(vdev_id, cm_id), len); 790 return; 791 } 792 793 pdev = wlan_vdev_get_pdev(cm_ctx->vdev); 794 if (!pdev) { 795 mlme_err(CM_PREFIX_FMT "Failed to find pdev", 796 CM_PREFIX_REF(vdev_id, cm_id)); 797 return; 798 } 799 800 hdr = (struct wlan_frame_hdr *)bcn_probe; 801 if ((hdr->i_fc[0] & QDF_IEEE80211_FC0_SUBTYPE_MASK) == 802 MGMT_SUBTYPE_PROBE_RESP) 803 frm_type = MGMT_PROBE_RESP; 804 805 rx_param.pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); 806 rx_param.chan_freq = freq; 807 rx_param.rssi = rssi; 808 809 /* Set all per chain rssi as invalid */ 810 for (i = 0; i < WLAN_MGMT_TXRX_HOST_MAX_ANTENNA; i++) 811 rx_param.rssi_ctl[i] = WLAN_INVALID_PER_CHAIN_RSSI; 812 813 buf = qdf_nbuf_alloc(NULL, qdf_roundup(len, 4), 0, 4, false); 814 if (!buf) 815 return; 816 817 qdf_nbuf_put_tail(buf, len); 818 qdf_nbuf_set_protocol(buf, ETH_P_CONTROL); 819 820 data = qdf_nbuf_data(buf); 821 qdf_mem_copy(data, bcn_probe, len); 822 /* buf will be freed by scan module in error or success case */ 823 wlan_scan_process_bcn_probe_rx_sync(wlan_pdev_get_psoc(pdev), buf, 824 &rx_param, frm_type); 825 } 826 827 bool cm_is_vdev_connecting(struct wlan_objmgr_vdev *vdev) 828 { 829 struct cnx_mgr *cm_ctx; 830 enum wlan_cm_sm_state state; 831 832 cm_ctx = cm_get_cm_ctx(vdev); 833 if (!cm_ctx) 834 return false; 835 836 state = cm_get_state(cm_ctx); 837 838 if (state == WLAN_CM_S_CONNECTING) 839 return true; 840 841 return false; 842 } 843 844 bool cm_is_vdev_connected(struct wlan_objmgr_vdev *vdev) 845 { 846 struct cnx_mgr *cm_ctx; 847 enum wlan_cm_sm_state state; 848 849 cm_ctx = cm_get_cm_ctx(vdev); 850 if (!cm_ctx) 851 return false; 852 853 state = cm_get_state(cm_ctx); 854 855 if (state == WLAN_CM_S_CONNECTED) 856 return true; 857 858 return false; 859 } 860 861 bool cm_is_vdev_disconnecting(struct wlan_objmgr_vdev *vdev) 862 { 863 struct cnx_mgr *cm_ctx; 864 enum wlan_cm_sm_state state; 865 866 cm_ctx = cm_get_cm_ctx(vdev); 867 if (!cm_ctx) 868 return false; 869 870 state = cm_get_state(cm_ctx); 871 872 if (state == WLAN_CM_S_DISCONNECTING) 873 return true; 874 875 return false; 876 } 877 878 bool cm_is_vdev_disconnected(struct wlan_objmgr_vdev *vdev) 879 { 880 struct cnx_mgr *cm_ctx; 881 enum wlan_cm_sm_state state; 882 883 cm_ctx = cm_get_cm_ctx(vdev); 884 if (!cm_ctx) 885 return false; 886 887 state = cm_get_state(cm_ctx); 888 889 if (state == WLAN_CM_S_INIT) 890 return true; 891 892 return false; 893 } 894 895 bool cm_is_vdev_roaming(struct wlan_objmgr_vdev *vdev) 896 { 897 struct cnx_mgr *cm_ctx; 898 enum wlan_cm_sm_state state; 899 900 cm_ctx = cm_get_cm_ctx(vdev); 901 if (!cm_ctx) 902 return false; 903 904 state = cm_get_state(cm_ctx); 905 906 if (state == WLAN_CM_S_ROAMING) 907 return true; 908 909 return false; 910 } 911 912 struct cm_req *cm_get_req_by_scan_id(struct cnx_mgr *cm_ctx, 913 wlan_scan_id scan_id) 914 { 915 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 916 struct cm_req *cm_req; 917 918 cm_req_lock_acquire(cm_ctx); 919 qdf_list_peek_front(&cm_ctx->req_list, &cur_node); 920 while (cur_node) { 921 qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node); 922 cm_req = qdf_container_of(cur_node, struct cm_req, node); 923 924 if (cm_req->connect_req.scan_id == scan_id) { 925 cm_req_lock_release(cm_ctx); 926 return cm_req; 927 } 928 929 cur_node = next_node; 930 next_node = NULL; 931 } 932 cm_req_lock_release(cm_ctx); 933 934 return NULL; 935 } 936 937 wlan_cm_id cm_get_cm_id_by_scan_id(struct cnx_mgr *cm_ctx, 938 wlan_scan_id scan_id) 939 { 940 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 941 struct cm_req *cm_req; 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->connect_req.scan_id == scan_id) { 950 cm_req_lock_release(cm_ctx); 951 return cm_req->cm_id; 952 } 953 954 cur_node = next_node; 955 next_node = NULL; 956 } 957 cm_req_lock_release(cm_ctx); 958 959 return CM_ID_INVALID; 960 } 961 962