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