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