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