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 = qdf_mem_malloc(WLAN_MAX_IE_LEN + 2); 446 if (!dst->alt_wcn_ie.ptr) { 447 scm_err("failed to allocate memory"); 448 return; 449 } 450 } 451 qdf_mem_copy(dst->alt_wcn_ie.ptr, 452 from->ie_list.wcn, alt_wcn_ie_len); 453 dst->alt_wcn_ie.len = alt_wcn_ie_len; 454 } 455 456 /** 457 * scm_update_mlme_info() - update mlme info 458 * @src: source scan entry 459 * @dest: destination scan entry 460 * 461 * Return: void 462 */ 463 static inline void 464 scm_update_mlme_info(struct scan_cache_entry *src, 465 struct scan_cache_entry *dest) 466 { 467 qdf_mem_copy(&dest->mlme_info, &src->mlme_info, 468 sizeof(struct mlme_info)); 469 } 470 471 /** 472 * scm_copy_info_from_dup_entry() - copy duplicate node info 473 * to new scan entry 474 * @scan_db: scan database 475 * @scan_params: new entry to be added 476 * @scan_node: duplicate entry 477 * 478 * Copy duplicate node info to new entry. 479 * 480 * Return: void 481 */ 482 static void 483 scm_copy_info_from_dup_entry(struct scan_dbs *scan_db, 484 struct scan_cache_entry *scan_params, 485 struct scan_cache_node *scan_node) 486 { 487 struct scan_cache_entry *scan_entry; 488 uint64_t time_gap; 489 490 scan_entry = scan_node->entry; 491 /* If old entry have the ssid but new entry does not */ 492 if (!scan_params->ssid.length && scan_entry->ssid.length) { 493 /* 494 * New entry has a hidden SSID and old one has the SSID. 495 * Add the entry by using the ssid of the old entry 496 * only if diff of saved SSID time and current time is 497 * less than HIDDEN_SSID_TIME time. 498 * This will avoid issues in case AP changes its SSID 499 * while remain hidden. 500 */ 501 time_gap = 502 qdf_mc_timer_get_system_time() - 503 scan_entry->hidden_ssid_timestamp; 504 if (time_gap <= HIDDEN_SSID_TIME) { 505 scan_params->hidden_ssid_timestamp = 506 scan_entry->hidden_ssid_timestamp; 507 scan_params->ssid.length = 508 scan_entry->ssid.length; 509 qdf_mem_copy(scan_params->ssid.ssid, 510 scan_entry->ssid.ssid, 511 scan_params->ssid.length); 512 } 513 } 514 515 /* 516 * Due to Rx sensitivity issue, sometime beacons are seen on adjacent 517 * channel so workaround in software is needed. If DS params or HT info 518 * are present driver can get proper channel info from these IEs and set 519 * channel_mismatch so that the older RSSI values are used in new entry. 520 * 521 * For the cases where DS params and HT info is not present, driver 522 * needs to check below conditions to get proper channel and set 523 * channel_mismatch so that the older RSSI values are used in new entry: 524 * -- The old entry channel and new entry channel are not same 525 * -- RSSI is less than -80, this indicate that the signal has leaked 526 * in adjacent channel. 527 */ 528 if ((scan_params->frm_subtype == MGMT_SUBTYPE_BEACON) && 529 !util_scan_entry_htinfo(scan_params) && 530 !util_scan_entry_ds_param(scan_params) && 531 (scan_params->channel.chan_idx != scan_entry->channel.chan_idx) && 532 (scan_params->rssi_raw < ADJACENT_CHANNEL_RSSI_THRESHOLD)) { 533 scan_params->channel.chan_idx = scan_entry->channel.chan_idx; 534 scan_params->channel_mismatch = true; 535 } 536 537 /* Use old value for rssi if beacon was heard on adjacent channel. */ 538 if (scan_params->channel_mismatch) { 539 scan_params->rssi_raw = scan_entry->rssi_raw; 540 scan_params->avg_rssi = scan_entry->avg_rssi; 541 scan_params->rssi_timestamp = 542 scan_entry->rssi_timestamp; 543 } else { 544 /* If elapsed time since last rssi update for this 545 * entry is smaller than a thresold, calculate a 546 * running average of the RSSI values. 547 * Otherwise new frames RSSI is more representive 548 * of the signal strength. 549 */ 550 time_gap = 551 scan_params->scan_entry_time - 552 scan_entry->rssi_timestamp; 553 if (time_gap > WLAN_RSSI_AVERAGING_TIME) 554 scan_params->avg_rssi = 555 WLAN_RSSI_IN(scan_params->rssi_raw); 556 else { 557 /* Copy previous average rssi to new entry */ 558 scan_params->avg_rssi = scan_entry->avg_rssi; 559 /* Average with previous samples */ 560 WLAN_RSSI_LPF(scan_params->avg_rssi, 561 scan_params->rssi_raw); 562 } 563 564 scan_params->rssi_timestamp = scan_params->scan_entry_time; 565 } 566 567 /* copy wsn ie from scan_entry to scan_params*/ 568 scm_update_alt_wcn_ie(scan_entry, scan_params); 569 570 /* copy mlme info from scan_entry to scan_params*/ 571 scm_update_mlme_info(scan_entry, scan_params); 572 } 573 574 /** 575 * scm_find_duplicate() - find duplicate entry, 576 * if present, add input scan entry before it and delete 577 * duplicate entry. otherwise add entry to tail 578 * @scan_db: scan db 579 * @entry: input scan cache entry 580 * @dup_node: node before which new entry to be added 581 * 582 * ref_cnt is taken for dup_node, caller should release ref taken 583 * if returns true. 584 * 585 * Return: bool 586 */ 587 static bool 588 scm_find_duplicate(struct scan_dbs *scan_db, 589 struct scan_cache_entry *entry, 590 struct scan_cache_node **dup_node) 591 { 592 uint8_t hash_idx; 593 struct scan_cache_node *cur_node; 594 struct scan_cache_node *next_node = NULL; 595 596 hash_idx = SCAN_GET_HASH(entry->bssid.bytes); 597 598 cur_node = scm_get_next_node(scan_db, 599 &scan_db->scan_hash_tbl[hash_idx], 600 NULL); 601 602 while (cur_node) { 603 if (util_is_scan_entry_match(entry, 604 cur_node->entry)) { 605 scm_copy_info_from_dup_entry(scan_db, entry, cur_node); 606 *dup_node = cur_node; 607 return true; 608 } 609 next_node = scm_get_next_node(scan_db, 610 &scan_db->scan_hash_tbl[hash_idx], cur_node); 611 cur_node = next_node; 612 next_node = NULL; 613 } 614 615 return false; 616 } 617 618 /** 619 * scm_add_update_entry() - add or update scan entry 620 * @psoc: psoc ptr 621 * @pdev: pdev pointer 622 * @scan_params: new received entry 623 * 624 * Return: QDF_STATUS 625 */ 626 static QDF_STATUS scm_add_update_entry(struct wlan_objmgr_psoc *psoc, 627 struct wlan_objmgr_pdev *pdev, struct scan_cache_entry *scan_params) 628 { 629 struct scan_cache_node *dup_node = NULL; 630 struct scan_cache_node *scan_node = NULL; 631 bool is_dup_found = false; 632 QDF_STATUS status; 633 struct scan_dbs *scan_db; 634 struct wlan_scan_obj *scan_obj; 635 636 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 637 if (!scan_db) { 638 scm_err("scan_db is NULL"); 639 return QDF_STATUS_E_INVAL; 640 } 641 642 scan_obj = wlan_psoc_get_scan_obj(psoc); 643 if (!scan_obj) { 644 scm_err("scan_obj is NULL"); 645 return QDF_STATUS_E_INVAL; 646 } 647 648 if (scan_params->frm_subtype == 649 MGMT_SUBTYPE_PROBE_RESP && 650 !scan_params->ie_list.ssid) 651 scm_info("Probe resp doesn't contain SSID"); 652 653 654 if (scan_params->ie_list.csa || 655 scan_params->ie_list.xcsa || 656 scan_params->ie_list.cswrp) 657 scm_info("CSA IE present for BSSID: %pM", 658 scan_params->bssid.bytes); 659 660 is_dup_found = scm_find_duplicate(scan_db, scan_params, &dup_node); 661 662 if (scan_obj->cb.inform_beacon) 663 scan_obj->cb.inform_beacon(pdev, scan_params); 664 665 if (scan_db->num_entries >= MAX_SCAN_CACHE_SIZE) { 666 status = scm_flush_oldest_entry(scan_db); 667 if (QDF_IS_STATUS_ERROR(status)) { 668 /* release ref taken for dup node */ 669 if (is_dup_found) 670 scm_scan_entry_put_ref(scan_db, dup_node, true); 671 return status; 672 } 673 } 674 675 scan_node = qdf_mem_malloc(sizeof(*scan_node)); 676 if (!scan_node) { 677 /* release ref taken for dup node */ 678 if (is_dup_found) 679 scm_scan_entry_put_ref(scan_db, dup_node, true); 680 return QDF_STATUS_E_NOMEM; 681 } 682 683 scan_node->entry = scan_params; 684 qdf_spin_lock_bh(&scan_db->scan_db_lock); 685 scm_add_scan_node(scan_db, scan_node, dup_node); 686 687 if (is_dup_found) { 688 /* release ref taken for dup node and delete it */ 689 scm_scan_entry_del(scan_db, dup_node); 690 scm_scan_entry_put_ref(scan_db, dup_node, false); 691 } 692 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 693 694 return QDF_STATUS_SUCCESS; 695 } 696 697 QDF_STATUS scm_handle_bcn_probe(struct scheduler_msg *msg) 698 { 699 struct scan_bcn_probe_event *bcn; 700 struct wlan_objmgr_psoc *psoc; 701 struct wlan_objmgr_pdev *pdev = NULL; 702 struct scan_cache_entry *scan_entry; 703 struct wlan_scan_obj *scan_obj; 704 qdf_list_t *scan_list = NULL; 705 QDF_STATUS status = QDF_STATUS_SUCCESS; 706 uint32_t list_count, i; 707 qdf_list_node_t *next_node = NULL; 708 struct scan_cache_node *scan_node; 709 710 bcn = msg->bodyptr; 711 if (!bcn) { 712 scm_err("bcn is NULL"); 713 return QDF_STATUS_E_INVAL; 714 } 715 if (!bcn->rx_data) { 716 scm_err("rx_data iS NULL"); 717 status = QDF_STATUS_E_INVAL; 718 goto free_nbuf; 719 } 720 if (!bcn->buf) { 721 scm_err("buf is NULL"); 722 status = QDF_STATUS_E_INVAL; 723 goto free_nbuf; 724 } 725 726 psoc = bcn->psoc; 727 pdev = wlan_objmgr_get_pdev_by_id(psoc, 728 bcn->rx_data->pdev_id, WLAN_SCAN_ID); 729 if (!pdev) { 730 scm_err("pdev is NULL"); 731 status = QDF_STATUS_E_INVAL; 732 goto free_nbuf; 733 } 734 scan_obj = wlan_psoc_get_scan_obj(psoc); 735 if (!scan_obj) { 736 scm_err("scan_obj is NULL"); 737 status = QDF_STATUS_E_INVAL; 738 goto free_nbuf; 739 } 740 741 if (qdf_nbuf_len(bcn->buf) <= 742 (sizeof(struct wlan_frame_hdr) + 743 offsetof(struct wlan_bcn_frame, ie))) { 744 scm_debug("invalid beacon/probe length"); 745 status = QDF_STATUS_E_INVAL; 746 goto free_nbuf; 747 } 748 749 scan_list = 750 util_scan_unpack_beacon_frame(pdev, qdf_nbuf_data(bcn->buf), 751 qdf_nbuf_len(bcn->buf), bcn->frm_type, 752 bcn->rx_data); 753 if (!scan_list || qdf_list_empty(scan_list)) { 754 scm_debug("failed to unpack frame"); 755 status = QDF_STATUS_E_INVAL; 756 goto free_nbuf; 757 } 758 759 list_count = qdf_list_size(scan_list); 760 for (i = 0; i < list_count; i++) { 761 status = qdf_list_remove_front(scan_list, &next_node); 762 if (QDF_IS_STATUS_ERROR(status) || next_node == NULL) { 763 scm_debug("failed to unpack frame"); 764 status = QDF_STATUS_E_INVAL; 765 goto free_nbuf; 766 } 767 768 scan_node = qdf_container_of(next_node, 769 struct scan_cache_node, node); 770 771 scan_entry = scan_node->entry; 772 773 scm_debug("Received %s from BSSID: %pM tsf_delta = %u Seq Num: %x ssid:%.*s, rssi: %d", 774 (bcn->frm_type == MGMT_SUBTYPE_PROBE_RESP) ? 775 "Probe Rsp" : "Beacon", scan_entry->bssid.bytes, 776 scan_entry->tsf_delta, scan_entry->seq_num, 777 scan_entry->ssid.length, scan_entry->ssid.ssid, 778 scan_entry->rssi_raw); 779 780 if (scan_obj->drop_bcn_on_chan_mismatch && 781 scan_entry->channel_mismatch) { 782 scm_debug("Drop frame, as channel mismatch Received for from BSSID: %pM ", 783 scan_entry->bssid.bytes); 784 util_scan_free_cache_entry(scan_entry); 785 qdf_mem_free(scan_node); 786 continue; 787 } 788 789 if (scan_obj->cb.update_beacon) 790 scan_obj->cb.update_beacon(pdev, scan_entry); 791 792 if (wlan_reg_11d_enabled_on_host(psoc)) 793 scm_11d_handle_country_info(psoc, pdev, scan_entry); 794 795 status = scm_add_update_entry(psoc, pdev, scan_entry); 796 if (QDF_IS_STATUS_ERROR(status)) { 797 scm_debug("failed to add entry for BSSID: %pM", 798 scan_entry->bssid.bytes); 799 util_scan_free_cache_entry(scan_entry); 800 qdf_mem_free(scan_node); 801 continue; 802 } 803 804 qdf_mem_free(scan_node); 805 } 806 807 free_nbuf: 808 if (scan_list) 809 qdf_mem_free(scan_list); 810 if (bcn->psoc) 811 wlan_objmgr_psoc_release_ref(bcn->psoc, WLAN_SCAN_ID); 812 if (pdev) 813 wlan_objmgr_pdev_release_ref(pdev, WLAN_SCAN_ID); 814 if (bcn->rx_data) 815 qdf_mem_free(bcn->rx_data); 816 if (bcn->buf) 817 qdf_nbuf_free(bcn->buf); 818 qdf_mem_free(bcn); 819 820 return status; 821 } 822 823 /** 824 * scm_list_insert_sorted() - add the entries in scan_list in sorted way 825 * @psoc: psoc ptr 826 * @filter: scan filter 827 * @scan_node: node entry to be inserted 828 * @scan_list: Temp scan list 829 * 830 * Add the entries in scan_list in sorted way considering 831 * cap_val and prefer val. The node is copy of original scan entry and 832 * thus no lock is required. 833 * 834 * Return: void 835 */ 836 static void scm_list_insert_sorted(struct wlan_objmgr_psoc *psoc, 837 struct scan_filter *filter, 838 struct scan_cache_node *scan_node, 839 qdf_list_t *scan_list) 840 { 841 struct scan_cache_node *cur_node; 842 qdf_list_node_t *cur_lst = NULL, *next_lst = NULL; 843 struct scan_default_params *params; 844 int pcl_chan_weight = 0; 845 846 params = wlan_scan_psoc_get_def_params(psoc); 847 if (!params) { 848 scm_err("wlan_scan_psoc_get_def_params failed"); 849 return; 850 } 851 852 if (filter->num_of_pcl_channels > 0 && 853 (scan_node->entry->rssi_raw > SCM_PCL_RSSI_THRESHOLD)) { 854 if (scm_get_pcl_weight_of_channel( 855 scan_node->entry->channel.chan_idx, 856 filter, &pcl_chan_weight, 857 filter->pcl_weight_list)) { 858 scm_debug("pcl channel %d pcl_chan_weight %d", 859 scan_node->entry->channel.chan_idx, 860 pcl_chan_weight); 861 } 862 } 863 if (params->is_bssid_hint_priority && 864 !qdf_mem_cmp(filter->bssid_hint.bytes, 865 scan_node->entry->bssid.bytes, 866 QDF_MAC_ADDR_SIZE)) 867 scan_node->entry->bss_score = BEST_CANDIDATE_MAX_BSS_SCORE; 868 else 869 scm_calculate_bss_score(psoc, params, 870 scan_node->entry, pcl_chan_weight); 871 872 if (qdf_list_empty(scan_list)) { 873 qdf_list_insert_front(scan_list, &scan_node->node); 874 return; 875 } 876 877 qdf_list_peek_front(scan_list, &cur_lst); 878 879 while (cur_lst) { 880 cur_node = qdf_container_of(cur_lst, 881 struct scan_cache_node, node); 882 if (scm_is_better_bss(params, 883 scan_node->entry, cur_node->entry)) { 884 qdf_list_insert_before(scan_list, 885 &scan_node->node, 886 &cur_node->node); 887 break; 888 } 889 qdf_list_peek_next(scan_list, 890 cur_lst, &next_lst); 891 cur_lst = next_lst; 892 next_lst = NULL; 893 } 894 895 if (!cur_lst) 896 qdf_list_insert_back(scan_list, 897 &scan_node->node); 898 899 } 900 901 /** 902 * scm_scan_apply_filter_get_entry() - apply filter and get the 903 * scan entry 904 * @psoc: psoc pointer 905 * @db_entry: scan entry 906 * @filter: filter to be applied 907 * @scan_list: scan list to which entry is added 908 * 909 * Return: QDF_STATUS 910 */ 911 static QDF_STATUS 912 scm_scan_apply_filter_get_entry(struct wlan_objmgr_psoc *psoc, 913 struct scan_cache_entry *db_entry, 914 struct scan_filter *filter, 915 qdf_list_t *scan_list) 916 { 917 struct scan_cache_node *scan_node = NULL; 918 struct security_info security = {0}; 919 bool match; 920 921 if (!filter) 922 match = true; 923 else 924 match = scm_filter_match(psoc, db_entry, 925 filter, &security); 926 927 if (!match) 928 return QDF_STATUS_SUCCESS; 929 930 scan_node = qdf_mem_malloc(sizeof(*scan_node)); 931 if (!scan_node) 932 return QDF_STATUS_E_NOMEM; 933 934 scan_node->entry = 935 util_scan_copy_cache_entry(db_entry); 936 937 if (!scan_node->entry) { 938 qdf_mem_free(scan_node); 939 return QDF_STATUS_E_NOMEM; 940 } 941 942 qdf_mem_copy(&scan_node->entry->neg_sec_info, 943 &security, sizeof(scan_node->entry->neg_sec_info)); 944 945 if (!filter || !filter->bss_scoring_required) 946 qdf_list_insert_front(scan_list, 947 &scan_node->node); 948 else 949 scm_list_insert_sorted(psoc, filter, scan_node, scan_list); 950 951 return QDF_STATUS_SUCCESS; 952 } 953 954 /** 955 * scm_get_results() - Iterate and get scan results 956 * @psoc: psoc ptr 957 * @scan_db: scan db 958 * @filter: filter to be applied 959 * @scan_list: scan list to which entry is added 960 * 961 * Return: void 962 */ 963 static void scm_get_results(struct wlan_objmgr_psoc *psoc, 964 struct scan_dbs *scan_db, struct scan_filter *filter, 965 qdf_list_t *scan_list) 966 { 967 int i, count; 968 struct scan_cache_node *cur_node; 969 struct scan_cache_node *next_node = NULL; 970 971 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 972 cur_node = scm_get_next_node(scan_db, 973 &scan_db->scan_hash_tbl[i], NULL); 974 count = qdf_list_size(&scan_db->scan_hash_tbl[i]); 975 if (!count) 976 continue; 977 while (cur_node) { 978 scm_scan_apply_filter_get_entry(psoc, 979 cur_node->entry, filter, scan_list); 980 next_node = scm_get_next_node(scan_db, 981 &scan_db->scan_hash_tbl[i], cur_node); 982 cur_node = next_node; 983 } 984 } 985 } 986 987 QDF_STATUS scm_purge_scan_results(qdf_list_t *scan_list) 988 { 989 QDF_STATUS status; 990 struct scan_cache_node *cur_node; 991 qdf_list_node_t *cur_lst = NULL, *next_lst = NULL; 992 993 if (!scan_list) { 994 scm_err("scan_result is NULL"); 995 return QDF_STATUS_E_INVAL; 996 } 997 998 status = qdf_list_peek_front(scan_list, &cur_lst); 999 1000 while (cur_lst) { 1001 qdf_list_peek_next( 1002 scan_list, cur_lst, &next_lst); 1003 cur_node = qdf_container_of(cur_lst, 1004 struct scan_cache_node, node); 1005 status = qdf_list_remove_node(scan_list, 1006 cur_lst); 1007 if (QDF_IS_STATUS_SUCCESS(status)) { 1008 util_scan_free_cache_entry(cur_node->entry); 1009 qdf_mem_free(cur_node); 1010 } 1011 cur_lst = next_lst; 1012 next_lst = NULL; 1013 } 1014 1015 qdf_list_destroy(scan_list); 1016 qdf_mem_free(scan_list); 1017 1018 return status; 1019 } 1020 1021 qdf_list_t *scm_get_scan_result(struct wlan_objmgr_pdev *pdev, 1022 struct scan_filter *filter) 1023 { 1024 struct wlan_objmgr_psoc *psoc; 1025 struct scan_dbs *scan_db; 1026 qdf_list_t *tmp_list; 1027 1028 if (!pdev) { 1029 scm_err("pdev is NULL"); 1030 return NULL; 1031 } 1032 1033 psoc = wlan_pdev_get_psoc(pdev); 1034 if (!psoc) { 1035 scm_err("psoc is NULL"); 1036 return NULL; 1037 } 1038 1039 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1040 if (!scan_db) { 1041 scm_err("scan_db is NULL"); 1042 return NULL; 1043 } 1044 1045 tmp_list = qdf_mem_malloc(sizeof(*tmp_list)); 1046 if (!tmp_list) { 1047 scm_err("failed tp allocate scan_result"); 1048 return NULL; 1049 } 1050 qdf_list_create(tmp_list, 1051 MAX_SCAN_CACHE_SIZE); 1052 scm_age_out_entries(psoc, scan_db); 1053 scm_get_results(psoc, scan_db, filter, tmp_list); 1054 1055 return tmp_list; 1056 } 1057 1058 /** 1059 * scm_iterate_db_and_call_func() - iterate and call the func 1060 * @scan_db: scan db 1061 * @func: func to be called 1062 * @arg: func arg 1063 * 1064 * Return: QDF_STATUS 1065 */ 1066 static QDF_STATUS 1067 scm_iterate_db_and_call_func(struct scan_dbs *scan_db, 1068 scan_iterator_func func, void *arg) 1069 { 1070 int i; 1071 QDF_STATUS status = QDF_STATUS_SUCCESS; 1072 struct scan_cache_node *cur_node; 1073 struct scan_cache_node *next_node = NULL; 1074 1075 if (!func) 1076 return QDF_STATUS_E_INVAL; 1077 1078 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 1079 cur_node = scm_get_next_node(scan_db, 1080 &scan_db->scan_hash_tbl[i], NULL); 1081 while (cur_node) { 1082 status = func(arg, cur_node->entry); 1083 if (QDF_IS_STATUS_ERROR(status)) { 1084 scm_scan_entry_put_ref(scan_db, 1085 cur_node, true); 1086 return status; 1087 } 1088 next_node = scm_get_next_node(scan_db, 1089 &scan_db->scan_hash_tbl[i], cur_node); 1090 cur_node = next_node; 1091 } 1092 } 1093 1094 return status; 1095 } 1096 1097 QDF_STATUS 1098 scm_iterate_scan_db(struct wlan_objmgr_pdev *pdev, 1099 scan_iterator_func func, void *arg) 1100 { 1101 struct wlan_objmgr_psoc *psoc; 1102 struct scan_dbs *scan_db; 1103 QDF_STATUS status; 1104 1105 if (!func) { 1106 scm_err("func is NULL"); 1107 return QDF_STATUS_E_INVAL; 1108 } 1109 1110 if (!pdev) { 1111 scm_err("pdev is NULL"); 1112 return QDF_STATUS_E_INVAL; 1113 } 1114 1115 psoc = wlan_pdev_get_psoc(pdev); 1116 if (!psoc) { 1117 scm_err("psoc is NULL"); 1118 return QDF_STATUS_E_INVAL; 1119 } 1120 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1121 if (!scan_db) { 1122 scm_err("scan_db is NULL"); 1123 return QDF_STATUS_E_INVAL; 1124 } 1125 1126 scm_age_out_entries(psoc, scan_db); 1127 status = scm_iterate_db_and_call_func(scan_db, func, arg); 1128 1129 return status; 1130 } 1131 1132 /** 1133 * scm_scan_apply_filter_flush_entry() -flush scan entries depending 1134 * on filter 1135 * @psoc: psoc ptr 1136 * @scan_db: scan db 1137 * @db_node: node on which filters are applied 1138 * @filter: filter to be applied 1139 * 1140 * Return: QDF_STATUS 1141 */ 1142 static QDF_STATUS 1143 scm_scan_apply_filter_flush_entry(struct wlan_objmgr_psoc *psoc, 1144 struct scan_dbs *scan_db, 1145 struct scan_cache_node *db_node, 1146 struct scan_filter *filter) 1147 { 1148 struct security_info security = {0}; 1149 bool match; 1150 1151 if (!filter) 1152 match = true; 1153 else 1154 match = scm_filter_match(psoc, db_node->entry, 1155 filter, &security); 1156 1157 if (!match) 1158 return QDF_STATUS_SUCCESS; 1159 1160 qdf_spin_lock_bh(&scan_db->scan_db_lock); 1161 scm_scan_entry_del(scan_db, db_node); 1162 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 1163 1164 return QDF_STATUS_SUCCESS; 1165 } 1166 1167 /** 1168 * scm_flush_scan_entries() - API to flush scan entries depending on filters 1169 * @psoc: psoc ptr 1170 * @scan_db: scan db 1171 * @filter: filter 1172 * 1173 * Return: void 1174 */ 1175 static void scm_flush_scan_entries(struct wlan_objmgr_psoc *psoc, 1176 struct scan_dbs *scan_db, 1177 struct scan_filter *filter) 1178 { 1179 int i; 1180 struct scan_cache_node *cur_node; 1181 struct scan_cache_node *next_node = NULL; 1182 1183 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 1184 cur_node = scm_get_next_node(scan_db, 1185 &scan_db->scan_hash_tbl[i], NULL); 1186 while (cur_node) { 1187 scm_scan_apply_filter_flush_entry(psoc, scan_db, 1188 cur_node, filter); 1189 next_node = scm_get_next_node(scan_db, 1190 &scan_db->scan_hash_tbl[i], cur_node); 1191 cur_node = next_node; 1192 } 1193 } 1194 } 1195 1196 QDF_STATUS scm_flush_results(struct wlan_objmgr_pdev *pdev, 1197 struct scan_filter *filter) 1198 { 1199 struct wlan_objmgr_psoc *psoc; 1200 struct scan_dbs *scan_db; 1201 QDF_STATUS status = QDF_STATUS_SUCCESS; 1202 1203 if (!pdev) { 1204 scm_err("pdev is NULL"); 1205 return QDF_STATUS_E_INVAL; 1206 } 1207 1208 psoc = wlan_pdev_get_psoc(pdev); 1209 if (!psoc) { 1210 scm_err("psoc is NULL"); 1211 return QDF_STATUS_E_INVAL; 1212 } 1213 1214 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1215 if (!scan_db) { 1216 scm_err("scan_db is NULL"); 1217 return QDF_STATUS_E_INVAL; 1218 } 1219 1220 scm_flush_scan_entries(psoc, scan_db, filter); 1221 1222 return status; 1223 } 1224 1225 /** 1226 * scm_filter_channels() - Remove entries not belonging to channel list 1227 * @scan_db: scan db 1228 * @db_node: node on which filters are applied 1229 * @chan_list: valid channel list 1230 * @num_chan: number of channels 1231 * 1232 * Return: QDF_STATUS 1233 */ 1234 static void scm_filter_channels(struct scan_dbs *scan_db, 1235 struct scan_cache_node *db_node, 1236 uint8_t *chan_list, uint32_t num_chan) 1237 { 1238 int i; 1239 bool match = false; 1240 1241 for (i = 0; i < num_chan; i++) { 1242 if (chan_list[i] == 1243 util_scan_entry_channel_num(db_node->entry)) { 1244 match = true; 1245 break; 1246 } 1247 } 1248 1249 if (!match) { 1250 qdf_spin_lock_bh(&scan_db->scan_db_lock); 1251 scm_scan_entry_del(scan_db, db_node); 1252 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 1253 } 1254 } 1255 1256 void scm_filter_valid_channel(struct wlan_objmgr_pdev *pdev, 1257 uint8_t *chan_list, uint32_t num_chan) 1258 { 1259 int i; 1260 struct wlan_objmgr_psoc *psoc; 1261 struct scan_dbs *scan_db; 1262 struct scan_cache_node *cur_node; 1263 struct scan_cache_node *next_node = NULL; 1264 1265 scm_info("num_chan = %d", num_chan); 1266 1267 if (!pdev) { 1268 scm_err("pdev is NULL"); 1269 return; 1270 } 1271 1272 psoc = wlan_pdev_get_psoc(pdev); 1273 if (!psoc) { 1274 scm_err("psoc is NULL"); 1275 return; 1276 } 1277 1278 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1279 if (!scan_db) { 1280 scm_err("scan_db is NULL"); 1281 return; 1282 } 1283 1284 for (i = 0 ; i < SCAN_HASH_SIZE; i++) { 1285 cur_node = scm_get_next_node(scan_db, 1286 &scan_db->scan_hash_tbl[i], NULL); 1287 while (cur_node) { 1288 scm_filter_channels(scan_db, 1289 cur_node, chan_list, num_chan); 1290 next_node = scm_get_next_node(scan_db, 1291 &scan_db->scan_hash_tbl[i], cur_node); 1292 cur_node = next_node; 1293 } 1294 } 1295 } 1296 1297 QDF_STATUS scm_scan_register_bcn_cb(struct wlan_objmgr_psoc *psoc, 1298 update_beacon_cb cb, enum scan_cb_type type) 1299 { 1300 struct wlan_scan_obj *scan_obj; 1301 1302 scan_obj = wlan_psoc_get_scan_obj(psoc); 1303 if (!scan_obj) { 1304 scm_err("scan obj is NULL"); 1305 return QDF_STATUS_E_INVAL; 1306 } 1307 switch (type) { 1308 case SCAN_CB_TYPE_INFORM_BCN: 1309 scan_obj->cb.inform_beacon = cb; 1310 break; 1311 case SCAN_CB_TYPE_UPDATE_BCN: 1312 scan_obj->cb.update_beacon = cb; 1313 break; 1314 default: 1315 scm_err("invalid cb type %d", type); 1316 } 1317 1318 return QDF_STATUS_SUCCESS; 1319 } 1320 1321 QDF_STATUS scm_db_init(struct wlan_objmgr_psoc *psoc) 1322 { 1323 int i, j; 1324 struct scan_dbs *scan_db; 1325 1326 if (!psoc) { 1327 scm_err("psoc is NULL"); 1328 return QDF_STATUS_E_INVAL; 1329 } 1330 1331 /* Initialize the scan database per pdev */ 1332 for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) { 1333 scan_db = wlan_pdevid_get_scan_db(psoc, i); 1334 if (!scan_db) { 1335 scm_err("scan_db is NULL %d", i); 1336 continue; 1337 } 1338 scan_db->num_entries = 0; 1339 qdf_spinlock_create(&scan_db->scan_db_lock); 1340 for (j = 0; j < SCAN_HASH_SIZE; j++) 1341 qdf_list_create(&scan_db->scan_hash_tbl[j], 1342 MAX_SCAN_CACHE_SIZE); 1343 } 1344 1345 return QDF_STATUS_SUCCESS; 1346 } 1347 1348 QDF_STATUS scm_db_deinit(struct wlan_objmgr_psoc *psoc) 1349 { 1350 int i, j; 1351 struct scan_dbs *scan_db; 1352 1353 if (!psoc) { 1354 scm_err("scan obj is NULL"); 1355 return QDF_STATUS_E_INVAL; 1356 } 1357 1358 /* Initialize the scan database per pdev */ 1359 for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) { 1360 scan_db = wlan_pdevid_get_scan_db(psoc, i); 1361 if (!scan_db) { 1362 scm_err("scan_db is NULL %d", i); 1363 continue; 1364 } 1365 1366 scm_flush_scan_entries(psoc, scan_db, NULL); 1367 for (j = 0; j < SCAN_HASH_SIZE; j++) 1368 qdf_list_destroy(&scan_db->scan_hash_tbl[j]); 1369 qdf_spinlock_destroy(&scan_db->scan_db_lock); 1370 } 1371 1372 return QDF_STATUS_SUCCESS; 1373 } 1374 1375 QDF_STATUS scm_update_scan_mlme_info(struct wlan_objmgr_pdev *pdev, 1376 struct scan_cache_entry *entry) 1377 { 1378 uint8_t hash_idx; 1379 struct scan_dbs *scan_db; 1380 struct scan_cache_node *cur_node; 1381 struct scan_cache_node *next_node = NULL; 1382 struct wlan_objmgr_psoc *psoc; 1383 1384 psoc = wlan_pdev_get_psoc(pdev); 1385 if (!psoc) { 1386 scm_err("psoc is NULL"); 1387 return QDF_STATUS_E_INVAL; 1388 } 1389 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1390 if (!scan_db) { 1391 scm_err("scan_db is NULL"); 1392 return QDF_STATUS_E_INVAL; 1393 } 1394 1395 hash_idx = SCAN_GET_HASH(entry->bssid.bytes); 1396 1397 cur_node = scm_get_next_node(scan_db, 1398 &scan_db->scan_hash_tbl[hash_idx], NULL); 1399 1400 while (cur_node) { 1401 if (util_is_scan_entry_match(entry, 1402 cur_node->entry)) { 1403 /* Acquire db lock to prevent simultaneous update */ 1404 qdf_spin_lock_bh(&scan_db->scan_db_lock); 1405 scm_update_mlme_info(entry, cur_node->entry); 1406 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 1407 scm_scan_entry_put_ref(scan_db, 1408 cur_node, true); 1409 return QDF_STATUS_SUCCESS; 1410 } 1411 next_node = scm_get_next_node(scan_db, 1412 &scan_db->scan_hash_tbl[hash_idx], cur_node); 1413 cur_node = next_node; 1414 } 1415 1416 return QDF_STATUS_E_INVAL; 1417 } 1418 1419 QDF_STATUS scm_scan_update_mlme_by_bssinfo(struct wlan_objmgr_pdev *pdev, 1420 struct bss_info *bss_info, struct mlme_info *mlme) 1421 { 1422 uint8_t hash_idx; 1423 struct scan_dbs *scan_db; 1424 struct scan_cache_node *cur_node; 1425 struct scan_cache_node *next_node = NULL; 1426 struct wlan_objmgr_psoc *psoc; 1427 struct scan_cache_entry *entry; 1428 1429 psoc = wlan_pdev_get_psoc(pdev); 1430 if (!psoc) { 1431 scm_err("psoc is NULL"); 1432 return QDF_STATUS_E_INVAL; 1433 } 1434 scan_db = wlan_pdev_get_scan_db(psoc, pdev); 1435 if (!scan_db) { 1436 scm_err("scan_db is NULL"); 1437 return QDF_STATUS_E_INVAL; 1438 } 1439 1440 hash_idx = SCAN_GET_HASH(bss_info->bssid.bytes); 1441 cur_node = scm_get_next_node(scan_db, 1442 &scan_db->scan_hash_tbl[hash_idx], NULL); 1443 while (cur_node) { 1444 entry = cur_node->entry; 1445 if (qdf_is_macaddr_equal(&bss_info->bssid, &entry->bssid) && 1446 (util_is_ssid_match(&bss_info->ssid, &entry->ssid)) && 1447 (bss_info->chan == entry->channel.chan_idx)) { 1448 /* Acquire db lock to prevent simultaneous update */ 1449 qdf_spin_lock_bh(&scan_db->scan_db_lock); 1450 qdf_mem_copy(&entry->mlme_info, mlme, 1451 sizeof(struct mlme_info)); 1452 scm_scan_entry_put_ref(scan_db, 1453 cur_node, false); 1454 qdf_spin_unlock_bh(&scan_db->scan_db_lock); 1455 return QDF_STATUS_SUCCESS; 1456 } 1457 next_node = scm_get_next_node(scan_db, 1458 &scan_db->scan_hash_tbl[hash_idx], cur_node); 1459 cur_node = next_node; 1460 } 1461 1462 return QDF_STATUS_E_INVAL; 1463 } 1464