1 /* 2 * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* 21 * DOC: contains scan cache api and functionality 22 * The Scan entries are protected by scan_db_lock. Holding the lock 23 * for whole scan operation during get/flush scan results may take 24 * more than 5 ms and thus ref count is used along with scan_db_lock. 25 * Below are the operation on scan cache entry: 26 * - While adding new node to the entry scan_db_lock is taken and ref_cnt 27 * is initialized and incremented. Also the cookie will be set to valid value. 28 * - The ref count incremented during adding new node should be decremented only 29 * by a delete operation on the node. But there can be multiple concurrent 30 * delete operations on a node from different threads which may lead to ref 31 * count being decremented multiple time and freeing the node even if node 32 * is in use. So to maintain atomicity between multiple delete operations 33 * on a same node from different threads, a cookie is used to check if node is 34 * logically deleted or not. A delete operation will set the cookie to 0 35 * making it invalid. So if the 2nd thread find the cookie as invalid it will 36 * not try to delete and decrement the ref count of the node again. 37 * - This Cookie is also used to check if node is valid while iterating through 38 * the scan cache to avoid duplicate entries. 39 * - Once ref_cnt become 0, i.e. it is logically deleted and no thread is using 40 * it the node is physically deleted from the scan cache. 41 * - While reading the node the ref_cnt should be incremented. Once reading 42 * operation is done ref_cnt is decremented. 43 */ 44 #include <qdf_status.h> 45 #include <wlan_objmgr_psoc_obj.h> 46 #include <wlan_objmgr_pdev_obj.h> 47 #include <wlan_objmgr_vdev_obj.h> 48 #include <wlan_scan_public_structs.h> 49 #include <wlan_scan_utils_api.h> 50 #include "wlan_scan_main.h" 51 #include "wlan_scan_cache_db_i.h" 52 #include "wlan_reg_services_api.h" 53 #include "wlan_reg_ucfg_api.h" 54 #include <wlan_objmgr_vdev_obj.h> 55 #include <wlan_dfs_utils_api.h> 56 #include "wlan_crypto_global_def.h" 57 #include "wlan_crypto_global_api.h" 58 #include "wlan_cm_bss_score_param.h" 59 60 #ifdef FEATURE_6G_SCAN_CHAN_SORT_ALGO 61 62 struct channel_list_db *scm_get_rnr_channel_db(struct wlan_objmgr_psoc *psoc) 63 { 64 struct wlan_scan_obj *scan_obj = NULL; 65 66 scan_obj = wlan_psoc_get_scan_obj(psoc); 67 68 if (!scan_obj) 69 return NULL; 70 71 return &scan_obj->rnr_channel_db; 72 } 73 74 struct meta_rnr_channel *scm_get_chan_meta(struct wlan_objmgr_psoc *psoc, 75 uint32_t chan_freq) 76 { 77 int i; 78 struct channel_list_db *rnr_channel_db; 79 80 if (!psoc || !chan_freq || !wlan_reg_is_6ghz_chan_freq(chan_freq)) 81 return NULL; 82 83 rnr_channel_db = scm_get_rnr_channel_db(psoc); 84 if (!rnr_channel_db) 85 return NULL; 86 87 for (i = 0; i < QDF_ARRAY_SIZE(rnr_channel_db->channel); i++) 88 if (rnr_channel_db->channel[i].chan_freq == chan_freq) 89 return &rnr_channel_db->channel[i]; 90 91 return NULL; 92 } 93 94 static void scm_add_rnr_channel_db(struct wlan_objmgr_psoc *psoc, 95 struct scan_cache_entry *entry) 96 { 97 uint32_t chan_freq; 98 uint8_t is_6g_bss, i; 99 struct meta_rnr_channel *channel; 100 struct rnr_bss_info *rnr_bss; 101 struct scan_rnr_node *rnr_node; 102 103 chan_freq = entry->channel.chan_freq; 104 is_6g_bss = wlan_reg_is_6ghz_chan_freq(chan_freq); 105 106 /* Return if the BSS is not 6G and RNR IE is not present */ 107 if (!(is_6g_bss || entry->ie_list.rnrie)) 108 return; 109 110 scm_debug("BSS freq %d BSSID: "QDF_MAC_ADDR_FMT, chan_freq, 111 QDF_MAC_ADDR_REF(entry->bssid.bytes)); 112 if (is_6g_bss) { 113 channel = scm_get_chan_meta(psoc, chan_freq); 114 if (!channel) { 115 scm_debug("Failed to get chan Meta freq %d", chan_freq); 116 return; 117 } 118 channel->bss_beacon_probe_count++; 119 channel->beacon_probe_last_time_found = entry->scan_entry_time; 120 } 121 122 /* 123 * If scan entry got RNR IE then loop through all 124 * entries and increase the BSS count in respective channels 125 */ 126 if (!entry->ie_list.rnrie) 127 return; 128 129 for (i = 0; i < MAX_RNR_BSS; i++) { 130 rnr_bss = &entry->rnr.bss_info[i]; 131 /* Skip if entry is not valid */ 132 if (!rnr_bss->channel_number) 133 continue; 134 chan_freq = wlan_reg_chan_opclass_to_freq(rnr_bss->channel_number, 135 rnr_bss->operating_class, 136 true); 137 channel = scm_get_chan_meta(psoc, chan_freq); 138 if (!channel) { 139 scm_debug("Failed to get chan Meta freq %d", chan_freq); 140 continue; 141 } 142 channel->bss_beacon_probe_count++; 143 /* Don't add RNR entry if list is full */ 144 if (qdf_list_size(&channel->rnr_list) >= WLAN_MAX_RNR_COUNT) { 145 scm_debug("List is full"); 146 return; 147 } 148 149 rnr_node = qdf_mem_malloc(sizeof(struct scan_rnr_node)); 150 if (!rnr_node) 151 return; 152 rnr_node->entry.timestamp = entry->scan_entry_time; 153 if (!qdf_is_macaddr_zero(&rnr_bss->bssid)) 154 qdf_mem_copy(&rnr_node->entry.bssid, 155 &rnr_bss->bssid, 156 QDF_MAC_ADDR_SIZE); 157 if (rnr_bss->short_ssid) 158 rnr_node->entry.short_ssid = rnr_bss->short_ssid; 159 if (rnr_bss->bss_params) 160 rnr_node->entry.bss_params = rnr_bss->bss_params; 161 scm_debug("Add freq %d: "QDF_MAC_ADDR_FMT" short ssid %x", chan_freq, 162 QDF_MAC_ADDR_REF(rnr_bss->bssid.bytes), 163 rnr_bss->short_ssid); 164 qdf_list_insert_back(&channel->rnr_list, 165 &rnr_node->node); 166 } 167 } 168 169 void scm_filter_rnr_flag_pno(struct wlan_objmgr_vdev *vdev, 170 uint32_t short_ssid, 171 struct chan_list *pno_chan_list) 172 { 173 uint8_t i; 174 uint32_t freq; 175 struct meta_rnr_channel *chan; 176 struct scan_rnr_node *rnr_node; 177 enum scan_mode_6ghz scan_mode; 178 struct wlan_scan_obj *scan_obj; 179 struct wlan_objmgr_psoc *psoc; 180 181 psoc = wlan_vdev_get_psoc(vdev); 182 if (!psoc) 183 return; 184 185 scan_obj = wlan_vdev_get_scan_obj(vdev); 186 if (!scan_obj) { 187 scm_err("scan_obj is NULL"); 188 return; 189 } 190 191 scan_mode = scan_obj->scan_def.scan_mode_6g; 192 /* No Filteration required for below scan modes since 193 * no RNR flag marked. 194 */ 195 if (scan_mode == SCAN_MODE_6G_NO_CHANNEL || 196 scan_mode == SCAN_MODE_6G_ALL_CHANNEL || 197 scan_mode == SCAN_MODE_6G_ALL_DUTY_CYCLE) 198 return; 199 200 for (i = 0; i < pno_chan_list->num_chan; i++) { 201 freq = pno_chan_list->chan[i].freq; 202 203 chan = scm_get_chan_meta(psoc, freq); 204 if (!chan || qdf_list_empty(&chan->rnr_list)) 205 continue; 206 207 qdf_list_for_each(&chan->rnr_list, rnr_node, node) { 208 if (rnr_node->entry.short_ssid) { 209 if (rnr_node->entry.short_ssid == short_ssid) { 210 /* If short ssid entry present in RNR db cache, remove 211 * FLAG_SCAN_ONLY_IF_RNR_FOUND flag from the channel. 212 */ 213 pno_chan_list->chan[i].flags &= 214 ~FLAG_SCAN_ONLY_IF_RNR_FOUND; 215 break; 216 } 217 } 218 } 219 } 220 } 221 #endif 222 223 /** 224 * scm_del_scan_node() - API to remove scan node from the list 225 * @list: hash list 226 * @scan_node: node to be removed 227 * 228 * This should be called while holding scan_db_lock. 229 * 230 * Return: void 231 */ 232 static void scm_del_scan_node(qdf_list_t *list, 233 struct scan_cache_node *scan_node) 234 { 235 QDF_STATUS status; 236 237 status = qdf_list_remove_node(list, &scan_node->node); 238 if (QDF_IS_STATUS_SUCCESS(status)) { 239 util_scan_free_cache_entry(scan_node->entry); 240 qdf_mem_free(scan_node); 241 } 242 } 243 244 /** 245 * scm_del_scan_node_from_db() - API to del the scan entry 246 * @scan_db: scan database 247 * @scan_entry:entry scan_node 248 * 249 * API to flush the scan entry. This should be called while 250 * holding scan_db_lock. 251 * 252 * Return: QDF status. 253 */ 254 static QDF_STATUS scm_del_scan_node_from_db(struct scan_dbs *scan_db, 255 struct scan_cache_node *scan_node) 256 { 257 QDF_STATUS status = QDF_STATUS_SUCCESS; 258 uint8_t hash_idx; 259 260 if (!scan_node) 261 return QDF_STATUS_E_INVAL; 262 263 hash_idx = SCAN_GET_HASH(scan_node->entry->bssid.bytes); 264 scm_del_scan_node(&scan_db->scan_hash_tbl[hash_idx], scan_node); 265 scan_db->num_entries--; 266 267 return status; 268 } 269 270 /** 271 * scm_scan_entry_get_ref() - api to increase ref count of scan entry 272 * @scan_node: scan node 273 * 274 * Return: void 275 */ 276 static void scm_scan_entry_get_ref(struct scan_cache_node *scan_node) 277 { 278 if (!scan_node) { 279 scm_err("scan_node is NULL"); 280 QDF_ASSERT(0); 281 return; 282 } 283 qdf_atomic_inc(&scan_node->ref_cnt); 284 } 285 286 /** 287 * scm_scan_entry_put_ref() - Api to decrease ref count of scan entry 288 * and free if it become 0 289 * @scan_db: scan database 290 * @scan_node: scan node 291 * @lock_needed: if scan_db_lock is needed 292 * 293 * Return: void 294 */ 295 static void scm_scan_entry_put_ref(struct scan_dbs *scan_db, 296 struct scan_cache_node *scan_node, bool lock_needed) 297 { 298 299 if (!scan_node) { 300 scm_err("scan_node is NULL"); 301 QDF_ASSERT(0); 302 return; 303 } 304 305 if (lock_needed) 306 qdf_spin_lock_bh(&scan_db->scan_db_lock); 307 308 if (!qdf_atomic_read(&scan_node->ref_cnt)) { 309 if (lock_needed) 310 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 311 scm_err("scan_node ref cnt is 0"); 312 QDF_ASSERT(0); 313 return; 314 } 315 316 /* Decrement ref count, free scan_node, if ref count == 0 */ 317 if (qdf_atomic_dec_and_test(&scan_node->ref_cnt)) 318 scm_del_scan_node_from_db(scan_db, scan_node); 319 320 if (lock_needed) 321 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 322 } 323 324 /** 325 * scm_scan_entry_del() - API to delete scan node 326 * @scan_db: data base 327 * @scan_node: node to be deleted 328 * 329 * Call must be protected by scan_db->scan_db_lock 330 * 331 * Return: void 332 */ 333 334 static void scm_scan_entry_del(struct scan_dbs *scan_db, 335 struct scan_cache_node *scan_node) 336 { 337 if (!scan_node) { 338 scm_err("scan node is NULL"); 339 QDF_ASSERT(0); 340 return; 341 } 342 343 if (scan_node->cookie != SCAN_NODE_ACTIVE_COOKIE) { 344 scm_debug("node is already deleted"); 345 return; 346 } 347 /* Seems node is already deleted */ 348 if (!qdf_atomic_read(&scan_node->ref_cnt)) { 349 scm_debug("node is already deleted ref 0"); 350 return; 351 } 352 scan_node->cookie = 0; 353 scm_scan_entry_put_ref(scan_db, scan_node, false); 354 } 355 356 /** 357 * scm_add_scan_node() - API to add scan node 358 * @scan_db: data base 359 * @scan_node: node to be added 360 * @dup_node: node before which new node to be added 361 * if it's not NULL, otherwise add node to tail 362 * 363 * Call must be protected by scan_db->scan_db_lock 364 * 365 * Return: void 366 */ 367 static void scm_add_scan_node(struct scan_dbs *scan_db, 368 struct scan_cache_node *scan_node, 369 struct scan_cache_node *dup_node) 370 { 371 uint8_t hash_idx; 372 373 hash_idx = 374 SCAN_GET_HASH(scan_node->entry->bssid.bytes); 375 376 qdf_atomic_init(&scan_node->ref_cnt); 377 scan_node->cookie = SCAN_NODE_ACTIVE_COOKIE; 378 scm_scan_entry_get_ref(scan_node); 379 if (!dup_node) 380 qdf_list_insert_back(&scan_db->scan_hash_tbl[hash_idx], 381 &scan_node->node); 382 else 383 qdf_list_insert_before(&scan_db->scan_hash_tbl[hash_idx], 384 &scan_node->node, &dup_node->node); 385 386 scan_db->num_entries++; 387 } 388 389 390 /** 391 * scm_get_next_valid_node() - API get the next valid scan node from 392 * the list 393 * @list: hash list 394 * @cur_node: current node pointer 395 * 396 * API to get next active node from the list. If cur_node is NULL 397 * it will return first node of the list. 398 * Call must be protected by scan_db->scan_db_lock 399 * 400 * Return: next scan node 401 */ 402 static qdf_list_node_t * 403 scm_get_next_valid_node(qdf_list_t *list, 404 qdf_list_node_t *cur_node) 405 { 406 qdf_list_node_t *next_node = NULL; 407 qdf_list_node_t *temp_node = NULL; 408 struct scan_cache_node *scan_node; 409 410 if (cur_node) 411 qdf_list_peek_next(list, cur_node, &next_node); 412 else 413 qdf_list_peek_front(list, &next_node); 414 415 while (next_node) { 416 scan_node = qdf_container_of(next_node, 417 struct scan_cache_node, node); 418 if (scan_node->cookie == SCAN_NODE_ACTIVE_COOKIE) 419 return next_node; 420 /* 421 * If node is not valid check for next entry 422 * to get next valid node. 423 */ 424 qdf_list_peek_next(list, next_node, &temp_node); 425 next_node = temp_node; 426 temp_node = NULL; 427 } 428 429 return next_node; 430 } 431 432 /** 433 * scm_get_next_node() - API get the next scan node from 434 * the list 435 * @scan_db: scan data base 436 * @list: hash list 437 * @cur_node: current node pointer 438 * 439 * API get the next node from the list. If cur_node is NULL 440 * it will return first node of the list 441 * 442 * Return: next scan cache node 443 */ 444 static struct scan_cache_node * 445 scm_get_next_node(struct scan_dbs *scan_db, 446 qdf_list_t *list, struct scan_cache_node *cur_node) 447 { 448 struct scan_cache_node *next_node = NULL; 449 qdf_list_node_t *next_list = NULL; 450 451 qdf_spin_lock_bh(&scan_db->scan_db_lock); 452 if (cur_node) { 453 next_list = scm_get_next_valid_node(list, &cur_node->node); 454 /* Decrement the ref count of the previous node */ 455 scm_scan_entry_put_ref(scan_db, 456 cur_node, false); 457 } else { 458 next_list = scm_get_next_valid_node(list, NULL); 459 } 460 /* Increase the ref count of the obtained node */ 461 if (next_list) { 462 next_node = qdf_container_of(next_list, 463 struct scan_cache_node, node); 464 scm_scan_entry_get_ref(next_node); 465 } 466 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 467 468 return next_node; 469 } 470 471 /** 472 * scm_check_and_age_out() - check and age out the old entries 473 * @scan_db: scan db 474 * @scan_node: node to check for age out 475 * @scan_aging_time: scan cache aging time 476 * 477 * Return: void 478 */ 479 static void scm_check_and_age_out(struct scan_dbs *scan_db, 480 struct scan_cache_node *node, 481 qdf_time_t scan_aging_time) 482 { 483 if (util_scan_entry_age(node->entry) >= 484 scan_aging_time) { 485 scm_debug("Aging out BSSID: "QDF_MAC_ADDR_FMT" with age %lu ms", 486 QDF_MAC_ADDR_REF(node->entry->bssid.bytes), 487 util_scan_entry_age(node->entry)); 488 qdf_spin_lock_bh(&scan_db->scan_db_lock); 489 scm_scan_entry_del(scan_db, node); 490 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 491 } 492 } 493 494 static bool scm_bss_is_connected(struct scan_cache_entry *entry) 495 { 496 if (entry->mlme_info.assoc_state == SCAN_ENTRY_CON_STATE_ASSOC) 497 return true; 498 return false; 499 } 500 501 /** 502 * scm_get_conn_node() - Get the scan cache entry node of the connected BSS 503 * @scan_db: scan DB pointer 504 * 505 * Return: scan cache entry node of connected BSS if exists, NULL otherwise 506 */ 507 static 508 struct scan_cache_node *scm_get_conn_node(struct scan_dbs *scan_db) 509 { 510 int i; 511 struct scan_cache_node *cur_node = NULL; 512 struct scan_cache_node *next_node = NULL; 513 514 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 515 cur_node = scm_get_next_node(scan_db, 516 &scan_db->scan_hash_tbl[i], NULL); 517 while (cur_node) { 518 if (scm_bss_is_connected(cur_node->entry)) 519 return cur_node; 520 next_node = scm_get_next_node(scan_db, 521 &scan_db->scan_hash_tbl[i], cur_node); 522 cur_node = next_node; 523 next_node = NULL; 524 } 525 } 526 527 return NULL; 528 } 529 530 static bool 531 scm_bss_is_nontx_of_conn_bss(struct scan_cache_node *conn_node, 532 struct scan_cache_node *cur_node) 533 { 534 if (cur_node->entry->mbssid_info.profile_num && 535 !memcmp(conn_node->entry->mbssid_info.trans_bssid, 536 cur_node->entry->mbssid_info.trans_bssid, 537 QDF_MAC_ADDR_SIZE)) 538 return true; 539 540 return false; 541 } 542 543 void scm_age_out_entries(struct wlan_objmgr_psoc *psoc, 544 struct scan_dbs *scan_db) 545 { 546 int i; 547 struct scan_cache_node *cur_node = NULL; 548 struct scan_cache_node *next_node = NULL; 549 struct scan_cache_node *conn_node = NULL; 550 struct scan_default_params *def_param; 551 552 def_param = wlan_scan_psoc_get_def_params(psoc); 553 if (!def_param) { 554 scm_err("wlan_scan_psoc_get_def_params failed"); 555 return; 556 } 557 558 conn_node = scm_get_conn_node(scan_db); 559 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 560 cur_node = scm_get_next_node(scan_db, 561 &scan_db->scan_hash_tbl[i], NULL); 562 while (cur_node) { 563 if (!conn_node /* if there is no connected node */ || 564 /* OR cur_node is not part of the MBSSID of the 565 * connected node 566 */ 567 (!scm_bss_is_connected(cur_node->entry) && 568 !scm_bss_is_nontx_of_conn_bss(conn_node, 569 cur_node))) { 570 scm_check_and_age_out(scan_db, cur_node, 571 def_param->scan_cache_aging_time); 572 } 573 next_node = scm_get_next_node(scan_db, 574 &scan_db->scan_hash_tbl[i], cur_node); 575 cur_node = next_node; 576 next_node = NULL; 577 } 578 } 579 580 if (conn_node) 581 scm_scan_entry_put_ref(scan_db, conn_node, true); 582 } 583 584 /** 585 * scm_flush_oldest_entry() - Iterate over scan db and flust out the 586 * oldest entry 587 * @scan_db: scan db from which oldest entry needs to be flushed 588 * 589 * Return: QDF_STATUS 590 */ 591 static QDF_STATUS scm_flush_oldest_entry(struct scan_dbs *scan_db) 592 { 593 int i; 594 struct scan_cache_node *oldest_node = NULL; 595 struct scan_cache_node *cur_node; 596 597 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 598 /* Get the first valid node for the hash */ 599 cur_node = scm_get_next_node(scan_db, 600 &scan_db->scan_hash_tbl[i], 601 NULL); 602 /* Iterate scan db and flush out oldest node 603 * take ref_cnt for oldest_node 604 */ 605 606 while (cur_node) { 607 if (!oldest_node || 608 (util_scan_entry_age(oldest_node->entry) < 609 util_scan_entry_age(cur_node->entry))) { 610 if (oldest_node) 611 scm_scan_entry_put_ref(scan_db, 612 oldest_node, 613 true); 614 qdf_spin_lock_bh(&scan_db->scan_db_lock); 615 oldest_node = cur_node; 616 scm_scan_entry_get_ref(oldest_node); 617 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 618 } 619 620 cur_node = scm_get_next_node(scan_db, 621 &scan_db->scan_hash_tbl[i], 622 cur_node); 623 }; 624 } 625 626 if (oldest_node) { 627 scm_debug("Flush oldest BSSID: "QDF_MAC_ADDR_FMT" with age %lu ms", 628 QDF_MAC_ADDR_REF(oldest_node->entry->bssid.bytes), 629 util_scan_entry_age(oldest_node->entry)); 630 /* Release ref_cnt taken for oldest_node and delete it */ 631 qdf_spin_lock_bh(&scan_db->scan_db_lock); 632 scm_scan_entry_del(scan_db, oldest_node); 633 scm_scan_entry_put_ref(scan_db, oldest_node, false); 634 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 635 } 636 637 return QDF_STATUS_SUCCESS; 638 } 639 640 /** 641 * scm_update_alt_wcn_ie() - update the alternate WCN IE 642 * @from: copy from 643 * @dst: copy to 644 * 645 * Return: void 646 */ 647 static void scm_update_alt_wcn_ie(struct scan_cache_entry *from, 648 struct scan_cache_entry *dst) 649 { 650 uint32_t alt_wcn_ie_len; 651 652 if (from->frm_subtype == dst->frm_subtype) 653 return; 654 655 if (!from->ie_list.wcn && !dst->ie_list.wcn) 656 return; 657 658 /* Existing WCN IE is empty. */ 659 if (!from->ie_list.wcn) 660 return; 661 662 alt_wcn_ie_len = 2 + from->ie_list.wcn[1]; 663 if (alt_wcn_ie_len > WLAN_MAX_IE_LEN + 2) { 664 scm_err("invalid IE len"); 665 return; 666 } 667 668 if (!dst->alt_wcn_ie.ptr) { 669 /* allocate this additional buffer for alternate WCN IE */ 670 dst->alt_wcn_ie.ptr = 671 qdf_mem_malloc_atomic(WLAN_MAX_IE_LEN + 2); 672 if (!dst->alt_wcn_ie.ptr) { 673 scm_err("failed to allocate memory"); 674 return; 675 } 676 } 677 qdf_mem_copy(dst->alt_wcn_ie.ptr, 678 from->ie_list.wcn, alt_wcn_ie_len); 679 dst->alt_wcn_ie.len = alt_wcn_ie_len; 680 } 681 682 /** 683 * scm_update_mlme_info() - update mlme info 684 * @src: source scan entry 685 * @dest: destination scan entry 686 * 687 * Return: void 688 */ 689 static inline void 690 scm_update_mlme_info(struct scan_cache_entry *src, 691 struct scan_cache_entry *dest) 692 { 693 qdf_mem_copy(&dest->mlme_info, &src->mlme_info, 694 sizeof(struct mlme_info)); 695 } 696 697 /** 698 * scm_copy_info_from_dup_entry() - copy duplicate node info 699 * to new scan entry 700 * @pdev: pdev ptr 701 * @scan_obj: scan obj ptr 702 * @scan_db: scan database 703 * @scan_params: new entry to be added 704 * @scan_node: duplicate entry 705 * 706 * Copy duplicate node info to new entry. 707 * 708 * Return: void 709 */ 710 static void 711 scm_copy_info_from_dup_entry(struct wlan_objmgr_pdev *pdev, 712 struct wlan_scan_obj *scan_obj, 713 struct scan_dbs *scan_db, 714 struct scan_cache_entry *scan_params, 715 struct scan_cache_node *scan_node) 716 { 717 struct scan_cache_entry *scan_entry; 718 uint64_t time_gap; 719 720 scan_entry = scan_node->entry; 721 722 /* Update probe resp entry as well if AP is in hidden mode */ 723 if (scan_params->frm_subtype == MGMT_SUBTYPE_PROBE_RESP && 724 scan_entry->is_hidden_ssid) 725 scan_params->is_hidden_ssid = true; 726 727 /* 728 * If AP changed its beacon from not having an SSID to showing it the 729 * kernel will drop the entry asumming that something is wrong with AP. 730 * This can result in connection failure while updating the bss during 731 * connection. So flush the hidden entry from kernel before indicating 732 * the new entry. 733 */ 734 if (scan_entry->is_hidden_ssid && 735 scan_params->frm_subtype == MGMT_SUBTYPE_BEACON && 736 !util_scan_is_null_ssid(&scan_params->ssid)) { 737 if (scan_obj->cb.unlink_bss) { 738 scm_debug("Hidden AP "QDF_MAC_ADDR_FMT" switch to non-hidden SSID, So unlink the entry", 739 QDF_MAC_ADDR_REF(scan_entry->bssid.bytes)); 740 scan_obj->cb.unlink_bss(pdev, scan_entry); 741 } 742 } 743 744 /* If old entry have the ssid but new entry does not */ 745 if (util_scan_is_null_ssid(&scan_params->ssid) && 746 scan_entry->ssid.length) { 747 /* 748 * New entry has a hidden SSID and old one has the SSID. 749 * Add the entry by using the ssid of the old entry 750 * only if diff of saved SSID time and current time is 751 * less than HIDDEN_SSID_TIME time. 752 * This will avoid issues in case AP changes its SSID 753 * while remain hidden. 754 */ 755 time_gap = 756 qdf_mc_timer_get_system_time() - 757 scan_entry->hidden_ssid_timestamp; 758 if (time_gap <= HIDDEN_SSID_TIME) { 759 scan_params->hidden_ssid_timestamp = 760 scan_entry->hidden_ssid_timestamp; 761 scan_params->ssid.length = 762 scan_entry->ssid.length; 763 qdf_mem_copy(scan_params->ssid.ssid, 764 scan_entry->ssid.ssid, 765 scan_entry->ssid.length); 766 } 767 } 768 769 /* 770 * Due to Rx sensitivity issue, sometime beacons are seen on adjacent 771 * channel so workaround in software is needed. If DS params or HT info 772 * are present driver can get proper channel info from these IEs and set 773 * channel_mismatch so that the older RSSI values are used in new entry. 774 * 775 * For the cases where DS params and HT info is not present, driver 776 * needs to check below conditions to get proper channel and set 777 * channel_mismatch so that the older RSSI values are used in new entry: 778 * -- The old entry channel and new entry channel are not same 779 * -- RSSI is less than -80, this indicate that the signal has leaked 780 * in adjacent channel. 781 */ 782 if ((scan_params->frm_subtype == MGMT_SUBTYPE_BEACON) && 783 !util_scan_entry_htinfo(scan_params) && 784 !util_scan_entry_ds_param(scan_params) && 785 (scan_params->channel.chan_freq != scan_entry->channel.chan_freq) && 786 (scan_params->rssi_raw < ADJACENT_CHANNEL_RSSI_THRESHOLD)) { 787 scan_params->channel.chan_freq = scan_entry->channel.chan_freq; 788 scan_params->channel_mismatch = true; 789 } 790 791 /* Use old value for rssi if beacon was heard on adjacent channel. */ 792 if (scan_params->channel_mismatch) { 793 scan_params->snr = scan_entry->snr; 794 scan_params->avg_snr = scan_entry->avg_snr; 795 scan_params->rssi_raw = scan_entry->rssi_raw; 796 scan_params->avg_rssi = scan_entry->avg_rssi; 797 scan_params->rssi_timestamp = 798 scan_entry->rssi_timestamp; 799 } else { 800 /* If elapsed time since last rssi and snr update for this 801 * entry is smaller than a threshold, calculate a 802 * running average of the RSSI and SNR values. 803 * Otherwise new frames RSSI and SNR are more representative 804 * of the signal strength. 805 */ 806 time_gap = 807 scan_params->scan_entry_time - 808 scan_entry->rssi_timestamp; 809 if (time_gap > WLAN_RSSI_AVERAGING_TIME) { 810 scan_params->avg_rssi = 811 WLAN_RSSI_IN(scan_params->rssi_raw); 812 scan_params->avg_snr = 813 WLAN_SNR_IN(scan_params->snr); 814 } 815 else { 816 /* Copy previous average rssi and snr to new entry */ 817 scan_params->avg_snr = scan_entry->avg_snr; 818 scan_params->avg_rssi = scan_entry->avg_rssi; 819 /* Average with previous samples */ 820 WLAN_RSSI_LPF(scan_params->avg_rssi, 821 scan_params->rssi_raw); 822 WLAN_SNR_LPF(scan_params->avg_snr, 823 scan_params->snr); 824 } 825 826 scan_params->rssi_timestamp = scan_params->scan_entry_time; 827 } 828 829 /* copy wsn ie from scan_entry to scan_params*/ 830 scm_update_alt_wcn_ie(scan_entry, scan_params); 831 832 /* copy mlme info from scan_entry to scan_params*/ 833 scm_update_mlme_info(scan_entry, scan_params); 834 } 835 836 /** 837 * scm_find_duplicate() - find duplicate entry, 838 * if present, add input scan entry before it and delete 839 * duplicate entry. otherwise add entry to tail 840 * @pdev: pdev ptr 841 * @scan_obj: scan obj ptr 842 * @scan_db: scan db 843 * @entry: input scan cache entry 844 * @dup_node: node before which new entry to be added 845 * 846 * ref_cnt is taken for dup_node, caller should release ref taken 847 * if returns true. 848 * 849 * Return: bool 850 */ 851 static bool 852 scm_find_duplicate(struct wlan_objmgr_pdev *pdev, 853 struct wlan_scan_obj *scan_obj, 854 struct scan_dbs *scan_db, 855 struct scan_cache_entry *entry, 856 struct scan_cache_node **dup_node) 857 { 858 uint8_t hash_idx; 859 struct scan_cache_node *cur_node; 860 struct scan_cache_node *next_node = NULL; 861 862 hash_idx = SCAN_GET_HASH(entry->bssid.bytes); 863 864 cur_node = scm_get_next_node(scan_db, 865 &scan_db->scan_hash_tbl[hash_idx], 866 NULL); 867 868 while (cur_node) { 869 if (util_is_scan_entry_match(entry, 870 cur_node->entry)) { 871 scm_copy_info_from_dup_entry(pdev, scan_obj, scan_db, 872 entry, cur_node); 873 *dup_node = cur_node; 874 return true; 875 } 876 next_node = scm_get_next_node(scan_db, 877 &scan_db->scan_hash_tbl[hash_idx], cur_node); 878 cur_node = next_node; 879 next_node = NULL; 880 } 881 882 return false; 883 } 884 885 /** 886 * scm_add_update_entry() - add or update scan entry 887 * @psoc: psoc ptr 888 * @pdev: pdev pointer 889 * @scan_params: new received entry 890 * 891 * Return: QDF_STATUS 892 */ 893 static QDF_STATUS scm_add_update_entry(struct wlan_objmgr_psoc *psoc, 894 struct wlan_objmgr_pdev *pdev, struct scan_cache_entry *scan_params) 895 { 896 struct scan_cache_node *dup_node = NULL; 897 struct scan_cache_node *scan_node = NULL; 898 bool is_dup_found = false; 899 QDF_STATUS status; 900 struct scan_dbs *scan_db; 901 struct wlan_scan_obj *scan_obj; 902 uint8_t security_type; 903 904 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 905 if (!scan_db) { 906 scm_err("scan_db is NULL"); 907 return QDF_STATUS_E_INVAL; 908 } 909 910 scan_obj = wlan_psoc_get_scan_obj(psoc); 911 if (!scan_obj) { 912 scm_err("scan_obj is NULL"); 913 return QDF_STATUS_E_INVAL; 914 } 915 916 if (scan_params->frm_subtype == 917 MGMT_SUBTYPE_PROBE_RESP && 918 !scan_params->ie_list.ssid) 919 scm_debug("Probe resp doesn't contain SSID"); 920 921 922 if (scan_params->ie_list.csa || 923 scan_params->ie_list.xcsa || 924 scan_params->ie_list.cswrp) 925 scm_debug("CSA IE present for BSSID: "QDF_MAC_ADDR_FMT, 926 QDF_MAC_ADDR_REF(scan_params->bssid.bytes)); 927 928 is_dup_found = scm_find_duplicate(pdev, scan_obj, scan_db, scan_params, 929 &dup_node); 930 931 security_type = scan_params->security_type; 932 scm_nofl_debug("Received %s: " QDF_MAC_ADDR_FMT " \"" QDF_SSID_FMT "\" freq %d rssi %d tsf_delta %u seq %d snr %d phy %d hidden %d mismatch %d %s%s%s%s pdev %d boot_time %llu ns", 933 (scan_params->frm_subtype == MGMT_SUBTYPE_PROBE_RESP) ? 934 "prb rsp" : "bcn", 935 QDF_MAC_ADDR_REF(scan_params->bssid.bytes), 936 QDF_SSID_REF(scan_params->ssid.length, 937 scan_params->ssid.ssid), 938 scan_params->channel.chan_freq, scan_params->rssi_raw, 939 scan_params->tsf_delta, scan_params->seq_num, 940 scan_params->snr, scan_params->phy_mode, 941 scan_params->is_hidden_ssid, 942 scan_params->channel_mismatch, 943 security_type & SCAN_SECURITY_TYPE_WPA ? "[WPA]" : "", 944 security_type & SCAN_SECURITY_TYPE_RSN ? "[RSN]" : "", 945 security_type & SCAN_SECURITY_TYPE_WAPI ? "[WAPI]" : "", 946 security_type & SCAN_SECURITY_TYPE_WEP ? "[WEP]" : "", 947 wlan_objmgr_pdev_get_pdev_id(pdev), 948 scan_params->boottime_ns); 949 950 if (scan_obj->cb.inform_beacon) 951 scan_obj->cb.inform_beacon(pdev, scan_params); 952 953 if (scan_db->num_entries >= MAX_SCAN_CACHE_SIZE) { 954 status = scm_flush_oldest_entry(scan_db); 955 if (QDF_IS_STATUS_ERROR(status)) { 956 /* release ref taken for dup node */ 957 if (is_dup_found) 958 scm_scan_entry_put_ref(scan_db, dup_node, true); 959 return status; 960 } 961 } 962 963 scan_node = qdf_mem_malloc(sizeof(*scan_node)); 964 if (!scan_node) { 965 /* release ref taken for dup node */ 966 if (is_dup_found) 967 scm_scan_entry_put_ref(scan_db, dup_node, true); 968 return QDF_STATUS_E_NOMEM; 969 } 970 971 scan_node->entry = scan_params; 972 qdf_spin_lock_bh(&scan_db->scan_db_lock); 973 scm_add_scan_node(scan_db, scan_node, dup_node); 974 975 if (is_dup_found) { 976 /* release ref taken for dup node and delete it */ 977 scm_scan_entry_del(scan_db, dup_node); 978 scm_scan_entry_put_ref(scan_db, dup_node, false); 979 } 980 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 981 982 return QDF_STATUS_SUCCESS; 983 } 984 985 #ifdef CONFIG_REG_CLIENT 986 /** 987 * scm_is_bss_allowed_for_country() - Check if bss is allowed to start for a 988 * specific country and power mode (VLP?LPI/SP) for 6GHz. 989 * @psoc: psoc ptr 990 * @scan_entry: ptr to scan entry 991 * 992 * Return: True if allowed, False if not. 993 */ 994 static bool scm_is_bss_allowed_for_country(struct wlan_objmgr_psoc *psoc, 995 struct scan_cache_entry *scan_entry) 996 { 997 struct wlan_country_ie *cc_ie; 998 uint8_t programmed_country[REG_ALPHA2_LEN + 1]; 999 1000 if (wlan_reg_is_6ghz_chan_freq(scan_entry->channel.chan_freq)) { 1001 cc_ie = util_scan_entry_country(scan_entry); 1002 if (!cc_ie) 1003 return false; 1004 wlan_reg_read_current_country(psoc, programmed_country); 1005 if (cc_ie && qdf_mem_cmp(cc_ie->cc, programmed_country, 1006 REG_ALPHA2_LEN)) { 1007 if (wlan_reg_is_us(programmed_country)) 1008 return false; 1009 } 1010 } 1011 return true; 1012 } 1013 #else 1014 static bool scm_is_bss_allowed_for_country(struct wlan_objmgr_psoc *psoc, 1015 struct scan_cache_entry *scan_entry) 1016 { 1017 return true; 1018 } 1019 #endif 1020 1021 /** 1022 * scm_is_p2p_wildcard_ssid() - check p2p wildcard ssid or not 1023 * @scan_entry: scan entry 1024 * 1025 * Return: true if SSID is wildcard "DIRECT-" ssid 1026 */ 1027 static bool scm_is_p2p_wildcard_ssid(struct scan_cache_entry *scan_entry) 1028 { 1029 static const char wildcard_ssid[] = "DIRECT-"; 1030 uint8_t len = sizeof(wildcard_ssid) - 1; 1031 1032 if (!scan_entry->is_p2p) 1033 return false; 1034 if (!qdf_mem_cmp(scan_entry->ssid.ssid, 1035 wildcard_ssid, len) && 1036 (scan_entry->ssid.length == len)) 1037 return true; 1038 1039 return false; 1040 } 1041 1042 QDF_STATUS __scm_handle_bcn_probe(struct scan_bcn_probe_event *bcn) 1043 { 1044 struct wlan_objmgr_psoc *psoc; 1045 struct wlan_objmgr_pdev *pdev = NULL; 1046 struct scan_cache_entry *scan_entry; 1047 struct wlan_scan_obj *scan_obj; 1048 qdf_list_t *scan_list = NULL; 1049 QDF_STATUS status = QDF_STATUS_SUCCESS; 1050 uint32_t list_count, i; 1051 qdf_list_node_t *next_node = NULL; 1052 struct scan_cache_node *scan_node; 1053 struct wlan_frame_hdr *hdr = NULL; 1054 struct wlan_crypto_params sec_params; 1055 1056 if (!bcn) { 1057 scm_err("bcn is NULL"); 1058 return QDF_STATUS_E_INVAL; 1059 } 1060 if (!bcn->rx_data) { 1061 scm_err("rx_data iS NULL"); 1062 status = QDF_STATUS_E_INVAL; 1063 goto free_nbuf; 1064 } 1065 if (!bcn->buf) { 1066 scm_err("buf is NULL"); 1067 status = QDF_STATUS_E_INVAL; 1068 goto free_nbuf; 1069 } 1070 1071 hdr = (struct wlan_frame_hdr *)qdf_nbuf_data(bcn->buf); 1072 psoc = bcn->psoc; 1073 pdev = wlan_objmgr_get_pdev_by_id(psoc, 1074 bcn->rx_data->pdev_id, WLAN_SCAN_ID); 1075 if (!pdev) { 1076 scm_err("pdev is NULL"); 1077 status = QDF_STATUS_E_INVAL; 1078 goto free_nbuf; 1079 } 1080 scan_obj = wlan_psoc_get_scan_obj(psoc); 1081 if (!scan_obj) { 1082 scm_err("scan_obj is NULL"); 1083 status = QDF_STATUS_E_INVAL; 1084 goto free_nbuf; 1085 } 1086 1087 if (qdf_nbuf_len(bcn->buf) <= 1088 (sizeof(struct wlan_frame_hdr) + 1089 offsetof(struct wlan_bcn_frame, ie))) { 1090 scm_debug("invalid beacon/probe length"); 1091 status = QDF_STATUS_E_INVAL; 1092 goto free_nbuf; 1093 } 1094 1095 if (bcn->frm_type == MGMT_SUBTYPE_BEACON && 1096 wlan_reg_is_dfs_for_freq(pdev, bcn->rx_data->chan_freq)) { 1097 util_scan_add_hidden_ssid(pdev, bcn->buf); 1098 } 1099 1100 scan_list = 1101 util_scan_unpack_beacon_frame(pdev, qdf_nbuf_data(bcn->buf), 1102 qdf_nbuf_len(bcn->buf), bcn->frm_type, 1103 bcn->rx_data); 1104 if (!scan_list || qdf_list_empty(scan_list)) { 1105 scm_debug("failed to unpack %d frame BSSID: "QDF_MAC_ADDR_FMT, 1106 bcn->frm_type, QDF_MAC_ADDR_REF(hdr->i_addr3)); 1107 status = QDF_STATUS_E_INVAL; 1108 goto free_nbuf; 1109 } 1110 1111 list_count = qdf_list_size(scan_list); 1112 for (i = 0; i < list_count; i++) { 1113 status = qdf_list_remove_front(scan_list, &next_node); 1114 if (QDF_IS_STATUS_ERROR(status) || !next_node) { 1115 scm_debug("list remove failure i:%d, lsize:%d, BSSID: "QDF_MAC_ADDR_FMT, 1116 i, list_count, QDF_MAC_ADDR_REF(hdr->i_addr3)); 1117 status = QDF_STATUS_E_INVAL; 1118 goto free_nbuf; 1119 } 1120 1121 scan_node = qdf_container_of(next_node, 1122 struct scan_cache_node, node); 1123 1124 scan_entry = scan_node->entry; 1125 1126 if (scan_obj->drop_bcn_on_chan_mismatch && 1127 scan_entry->channel_mismatch) { 1128 scm_nofl_debug("Drop frame for chan mismatch "QDF_MAC_ADDR_FMT" Seq Num: %d freq %d RSSI %d", 1129 QDF_MAC_ADDR_REF(scan_entry->bssid.bytes), 1130 scan_entry->seq_num, 1131 scan_entry->channel.chan_freq, 1132 scan_entry->rssi_raw); 1133 util_scan_free_cache_entry(scan_entry); 1134 qdf_mem_free(scan_node); 1135 continue; 1136 } 1137 /* Do not add invalid channel entry as kernel will reject it */ 1138 if (scan_obj->drop_bcn_on_invalid_freq && 1139 wlan_reg_is_disable_for_pwrmode( 1140 pdev, 1141 scan_entry->channel.chan_freq, 1142 REG_BEST_PWR_MODE)) { 1143 scm_nofl_debug("Drop frame for invalid freq %d: "QDF_MAC_ADDR_FMT" Seq Num: %d RSSI %d", 1144 scan_entry->channel.chan_freq, 1145 QDF_MAC_ADDR_REF(scan_entry->bssid.bytes), 1146 scan_entry->seq_num, 1147 scan_entry->rssi_raw); 1148 util_scan_free_cache_entry(scan_entry); 1149 qdf_mem_free(scan_node); 1150 continue; 1151 } 1152 if (util_scan_entry_rsn(scan_entry)) { 1153 status = wlan_crypto_rsnie_check( 1154 &sec_params, 1155 util_scan_entry_rsn(scan_entry)); 1156 if (QDF_IS_STATUS_ERROR(status) && 1157 !scm_is_p2p_wildcard_ssid(scan_entry)) { 1158 scm_nofl_debug("Drop frame from invalid RSN IE AP" 1159 QDF_MAC_ADDR_FMT 1160 ": RSN IE parse failed, status %d", 1161 QDF_MAC_ADDR_REF( 1162 scan_entry->bssid.bytes), 1163 status); 1164 util_scan_free_cache_entry(scan_entry); 1165 qdf_mem_free(scan_node); 1166 continue; 1167 } 1168 } 1169 if (wlan_cm_get_check_6ghz_security(psoc) && 1170 wlan_reg_is_6ghz_chan_freq(scan_entry->channel.chan_freq)) { 1171 if (!util_scan_entry_rsn(scan_entry)) { 1172 scm_info_rl( 1173 "Drop frame from "QDF_MAC_ADDR_FMT 1174 ": No RSN IE for 6GHz AP", 1175 QDF_MAC_ADDR_REF( 1176 scan_entry->bssid.bytes)); 1177 util_scan_free_cache_entry(scan_entry); 1178 qdf_mem_free(scan_node); 1179 continue; 1180 } 1181 status = wlan_crypto_rsnie_check(&sec_params, 1182 util_scan_entry_rsn(scan_entry)); 1183 if (QDF_IS_STATUS_ERROR(status)) { 1184 scm_info_rl( 1185 "Drop frame from 6GHz AP " 1186 QDF_MAC_ADDR_FMT 1187 ": RSN IE parse failed, status %d", 1188 QDF_MAC_ADDR_REF( 1189 scan_entry->bssid.bytes), 1190 status); 1191 util_scan_free_cache_entry(scan_entry); 1192 qdf_mem_free(scan_node); 1193 continue; 1194 } 1195 if ((QDF_HAS_PARAM(sec_params.ucastcipherset, 1196 WLAN_CRYPTO_CIPHER_NONE)) || 1197 (QDF_HAS_PARAM(sec_params.ucastcipherset, 1198 WLAN_CRYPTO_CIPHER_TKIP)) || 1199 (QDF_HAS_PARAM(sec_params.ucastcipherset, 1200 WLAN_CRYPTO_CIPHER_WEP_40)) || 1201 (QDF_HAS_PARAM(sec_params.ucastcipherset, 1202 WLAN_CRYPTO_CIPHER_WEP_104))) { 1203 scm_info_rl( 1204 "Drop frame from "QDF_MAC_ADDR_FMT 1205 ": Invalid sec type %0X for 6GHz AP", 1206 QDF_MAC_ADDR_REF( 1207 scan_entry->bssid.bytes), 1208 sec_params.ucastcipherset); 1209 util_scan_free_cache_entry(scan_entry); 1210 qdf_mem_free(scan_node); 1211 continue; 1212 } 1213 if (!wlan_cm_6ghz_allowed_for_akm(psoc, 1214 sec_params.key_mgmt, 1215 sec_params.rsn_caps, 1216 util_scan_entry_rsnxe(scan_entry), 1217 0, false)) { 1218 scm_info_rl( 1219 "Drop frame from "QDF_MAC_ADDR_FMT 1220 ": Invalid AKM suite %0X for 6GHz AP", 1221 QDF_MAC_ADDR_REF( 1222 scan_entry->bssid.bytes), 1223 sec_params.key_mgmt); 1224 util_scan_free_cache_entry(scan_entry); 1225 qdf_mem_free(scan_node); 1226 continue; 1227 } 1228 } 1229 if (scan_obj->cb.update_beacon) 1230 scan_obj->cb.update_beacon(pdev, scan_entry); 1231 1232 /** 1233 * Do not drop the frame if Wi-Fi safe mode or RF test mode is 1234 * enabled. wlan_cm_get_check_6ghz_security API returns true if 1235 * neither Safe mode nor RF test mode are enabled. 1236 */ 1237 if (!scm_is_bss_allowed_for_country(psoc, scan_entry) && 1238 wlan_cm_get_check_6ghz_security(psoc)) { 1239 scm_info_rl( 1240 "Drop frame from "QDF_MAC_ADDR_FMT 1241 ": AP in VLP mode not supported for US", 1242 QDF_MAC_ADDR_REF(scan_entry->bssid.bytes)); 1243 util_scan_free_cache_entry(scan_entry); 1244 qdf_mem_free(scan_node); 1245 continue; 1246 } 1247 1248 status = scm_add_update_entry(psoc, pdev, scan_entry); 1249 if (QDF_IS_STATUS_ERROR(status)) { 1250 scm_debug("failed to add entry for BSSID: "QDF_MAC_ADDR_FMT" Seq Num: %d", 1251 QDF_MAC_ADDR_REF(scan_entry->bssid.bytes), 1252 scan_entry->seq_num); 1253 util_scan_free_cache_entry(scan_entry); 1254 qdf_mem_free(scan_node); 1255 continue; 1256 } 1257 1258 qdf_mem_free(scan_node); 1259 } 1260 1261 free_nbuf: 1262 if (scan_list) 1263 qdf_mem_free(scan_list); 1264 if (bcn->psoc) 1265 wlan_objmgr_psoc_release_ref(bcn->psoc, WLAN_SCAN_ID); 1266 if (pdev) 1267 wlan_objmgr_pdev_release_ref(pdev, WLAN_SCAN_ID); 1268 if (bcn->rx_data) 1269 qdf_mem_free(bcn->rx_data); 1270 if (bcn->buf) 1271 qdf_nbuf_free(bcn->buf); 1272 qdf_mem_free(bcn); 1273 1274 return status; 1275 } 1276 1277 QDF_STATUS scm_handle_bcn_probe(struct scheduler_msg *msg) 1278 { 1279 if (!msg) { 1280 scm_err("msg is NULL"); 1281 return QDF_STATUS_E_NULL_VALUE; 1282 } 1283 1284 return __scm_handle_bcn_probe(msg->bodyptr); 1285 } 1286 1287 /** 1288 * scm_scan_apply_filter_get_entry() - apply filter and get the 1289 * scan entry 1290 * @psoc: psoc pointer 1291 * @db_entry: scan entry 1292 * @filter: filter to be applied 1293 * @scan_list: scan list to which entry is added 1294 * 1295 * Return: QDF_STATUS 1296 */ 1297 static QDF_STATUS 1298 scm_scan_apply_filter_get_entry(struct wlan_objmgr_psoc *psoc, 1299 struct scan_cache_entry *db_entry, 1300 struct scan_filter *filter, 1301 qdf_list_t *scan_list) 1302 { 1303 struct scan_cache_node *scan_node = NULL; 1304 struct security_info security = {0}; 1305 bool match; 1306 1307 if (!filter) 1308 match = true; 1309 else 1310 match = scm_filter_match(psoc, db_entry, 1311 filter, &security); 1312 1313 if (!match) 1314 return QDF_STATUS_SUCCESS; 1315 1316 scan_node = qdf_mem_malloc_atomic(sizeof(*scan_node)); 1317 if (!scan_node) 1318 return QDF_STATUS_E_NOMEM; 1319 1320 scan_node->entry = 1321 util_scan_copy_cache_entry(db_entry); 1322 1323 if (!scan_node->entry) { 1324 qdf_mem_free(scan_node); 1325 return QDF_STATUS_E_NOMEM; 1326 } 1327 1328 qdf_mem_copy(&scan_node->entry->neg_sec_info, 1329 &security, sizeof(scan_node->entry->neg_sec_info)); 1330 1331 qdf_list_insert_front(scan_list, &scan_node->node); 1332 1333 return QDF_STATUS_SUCCESS; 1334 } 1335 1336 /** 1337 * scm_get_results() - Iterate and get scan results 1338 * @psoc: psoc ptr 1339 * @scan_db: scan db 1340 * @filter: filter to be applied 1341 * @scan_list: scan list to which entry is added 1342 * 1343 * Return: void 1344 */ 1345 static void scm_get_results(struct wlan_objmgr_psoc *psoc, 1346 struct scan_dbs *scan_db, struct scan_filter *filter, 1347 qdf_list_t *scan_list) 1348 { 1349 int i, count; 1350 struct scan_cache_node *cur_node; 1351 struct scan_cache_node *next_node = NULL; 1352 1353 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 1354 cur_node = scm_get_next_node(scan_db, 1355 &scan_db->scan_hash_tbl[i], NULL); 1356 count = qdf_list_size(&scan_db->scan_hash_tbl[i]); 1357 if (!count) 1358 continue; 1359 while (cur_node) { 1360 scm_scan_apply_filter_get_entry(psoc, 1361 cur_node->entry, filter, scan_list); 1362 next_node = scm_get_next_node(scan_db, 1363 &scan_db->scan_hash_tbl[i], cur_node); 1364 cur_node = next_node; 1365 } 1366 } 1367 } 1368 1369 QDF_STATUS scm_purge_scan_results(qdf_list_t *scan_list) 1370 { 1371 QDF_STATUS status; 1372 struct scan_cache_node *cur_node; 1373 qdf_list_node_t *cur_lst = NULL, *next_lst = NULL; 1374 1375 if (!scan_list) { 1376 scm_err("scan_result is NULL"); 1377 return QDF_STATUS_E_INVAL; 1378 } 1379 1380 status = qdf_list_peek_front(scan_list, &cur_lst); 1381 1382 while (cur_lst) { 1383 qdf_list_peek_next( 1384 scan_list, cur_lst, &next_lst); 1385 cur_node = qdf_container_of(cur_lst, 1386 struct scan_cache_node, node); 1387 status = qdf_list_remove_node(scan_list, 1388 cur_lst); 1389 if (QDF_IS_STATUS_SUCCESS(status)) { 1390 util_scan_free_cache_entry(cur_node->entry); 1391 qdf_mem_free(cur_node); 1392 } 1393 cur_lst = next_lst; 1394 next_lst = NULL; 1395 } 1396 1397 qdf_list_destroy(scan_list); 1398 qdf_mem_free(scan_list); 1399 1400 return status; 1401 } 1402 1403 qdf_list_t *scm_get_scan_result(struct wlan_objmgr_pdev *pdev, 1404 struct scan_filter *filter) 1405 { 1406 struct wlan_objmgr_psoc *psoc; 1407 struct scan_dbs *scan_db; 1408 qdf_list_t *tmp_list; 1409 1410 if (!pdev) { 1411 scm_err("pdev is NULL"); 1412 return NULL; 1413 } 1414 1415 psoc = wlan_pdev_get_psoc(pdev); 1416 if (!psoc) { 1417 scm_err("psoc is NULL"); 1418 return NULL; 1419 } 1420 1421 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1422 if (!scan_db) { 1423 scm_err("scan_db is NULL"); 1424 return NULL; 1425 } 1426 1427 tmp_list = qdf_mem_malloc_atomic(sizeof(*tmp_list)); 1428 if (!tmp_list) { 1429 scm_err("failed tp allocate scan_result"); 1430 return NULL; 1431 } 1432 qdf_list_create(tmp_list, 1433 MAX_SCAN_CACHE_SIZE); 1434 scm_age_out_entries(psoc, scan_db); 1435 scm_get_results(psoc, scan_db, filter, tmp_list); 1436 1437 return tmp_list; 1438 } 1439 1440 /** 1441 * scm_iterate_db_and_call_func() - iterate and call the func 1442 * @scan_db: scan db 1443 * @func: func to be called 1444 * @arg: func arg 1445 * 1446 * Return: QDF_STATUS 1447 */ 1448 static QDF_STATUS 1449 scm_iterate_db_and_call_func(struct scan_dbs *scan_db, 1450 scan_iterator_func func, void *arg) 1451 { 1452 int i; 1453 QDF_STATUS status = QDF_STATUS_SUCCESS; 1454 struct scan_cache_node *cur_node; 1455 struct scan_cache_node *next_node = NULL; 1456 1457 if (!func) 1458 return QDF_STATUS_E_INVAL; 1459 1460 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 1461 cur_node = scm_get_next_node(scan_db, 1462 &scan_db->scan_hash_tbl[i], NULL); 1463 while (cur_node) { 1464 status = func(arg, cur_node->entry); 1465 if (QDF_IS_STATUS_ERROR(status)) { 1466 scm_scan_entry_put_ref(scan_db, 1467 cur_node, true); 1468 return status; 1469 } 1470 next_node = scm_get_next_node(scan_db, 1471 &scan_db->scan_hash_tbl[i], cur_node); 1472 cur_node = next_node; 1473 } 1474 } 1475 1476 return status; 1477 } 1478 1479 QDF_STATUS 1480 scm_iterate_scan_db(struct wlan_objmgr_pdev *pdev, 1481 scan_iterator_func func, void *arg) 1482 { 1483 struct wlan_objmgr_psoc *psoc; 1484 struct scan_dbs *scan_db; 1485 QDF_STATUS status; 1486 1487 if (!func) { 1488 scm_err("func is NULL"); 1489 return QDF_STATUS_E_INVAL; 1490 } 1491 1492 if (!pdev) { 1493 scm_err("pdev is NULL"); 1494 return QDF_STATUS_E_INVAL; 1495 } 1496 1497 psoc = wlan_pdev_get_psoc(pdev); 1498 if (!psoc) { 1499 scm_err("psoc is NULL"); 1500 return QDF_STATUS_E_INVAL; 1501 } 1502 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1503 if (!scan_db) { 1504 scm_err("scan_db is NULL"); 1505 return QDF_STATUS_E_INVAL; 1506 } 1507 1508 scm_age_out_entries(psoc, scan_db); 1509 status = scm_iterate_db_and_call_func(scan_db, func, arg); 1510 1511 return status; 1512 } 1513 1514 /** 1515 * scm_scan_apply_filter_flush_entry() -flush scan entries depending 1516 * on filter 1517 * @psoc: psoc ptr 1518 * @scan_db: scan db 1519 * @db_node: node on which filters are applied 1520 * @filter: filter to be applied 1521 * 1522 * Return: QDF_STATUS 1523 */ 1524 static QDF_STATUS 1525 scm_scan_apply_filter_flush_entry(struct wlan_objmgr_psoc *psoc, 1526 struct scan_dbs *scan_db, 1527 struct scan_cache_node *db_node, 1528 struct scan_filter *filter) 1529 { 1530 struct security_info security = {0}; 1531 bool match; 1532 1533 if (!filter) 1534 match = true; 1535 else 1536 match = scm_filter_match(psoc, db_node->entry, 1537 filter, &security); 1538 1539 if (!match) 1540 return QDF_STATUS_SUCCESS; 1541 1542 qdf_spin_lock_bh(&scan_db->scan_db_lock); 1543 scm_scan_entry_del(scan_db, db_node); 1544 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 1545 1546 return QDF_STATUS_SUCCESS; 1547 } 1548 1549 /** 1550 * scm_flush_scan_entries() - API to flush scan entries depending on filters 1551 * @psoc: psoc ptr 1552 * @scan_db: scan db 1553 * @filter: filter 1554 * 1555 * Return: void 1556 */ 1557 static void scm_flush_scan_entries(struct wlan_objmgr_psoc *psoc, 1558 struct scan_dbs *scan_db, 1559 struct scan_filter *filter) 1560 { 1561 int i; 1562 struct scan_cache_node *cur_node; 1563 struct scan_cache_node *next_node = NULL; 1564 1565 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 1566 cur_node = scm_get_next_node(scan_db, 1567 &scan_db->scan_hash_tbl[i], NULL); 1568 while (cur_node) { 1569 scm_scan_apply_filter_flush_entry(psoc, scan_db, 1570 cur_node, filter); 1571 next_node = scm_get_next_node(scan_db, 1572 &scan_db->scan_hash_tbl[i], cur_node); 1573 cur_node = next_node; 1574 } 1575 } 1576 } 1577 1578 QDF_STATUS scm_flush_results(struct wlan_objmgr_pdev *pdev, 1579 struct scan_filter *filter) 1580 { 1581 struct wlan_objmgr_psoc *psoc; 1582 struct scan_dbs *scan_db; 1583 QDF_STATUS status = QDF_STATUS_SUCCESS; 1584 1585 if (!pdev) { 1586 scm_err("pdev is NULL"); 1587 return QDF_STATUS_E_INVAL; 1588 } 1589 1590 psoc = wlan_pdev_get_psoc(pdev); 1591 if (!psoc) { 1592 scm_err("psoc is NULL"); 1593 return QDF_STATUS_E_INVAL; 1594 } 1595 1596 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1597 if (!scan_db) { 1598 scm_err("scan_db is NULL"); 1599 return QDF_STATUS_E_INVAL; 1600 } 1601 1602 scm_flush_scan_entries(psoc, scan_db, filter); 1603 1604 return status; 1605 } 1606 1607 /** 1608 * scm_filter_channels() - Remove entries not belonging to channel list 1609 * @scan_db: scan db 1610 * @db_node: node on which filters are applied 1611 * @chan_freq_list: valid channel frequency (in MHz) list 1612 * @num_chan: number of channels 1613 * 1614 * Return: QDF_STATUS 1615 */ 1616 static void scm_filter_channels(struct wlan_objmgr_pdev *pdev, 1617 struct scan_dbs *scan_db, 1618 struct scan_cache_node *db_node, 1619 uint32_t *chan_freq_list, uint32_t num_chan) 1620 { 1621 int i; 1622 bool match = false; 1623 1624 for (i = 0; i < num_chan; i++) { 1625 if (chan_freq_list[i] == util_scan_entry_channel_frequency( 1626 db_node->entry)) { 1627 match = true; 1628 break; 1629 } 1630 } 1631 1632 if (!match) { 1633 qdf_spin_lock_bh(&scan_db->scan_db_lock); 1634 scm_scan_entry_del(scan_db, db_node); 1635 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 1636 } 1637 } 1638 1639 void scm_filter_valid_channel(struct wlan_objmgr_pdev *pdev, 1640 uint32_t *chan_freq_list, uint32_t num_chan) 1641 { 1642 int i; 1643 struct wlan_objmgr_psoc *psoc; 1644 struct scan_dbs *scan_db; 1645 struct scan_cache_node *cur_node; 1646 struct scan_cache_node *next_node = NULL; 1647 1648 scm_debug("num_chan = %d", num_chan); 1649 1650 if (!pdev) { 1651 scm_err("pdev is NULL"); 1652 return; 1653 } 1654 1655 psoc = wlan_pdev_get_psoc(pdev); 1656 if (!psoc) { 1657 scm_err("psoc is NULL"); 1658 return; 1659 } 1660 1661 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1662 if (!scan_db) { 1663 scm_err("scan_db is NULL"); 1664 return; 1665 } 1666 1667 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 1668 cur_node = scm_get_next_node(scan_db, 1669 &scan_db->scan_hash_tbl[i], NULL); 1670 while (cur_node) { 1671 scm_filter_channels(pdev, scan_db, 1672 cur_node, chan_freq_list, num_chan); 1673 next_node = scm_get_next_node(scan_db, 1674 &scan_db->scan_hash_tbl[i], cur_node); 1675 cur_node = next_node; 1676 } 1677 } 1678 } 1679 1680 QDF_STATUS scm_scan_register_bcn_cb(struct wlan_objmgr_psoc *psoc, 1681 update_beacon_cb cb, enum scan_cb_type type) 1682 { 1683 struct wlan_scan_obj *scan_obj; 1684 1685 scan_obj = wlan_psoc_get_scan_obj(psoc); 1686 if (!scan_obj) { 1687 scm_err("scan obj is NULL"); 1688 return QDF_STATUS_E_INVAL; 1689 } 1690 switch (type) { 1691 case SCAN_CB_TYPE_INFORM_BCN: 1692 scan_obj->cb.inform_beacon = cb; 1693 break; 1694 case SCAN_CB_TYPE_UPDATE_BCN: 1695 scan_obj->cb.update_beacon = cb; 1696 break; 1697 case SCAN_CB_TYPE_UNLINK_BSS: 1698 scan_obj->cb.unlink_bss = cb; 1699 break; 1700 default: 1701 scm_err("invalid cb type %d", type); 1702 } 1703 1704 return QDF_STATUS_SUCCESS; 1705 } 1706 1707 QDF_STATUS scm_db_init(struct wlan_objmgr_psoc *psoc) 1708 { 1709 int i, j; 1710 struct scan_dbs *scan_db; 1711 1712 if (!psoc) { 1713 scm_err("psoc is NULL"); 1714 return QDF_STATUS_E_INVAL; 1715 } 1716 1717 /* Initialize the scan database per pdev */ 1718 for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) { 1719 scan_db = wlan_pdevid_get_scan_db(psoc, i); 1720 if (!scan_db) { 1721 scm_err("scan_db is NULL %d", i); 1722 continue; 1723 } 1724 scan_db->num_entries = 0; 1725 qdf_spinlock_create(&scan_db->scan_db_lock); 1726 for (j = 0; j < SCAN_HASH_SIZE; j++) 1727 qdf_list_create(&scan_db->scan_hash_tbl[j], 1728 MAX_SCAN_CACHE_SIZE); 1729 } 1730 return QDF_STATUS_SUCCESS; 1731 } 1732 1733 QDF_STATUS scm_db_deinit(struct wlan_objmgr_psoc *psoc) 1734 { 1735 int i, j; 1736 struct scan_dbs *scan_db; 1737 1738 if (!psoc) { 1739 scm_err("scan obj is NULL"); 1740 return QDF_STATUS_E_INVAL; 1741 } 1742 1743 /* Initialize the scan database per pdev */ 1744 for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) { 1745 scan_db = wlan_pdevid_get_scan_db(psoc, i); 1746 if (!scan_db) { 1747 scm_err("scan_db is NULL %d", i); 1748 continue; 1749 } 1750 1751 scm_flush_scan_entries(psoc, scan_db, NULL); 1752 for (j = 0; j < SCAN_HASH_SIZE; j++) 1753 qdf_list_destroy(&scan_db->scan_hash_tbl[j]); 1754 qdf_spinlock_destroy(&scan_db->scan_db_lock); 1755 } 1756 1757 return QDF_STATUS_SUCCESS; 1758 } 1759 1760 #ifdef FEATURE_6G_SCAN_CHAN_SORT_ALGO 1761 QDF_STATUS scm_channel_list_db_init(struct wlan_objmgr_psoc *psoc) 1762 { 1763 uint32_t i, j; 1764 uint32_t min_freq, max_freq; 1765 struct channel_list_db *rnr_channel_db; 1766 1767 min_freq = wlan_reg_min_6ghz_chan_freq(); 1768 max_freq = wlan_reg_max_6ghz_chan_freq(); 1769 1770 scm_info("min_freq %d max_freq %d", min_freq, max_freq); 1771 i = min_freq; 1772 rnr_channel_db = scm_get_rnr_channel_db(psoc); 1773 if (!rnr_channel_db) 1774 return QDF_STATUS_E_INVAL; 1775 1776 for (j = 0; j < QDF_ARRAY_SIZE(rnr_channel_db->channel); j++) { 1777 if (i >= min_freq && i <= max_freq) 1778 rnr_channel_db->channel[j].chan_freq = i; 1779 i += 20; 1780 /* init list for all to avoid uninitialized list */ 1781 qdf_list_create(&rnr_channel_db->channel[j].rnr_list, 1782 WLAN_MAX_RNR_COUNT); 1783 } 1784 return QDF_STATUS_SUCCESS; 1785 } 1786 1787 QDF_STATUS scm_channel_list_db_deinit(struct wlan_objmgr_psoc *psoc) 1788 { 1789 int i; 1790 qdf_list_node_t *cur_node, *next_node; 1791 struct meta_rnr_channel *channel; 1792 struct scan_rnr_node *rnr_node; 1793 struct channel_list_db *rnr_channel_db; 1794 1795 rnr_channel_db = scm_get_rnr_channel_db(psoc); 1796 if (!rnr_channel_db) 1797 return QDF_STATUS_E_INVAL; 1798 1799 for (i = 0; i < QDF_ARRAY_SIZE(rnr_channel_db->channel); i++) { 1800 channel = &rnr_channel_db->channel[i]; 1801 channel->chan_freq = 0; 1802 channel->beacon_probe_last_time_found = 0; 1803 channel->bss_beacon_probe_count = 0; 1804 channel->saved_profile_count = 0; 1805 cur_node = NULL; 1806 qdf_list_peek_front(&channel->rnr_list, &cur_node); 1807 while (cur_node) { 1808 next_node = NULL; 1809 qdf_list_peek_next(&channel->rnr_list, cur_node, 1810 &next_node); 1811 rnr_node = qdf_container_of(cur_node, 1812 struct scan_rnr_node, 1813 node); 1814 qdf_list_remove_node(&channel->rnr_list, 1815 &rnr_node->node); 1816 qdf_mem_free(rnr_node); 1817 cur_node = next_node; 1818 next_node = NULL; 1819 } 1820 qdf_list_destroy(&channel->rnr_list); 1821 } 1822 1823 return QDF_STATUS_SUCCESS; 1824 } 1825 1826 QDF_STATUS scm_rnr_db_flush(struct wlan_objmgr_psoc *psoc) 1827 { 1828 int i; 1829 qdf_list_node_t *cur_node, *next_node; 1830 struct meta_rnr_channel *channel; 1831 struct scan_rnr_node *rnr_node; 1832 struct channel_list_db *rnr_channel_db; 1833 1834 rnr_channel_db = scm_get_rnr_channel_db(psoc); 1835 if (!rnr_channel_db) 1836 return QDF_STATUS_E_INVAL; 1837 1838 for (i = 0; i < QDF_ARRAY_SIZE(rnr_channel_db->channel); i++) { 1839 channel = &rnr_channel_db->channel[i]; 1840 cur_node = NULL; 1841 qdf_list_peek_front(&channel->rnr_list, &cur_node); 1842 while (cur_node) { 1843 next_node = NULL; 1844 qdf_list_peek_next(&channel->rnr_list, cur_node, 1845 &next_node); 1846 rnr_node = qdf_container_of(cur_node, 1847 struct scan_rnr_node, 1848 node); 1849 qdf_list_remove_node(&channel->rnr_list, 1850 &rnr_node->node); 1851 qdf_mem_free(rnr_node); 1852 cur_node = next_node; 1853 next_node = NULL; 1854 } 1855 /* Reset beacon info */ 1856 channel->beacon_probe_last_time_found = 0; 1857 channel->bss_beacon_probe_count = 0; 1858 } 1859 1860 return QDF_STATUS_SUCCESS; 1861 } 1862 1863 void scm_update_rnr_from_scan_cache(struct wlan_objmgr_pdev *pdev) 1864 { 1865 uint8_t i; 1866 struct scan_dbs *scan_db; 1867 struct scan_cache_node *cur_node; 1868 struct scan_cache_node *next_node = NULL; 1869 struct wlan_objmgr_psoc *psoc; 1870 struct scan_cache_entry *entry; 1871 1872 psoc = wlan_pdev_get_psoc(pdev); 1873 if (!psoc) { 1874 scm_err("psoc is NULL"); 1875 return; 1876 } 1877 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1878 if (!scan_db) { 1879 scm_err("scan_db is NULL"); 1880 return; 1881 } 1882 1883 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 1884 cur_node = scm_get_next_node(scan_db, 1885 &scan_db->scan_hash_tbl[i], NULL); 1886 while (cur_node) { 1887 entry = cur_node->entry; 1888 scm_add_rnr_channel_db(psoc, entry); 1889 next_node = 1890 scm_get_next_node(scan_db, 1891 &scan_db->scan_hash_tbl[i], 1892 cur_node); 1893 cur_node = next_node; 1894 next_node = NULL; 1895 } 1896 } 1897 } 1898 #endif 1899 1900 QDF_STATUS scm_update_scan_mlme_info(struct wlan_objmgr_pdev *pdev, 1901 struct scan_cache_entry *entry) 1902 { 1903 uint8_t hash_idx; 1904 struct scan_dbs *scan_db; 1905 struct scan_cache_node *cur_node; 1906 struct scan_cache_node *next_node = NULL; 1907 struct wlan_objmgr_psoc *psoc; 1908 1909 psoc = wlan_pdev_get_psoc(pdev); 1910 if (!psoc) { 1911 scm_err("psoc is NULL"); 1912 return QDF_STATUS_E_INVAL; 1913 } 1914 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1915 if (!scan_db) { 1916 scm_err("scan_db is NULL"); 1917 return QDF_STATUS_E_INVAL; 1918 } 1919 1920 hash_idx = SCAN_GET_HASH(entry->bssid.bytes); 1921 1922 cur_node = scm_get_next_node(scan_db, 1923 &scan_db->scan_hash_tbl[hash_idx], NULL); 1924 1925 while (cur_node) { 1926 if (util_is_scan_entry_match(entry, 1927 cur_node->entry)) { 1928 /* Acquire db lock to prevent simultaneous update */ 1929 qdf_spin_lock_bh(&scan_db->scan_db_lock); 1930 scm_update_mlme_info(entry, cur_node->entry); 1931 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 1932 scm_scan_entry_put_ref(scan_db, 1933 cur_node, true); 1934 return QDF_STATUS_SUCCESS; 1935 } 1936 next_node = scm_get_next_node(scan_db, 1937 &scan_db->scan_hash_tbl[hash_idx], cur_node); 1938 cur_node = next_node; 1939 } 1940 1941 return QDF_STATUS_E_INVAL; 1942 } 1943 1944 QDF_STATUS scm_scan_update_mlme_by_bssinfo(struct wlan_objmgr_pdev *pdev, 1945 struct bss_info *bss_info, struct mlme_info *mlme) 1946 { 1947 uint8_t hash_idx; 1948 struct scan_dbs *scan_db; 1949 struct scan_cache_node *cur_node; 1950 struct scan_cache_node *next_node = NULL; 1951 struct wlan_objmgr_psoc *psoc; 1952 struct scan_cache_entry *entry; 1953 1954 psoc = wlan_pdev_get_psoc(pdev); 1955 if (!psoc) { 1956 scm_err("psoc is NULL"); 1957 return QDF_STATUS_E_INVAL; 1958 } 1959 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1960 if (!scan_db) { 1961 scm_err("scan_db is NULL"); 1962 return QDF_STATUS_E_INVAL; 1963 } 1964 1965 hash_idx = SCAN_GET_HASH(bss_info->bssid.bytes); 1966 cur_node = scm_get_next_node(scan_db, 1967 &scan_db->scan_hash_tbl[hash_idx], NULL); 1968 while (cur_node) { 1969 entry = cur_node->entry; 1970 if (qdf_is_macaddr_equal(&bss_info->bssid, &entry->bssid) && 1971 (util_is_ssid_match(&bss_info->ssid, &entry->ssid)) && 1972 (bss_info->freq == entry->channel.chan_freq)) { 1973 /* Acquire db lock to prevent simultaneous update */ 1974 qdf_spin_lock_bh(&scan_db->scan_db_lock); 1975 qdf_mem_copy(&entry->mlme_info, mlme, 1976 sizeof(struct mlme_info)); 1977 scm_debug("BSSID: "QDF_MAC_ADDR_FMT" set assoc_state to %d with age %lu ms", 1978 QDF_MAC_ADDR_REF(entry->bssid.bytes), 1979 mlme->assoc_state, 1980 util_scan_entry_age(entry)); 1981 scm_scan_entry_put_ref(scan_db, 1982 cur_node, false); 1983 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 1984 return QDF_STATUS_SUCCESS; 1985 } 1986 next_node = scm_get_next_node(scan_db, 1987 &scan_db->scan_hash_tbl[hash_idx], cur_node); 1988 cur_node = next_node; 1989 } 1990 1991 return QDF_STATUS_E_INVAL; 1992 } 1993 1994 uint32_t scm_get_last_scan_time_per_channel(struct wlan_objmgr_vdev *vdev, 1995 uint32_t freq) 1996 { 1997 struct wlan_scan_obj *scan; 1998 struct chan_list_scan_info *chan_info; 1999 uint8_t pdev_id; 2000 int i; 2001 2002 scan = wlan_vdev_get_scan_obj(vdev); 2003 if (!scan) 2004 return 0; 2005 2006 pdev_id = wlan_scan_vdev_get_pdev_id(vdev); 2007 chan_info = &scan->pdev_info[pdev_id].chan_scan_info; 2008 2009 for (i = 0; i < chan_info->num_chan ; i++) { 2010 if (chan_info->ch_scan_info[i].freq == freq) 2011 return chan_info->ch_scan_info[i].last_scan_time; 2012 } 2013 2014 return 0; 2015 } 2016