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