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