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