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