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 void scm_age_out_entries(struct wlan_objmgr_psoc *psoc, 440 struct scan_dbs *scan_db) 441 { 442 int i; 443 struct scan_cache_node *cur_node = NULL; 444 struct scan_cache_node *next_node = NULL; 445 struct scan_default_params *def_param; 446 447 def_param = wlan_scan_psoc_get_def_params(psoc); 448 if (!def_param) { 449 scm_err("wlan_scan_psoc_get_def_params failed"); 450 return; 451 } 452 453 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 454 cur_node = scm_get_next_node(scan_db, 455 &scan_db->scan_hash_tbl[i], NULL); 456 while (cur_node) { 457 if (!scm_bss_is_connected(cur_node->entry)) 458 scm_check_and_age_out(scan_db, cur_node, 459 def_param->scan_cache_aging_time); 460 next_node = scm_get_next_node(scan_db, 461 &scan_db->scan_hash_tbl[i], cur_node); 462 cur_node = next_node; 463 next_node = NULL; 464 } 465 } 466 } 467 468 /** 469 * scm_flush_oldest_entry() - Iterate over scan db and flust out the 470 * oldest entry 471 * @scan_db: scan db from which oldest entry needs to be flushed 472 * 473 * Return: QDF_STATUS 474 */ 475 static QDF_STATUS scm_flush_oldest_entry(struct scan_dbs *scan_db) 476 { 477 int i; 478 struct scan_cache_node *oldest_node = NULL; 479 struct scan_cache_node *cur_node; 480 481 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 482 /* Get the first valid node for the hash */ 483 cur_node = scm_get_next_node(scan_db, 484 &scan_db->scan_hash_tbl[i], 485 NULL); 486 /* Iterate scan db and flush out oldest node 487 * take ref_cnt for oldest_node 488 */ 489 490 while (cur_node) { 491 if (!oldest_node || 492 (util_scan_entry_age(oldest_node->entry) < 493 util_scan_entry_age(cur_node->entry))) { 494 if (oldest_node) 495 scm_scan_entry_put_ref(scan_db, 496 oldest_node, 497 true); 498 oldest_node = cur_node; 499 scm_scan_entry_get_ref(oldest_node); 500 } 501 502 cur_node = scm_get_next_node(scan_db, 503 &scan_db->scan_hash_tbl[i], 504 cur_node); 505 }; 506 } 507 508 if (oldest_node) { 509 scm_debug("Flush oldest BSSID: %pM with age %lu ms", 510 oldest_node->entry->bssid.bytes, 511 util_scan_entry_age(oldest_node->entry)); 512 /* Release ref_cnt taken for oldest_node and delete it */ 513 qdf_spin_lock_bh(&scan_db->scan_db_lock); 514 scm_scan_entry_del(scan_db, oldest_node); 515 scm_scan_entry_put_ref(scan_db, oldest_node, false); 516 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 517 } 518 519 return QDF_STATUS_SUCCESS; 520 } 521 522 /** 523 * scm_update_alt_wcn_ie() - update the alternate WCN IE 524 * @from: copy from 525 * @dst: copy to 526 * 527 * Return: void 528 */ 529 static void scm_update_alt_wcn_ie(struct scan_cache_entry *from, 530 struct scan_cache_entry *dst) 531 { 532 uint32_t alt_wcn_ie_len; 533 534 if (from->frm_subtype == dst->frm_subtype) 535 return; 536 537 if (!from->ie_list.wcn && !dst->ie_list.wcn) 538 return; 539 540 /* Existing WCN IE is empty. */ 541 if (!from->ie_list.wcn) 542 return; 543 544 alt_wcn_ie_len = 2 + from->ie_list.wcn[1]; 545 if (alt_wcn_ie_len > WLAN_MAX_IE_LEN + 2) { 546 scm_err("invalid IE len"); 547 return; 548 } 549 550 if (!dst->alt_wcn_ie.ptr) { 551 /* allocate this additional buffer for alternate WCN IE */ 552 dst->alt_wcn_ie.ptr = 553 qdf_mem_malloc_atomic(WLAN_MAX_IE_LEN + 2); 554 if (!dst->alt_wcn_ie.ptr) { 555 scm_err("failed to allocate memory"); 556 return; 557 } 558 } 559 qdf_mem_copy(dst->alt_wcn_ie.ptr, 560 from->ie_list.wcn, alt_wcn_ie_len); 561 dst->alt_wcn_ie.len = alt_wcn_ie_len; 562 } 563 564 /** 565 * scm_update_mlme_info() - update mlme info 566 * @src: source scan entry 567 * @dest: destination scan entry 568 * 569 * Return: void 570 */ 571 static inline void 572 scm_update_mlme_info(struct scan_cache_entry *src, 573 struct scan_cache_entry *dest) 574 { 575 qdf_mem_copy(&dest->mlme_info, &src->mlme_info, 576 sizeof(struct mlme_info)); 577 } 578 579 /** 580 * scm_copy_info_from_dup_entry() - copy duplicate node info 581 * to new scan entry 582 * @pdev: pdev ptr 583 * @scan_obj: scan obj ptr 584 * @scan_db: scan database 585 * @scan_params: new entry to be added 586 * @scan_node: duplicate entry 587 * 588 * Copy duplicate node info to new entry. 589 * 590 * Return: void 591 */ 592 static void 593 scm_copy_info_from_dup_entry(struct wlan_objmgr_pdev *pdev, 594 struct wlan_scan_obj *scan_obj, 595 struct scan_dbs *scan_db, 596 struct scan_cache_entry *scan_params, 597 struct scan_cache_node *scan_node) 598 { 599 struct scan_cache_entry *scan_entry; 600 uint64_t time_gap; 601 602 scan_entry = scan_node->entry; 603 604 /* Update probe resp entry as well if AP is in hidden mode */ 605 if (scan_params->frm_subtype == MGMT_SUBTYPE_PROBE_RESP && 606 scan_entry->is_hidden_ssid) 607 scan_params->is_hidden_ssid = true; 608 609 /* 610 * If AP changed its beacon from not having an SSID to showing it the 611 * kernel will drop the entry asumming that something is wrong with AP. 612 * This can result in connection failure while updating the bss during 613 * connection. So flush the hidden entry from kernel before indicating 614 * the new entry. 615 */ 616 if (scan_entry->is_hidden_ssid && 617 scan_params->frm_subtype == MGMT_SUBTYPE_BEACON && 618 !util_scan_is_null_ssid(&scan_params->ssid)) { 619 if (scan_obj->cb.unlink_bss) { 620 scm_debug("Hidden AP %pM switch to non-hidden SSID, So unlink the entry", 621 scan_entry->bssid.bytes); 622 scan_obj->cb.unlink_bss(pdev, scan_entry); 623 } 624 } 625 626 /* If old entry have the ssid but new entry does not */ 627 if (util_scan_is_null_ssid(&scan_params->ssid) && 628 scan_entry->ssid.length) { 629 /* 630 * New entry has a hidden SSID and old one has the SSID. 631 * Add the entry by using the ssid of the old entry 632 * only if diff of saved SSID time and current time is 633 * less than HIDDEN_SSID_TIME time. 634 * This will avoid issues in case AP changes its SSID 635 * while remain hidden. 636 */ 637 time_gap = 638 qdf_mc_timer_get_system_time() - 639 scan_entry->hidden_ssid_timestamp; 640 if (time_gap <= HIDDEN_SSID_TIME) { 641 scan_params->hidden_ssid_timestamp = 642 scan_entry->hidden_ssid_timestamp; 643 scan_params->ssid.length = 644 scan_entry->ssid.length; 645 qdf_mem_copy(scan_params->ssid.ssid, 646 scan_entry->ssid.ssid, 647 scan_entry->ssid.length); 648 } 649 } 650 651 /* 652 * Due to Rx sensitivity issue, sometime beacons are seen on adjacent 653 * channel so workaround in software is needed. If DS params or HT info 654 * are present driver can get proper channel info from these IEs and set 655 * channel_mismatch so that the older RSSI values are used in new entry. 656 * 657 * For the cases where DS params and HT info is not present, driver 658 * needs to check below conditions to get proper channel and set 659 * channel_mismatch so that the older RSSI values are used in new entry: 660 * -- The old entry channel and new entry channel are not same 661 * -- RSSI is less than -80, this indicate that the signal has leaked 662 * in adjacent channel. 663 */ 664 if ((scan_params->frm_subtype == MGMT_SUBTYPE_BEACON) && 665 !util_scan_entry_htinfo(scan_params) && 666 !util_scan_entry_ds_param(scan_params) && 667 (scan_params->channel.chan_freq != scan_entry->channel.chan_freq) && 668 (scan_params->rssi_raw < ADJACENT_CHANNEL_RSSI_THRESHOLD)) { 669 scan_params->channel.chan_freq = scan_entry->channel.chan_freq; 670 scan_params->channel_mismatch = true; 671 } 672 673 /* Use old value for rssi if beacon was heard on adjacent channel. */ 674 if (scan_params->channel_mismatch) { 675 scan_params->snr = scan_entry->snr; 676 scan_params->avg_snr = scan_entry->avg_snr; 677 scan_params->rssi_raw = scan_entry->rssi_raw; 678 scan_params->avg_rssi = scan_entry->avg_rssi; 679 scan_params->rssi_timestamp = 680 scan_entry->rssi_timestamp; 681 } else { 682 /* If elapsed time since last rssi and snr update for this 683 * entry is smaller than a thresold, calculate a 684 * running average of the RSSI and SNR values. 685 * Otherwise new frames RSSI and SNR are more representive 686 * of the signal strength. 687 */ 688 time_gap = 689 scan_params->scan_entry_time - 690 scan_entry->rssi_timestamp; 691 if (time_gap > WLAN_RSSI_AVERAGING_TIME) { 692 scan_params->avg_rssi = 693 WLAN_RSSI_IN(scan_params->rssi_raw); 694 scan_params->avg_snr = 695 WLAN_SNR_IN(scan_params->snr); 696 } 697 else { 698 /* Copy previous average rssi and snr to new entry */ 699 scan_params->avg_snr = scan_entry->avg_snr; 700 scan_params->avg_rssi = scan_entry->avg_rssi; 701 /* Average with previous samples */ 702 WLAN_RSSI_LPF(scan_params->avg_rssi, 703 scan_params->rssi_raw); 704 WLAN_SNR_LPF(scan_params->avg_snr, 705 scan_params->snr); 706 } 707 708 scan_params->rssi_timestamp = scan_params->scan_entry_time; 709 } 710 711 /* copy wsn ie from scan_entry to scan_params*/ 712 scm_update_alt_wcn_ie(scan_entry, scan_params); 713 714 /* copy mlme info from scan_entry to scan_params*/ 715 scm_update_mlme_info(scan_entry, scan_params); 716 } 717 718 /** 719 * scm_find_duplicate() - find duplicate entry, 720 * if present, add input scan entry before it and delete 721 * duplicate entry. otherwise add entry to tail 722 * @pdev: pdev ptr 723 * @scan_obj: scan obj ptr 724 * @scan_db: scan db 725 * @entry: input scan cache entry 726 * @dup_node: node before which new entry to be added 727 * 728 * ref_cnt is taken for dup_node, caller should release ref taken 729 * if returns true. 730 * 731 * Return: bool 732 */ 733 static bool 734 scm_find_duplicate(struct wlan_objmgr_pdev *pdev, 735 struct wlan_scan_obj *scan_obj, 736 struct scan_dbs *scan_db, 737 struct scan_cache_entry *entry, 738 struct scan_cache_node **dup_node) 739 { 740 uint8_t hash_idx; 741 struct scan_cache_node *cur_node; 742 struct scan_cache_node *next_node = NULL; 743 744 hash_idx = SCAN_GET_HASH(entry->bssid.bytes); 745 746 cur_node = scm_get_next_node(scan_db, 747 &scan_db->scan_hash_tbl[hash_idx], 748 NULL); 749 750 while (cur_node) { 751 if (util_is_scan_entry_match(entry, 752 cur_node->entry)) { 753 scm_copy_info_from_dup_entry(pdev, scan_obj, scan_db, 754 entry, cur_node); 755 *dup_node = cur_node; 756 return true; 757 } 758 next_node = scm_get_next_node(scan_db, 759 &scan_db->scan_hash_tbl[hash_idx], cur_node); 760 cur_node = next_node; 761 next_node = NULL; 762 } 763 764 return false; 765 } 766 767 /** 768 * scm_add_update_entry() - add or update scan entry 769 * @psoc: psoc ptr 770 * @pdev: pdev pointer 771 * @scan_params: new received entry 772 * 773 * Return: QDF_STATUS 774 */ 775 static QDF_STATUS scm_add_update_entry(struct wlan_objmgr_psoc *psoc, 776 struct wlan_objmgr_pdev *pdev, struct scan_cache_entry *scan_params) 777 { 778 struct scan_cache_node *dup_node = NULL; 779 struct scan_cache_node *scan_node = NULL; 780 bool is_dup_found = false; 781 QDF_STATUS status; 782 struct scan_dbs *scan_db; 783 struct wlan_scan_obj *scan_obj; 784 uint8_t security_type; 785 786 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 787 if (!scan_db) { 788 scm_err("scan_db is NULL"); 789 return QDF_STATUS_E_INVAL; 790 } 791 792 scan_obj = wlan_psoc_get_scan_obj(psoc); 793 if (!scan_obj) { 794 scm_err("scan_obj is NULL"); 795 return QDF_STATUS_E_INVAL; 796 } 797 798 if (scan_params->frm_subtype == 799 MGMT_SUBTYPE_PROBE_RESP && 800 !scan_params->ie_list.ssid) 801 scm_debug("Probe resp doesn't contain SSID"); 802 803 804 if (scan_params->ie_list.csa || 805 scan_params->ie_list.xcsa || 806 scan_params->ie_list.cswrp) 807 scm_debug("CSA IE present for BSSID: %pM", 808 scan_params->bssid.bytes); 809 810 is_dup_found = scm_find_duplicate(pdev, scan_obj, scan_db, scan_params, 811 &dup_node); 812 813 security_type = scan_params->security_type; 814 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", 815 (scan_params->frm_subtype == MGMT_SUBTYPE_PROBE_RESP) ? 816 "prb rsp" : "bcn", scan_params->bssid.bytes, 817 scan_params->ssid.length, scan_params->ssid.ssid, 818 scan_params->channel.chan_freq, scan_params->rssi_raw, 819 scan_params->tsf_delta, scan_params->seq_num, 820 scan_params->snr, scan_params->phy_mode, 821 scan_params->is_hidden_ssid, 822 scan_params->channel_mismatch, 823 security_type & SCAN_SECURITY_TYPE_WPA ? "[WPA]" : "", 824 security_type & SCAN_SECURITY_TYPE_RSN ? "[RSN]" : "", 825 security_type & SCAN_SECURITY_TYPE_WAPI ? "[WAPI]" : "", 826 security_type & SCAN_SECURITY_TYPE_WEP ? "[WEP]" : "", 827 wlan_objmgr_pdev_get_pdev_id(pdev), 828 scan_params->boottime_ns); 829 830 if (scan_obj->cb.inform_beacon) 831 scan_obj->cb.inform_beacon(pdev, scan_params); 832 833 if (scan_db->num_entries >= MAX_SCAN_CACHE_SIZE) { 834 status = scm_flush_oldest_entry(scan_db); 835 if (QDF_IS_STATUS_ERROR(status)) { 836 /* release ref taken for dup node */ 837 if (is_dup_found) 838 scm_scan_entry_put_ref(scan_db, dup_node, true); 839 return status; 840 } 841 } 842 843 scan_node = qdf_mem_malloc(sizeof(*scan_node)); 844 if (!scan_node) { 845 /* release ref taken for dup node */ 846 if (is_dup_found) 847 scm_scan_entry_put_ref(scan_db, dup_node, true); 848 return QDF_STATUS_E_NOMEM; 849 } 850 851 scan_node->entry = scan_params; 852 qdf_spin_lock_bh(&scan_db->scan_db_lock); 853 scm_add_scan_node(scan_db, scan_node, dup_node); 854 855 if (is_dup_found) { 856 /* release ref taken for dup node and delete it */ 857 scm_scan_entry_del(scan_db, dup_node); 858 scm_scan_entry_put_ref(scan_db, dup_node, false); 859 } 860 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 861 862 return QDF_STATUS_SUCCESS; 863 } 864 865 QDF_STATUS __scm_handle_bcn_probe(struct scan_bcn_probe_event *bcn) 866 { 867 struct wlan_objmgr_psoc *psoc; 868 struct wlan_objmgr_pdev *pdev = NULL; 869 struct scan_cache_entry *scan_entry; 870 struct wlan_scan_obj *scan_obj; 871 qdf_list_t *scan_list = NULL; 872 QDF_STATUS status = QDF_STATUS_SUCCESS; 873 uint32_t list_count, i; 874 qdf_list_node_t *next_node = NULL; 875 struct scan_cache_node *scan_node; 876 struct wlan_frame_hdr *hdr = NULL; 877 878 if (!bcn) { 879 scm_err("bcn is NULL"); 880 return QDF_STATUS_E_INVAL; 881 } 882 if (!bcn->rx_data) { 883 scm_err("rx_data iS NULL"); 884 status = QDF_STATUS_E_INVAL; 885 goto free_nbuf; 886 } 887 if (!bcn->buf) { 888 scm_err("buf is NULL"); 889 status = QDF_STATUS_E_INVAL; 890 goto free_nbuf; 891 } 892 893 hdr = (struct wlan_frame_hdr *)qdf_nbuf_data(bcn->buf); 894 psoc = bcn->psoc; 895 pdev = wlan_objmgr_get_pdev_by_id(psoc, 896 bcn->rx_data->pdev_id, WLAN_SCAN_ID); 897 if (!pdev) { 898 scm_err("pdev is NULL"); 899 status = QDF_STATUS_E_INVAL; 900 goto free_nbuf; 901 } 902 scan_obj = wlan_psoc_get_scan_obj(psoc); 903 if (!scan_obj) { 904 scm_err("scan_obj is NULL"); 905 status = QDF_STATUS_E_INVAL; 906 goto free_nbuf; 907 } 908 909 if (qdf_nbuf_len(bcn->buf) <= 910 (sizeof(struct wlan_frame_hdr) + 911 offsetof(struct wlan_bcn_frame, ie))) { 912 scm_debug("invalid beacon/probe length"); 913 status = QDF_STATUS_E_INVAL; 914 goto free_nbuf; 915 } 916 917 if (bcn->frm_type == MGMT_SUBTYPE_BEACON && 918 wlan_reg_is_dfs_for_freq(pdev, bcn->rx_data->chan_freq)) { 919 util_scan_add_hidden_ssid(pdev, bcn->buf); 920 } 921 922 scan_list = 923 util_scan_unpack_beacon_frame(pdev, qdf_nbuf_data(bcn->buf), 924 qdf_nbuf_len(bcn->buf), bcn->frm_type, 925 bcn->rx_data); 926 if (!scan_list || qdf_list_empty(scan_list)) { 927 scm_debug("failed to unpack %d frame BSSID: %pM", 928 bcn->frm_type, hdr->i_addr3); 929 status = QDF_STATUS_E_INVAL; 930 goto free_nbuf; 931 } 932 933 list_count = qdf_list_size(scan_list); 934 for (i = 0; i < list_count; i++) { 935 status = qdf_list_remove_front(scan_list, &next_node); 936 if (QDF_IS_STATUS_ERROR(status) || !next_node) { 937 scm_debug("list remove failure i:%d, lsize:%d, BSSID: %pM", 938 i, list_count, hdr->i_addr3); 939 status = QDF_STATUS_E_INVAL; 940 goto free_nbuf; 941 } 942 943 scan_node = qdf_container_of(next_node, 944 struct scan_cache_node, node); 945 946 scan_entry = scan_node->entry; 947 948 if (scan_obj->drop_bcn_on_chan_mismatch && 949 scan_entry->channel_mismatch) { 950 scm_nofl_debug("Drop frame for chan mismatch %pM Seq Num: %d freq %d RSSI %d", 951 scan_entry->bssid.bytes, 952 scan_entry->seq_num, 953 scan_entry->channel.chan_freq, 954 scan_entry->rssi_raw); 955 util_scan_free_cache_entry(scan_entry); 956 qdf_mem_free(scan_node); 957 continue; 958 } 959 /* Do not add invalid channel entry as kernel will reject it */ 960 if (scan_obj->drop_bcn_on_invalid_freq && 961 wlan_reg_is_disable_for_freq(pdev, 962 scan_entry->channel.chan_freq)) { 963 scm_nofl_debug("Drop frame for invalid freq %d: %pM Seq Num: %d RSSI %d", 964 scan_entry->channel.chan_freq, 965 scan_entry->bssid.bytes, 966 scan_entry->seq_num, 967 scan_entry->rssi_raw); 968 util_scan_free_cache_entry(scan_entry); 969 qdf_mem_free(scan_node); 970 continue; 971 } 972 if (scan_obj->cb.update_beacon) 973 scan_obj->cb.update_beacon(pdev, scan_entry); 974 975 if (wlan_reg_11d_enabled_on_host(psoc)) 976 scm_11d_handle_country_info(psoc, pdev, scan_entry); 977 978 status = scm_add_update_entry(psoc, pdev, scan_entry); 979 if (QDF_IS_STATUS_ERROR(status)) { 980 scm_debug("failed to add entry for BSSID: %pM Seq Num: %d", 981 scan_entry->bssid.bytes, 982 scan_entry->seq_num); 983 util_scan_free_cache_entry(scan_entry); 984 qdf_mem_free(scan_node); 985 continue; 986 } 987 988 qdf_mem_free(scan_node); 989 } 990 991 free_nbuf: 992 if (scan_list) 993 qdf_mem_free(scan_list); 994 if (bcn->psoc) 995 wlan_objmgr_psoc_release_ref(bcn->psoc, WLAN_SCAN_ID); 996 if (pdev) 997 wlan_objmgr_pdev_release_ref(pdev, WLAN_SCAN_ID); 998 if (bcn->rx_data) 999 qdf_mem_free(bcn->rx_data); 1000 if (bcn->buf) 1001 qdf_nbuf_free(bcn->buf); 1002 qdf_mem_free(bcn); 1003 1004 return status; 1005 } 1006 1007 QDF_STATUS scm_handle_bcn_probe(struct scheduler_msg *msg) 1008 { 1009 if (!msg) { 1010 scm_err("msg is NULL"); 1011 return QDF_STATUS_E_NULL_VALUE; 1012 } 1013 1014 return __scm_handle_bcn_probe(msg->bodyptr); 1015 } 1016 1017 /** 1018 * scm_scan_apply_filter_get_entry() - apply filter and get the 1019 * scan entry 1020 * @psoc: psoc pointer 1021 * @db_entry: scan entry 1022 * @filter: filter to be applied 1023 * @scan_list: scan list to which entry is added 1024 * 1025 * Return: QDF_STATUS 1026 */ 1027 static QDF_STATUS 1028 scm_scan_apply_filter_get_entry(struct wlan_objmgr_psoc *psoc, 1029 struct scan_cache_entry *db_entry, 1030 struct scan_filter *filter, 1031 qdf_list_t *scan_list) 1032 { 1033 struct scan_cache_node *scan_node = NULL; 1034 struct security_info security = {0}; 1035 bool match; 1036 1037 if (!filter) 1038 match = true; 1039 else 1040 match = scm_filter_match(psoc, db_entry, 1041 filter, &security); 1042 1043 if (!match) 1044 return QDF_STATUS_SUCCESS; 1045 1046 scan_node = qdf_mem_malloc_atomic(sizeof(*scan_node)); 1047 if (!scan_node) 1048 return QDF_STATUS_E_NOMEM; 1049 1050 scan_node->entry = 1051 util_scan_copy_cache_entry(db_entry); 1052 1053 if (!scan_node->entry) { 1054 qdf_mem_free(scan_node); 1055 return QDF_STATUS_E_NOMEM; 1056 } 1057 1058 qdf_mem_copy(&scan_node->entry->neg_sec_info, 1059 &security, sizeof(scan_node->entry->neg_sec_info)); 1060 1061 qdf_list_insert_front(scan_list, &scan_node->node); 1062 1063 return QDF_STATUS_SUCCESS; 1064 } 1065 1066 /** 1067 * scm_get_results() - Iterate and get scan results 1068 * @psoc: psoc ptr 1069 * @scan_db: scan db 1070 * @filter: filter to be applied 1071 * @scan_list: scan list to which entry is added 1072 * 1073 * Return: void 1074 */ 1075 static void scm_get_results(struct wlan_objmgr_psoc *psoc, 1076 struct scan_dbs *scan_db, struct scan_filter *filter, 1077 qdf_list_t *scan_list) 1078 { 1079 int i, count; 1080 struct scan_cache_node *cur_node; 1081 struct scan_cache_node *next_node = NULL; 1082 1083 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 1084 cur_node = scm_get_next_node(scan_db, 1085 &scan_db->scan_hash_tbl[i], NULL); 1086 count = qdf_list_size(&scan_db->scan_hash_tbl[i]); 1087 if (!count) 1088 continue; 1089 while (cur_node) { 1090 scm_scan_apply_filter_get_entry(psoc, 1091 cur_node->entry, filter, scan_list); 1092 next_node = scm_get_next_node(scan_db, 1093 &scan_db->scan_hash_tbl[i], cur_node); 1094 cur_node = next_node; 1095 } 1096 } 1097 } 1098 1099 QDF_STATUS scm_purge_scan_results(qdf_list_t *scan_list) 1100 { 1101 QDF_STATUS status; 1102 struct scan_cache_node *cur_node; 1103 qdf_list_node_t *cur_lst = NULL, *next_lst = NULL; 1104 1105 if (!scan_list) { 1106 scm_err("scan_result is NULL"); 1107 return QDF_STATUS_E_INVAL; 1108 } 1109 1110 status = qdf_list_peek_front(scan_list, &cur_lst); 1111 1112 while (cur_lst) { 1113 qdf_list_peek_next( 1114 scan_list, cur_lst, &next_lst); 1115 cur_node = qdf_container_of(cur_lst, 1116 struct scan_cache_node, node); 1117 status = qdf_list_remove_node(scan_list, 1118 cur_lst); 1119 if (QDF_IS_STATUS_SUCCESS(status)) { 1120 util_scan_free_cache_entry(cur_node->entry); 1121 qdf_mem_free(cur_node); 1122 } 1123 cur_lst = next_lst; 1124 next_lst = NULL; 1125 } 1126 1127 qdf_list_destroy(scan_list); 1128 qdf_mem_free(scan_list); 1129 1130 return status; 1131 } 1132 1133 qdf_list_t *scm_get_scan_result(struct wlan_objmgr_pdev *pdev, 1134 struct scan_filter *filter) 1135 { 1136 struct wlan_objmgr_psoc *psoc; 1137 struct scan_dbs *scan_db; 1138 qdf_list_t *tmp_list; 1139 1140 if (!pdev) { 1141 scm_err("pdev is NULL"); 1142 return NULL; 1143 } 1144 1145 psoc = wlan_pdev_get_psoc(pdev); 1146 if (!psoc) { 1147 scm_err("psoc is NULL"); 1148 return NULL; 1149 } 1150 1151 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1152 if (!scan_db) { 1153 scm_err("scan_db is NULL"); 1154 return NULL; 1155 } 1156 1157 tmp_list = qdf_mem_malloc_atomic(sizeof(*tmp_list)); 1158 if (!tmp_list) { 1159 scm_err("failed tp allocate scan_result"); 1160 return NULL; 1161 } 1162 qdf_list_create(tmp_list, 1163 MAX_SCAN_CACHE_SIZE); 1164 scm_age_out_entries(psoc, scan_db); 1165 scm_get_results(psoc, scan_db, filter, tmp_list); 1166 1167 return tmp_list; 1168 } 1169 1170 /** 1171 * scm_iterate_db_and_call_func() - iterate and call the func 1172 * @scan_db: scan db 1173 * @func: func to be called 1174 * @arg: func arg 1175 * 1176 * Return: QDF_STATUS 1177 */ 1178 static QDF_STATUS 1179 scm_iterate_db_and_call_func(struct scan_dbs *scan_db, 1180 scan_iterator_func func, void *arg) 1181 { 1182 int i; 1183 QDF_STATUS status = QDF_STATUS_SUCCESS; 1184 struct scan_cache_node *cur_node; 1185 struct scan_cache_node *next_node = NULL; 1186 1187 if (!func) 1188 return QDF_STATUS_E_INVAL; 1189 1190 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 1191 cur_node = scm_get_next_node(scan_db, 1192 &scan_db->scan_hash_tbl[i], NULL); 1193 while (cur_node) { 1194 status = func(arg, cur_node->entry); 1195 if (QDF_IS_STATUS_ERROR(status)) { 1196 scm_scan_entry_put_ref(scan_db, 1197 cur_node, true); 1198 return status; 1199 } 1200 next_node = scm_get_next_node(scan_db, 1201 &scan_db->scan_hash_tbl[i], cur_node); 1202 cur_node = next_node; 1203 } 1204 } 1205 1206 return status; 1207 } 1208 1209 QDF_STATUS 1210 scm_iterate_scan_db(struct wlan_objmgr_pdev *pdev, 1211 scan_iterator_func func, void *arg) 1212 { 1213 struct wlan_objmgr_psoc *psoc; 1214 struct scan_dbs *scan_db; 1215 QDF_STATUS status; 1216 1217 if (!func) { 1218 scm_err("func is NULL"); 1219 return QDF_STATUS_E_INVAL; 1220 } 1221 1222 if (!pdev) { 1223 scm_err("pdev is NULL"); 1224 return QDF_STATUS_E_INVAL; 1225 } 1226 1227 psoc = wlan_pdev_get_psoc(pdev); 1228 if (!psoc) { 1229 scm_err("psoc is NULL"); 1230 return QDF_STATUS_E_INVAL; 1231 } 1232 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1233 if (!scan_db) { 1234 scm_err("scan_db is NULL"); 1235 return QDF_STATUS_E_INVAL; 1236 } 1237 1238 scm_age_out_entries(psoc, scan_db); 1239 status = scm_iterate_db_and_call_func(scan_db, func, arg); 1240 1241 return status; 1242 } 1243 1244 /** 1245 * scm_scan_apply_filter_flush_entry() -flush scan entries depending 1246 * on filter 1247 * @psoc: psoc ptr 1248 * @scan_db: scan db 1249 * @db_node: node on which filters are applied 1250 * @filter: filter to be applied 1251 * 1252 * Return: QDF_STATUS 1253 */ 1254 static QDF_STATUS 1255 scm_scan_apply_filter_flush_entry(struct wlan_objmgr_psoc *psoc, 1256 struct scan_dbs *scan_db, 1257 struct scan_cache_node *db_node, 1258 struct scan_filter *filter) 1259 { 1260 struct security_info security = {0}; 1261 bool match; 1262 1263 if (!filter) 1264 match = true; 1265 else 1266 match = scm_filter_match(psoc, db_node->entry, 1267 filter, &security); 1268 1269 if (!match) 1270 return QDF_STATUS_SUCCESS; 1271 1272 qdf_spin_lock_bh(&scan_db->scan_db_lock); 1273 scm_scan_entry_del(scan_db, db_node); 1274 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 1275 1276 return QDF_STATUS_SUCCESS; 1277 } 1278 1279 /** 1280 * scm_flush_scan_entries() - API to flush scan entries depending on filters 1281 * @psoc: psoc ptr 1282 * @scan_db: scan db 1283 * @filter: filter 1284 * 1285 * Return: void 1286 */ 1287 static void scm_flush_scan_entries(struct wlan_objmgr_psoc *psoc, 1288 struct scan_dbs *scan_db, 1289 struct scan_filter *filter) 1290 { 1291 int i; 1292 struct scan_cache_node *cur_node; 1293 struct scan_cache_node *next_node = NULL; 1294 1295 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 1296 cur_node = scm_get_next_node(scan_db, 1297 &scan_db->scan_hash_tbl[i], NULL); 1298 while (cur_node) { 1299 scm_scan_apply_filter_flush_entry(psoc, scan_db, 1300 cur_node, filter); 1301 next_node = scm_get_next_node(scan_db, 1302 &scan_db->scan_hash_tbl[i], cur_node); 1303 cur_node = next_node; 1304 } 1305 } 1306 } 1307 1308 QDF_STATUS scm_flush_results(struct wlan_objmgr_pdev *pdev, 1309 struct scan_filter *filter) 1310 { 1311 struct wlan_objmgr_psoc *psoc; 1312 struct scan_dbs *scan_db; 1313 QDF_STATUS status = QDF_STATUS_SUCCESS; 1314 1315 if (!pdev) { 1316 scm_err("pdev is NULL"); 1317 return QDF_STATUS_E_INVAL; 1318 } 1319 1320 psoc = wlan_pdev_get_psoc(pdev); 1321 if (!psoc) { 1322 scm_err("psoc is NULL"); 1323 return QDF_STATUS_E_INVAL; 1324 } 1325 1326 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1327 if (!scan_db) { 1328 scm_err("scan_db is NULL"); 1329 return QDF_STATUS_E_INVAL; 1330 } 1331 1332 scm_flush_scan_entries(psoc, scan_db, filter); 1333 1334 return status; 1335 } 1336 1337 /** 1338 * scm_filter_channels() - Remove entries not belonging to channel list 1339 * @scan_db: scan db 1340 * @db_node: node on which filters are applied 1341 * @chan_freq_list: valid channel frequency (in MHz) list 1342 * @num_chan: number of channels 1343 * 1344 * Return: QDF_STATUS 1345 */ 1346 static void scm_filter_channels(struct wlan_objmgr_pdev *pdev, 1347 struct scan_dbs *scan_db, 1348 struct scan_cache_node *db_node, 1349 uint32_t *chan_freq_list, uint32_t num_chan) 1350 { 1351 int i; 1352 bool match = false; 1353 1354 for (i = 0; i < num_chan; i++) { 1355 if (chan_freq_list[i] == util_scan_entry_channel_frequency( 1356 db_node->entry)) { 1357 match = true; 1358 break; 1359 } 1360 } 1361 1362 if (!match) { 1363 qdf_spin_lock_bh(&scan_db->scan_db_lock); 1364 scm_scan_entry_del(scan_db, db_node); 1365 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 1366 } 1367 } 1368 1369 void scm_filter_valid_channel(struct wlan_objmgr_pdev *pdev, 1370 uint32_t *chan_freq_list, uint32_t num_chan) 1371 { 1372 int i; 1373 struct wlan_objmgr_psoc *psoc; 1374 struct scan_dbs *scan_db; 1375 struct scan_cache_node *cur_node; 1376 struct scan_cache_node *next_node = NULL; 1377 1378 scm_debug("num_chan = %d", num_chan); 1379 1380 if (!pdev) { 1381 scm_err("pdev is NULL"); 1382 return; 1383 } 1384 1385 psoc = wlan_pdev_get_psoc(pdev); 1386 if (!psoc) { 1387 scm_err("psoc is NULL"); 1388 return; 1389 } 1390 1391 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1392 if (!scan_db) { 1393 scm_err("scan_db is NULL"); 1394 return; 1395 } 1396 1397 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 1398 cur_node = scm_get_next_node(scan_db, 1399 &scan_db->scan_hash_tbl[i], NULL); 1400 while (cur_node) { 1401 scm_filter_channels(pdev, scan_db, 1402 cur_node, chan_freq_list, num_chan); 1403 next_node = scm_get_next_node(scan_db, 1404 &scan_db->scan_hash_tbl[i], cur_node); 1405 cur_node = next_node; 1406 } 1407 } 1408 } 1409 1410 QDF_STATUS scm_scan_register_bcn_cb(struct wlan_objmgr_psoc *psoc, 1411 update_beacon_cb cb, enum scan_cb_type type) 1412 { 1413 struct wlan_scan_obj *scan_obj; 1414 1415 scan_obj = wlan_psoc_get_scan_obj(psoc); 1416 if (!scan_obj) { 1417 scm_err("scan obj is NULL"); 1418 return QDF_STATUS_E_INVAL; 1419 } 1420 switch (type) { 1421 case SCAN_CB_TYPE_INFORM_BCN: 1422 scan_obj->cb.inform_beacon = cb; 1423 break; 1424 case SCAN_CB_TYPE_UPDATE_BCN: 1425 scan_obj->cb.update_beacon = cb; 1426 break; 1427 case SCAN_CB_TYPE_UNLINK_BSS: 1428 scan_obj->cb.unlink_bss = cb; 1429 break; 1430 default: 1431 scm_err("invalid cb type %d", type); 1432 } 1433 1434 return QDF_STATUS_SUCCESS; 1435 } 1436 1437 QDF_STATUS scm_db_init(struct wlan_objmgr_psoc *psoc) 1438 { 1439 int i, j; 1440 struct scan_dbs *scan_db; 1441 1442 if (!psoc) { 1443 scm_err("psoc is NULL"); 1444 return QDF_STATUS_E_INVAL; 1445 } 1446 1447 /* Initialize the scan database per pdev */ 1448 for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) { 1449 scan_db = wlan_pdevid_get_scan_db(psoc, i); 1450 if (!scan_db) { 1451 scm_err("scan_db is NULL %d", i); 1452 continue; 1453 } 1454 scan_db->num_entries = 0; 1455 qdf_spinlock_create(&scan_db->scan_db_lock); 1456 for (j = 0; j < SCAN_HASH_SIZE; j++) 1457 qdf_list_create(&scan_db->scan_hash_tbl[j], 1458 MAX_SCAN_CACHE_SIZE); 1459 } 1460 return QDF_STATUS_SUCCESS; 1461 } 1462 1463 QDF_STATUS scm_db_deinit(struct wlan_objmgr_psoc *psoc) 1464 { 1465 int i, j; 1466 struct scan_dbs *scan_db; 1467 1468 if (!psoc) { 1469 scm_err("scan obj is NULL"); 1470 return QDF_STATUS_E_INVAL; 1471 } 1472 1473 /* Initialize the scan database per pdev */ 1474 for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) { 1475 scan_db = wlan_pdevid_get_scan_db(psoc, i); 1476 if (!scan_db) { 1477 scm_err("scan_db is NULL %d", i); 1478 continue; 1479 } 1480 1481 scm_flush_scan_entries(psoc, scan_db, NULL); 1482 for (j = 0; j < SCAN_HASH_SIZE; j++) 1483 qdf_list_destroy(&scan_db->scan_hash_tbl[j]); 1484 qdf_spinlock_destroy(&scan_db->scan_db_lock); 1485 } 1486 1487 return QDF_STATUS_SUCCESS; 1488 } 1489 1490 #ifdef FEATURE_6G_SCAN_CHAN_SORT_ALGO 1491 QDF_STATUS scm_channel_list_db_init(struct wlan_objmgr_psoc *psoc) 1492 { 1493 uint32_t i, j; 1494 uint32_t min_freq, max_freq; 1495 struct channel_list_db *rnr_channel_db; 1496 1497 min_freq = wlan_reg_min_6ghz_chan_freq(); 1498 max_freq = wlan_reg_max_6ghz_chan_freq(); 1499 1500 scm_info("min_freq %d max_freq %d", min_freq, max_freq); 1501 i = min_freq; 1502 rnr_channel_db = scm_get_rnr_channel_db(psoc); 1503 if (!rnr_channel_db) 1504 return QDF_STATUS_E_INVAL; 1505 1506 for (j = 0; j < QDF_ARRAY_SIZE(rnr_channel_db->channel); j++) { 1507 if (i >= min_freq && i <= max_freq) 1508 rnr_channel_db->channel[j].chan_freq = i; 1509 i += 20; 1510 /* init list for all to avoid uninitialized list */ 1511 qdf_list_create(&rnr_channel_db->channel[j].rnr_list, 1512 WLAN_MAX_RNR_COUNT); 1513 } 1514 return QDF_STATUS_SUCCESS; 1515 } 1516 1517 QDF_STATUS scm_channel_list_db_deinit(struct wlan_objmgr_psoc *psoc) 1518 { 1519 int i; 1520 qdf_list_node_t *cur_node, *next_node; 1521 struct meta_rnr_channel *channel; 1522 struct scan_rnr_node *rnr_node; 1523 struct channel_list_db *rnr_channel_db; 1524 1525 rnr_channel_db = scm_get_rnr_channel_db(psoc); 1526 if (!rnr_channel_db) 1527 return QDF_STATUS_E_INVAL; 1528 1529 for (i = 0; i < QDF_ARRAY_SIZE(rnr_channel_db->channel); i++) { 1530 channel = &rnr_channel_db->channel[i]; 1531 channel->chan_freq = 0; 1532 channel->beacon_probe_last_time_found = 0; 1533 channel->bss_beacon_probe_count = 0; 1534 channel->saved_profile_count = 0; 1535 cur_node = NULL; 1536 qdf_list_peek_front(&channel->rnr_list, &cur_node); 1537 while (cur_node) { 1538 next_node = NULL; 1539 qdf_list_peek_next(&channel->rnr_list, cur_node, 1540 &next_node); 1541 rnr_node = qdf_container_of(cur_node, 1542 struct scan_rnr_node, 1543 node); 1544 qdf_list_remove_node(&channel->rnr_list, 1545 &rnr_node->node); 1546 qdf_mem_free(rnr_node); 1547 cur_node = next_node; 1548 next_node = NULL; 1549 } 1550 qdf_list_destroy(&channel->rnr_list); 1551 } 1552 1553 return QDF_STATUS_SUCCESS; 1554 } 1555 1556 QDF_STATUS scm_rnr_db_flush(struct wlan_objmgr_psoc *psoc) 1557 { 1558 int i; 1559 qdf_list_node_t *cur_node, *next_node; 1560 struct meta_rnr_channel *channel; 1561 struct scan_rnr_node *rnr_node; 1562 struct channel_list_db *rnr_channel_db; 1563 1564 rnr_channel_db = scm_get_rnr_channel_db(psoc); 1565 if (!rnr_channel_db) 1566 return QDF_STATUS_E_INVAL; 1567 1568 for (i = 0; i < QDF_ARRAY_SIZE(rnr_channel_db->channel); i++) { 1569 channel = &rnr_channel_db->channel[i]; 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 /* Reset beacon info */ 1586 channel->beacon_probe_last_time_found = 0; 1587 channel->bss_beacon_probe_count = 0; 1588 } 1589 1590 return QDF_STATUS_SUCCESS; 1591 } 1592 1593 void scm_update_rnr_from_scan_cache(struct wlan_objmgr_pdev *pdev) 1594 { 1595 uint8_t i; 1596 struct scan_dbs *scan_db; 1597 struct scan_cache_node *cur_node; 1598 struct scan_cache_node *next_node = NULL; 1599 struct wlan_objmgr_psoc *psoc; 1600 struct scan_cache_entry *entry; 1601 1602 psoc = wlan_pdev_get_psoc(pdev); 1603 if (!psoc) { 1604 scm_err("psoc is NULL"); 1605 return; 1606 } 1607 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1608 if (!scan_db) { 1609 scm_err("scan_db is NULL"); 1610 return; 1611 } 1612 1613 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 1614 cur_node = scm_get_next_node(scan_db, 1615 &scan_db->scan_hash_tbl[i], NULL); 1616 while (cur_node) { 1617 entry = cur_node->entry; 1618 scm_add_rnr_channel_db(psoc, entry); 1619 next_node = 1620 scm_get_next_node(scan_db, 1621 &scan_db->scan_hash_tbl[i], 1622 cur_node); 1623 cur_node = next_node; 1624 next_node = NULL; 1625 } 1626 } 1627 } 1628 #endif 1629 1630 QDF_STATUS scm_update_scan_mlme_info(struct wlan_objmgr_pdev *pdev, 1631 struct scan_cache_entry *entry) 1632 { 1633 uint8_t hash_idx; 1634 struct scan_dbs *scan_db; 1635 struct scan_cache_node *cur_node; 1636 struct scan_cache_node *next_node = NULL; 1637 struct wlan_objmgr_psoc *psoc; 1638 1639 psoc = wlan_pdev_get_psoc(pdev); 1640 if (!psoc) { 1641 scm_err("psoc is NULL"); 1642 return QDF_STATUS_E_INVAL; 1643 } 1644 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1645 if (!scan_db) { 1646 scm_err("scan_db is NULL"); 1647 return QDF_STATUS_E_INVAL; 1648 } 1649 1650 hash_idx = SCAN_GET_HASH(entry->bssid.bytes); 1651 1652 cur_node = scm_get_next_node(scan_db, 1653 &scan_db->scan_hash_tbl[hash_idx], NULL); 1654 1655 while (cur_node) { 1656 if (util_is_scan_entry_match(entry, 1657 cur_node->entry)) { 1658 /* Acquire db lock to prevent simultaneous update */ 1659 qdf_spin_lock_bh(&scan_db->scan_db_lock); 1660 scm_update_mlme_info(entry, cur_node->entry); 1661 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 1662 scm_scan_entry_put_ref(scan_db, 1663 cur_node, true); 1664 return QDF_STATUS_SUCCESS; 1665 } 1666 next_node = scm_get_next_node(scan_db, 1667 &scan_db->scan_hash_tbl[hash_idx], cur_node); 1668 cur_node = next_node; 1669 } 1670 1671 return QDF_STATUS_E_INVAL; 1672 } 1673 1674 QDF_STATUS scm_scan_update_mlme_by_bssinfo(struct wlan_objmgr_pdev *pdev, 1675 struct bss_info *bss_info, struct mlme_info *mlme) 1676 { 1677 uint8_t hash_idx; 1678 struct scan_dbs *scan_db; 1679 struct scan_cache_node *cur_node; 1680 struct scan_cache_node *next_node = NULL; 1681 struct wlan_objmgr_psoc *psoc; 1682 struct scan_cache_entry *entry; 1683 1684 psoc = wlan_pdev_get_psoc(pdev); 1685 if (!psoc) { 1686 scm_err("psoc is NULL"); 1687 return QDF_STATUS_E_INVAL; 1688 } 1689 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1690 if (!scan_db) { 1691 scm_err("scan_db is NULL"); 1692 return QDF_STATUS_E_INVAL; 1693 } 1694 1695 hash_idx = SCAN_GET_HASH(bss_info->bssid.bytes); 1696 cur_node = scm_get_next_node(scan_db, 1697 &scan_db->scan_hash_tbl[hash_idx], NULL); 1698 while (cur_node) { 1699 entry = cur_node->entry; 1700 if (qdf_is_macaddr_equal(&bss_info->bssid, &entry->bssid) && 1701 (util_is_ssid_match(&bss_info->ssid, &entry->ssid)) && 1702 (bss_info->freq == entry->channel.chan_freq)) { 1703 /* Acquire db lock to prevent simultaneous update */ 1704 qdf_spin_lock_bh(&scan_db->scan_db_lock); 1705 qdf_mem_copy(&entry->mlme_info, mlme, 1706 sizeof(struct mlme_info)); 1707 scm_scan_entry_put_ref(scan_db, 1708 cur_node, false); 1709 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 1710 return QDF_STATUS_SUCCESS; 1711 } 1712 next_node = scm_get_next_node(scan_db, 1713 &scan_db->scan_hash_tbl[hash_idx], cur_node); 1714 cur_node = next_node; 1715 } 1716 1717 return QDF_STATUS_E_INVAL; 1718 } 1719