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