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