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("Drop frame from "QDF_MAC_ADDR_FMT 1062 ": No RSN IE for 6GHz AP", 1063 QDF_MAC_ADDR_REF( 1064 scan_entry->bssid.bytes)); 1065 util_scan_free_cache_entry(scan_entry); 1066 qdf_mem_free(scan_node); 1067 continue; 1068 } 1069 status = wlan_crypto_rsnie_check(&sec_params, 1070 util_scan_entry_rsn(scan_entry)); 1071 if (QDF_IS_STATUS_ERROR(status)) { 1072 scm_info("Drop frame from 6GHz AP " 1073 QDF_MAC_ADDR_FMT 1074 ": RSN IE parse failed, status %d", 1075 QDF_MAC_ADDR_REF( 1076 scan_entry->bssid.bytes), 1077 status); 1078 util_scan_free_cache_entry(scan_entry); 1079 qdf_mem_free(scan_node); 1080 continue; 1081 } 1082 if ((QDF_HAS_PARAM(sec_params.ucastcipherset, 1083 WLAN_CRYPTO_CIPHER_NONE)) || 1084 (QDF_HAS_PARAM(sec_params.ucastcipherset, 1085 WLAN_CRYPTO_CIPHER_TKIP)) || 1086 (QDF_HAS_PARAM(sec_params.ucastcipherset, 1087 WLAN_CRYPTO_CIPHER_WEP_40)) || 1088 (QDF_HAS_PARAM(sec_params.ucastcipherset, 1089 WLAN_CRYPTO_CIPHER_WEP_104))) { 1090 scm_info("Drop frame from "QDF_MAC_ADDR_FMT 1091 ": Invalid sec type %0X for 6GHz AP", 1092 QDF_MAC_ADDR_REF( 1093 scan_entry->bssid.bytes), 1094 sec_params.ucastcipherset); 1095 continue; 1096 } 1097 if (!wlan_cm_6ghz_allowed_for_akm(psoc, 1098 sec_params.key_mgmt, 1099 sec_params.rsn_caps, 1100 util_scan_entry_rsnxe(scan_entry), 1101 0, false)) { 1102 scm_info("Drop frame from "QDF_MAC_ADDR_FMT 1103 ": Invalid AKM suite %0X for 6GHz AP", 1104 QDF_MAC_ADDR_REF( 1105 scan_entry->bssid.bytes), 1106 sec_params.key_mgmt); 1107 util_scan_free_cache_entry(scan_entry); 1108 qdf_mem_free(scan_node); 1109 continue; 1110 } 1111 } 1112 if (scan_obj->cb.update_beacon) 1113 scan_obj->cb.update_beacon(pdev, scan_entry); 1114 1115 if (!scm_is_bss_allowed_for_country(psoc, scan_entry)) { 1116 scm_info("Drop frame from "QDF_MAC_ADDR_FMT 1117 ": AP in VLP mode not supported for US", 1118 QDF_MAC_ADDR_REF(scan_entry->bssid.bytes)); 1119 util_scan_free_cache_entry(scan_entry); 1120 qdf_mem_free(scan_node); 1121 continue; 1122 } 1123 1124 status = scm_add_update_entry(psoc, pdev, scan_entry); 1125 if (QDF_IS_STATUS_ERROR(status)) { 1126 scm_debug("failed to add entry for BSSID: "QDF_MAC_ADDR_FMT" Seq Num: %d", 1127 QDF_MAC_ADDR_REF(scan_entry->bssid.bytes), 1128 scan_entry->seq_num); 1129 util_scan_free_cache_entry(scan_entry); 1130 qdf_mem_free(scan_node); 1131 continue; 1132 } 1133 1134 qdf_mem_free(scan_node); 1135 } 1136 1137 free_nbuf: 1138 if (scan_list) 1139 qdf_mem_free(scan_list); 1140 if (bcn->psoc) 1141 wlan_objmgr_psoc_release_ref(bcn->psoc, WLAN_SCAN_ID); 1142 if (pdev) 1143 wlan_objmgr_pdev_release_ref(pdev, WLAN_SCAN_ID); 1144 if (bcn->rx_data) 1145 qdf_mem_free(bcn->rx_data); 1146 if (bcn->buf) 1147 qdf_nbuf_free(bcn->buf); 1148 qdf_mem_free(bcn); 1149 1150 return status; 1151 } 1152 1153 QDF_STATUS scm_handle_bcn_probe(struct scheduler_msg *msg) 1154 { 1155 if (!msg) { 1156 scm_err("msg is NULL"); 1157 return QDF_STATUS_E_NULL_VALUE; 1158 } 1159 1160 return __scm_handle_bcn_probe(msg->bodyptr); 1161 } 1162 1163 /** 1164 * scm_scan_apply_filter_get_entry() - apply filter and get the 1165 * scan entry 1166 * @psoc: psoc pointer 1167 * @db_entry: scan entry 1168 * @filter: filter to be applied 1169 * @scan_list: scan list to which entry is added 1170 * 1171 * Return: QDF_STATUS 1172 */ 1173 static QDF_STATUS 1174 scm_scan_apply_filter_get_entry(struct wlan_objmgr_psoc *psoc, 1175 struct scan_cache_entry *db_entry, 1176 struct scan_filter *filter, 1177 qdf_list_t *scan_list) 1178 { 1179 struct scan_cache_node *scan_node = NULL; 1180 struct security_info security = {0}; 1181 bool match; 1182 1183 if (!filter) 1184 match = true; 1185 else 1186 match = scm_filter_match(psoc, db_entry, 1187 filter, &security); 1188 1189 if (!match) 1190 return QDF_STATUS_SUCCESS; 1191 1192 scan_node = qdf_mem_malloc_atomic(sizeof(*scan_node)); 1193 if (!scan_node) 1194 return QDF_STATUS_E_NOMEM; 1195 1196 scan_node->entry = 1197 util_scan_copy_cache_entry(db_entry); 1198 1199 if (!scan_node->entry) { 1200 qdf_mem_free(scan_node); 1201 return QDF_STATUS_E_NOMEM; 1202 } 1203 1204 qdf_mem_copy(&scan_node->entry->neg_sec_info, 1205 &security, sizeof(scan_node->entry->neg_sec_info)); 1206 1207 qdf_list_insert_front(scan_list, &scan_node->node); 1208 1209 return QDF_STATUS_SUCCESS; 1210 } 1211 1212 /** 1213 * scm_get_results() - Iterate and get scan results 1214 * @psoc: psoc ptr 1215 * @scan_db: scan db 1216 * @filter: filter to be applied 1217 * @scan_list: scan list to which entry is added 1218 * 1219 * Return: void 1220 */ 1221 static void scm_get_results(struct wlan_objmgr_psoc *psoc, 1222 struct scan_dbs *scan_db, struct scan_filter *filter, 1223 qdf_list_t *scan_list) 1224 { 1225 int i, count; 1226 struct scan_cache_node *cur_node; 1227 struct scan_cache_node *next_node = NULL; 1228 1229 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 1230 cur_node = scm_get_next_node(scan_db, 1231 &scan_db->scan_hash_tbl[i], NULL); 1232 count = qdf_list_size(&scan_db->scan_hash_tbl[i]); 1233 if (!count) 1234 continue; 1235 while (cur_node) { 1236 scm_scan_apply_filter_get_entry(psoc, 1237 cur_node->entry, filter, scan_list); 1238 next_node = scm_get_next_node(scan_db, 1239 &scan_db->scan_hash_tbl[i], cur_node); 1240 cur_node = next_node; 1241 } 1242 } 1243 } 1244 1245 QDF_STATUS scm_purge_scan_results(qdf_list_t *scan_list) 1246 { 1247 QDF_STATUS status; 1248 struct scan_cache_node *cur_node; 1249 qdf_list_node_t *cur_lst = NULL, *next_lst = NULL; 1250 1251 if (!scan_list) { 1252 scm_err("scan_result is NULL"); 1253 return QDF_STATUS_E_INVAL; 1254 } 1255 1256 status = qdf_list_peek_front(scan_list, &cur_lst); 1257 1258 while (cur_lst) { 1259 qdf_list_peek_next( 1260 scan_list, cur_lst, &next_lst); 1261 cur_node = qdf_container_of(cur_lst, 1262 struct scan_cache_node, node); 1263 status = qdf_list_remove_node(scan_list, 1264 cur_lst); 1265 if (QDF_IS_STATUS_SUCCESS(status)) { 1266 util_scan_free_cache_entry(cur_node->entry); 1267 qdf_mem_free(cur_node); 1268 } 1269 cur_lst = next_lst; 1270 next_lst = NULL; 1271 } 1272 1273 qdf_list_destroy(scan_list); 1274 qdf_mem_free(scan_list); 1275 1276 return status; 1277 } 1278 1279 qdf_list_t *scm_get_scan_result(struct wlan_objmgr_pdev *pdev, 1280 struct scan_filter *filter) 1281 { 1282 struct wlan_objmgr_psoc *psoc; 1283 struct scan_dbs *scan_db; 1284 qdf_list_t *tmp_list; 1285 1286 if (!pdev) { 1287 scm_err("pdev is NULL"); 1288 return NULL; 1289 } 1290 1291 psoc = wlan_pdev_get_psoc(pdev); 1292 if (!psoc) { 1293 scm_err("psoc is NULL"); 1294 return NULL; 1295 } 1296 1297 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1298 if (!scan_db) { 1299 scm_err("scan_db is NULL"); 1300 return NULL; 1301 } 1302 1303 tmp_list = qdf_mem_malloc_atomic(sizeof(*tmp_list)); 1304 if (!tmp_list) { 1305 scm_err("failed tp allocate scan_result"); 1306 return NULL; 1307 } 1308 qdf_list_create(tmp_list, 1309 MAX_SCAN_CACHE_SIZE); 1310 scm_age_out_entries(psoc, scan_db); 1311 scm_get_results(psoc, scan_db, filter, tmp_list); 1312 1313 return tmp_list; 1314 } 1315 1316 /** 1317 * scm_iterate_db_and_call_func() - iterate and call the func 1318 * @scan_db: scan db 1319 * @func: func to be called 1320 * @arg: func arg 1321 * 1322 * Return: QDF_STATUS 1323 */ 1324 static QDF_STATUS 1325 scm_iterate_db_and_call_func(struct scan_dbs *scan_db, 1326 scan_iterator_func func, void *arg) 1327 { 1328 int i; 1329 QDF_STATUS status = QDF_STATUS_SUCCESS; 1330 struct scan_cache_node *cur_node; 1331 struct scan_cache_node *next_node = NULL; 1332 1333 if (!func) 1334 return QDF_STATUS_E_INVAL; 1335 1336 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 1337 cur_node = scm_get_next_node(scan_db, 1338 &scan_db->scan_hash_tbl[i], NULL); 1339 while (cur_node) { 1340 status = func(arg, cur_node->entry); 1341 if (QDF_IS_STATUS_ERROR(status)) { 1342 scm_scan_entry_put_ref(scan_db, 1343 cur_node, true); 1344 return status; 1345 } 1346 next_node = scm_get_next_node(scan_db, 1347 &scan_db->scan_hash_tbl[i], cur_node); 1348 cur_node = next_node; 1349 } 1350 } 1351 1352 return status; 1353 } 1354 1355 QDF_STATUS 1356 scm_iterate_scan_db(struct wlan_objmgr_pdev *pdev, 1357 scan_iterator_func func, void *arg) 1358 { 1359 struct wlan_objmgr_psoc *psoc; 1360 struct scan_dbs *scan_db; 1361 QDF_STATUS status; 1362 1363 if (!func) { 1364 scm_err("func is NULL"); 1365 return QDF_STATUS_E_INVAL; 1366 } 1367 1368 if (!pdev) { 1369 scm_err("pdev is NULL"); 1370 return QDF_STATUS_E_INVAL; 1371 } 1372 1373 psoc = wlan_pdev_get_psoc(pdev); 1374 if (!psoc) { 1375 scm_err("psoc is NULL"); 1376 return QDF_STATUS_E_INVAL; 1377 } 1378 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1379 if (!scan_db) { 1380 scm_err("scan_db is NULL"); 1381 return QDF_STATUS_E_INVAL; 1382 } 1383 1384 scm_age_out_entries(psoc, scan_db); 1385 status = scm_iterate_db_and_call_func(scan_db, func, arg); 1386 1387 return status; 1388 } 1389 1390 /** 1391 * scm_scan_apply_filter_flush_entry() -flush scan entries depending 1392 * on filter 1393 * @psoc: psoc ptr 1394 * @scan_db: scan db 1395 * @db_node: node on which filters are applied 1396 * @filter: filter to be applied 1397 * 1398 * Return: QDF_STATUS 1399 */ 1400 static QDF_STATUS 1401 scm_scan_apply_filter_flush_entry(struct wlan_objmgr_psoc *psoc, 1402 struct scan_dbs *scan_db, 1403 struct scan_cache_node *db_node, 1404 struct scan_filter *filter) 1405 { 1406 struct security_info security = {0}; 1407 bool match; 1408 1409 if (!filter) 1410 match = true; 1411 else 1412 match = scm_filter_match(psoc, db_node->entry, 1413 filter, &security); 1414 1415 if (!match) 1416 return QDF_STATUS_SUCCESS; 1417 1418 qdf_spin_lock_bh(&scan_db->scan_db_lock); 1419 scm_scan_entry_del(scan_db, db_node); 1420 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 1421 1422 return QDF_STATUS_SUCCESS; 1423 } 1424 1425 /** 1426 * scm_flush_scan_entries() - API to flush scan entries depending on filters 1427 * @psoc: psoc ptr 1428 * @scan_db: scan db 1429 * @filter: filter 1430 * 1431 * Return: void 1432 */ 1433 static void scm_flush_scan_entries(struct wlan_objmgr_psoc *psoc, 1434 struct scan_dbs *scan_db, 1435 struct scan_filter *filter) 1436 { 1437 int i; 1438 struct scan_cache_node *cur_node; 1439 struct scan_cache_node *next_node = NULL; 1440 1441 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 1442 cur_node = scm_get_next_node(scan_db, 1443 &scan_db->scan_hash_tbl[i], NULL); 1444 while (cur_node) { 1445 scm_scan_apply_filter_flush_entry(psoc, scan_db, 1446 cur_node, filter); 1447 next_node = scm_get_next_node(scan_db, 1448 &scan_db->scan_hash_tbl[i], cur_node); 1449 cur_node = next_node; 1450 } 1451 } 1452 } 1453 1454 QDF_STATUS scm_flush_results(struct wlan_objmgr_pdev *pdev, 1455 struct scan_filter *filter) 1456 { 1457 struct wlan_objmgr_psoc *psoc; 1458 struct scan_dbs *scan_db; 1459 QDF_STATUS status = QDF_STATUS_SUCCESS; 1460 1461 if (!pdev) { 1462 scm_err("pdev is NULL"); 1463 return QDF_STATUS_E_INVAL; 1464 } 1465 1466 psoc = wlan_pdev_get_psoc(pdev); 1467 if (!psoc) { 1468 scm_err("psoc is NULL"); 1469 return QDF_STATUS_E_INVAL; 1470 } 1471 1472 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1473 if (!scan_db) { 1474 scm_err("scan_db is NULL"); 1475 return QDF_STATUS_E_INVAL; 1476 } 1477 1478 scm_flush_scan_entries(psoc, scan_db, filter); 1479 1480 return status; 1481 } 1482 1483 /** 1484 * scm_filter_channels() - Remove entries not belonging to channel list 1485 * @scan_db: scan db 1486 * @db_node: node on which filters are applied 1487 * @chan_freq_list: valid channel frequency (in MHz) list 1488 * @num_chan: number of channels 1489 * 1490 * Return: QDF_STATUS 1491 */ 1492 static void scm_filter_channels(struct wlan_objmgr_pdev *pdev, 1493 struct scan_dbs *scan_db, 1494 struct scan_cache_node *db_node, 1495 uint32_t *chan_freq_list, uint32_t num_chan) 1496 { 1497 int i; 1498 bool match = false; 1499 1500 for (i = 0; i < num_chan; i++) { 1501 if (chan_freq_list[i] == util_scan_entry_channel_frequency( 1502 db_node->entry)) { 1503 match = true; 1504 break; 1505 } 1506 } 1507 1508 if (!match) { 1509 qdf_spin_lock_bh(&scan_db->scan_db_lock); 1510 scm_scan_entry_del(scan_db, db_node); 1511 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 1512 } 1513 } 1514 1515 void scm_filter_valid_channel(struct wlan_objmgr_pdev *pdev, 1516 uint32_t *chan_freq_list, uint32_t num_chan) 1517 { 1518 int i; 1519 struct wlan_objmgr_psoc *psoc; 1520 struct scan_dbs *scan_db; 1521 struct scan_cache_node *cur_node; 1522 struct scan_cache_node *next_node = NULL; 1523 1524 scm_debug("num_chan = %d", num_chan); 1525 1526 if (!pdev) { 1527 scm_err("pdev is NULL"); 1528 return; 1529 } 1530 1531 psoc = wlan_pdev_get_psoc(pdev); 1532 if (!psoc) { 1533 scm_err("psoc is NULL"); 1534 return; 1535 } 1536 1537 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1538 if (!scan_db) { 1539 scm_err("scan_db is NULL"); 1540 return; 1541 } 1542 1543 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 1544 cur_node = scm_get_next_node(scan_db, 1545 &scan_db->scan_hash_tbl[i], NULL); 1546 while (cur_node) { 1547 scm_filter_channels(pdev, scan_db, 1548 cur_node, chan_freq_list, num_chan); 1549 next_node = scm_get_next_node(scan_db, 1550 &scan_db->scan_hash_tbl[i], cur_node); 1551 cur_node = next_node; 1552 } 1553 } 1554 } 1555 1556 QDF_STATUS scm_scan_register_bcn_cb(struct wlan_objmgr_psoc *psoc, 1557 update_beacon_cb cb, enum scan_cb_type type) 1558 { 1559 struct wlan_scan_obj *scan_obj; 1560 1561 scan_obj = wlan_psoc_get_scan_obj(psoc); 1562 if (!scan_obj) { 1563 scm_err("scan obj is NULL"); 1564 return QDF_STATUS_E_INVAL; 1565 } 1566 switch (type) { 1567 case SCAN_CB_TYPE_INFORM_BCN: 1568 scan_obj->cb.inform_beacon = cb; 1569 break; 1570 case SCAN_CB_TYPE_UPDATE_BCN: 1571 scan_obj->cb.update_beacon = cb; 1572 break; 1573 case SCAN_CB_TYPE_UNLINK_BSS: 1574 scan_obj->cb.unlink_bss = cb; 1575 break; 1576 default: 1577 scm_err("invalid cb type %d", type); 1578 } 1579 1580 return QDF_STATUS_SUCCESS; 1581 } 1582 1583 QDF_STATUS scm_db_init(struct wlan_objmgr_psoc *psoc) 1584 { 1585 int i, j; 1586 struct scan_dbs *scan_db; 1587 1588 if (!psoc) { 1589 scm_err("psoc is NULL"); 1590 return QDF_STATUS_E_INVAL; 1591 } 1592 1593 /* Initialize the scan database per pdev */ 1594 for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) { 1595 scan_db = wlan_pdevid_get_scan_db(psoc, i); 1596 if (!scan_db) { 1597 scm_err("scan_db is NULL %d", i); 1598 continue; 1599 } 1600 scan_db->num_entries = 0; 1601 qdf_spinlock_create(&scan_db->scan_db_lock); 1602 for (j = 0; j < SCAN_HASH_SIZE; j++) 1603 qdf_list_create(&scan_db->scan_hash_tbl[j], 1604 MAX_SCAN_CACHE_SIZE); 1605 } 1606 return QDF_STATUS_SUCCESS; 1607 } 1608 1609 QDF_STATUS scm_db_deinit(struct wlan_objmgr_psoc *psoc) 1610 { 1611 int i, j; 1612 struct scan_dbs *scan_db; 1613 1614 if (!psoc) { 1615 scm_err("scan obj is NULL"); 1616 return QDF_STATUS_E_INVAL; 1617 } 1618 1619 /* Initialize the scan database per pdev */ 1620 for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) { 1621 scan_db = wlan_pdevid_get_scan_db(psoc, i); 1622 if (!scan_db) { 1623 scm_err("scan_db is NULL %d", i); 1624 continue; 1625 } 1626 1627 scm_flush_scan_entries(psoc, scan_db, NULL); 1628 for (j = 0; j < SCAN_HASH_SIZE; j++) 1629 qdf_list_destroy(&scan_db->scan_hash_tbl[j]); 1630 qdf_spinlock_destroy(&scan_db->scan_db_lock); 1631 } 1632 1633 return QDF_STATUS_SUCCESS; 1634 } 1635 1636 #ifdef FEATURE_6G_SCAN_CHAN_SORT_ALGO 1637 QDF_STATUS scm_channel_list_db_init(struct wlan_objmgr_psoc *psoc) 1638 { 1639 uint32_t i, j; 1640 uint32_t min_freq, max_freq; 1641 struct channel_list_db *rnr_channel_db; 1642 1643 min_freq = wlan_reg_min_6ghz_chan_freq(); 1644 max_freq = wlan_reg_max_6ghz_chan_freq(); 1645 1646 scm_info("min_freq %d max_freq %d", min_freq, max_freq); 1647 i = min_freq; 1648 rnr_channel_db = scm_get_rnr_channel_db(psoc); 1649 if (!rnr_channel_db) 1650 return QDF_STATUS_E_INVAL; 1651 1652 for (j = 0; j < QDF_ARRAY_SIZE(rnr_channel_db->channel); j++) { 1653 if (i >= min_freq && i <= max_freq) 1654 rnr_channel_db->channel[j].chan_freq = i; 1655 i += 20; 1656 /* init list for all to avoid uninitialized list */ 1657 qdf_list_create(&rnr_channel_db->channel[j].rnr_list, 1658 WLAN_MAX_RNR_COUNT); 1659 } 1660 return QDF_STATUS_SUCCESS; 1661 } 1662 1663 QDF_STATUS scm_channel_list_db_deinit(struct wlan_objmgr_psoc *psoc) 1664 { 1665 int i; 1666 qdf_list_node_t *cur_node, *next_node; 1667 struct meta_rnr_channel *channel; 1668 struct scan_rnr_node *rnr_node; 1669 struct channel_list_db *rnr_channel_db; 1670 1671 rnr_channel_db = scm_get_rnr_channel_db(psoc); 1672 if (!rnr_channel_db) 1673 return QDF_STATUS_E_INVAL; 1674 1675 for (i = 0; i < QDF_ARRAY_SIZE(rnr_channel_db->channel); i++) { 1676 channel = &rnr_channel_db->channel[i]; 1677 channel->chan_freq = 0; 1678 channel->beacon_probe_last_time_found = 0; 1679 channel->bss_beacon_probe_count = 0; 1680 channel->saved_profile_count = 0; 1681 cur_node = NULL; 1682 qdf_list_peek_front(&channel->rnr_list, &cur_node); 1683 while (cur_node) { 1684 next_node = NULL; 1685 qdf_list_peek_next(&channel->rnr_list, cur_node, 1686 &next_node); 1687 rnr_node = qdf_container_of(cur_node, 1688 struct scan_rnr_node, 1689 node); 1690 qdf_list_remove_node(&channel->rnr_list, 1691 &rnr_node->node); 1692 qdf_mem_free(rnr_node); 1693 cur_node = next_node; 1694 next_node = NULL; 1695 } 1696 qdf_list_destroy(&channel->rnr_list); 1697 } 1698 1699 return QDF_STATUS_SUCCESS; 1700 } 1701 1702 QDF_STATUS scm_rnr_db_flush(struct wlan_objmgr_psoc *psoc) 1703 { 1704 int i; 1705 qdf_list_node_t *cur_node, *next_node; 1706 struct meta_rnr_channel *channel; 1707 struct scan_rnr_node *rnr_node; 1708 struct channel_list_db *rnr_channel_db; 1709 1710 rnr_channel_db = scm_get_rnr_channel_db(psoc); 1711 if (!rnr_channel_db) 1712 return QDF_STATUS_E_INVAL; 1713 1714 for (i = 0; i < QDF_ARRAY_SIZE(rnr_channel_db->channel); i++) { 1715 channel = &rnr_channel_db->channel[i]; 1716 cur_node = NULL; 1717 qdf_list_peek_front(&channel->rnr_list, &cur_node); 1718 while (cur_node) { 1719 next_node = NULL; 1720 qdf_list_peek_next(&channel->rnr_list, cur_node, 1721 &next_node); 1722 rnr_node = qdf_container_of(cur_node, 1723 struct scan_rnr_node, 1724 node); 1725 qdf_list_remove_node(&channel->rnr_list, 1726 &rnr_node->node); 1727 qdf_mem_free(rnr_node); 1728 cur_node = next_node; 1729 next_node = NULL; 1730 } 1731 /* Reset beacon info */ 1732 channel->beacon_probe_last_time_found = 0; 1733 channel->bss_beacon_probe_count = 0; 1734 } 1735 1736 return QDF_STATUS_SUCCESS; 1737 } 1738 1739 void scm_update_rnr_from_scan_cache(struct wlan_objmgr_pdev *pdev) 1740 { 1741 uint8_t i; 1742 struct scan_dbs *scan_db; 1743 struct scan_cache_node *cur_node; 1744 struct scan_cache_node *next_node = NULL; 1745 struct wlan_objmgr_psoc *psoc; 1746 struct scan_cache_entry *entry; 1747 1748 psoc = wlan_pdev_get_psoc(pdev); 1749 if (!psoc) { 1750 scm_err("psoc is NULL"); 1751 return; 1752 } 1753 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1754 if (!scan_db) { 1755 scm_err("scan_db is NULL"); 1756 return; 1757 } 1758 1759 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 1760 cur_node = scm_get_next_node(scan_db, 1761 &scan_db->scan_hash_tbl[i], NULL); 1762 while (cur_node) { 1763 entry = cur_node->entry; 1764 scm_add_rnr_channel_db(psoc, entry); 1765 next_node = 1766 scm_get_next_node(scan_db, 1767 &scan_db->scan_hash_tbl[i], 1768 cur_node); 1769 cur_node = next_node; 1770 next_node = NULL; 1771 } 1772 } 1773 } 1774 #endif 1775 1776 QDF_STATUS scm_update_scan_mlme_info(struct wlan_objmgr_pdev *pdev, 1777 struct scan_cache_entry *entry) 1778 { 1779 uint8_t hash_idx; 1780 struct scan_dbs *scan_db; 1781 struct scan_cache_node *cur_node; 1782 struct scan_cache_node *next_node = NULL; 1783 struct wlan_objmgr_psoc *psoc; 1784 1785 psoc = wlan_pdev_get_psoc(pdev); 1786 if (!psoc) { 1787 scm_err("psoc is NULL"); 1788 return QDF_STATUS_E_INVAL; 1789 } 1790 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1791 if (!scan_db) { 1792 scm_err("scan_db is NULL"); 1793 return QDF_STATUS_E_INVAL; 1794 } 1795 1796 hash_idx = SCAN_GET_HASH(entry->bssid.bytes); 1797 1798 cur_node = scm_get_next_node(scan_db, 1799 &scan_db->scan_hash_tbl[hash_idx], NULL); 1800 1801 while (cur_node) { 1802 if (util_is_scan_entry_match(entry, 1803 cur_node->entry)) { 1804 /* Acquire db lock to prevent simultaneous update */ 1805 qdf_spin_lock_bh(&scan_db->scan_db_lock); 1806 scm_update_mlme_info(entry, cur_node->entry); 1807 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 1808 scm_scan_entry_put_ref(scan_db, 1809 cur_node, true); 1810 return QDF_STATUS_SUCCESS; 1811 } 1812 next_node = scm_get_next_node(scan_db, 1813 &scan_db->scan_hash_tbl[hash_idx], cur_node); 1814 cur_node = next_node; 1815 } 1816 1817 return QDF_STATUS_E_INVAL; 1818 } 1819 1820 QDF_STATUS scm_scan_update_mlme_by_bssinfo(struct wlan_objmgr_pdev *pdev, 1821 struct bss_info *bss_info, struct mlme_info *mlme) 1822 { 1823 uint8_t hash_idx; 1824 struct scan_dbs *scan_db; 1825 struct scan_cache_node *cur_node; 1826 struct scan_cache_node *next_node = NULL; 1827 struct wlan_objmgr_psoc *psoc; 1828 struct scan_cache_entry *entry; 1829 1830 psoc = wlan_pdev_get_psoc(pdev); 1831 if (!psoc) { 1832 scm_err("psoc is NULL"); 1833 return QDF_STATUS_E_INVAL; 1834 } 1835 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1836 if (!scan_db) { 1837 scm_err("scan_db is NULL"); 1838 return QDF_STATUS_E_INVAL; 1839 } 1840 1841 hash_idx = SCAN_GET_HASH(bss_info->bssid.bytes); 1842 cur_node = scm_get_next_node(scan_db, 1843 &scan_db->scan_hash_tbl[hash_idx], NULL); 1844 while (cur_node) { 1845 entry = cur_node->entry; 1846 if (qdf_is_macaddr_equal(&bss_info->bssid, &entry->bssid) && 1847 (util_is_ssid_match(&bss_info->ssid, &entry->ssid)) && 1848 (bss_info->freq == entry->channel.chan_freq)) { 1849 /* Acquire db lock to prevent simultaneous update */ 1850 qdf_spin_lock_bh(&scan_db->scan_db_lock); 1851 qdf_mem_copy(&entry->mlme_info, mlme, 1852 sizeof(struct mlme_info)); 1853 scm_scan_entry_put_ref(scan_db, 1854 cur_node, false); 1855 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 1856 return QDF_STATUS_SUCCESS; 1857 } 1858 next_node = scm_get_next_node(scan_db, 1859 &scan_db->scan_hash_tbl[hash_idx], cur_node); 1860 cur_node = next_node; 1861 } 1862 1863 return QDF_STATUS_E_INVAL; 1864 } 1865