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