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