1 /*
2 * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /*
21 * DOC: contains scan cache api and functionality
22 * The Scan entries are protected by scan_db_lock. Holding the lock
23 * for whole scan operation during get/flush scan results may take
24 * more than 5 ms and thus ref count is used along with scan_db_lock.
25 * Below are the operation on scan cache entry:
26 * - While adding new node to the entry scan_db_lock is taken and ref_cnt
27 * is initialized and incremented. Also the cookie will be set to valid value.
28 * - The ref count incremented during adding new node should be decremented only
29 * by a delete operation on the node. But there can be multiple concurrent
30 * delete operations on a node from different threads which may lead to ref
31 * count being decremented multiple time and freeing the node even if node
32 * is in use. So to maintain atomicity between multiple delete operations
33 * on a same node from different threads, a cookie is used to check if node is
34 * logically deleted or not. A delete operation will set the cookie to 0
35 * making it invalid. So if the 2nd thread find the cookie as invalid it will
36 * not try to delete and decrement the ref count of the node again.
37 * - This Cookie is also used to check if node is valid while iterating through
38 * the scan cache to avoid duplicate entries.
39 * - Once ref_cnt become 0, i.e. it is logically deleted and no thread is using
40 * it the node is physically deleted from the scan cache.
41 * - While reading the node the ref_cnt should be incremented. Once reading
42 * operation is done ref_cnt is decremented.
43 */
44 #include <qdf_status.h>
45 #include <wlan_objmgr_psoc_obj.h>
46 #include <wlan_objmgr_pdev_obj.h>
47 #include <wlan_objmgr_vdev_obj.h>
48 #include <wlan_scan_public_structs.h>
49 #include <wlan_scan_utils_api.h>
50 #include "wlan_scan_main.h"
51 #include "wlan_scan_cache_db_i.h"
52 #include "wlan_reg_services_api.h"
53 #include "wlan_reg_ucfg_api.h"
54 #include <wlan_objmgr_vdev_obj.h>
55 #include <wlan_dfs_utils_api.h>
56 #include "wlan_crypto_def_i.h"
57 #include "wlan_crypto_global_api.h"
58 #include "wlan_cm_bss_score_param.h"
59
60 #ifdef FEATURE_6G_SCAN_CHAN_SORT_ALGO
61
scm_get_rnr_channel_db(struct wlan_objmgr_psoc * psoc)62 struct channel_list_db *scm_get_rnr_channel_db(struct wlan_objmgr_psoc *psoc)
63 {
64 struct wlan_scan_obj *scan_obj = NULL;
65
66 scan_obj = wlan_psoc_get_scan_obj(psoc);
67
68 if (!scan_obj)
69 return NULL;
70
71 return &scan_obj->rnr_channel_db;
72 }
73
scm_get_chan_meta(struct wlan_objmgr_psoc * psoc,uint32_t chan_freq)74 struct meta_rnr_channel *scm_get_chan_meta(struct wlan_objmgr_psoc *psoc,
75 uint32_t chan_freq)
76 {
77 int i;
78 struct channel_list_db *rnr_channel_db;
79
80 if (!psoc || !chan_freq || !wlan_reg_is_6ghz_chan_freq(chan_freq))
81 return NULL;
82
83 rnr_channel_db = scm_get_rnr_channel_db(psoc);
84 if (!rnr_channel_db)
85 return NULL;
86
87 for (i = 0; i < QDF_ARRAY_SIZE(rnr_channel_db->channel); i++)
88 if (rnr_channel_db->channel[i].chan_freq == chan_freq)
89 return &rnr_channel_db->channel[i];
90
91 return NULL;
92 }
93
scm_is_rnr_present(struct meta_rnr_channel * chan,struct qdf_mac_addr * bssid,uint32_t short_ssid)94 static bool scm_is_rnr_present(struct meta_rnr_channel *chan,
95 struct qdf_mac_addr *bssid,
96 uint32_t short_ssid)
97 {
98 qdf_list_node_t *cur_node = NULL, *next_node = NULL;
99 struct scan_rnr_node *rnr_node;
100 QDF_STATUS status;
101
102 if (!chan || qdf_list_empty(&chan->rnr_list))
103 return false;
104
105 qdf_list_peek_front(&chan->rnr_list, &cur_node);
106 while (cur_node) {
107 rnr_node = qdf_container_of(cur_node,
108 struct scan_rnr_node,
109 node);
110 if (qdf_is_macaddr_equal(&rnr_node->entry.bssid, bssid) &&
111 rnr_node->entry.short_ssid == short_ssid)
112 return true;
113
114 status = qdf_list_peek_next(&chan->rnr_list, cur_node,
115 &next_node);
116 if (QDF_IS_STATUS_ERROR(status))
117 break;
118 cur_node = next_node;
119 next_node = NULL;
120 }
121
122 return false;
123 }
124
scm_add_rnr_channel_db(struct wlan_objmgr_psoc * psoc,struct scan_cache_entry * entry)125 static void scm_add_rnr_channel_db(struct wlan_objmgr_psoc *psoc,
126 struct scan_cache_entry *entry)
127 {
128 uint32_t chan_freq;
129 uint8_t is_6g_bss, i;
130 struct meta_rnr_channel *channel;
131 struct rnr_bss_info *rnr_bss;
132 struct scan_rnr_node *rnr_node;
133
134 chan_freq = entry->channel.chan_freq;
135 is_6g_bss = wlan_reg_is_6ghz_chan_freq(chan_freq);
136
137 /* Return if the BSS is not 6G and RNR IE is not present */
138 if (!(is_6g_bss || entry->ie_list.rnrie))
139 return;
140
141 scm_debug("BSS freq %d BSSID: "QDF_MAC_ADDR_FMT, chan_freq,
142 QDF_MAC_ADDR_REF(entry->bssid.bytes));
143 if (is_6g_bss) {
144 channel = scm_get_chan_meta(psoc, chan_freq);
145 if (!channel) {
146 scm_debug("Failed to get chan Meta freq %d", chan_freq);
147 return;
148 }
149 channel->bss_beacon_probe_count++;
150 channel->beacon_probe_last_time_found = entry->scan_entry_time;
151 }
152
153 /*
154 * If scan entry got RNR IE then loop through all
155 * entries and increase the BSS count in respective channels
156 */
157 if (!entry->ie_list.rnrie)
158 return;
159
160 for (i = 0; i < MAX_RNR_BSS; i++) {
161 rnr_bss = &entry->rnr.bss_info[i];
162 /* Skip if entry is not valid */
163 if (!rnr_bss->channel_number)
164 continue;
165 chan_freq = wlan_reg_chan_opclass_to_freq(rnr_bss->channel_number,
166 rnr_bss->operating_class,
167 true);
168 channel = scm_get_chan_meta(psoc, chan_freq);
169 if (!channel) {
170 scm_debug("Failed to get chan Meta freq %d", chan_freq);
171 continue;
172 }
173 channel->bss_beacon_probe_count++;
174 /* Don't add RNR entry if list is full */
175 if (qdf_list_size(&channel->rnr_list) >= WLAN_MAX_RNR_COUNT) {
176 scm_debug("List is full");
177 return;
178 }
179 if (scm_is_rnr_present(channel, &rnr_bss->bssid,
180 rnr_bss->short_ssid)) {
181 scm_debug("skip dup freq %d: "QDF_MAC_ADDR_FMT" short ssid %x",
182 chan_freq,
183 QDF_MAC_ADDR_REF(rnr_bss->bssid.bytes),
184 rnr_bss->short_ssid);
185 continue;
186 }
187 rnr_node = qdf_mem_malloc(sizeof(struct scan_rnr_node));
188 if (!rnr_node)
189 return;
190 rnr_node->entry.timestamp = entry->scan_entry_time;
191 if (!qdf_is_macaddr_zero(&rnr_bss->bssid))
192 qdf_mem_copy(&rnr_node->entry.bssid,
193 &rnr_bss->bssid,
194 QDF_MAC_ADDR_SIZE);
195 if (rnr_bss->short_ssid)
196 rnr_node->entry.short_ssid = rnr_bss->short_ssid;
197 if (rnr_bss->bss_params)
198 rnr_node->entry.bss_params = rnr_bss->bss_params;
199 scm_debug("Add freq %d: "QDF_MAC_ADDR_FMT" short ssid %x", chan_freq,
200 QDF_MAC_ADDR_REF(rnr_bss->bssid.bytes),
201 rnr_bss->short_ssid);
202 qdf_list_insert_back(&channel->rnr_list,
203 &rnr_node->node);
204 }
205 }
206
scm_filter_rnr_flag_pno(struct wlan_objmgr_vdev * vdev,uint32_t short_ssid,struct chan_list * pno_chan_list)207 void scm_filter_rnr_flag_pno(struct wlan_objmgr_vdev *vdev,
208 uint32_t short_ssid,
209 struct chan_list *pno_chan_list)
210 {
211 uint8_t i;
212 uint32_t freq;
213 struct meta_rnr_channel *chan;
214 struct scan_rnr_node *rnr_node;
215 enum scan_mode_6ghz scan_mode;
216 struct wlan_scan_obj *scan_obj;
217 struct wlan_objmgr_psoc *psoc;
218
219 psoc = wlan_vdev_get_psoc(vdev);
220 if (!psoc)
221 return;
222
223 scan_obj = wlan_vdev_get_scan_obj(vdev);
224 if (!scan_obj) {
225 scm_err("scan_obj is NULL");
226 return;
227 }
228
229 scan_mode = scan_obj->scan_def.scan_mode_6g;
230 /* No Filteration required for below scan modes since
231 * no RNR flag marked.
232 */
233 if (scan_mode == SCAN_MODE_6G_NO_CHANNEL ||
234 scan_mode == SCAN_MODE_6G_ALL_CHANNEL ||
235 scan_mode == SCAN_MODE_6G_ALL_DUTY_CYCLE)
236 return;
237
238 for (i = 0; i < pno_chan_list->num_chan; i++) {
239 freq = pno_chan_list->chan[i].freq;
240
241 chan = scm_get_chan_meta(psoc, freq);
242 if (!chan || qdf_list_empty(&chan->rnr_list))
243 continue;
244
245 qdf_list_for_each(&chan->rnr_list, rnr_node, node) {
246 if (!rnr_node)
247 continue;
248 if (rnr_node->entry.short_ssid) {
249 if (rnr_node->entry.short_ssid == short_ssid) {
250 /* If short ssid entry present in RNR db cache, remove
251 * FLAG_SCAN_ONLY_IF_RNR_FOUND flag from the channel.
252 */
253 pno_chan_list->chan[i].flags &=
254 ~FLAG_SCAN_ONLY_IF_RNR_FOUND;
255 break;
256 }
257 }
258 }
259 }
260 }
261 #else
scm_add_rnr_channel_db(struct wlan_objmgr_psoc * psoc,struct scan_cache_entry * entry)262 static void scm_add_rnr_channel_db(struct wlan_objmgr_psoc *psoc,
263 struct scan_cache_entry *entry)
264 {
265 }
266 #endif
267
268 /**
269 * scm_del_scan_node() - API to remove scan node from the list
270 * @list: hash list
271 * @scan_node: node to be removed
272 *
273 * This should be called while holding scan_db_lock.
274 *
275 * Return: void
276 */
scm_del_scan_node(qdf_list_t * list,struct scan_cache_node * scan_node)277 static void scm_del_scan_node(qdf_list_t *list,
278 struct scan_cache_node *scan_node)
279 {
280 QDF_STATUS status;
281
282 status = qdf_list_remove_node(list, &scan_node->node);
283 if (QDF_IS_STATUS_SUCCESS(status)) {
284 util_scan_free_cache_entry(scan_node->entry);
285 qdf_mem_free(scan_node);
286 }
287 }
288
289 /**
290 * scm_del_scan_node_from_db() - API to del the scan entry
291 * @scan_db: scan database
292 * @scan_node:entry scan_node
293 *
294 * API to flush the scan entry. This should be called while
295 * holding scan_db_lock.
296 *
297 * Return: QDF status.
298 */
scm_del_scan_node_from_db(struct scan_dbs * scan_db,struct scan_cache_node * scan_node)299 static QDF_STATUS scm_del_scan_node_from_db(struct scan_dbs *scan_db,
300 struct scan_cache_node *scan_node)
301 {
302 QDF_STATUS status = QDF_STATUS_SUCCESS;
303 uint8_t hash_idx;
304
305 if (!scan_node)
306 return QDF_STATUS_E_INVAL;
307
308 hash_idx = SCAN_GET_HASH(scan_node->entry->bssid.bytes);
309 scm_del_scan_node(&scan_db->scan_hash_tbl[hash_idx], scan_node);
310 scan_db->num_entries--;
311
312 return status;
313 }
314
315 /**
316 * scm_scan_entry_get_ref() - api to increase ref count of scan entry
317 * @scan_node: scan node
318 *
319 * Return: void
320 */
scm_scan_entry_get_ref(struct scan_cache_node * scan_node)321 static void scm_scan_entry_get_ref(struct scan_cache_node *scan_node)
322 {
323 if (!scan_node) {
324 scm_err("scan_node is NULL");
325 QDF_ASSERT(0);
326 return;
327 }
328 qdf_atomic_inc(&scan_node->ref_cnt);
329 }
330
331 /**
332 * scm_scan_entry_put_ref() - Api to decrease ref count of scan entry
333 * and free if it become 0
334 * @scan_db: scan database
335 * @scan_node: scan node
336 * @lock_needed: if scan_db_lock is needed
337 *
338 * Return: void
339 */
scm_scan_entry_put_ref(struct scan_dbs * scan_db,struct scan_cache_node * scan_node,bool lock_needed)340 static void scm_scan_entry_put_ref(struct scan_dbs *scan_db,
341 struct scan_cache_node *scan_node, bool lock_needed)
342 {
343
344 if (!scan_node) {
345 scm_err("scan_node is NULL");
346 QDF_ASSERT(0);
347 return;
348 }
349
350 if (lock_needed)
351 qdf_spin_lock_bh(&scan_db->scan_db_lock);
352
353 if (!qdf_atomic_read(&scan_node->ref_cnt)) {
354 if (lock_needed)
355 qdf_spin_unlock_bh(&scan_db->scan_db_lock);
356 scm_err("scan_node ref cnt is 0");
357 QDF_ASSERT(0);
358 return;
359 }
360
361 /* Decrement ref count, free scan_node, if ref count == 0 */
362 if (qdf_atomic_dec_and_test(&scan_node->ref_cnt))
363 scm_del_scan_node_from_db(scan_db, scan_node);
364
365 if (lock_needed)
366 qdf_spin_unlock_bh(&scan_db->scan_db_lock);
367 }
368
369 /**
370 * scm_scan_entry_del() - API to delete scan node
371 * @scan_db: data base
372 * @scan_node: node to be deleted
373 *
374 * Call must be protected by scan_db->scan_db_lock
375 *
376 * Return: void
377 */
378
scm_scan_entry_del(struct scan_dbs * scan_db,struct scan_cache_node * scan_node)379 static void scm_scan_entry_del(struct scan_dbs *scan_db,
380 struct scan_cache_node *scan_node)
381 {
382 if (!scan_node) {
383 scm_err("scan node is NULL");
384 QDF_ASSERT(0);
385 return;
386 }
387
388 if (scan_node->cookie != SCAN_NODE_ACTIVE_COOKIE) {
389 scm_debug("node is already deleted");
390 return;
391 }
392 /* Seems node is already deleted */
393 if (!qdf_atomic_read(&scan_node->ref_cnt)) {
394 scm_debug("node is already deleted ref 0");
395 return;
396 }
397 scan_node->cookie = 0;
398 scm_scan_entry_put_ref(scan_db, scan_node, false);
399 }
400
401 /**
402 * scm_add_scan_node() - API to add scan node
403 * @scan_db: data base
404 * @scan_node: node to be added
405 * @dup_node: node before which new node to be added
406 * if it's not NULL, otherwise add node to tail
407 *
408 * Call must be protected by scan_db->scan_db_lock
409 *
410 * Return: void
411 */
scm_add_scan_node(struct scan_dbs * scan_db,struct scan_cache_node * scan_node,struct scan_cache_node * dup_node)412 static void scm_add_scan_node(struct scan_dbs *scan_db,
413 struct scan_cache_node *scan_node,
414 struct scan_cache_node *dup_node)
415 {
416 uint8_t hash_idx;
417
418 hash_idx =
419 SCAN_GET_HASH(scan_node->entry->bssid.bytes);
420
421 qdf_atomic_init(&scan_node->ref_cnt);
422 scan_node->cookie = SCAN_NODE_ACTIVE_COOKIE;
423 scm_scan_entry_get_ref(scan_node);
424 if (!dup_node)
425 qdf_list_insert_back(&scan_db->scan_hash_tbl[hash_idx],
426 &scan_node->node);
427 else
428 qdf_list_insert_before(&scan_db->scan_hash_tbl[hash_idx],
429 &scan_node->node, &dup_node->node);
430
431 scan_db->num_entries++;
432 }
433
434
435 /**
436 * scm_get_next_valid_node() - API get the next valid scan node from
437 * the list
438 * @list: hash list
439 * @cur_node: current node pointer
440 *
441 * API to get next active node from the list. If cur_node is NULL
442 * it will return first node of the list.
443 * Call must be protected by scan_db->scan_db_lock
444 *
445 * Return: next scan node
446 */
447 static qdf_list_node_t *
scm_get_next_valid_node(qdf_list_t * list,qdf_list_node_t * cur_node)448 scm_get_next_valid_node(qdf_list_t *list,
449 qdf_list_node_t *cur_node)
450 {
451 qdf_list_node_t *next_node = NULL;
452 qdf_list_node_t *temp_node = NULL;
453 struct scan_cache_node *scan_node;
454
455 if (cur_node)
456 qdf_list_peek_next(list, cur_node, &next_node);
457 else
458 qdf_list_peek_front(list, &next_node);
459
460 while (next_node) {
461 scan_node = qdf_container_of(next_node,
462 struct scan_cache_node, node);
463 if (scan_node->cookie == SCAN_NODE_ACTIVE_COOKIE)
464 return next_node;
465 /*
466 * If node is not valid check for next entry
467 * to get next valid node.
468 */
469 qdf_list_peek_next(list, next_node, &temp_node);
470 next_node = temp_node;
471 temp_node = NULL;
472 }
473
474 return next_node;
475 }
476
477 /**
478 * scm_get_next_node() - API get the next scan node from
479 * the list
480 * @scan_db: scan data base
481 * @list: hash list
482 * @cur_node: current node pointer
483 *
484 * API get the next node from the list. If cur_node is NULL
485 * it will return first node of the list
486 *
487 * Return: next scan cache node
488 */
489 static struct scan_cache_node *
scm_get_next_node(struct scan_dbs * scan_db,qdf_list_t * list,struct scan_cache_node * cur_node)490 scm_get_next_node(struct scan_dbs *scan_db,
491 qdf_list_t *list, struct scan_cache_node *cur_node)
492 {
493 struct scan_cache_node *next_node = NULL;
494 qdf_list_node_t *next_list = NULL;
495
496 qdf_spin_lock_bh(&scan_db->scan_db_lock);
497 if (cur_node) {
498 next_list = scm_get_next_valid_node(list, &cur_node->node);
499 /* Decrement the ref count of the previous node */
500 scm_scan_entry_put_ref(scan_db,
501 cur_node, false);
502 } else {
503 next_list = scm_get_next_valid_node(list, NULL);
504 }
505 /* Increase the ref count of the obtained node */
506 if (next_list) {
507 next_node = qdf_container_of(next_list,
508 struct scan_cache_node, node);
509 scm_scan_entry_get_ref(next_node);
510 }
511 qdf_spin_unlock_bh(&scan_db->scan_db_lock);
512
513 return next_node;
514 }
515
516 /**
517 * scm_check_and_age_out() - check and age out the old entries
518 * @scan_db: scan db
519 * @node: node to check for age out
520 * @scan_aging_time: scan cache aging time
521 *
522 * Return: void
523 */
scm_check_and_age_out(struct scan_dbs * scan_db,struct scan_cache_node * node,qdf_time_t scan_aging_time)524 static void scm_check_and_age_out(struct scan_dbs *scan_db,
525 struct scan_cache_node *node,
526 qdf_time_t scan_aging_time)
527 {
528 if (util_scan_entry_age(node->entry) >=
529 scan_aging_time) {
530 scm_debug("Aging out BSSID: "QDF_MAC_ADDR_FMT" with age %lu ms",
531 QDF_MAC_ADDR_REF(node->entry->bssid.bytes),
532 util_scan_entry_age(node->entry));
533 qdf_spin_lock_bh(&scan_db->scan_db_lock);
534 scm_scan_entry_del(scan_db, node);
535 qdf_spin_unlock_bh(&scan_db->scan_db_lock);
536 }
537 }
538
scm_bss_is_connected(struct scan_cache_entry * entry)539 static bool scm_bss_is_connected(struct scan_cache_entry *entry)
540 {
541 if (entry->mlme_info.assoc_state == SCAN_ENTRY_CON_STATE_ASSOC)
542 return true;
543 return false;
544 }
545
546 /**
547 * scm_get_conn_node() - Get the scan cache entry node of the connected BSS
548 * @scan_db: scan DB pointer
549 *
550 * Return: scan cache entry node of connected BSS if exists, NULL otherwise
551 */
552 static
scm_get_conn_node(struct scan_dbs * scan_db)553 struct scan_cache_node *scm_get_conn_node(struct scan_dbs *scan_db)
554 {
555 int i;
556 struct scan_cache_node *cur_node = NULL;
557 struct scan_cache_node *next_node = NULL;
558
559 for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
560 cur_node = scm_get_next_node(scan_db,
561 &scan_db->scan_hash_tbl[i], NULL);
562 while (cur_node) {
563 if (scm_bss_is_connected(cur_node->entry))
564 return cur_node;
565 next_node = scm_get_next_node(scan_db,
566 &scan_db->scan_hash_tbl[i], cur_node);
567 cur_node = next_node;
568 next_node = NULL;
569 }
570 }
571
572 return NULL;
573 }
574
575 static bool
scm_bss_is_nontx_of_conn_bss(struct scan_cache_node * conn_node,struct scan_cache_node * cur_node)576 scm_bss_is_nontx_of_conn_bss(struct scan_cache_node *conn_node,
577 struct scan_cache_node *cur_node)
578 {
579 if (cur_node->entry->mbssid_info.profile_num &&
580 !memcmp(conn_node->entry->mbssid_info.trans_bssid,
581 cur_node->entry->mbssid_info.trans_bssid,
582 QDF_MAC_ADDR_SIZE))
583 return true;
584
585 return false;
586 }
587
scm_age_out_entries(struct wlan_objmgr_psoc * psoc,struct scan_dbs * scan_db)588 void scm_age_out_entries(struct wlan_objmgr_psoc *psoc,
589 struct scan_dbs *scan_db)
590 {
591 int i;
592 struct scan_cache_node *cur_node = NULL;
593 struct scan_cache_node *next_node = NULL;
594 struct scan_cache_node *conn_node = NULL;
595 struct scan_default_params *def_param;
596
597 def_param = wlan_scan_psoc_get_def_params(psoc);
598 if (!def_param) {
599 scm_err("wlan_scan_psoc_get_def_params failed");
600 return;
601 }
602
603 conn_node = scm_get_conn_node(scan_db);
604 for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
605 cur_node = scm_get_next_node(scan_db,
606 &scan_db->scan_hash_tbl[i], NULL);
607 while (cur_node) {
608 if (!conn_node /* if there is no connected node */ ||
609 /* OR cur_node is not part of the MBSSID of the
610 * connected node
611 */
612 (!scm_bss_is_connected(cur_node->entry) &&
613 !scm_bss_is_nontx_of_conn_bss(conn_node,
614 cur_node))) {
615 scm_check_and_age_out(scan_db, cur_node,
616 def_param->scan_cache_aging_time);
617 }
618 next_node = scm_get_next_node(scan_db,
619 &scan_db->scan_hash_tbl[i], cur_node);
620 cur_node = next_node;
621 next_node = NULL;
622 }
623 }
624
625 if (conn_node)
626 scm_scan_entry_put_ref(scan_db, conn_node, true);
627 }
628
629 /**
630 * scm_flush_oldest_entry() - Iterate over scan db and flust out the
631 * oldest entry
632 * @scan_db: scan db from which oldest entry needs to be flushed
633 *
634 * Return: QDF_STATUS
635 */
scm_flush_oldest_entry(struct scan_dbs * scan_db)636 static QDF_STATUS scm_flush_oldest_entry(struct scan_dbs *scan_db)
637 {
638 int i;
639 struct scan_cache_node *oldest_node = NULL;
640 struct scan_cache_node *cur_node;
641
642 for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
643 /* Get the first valid node for the hash */
644 cur_node = scm_get_next_node(scan_db,
645 &scan_db->scan_hash_tbl[i],
646 NULL);
647 /* Iterate scan db and flush out oldest node
648 * take ref_cnt for oldest_node
649 */
650
651 while (cur_node) {
652 if (!oldest_node ||
653 (util_scan_entry_age(oldest_node->entry) <
654 util_scan_entry_age(cur_node->entry))) {
655 if (oldest_node)
656 scm_scan_entry_put_ref(scan_db,
657 oldest_node,
658 true);
659 qdf_spin_lock_bh(&scan_db->scan_db_lock);
660 oldest_node = cur_node;
661 scm_scan_entry_get_ref(oldest_node);
662 qdf_spin_unlock_bh(&scan_db->scan_db_lock);
663 }
664
665 cur_node = scm_get_next_node(scan_db,
666 &scan_db->scan_hash_tbl[i],
667 cur_node);
668 };
669 }
670
671 if (oldest_node) {
672 scm_debug("Flush oldest BSSID: "QDF_MAC_ADDR_FMT" with age %lu ms",
673 QDF_MAC_ADDR_REF(oldest_node->entry->bssid.bytes),
674 util_scan_entry_age(oldest_node->entry));
675 /* Release ref_cnt taken for oldest_node and delete it */
676 qdf_spin_lock_bh(&scan_db->scan_db_lock);
677 scm_scan_entry_del(scan_db, oldest_node);
678 scm_scan_entry_put_ref(scan_db, oldest_node, false);
679 qdf_spin_unlock_bh(&scan_db->scan_db_lock);
680 }
681
682 return QDF_STATUS_SUCCESS;
683 }
684
685 /**
686 * scm_update_alt_wcn_ie() - update the alternate WCN IE
687 * @from: copy from
688 * @dst: copy to
689 *
690 * Return: void
691 */
scm_update_alt_wcn_ie(struct scan_cache_entry * from,struct scan_cache_entry * dst)692 static void scm_update_alt_wcn_ie(struct scan_cache_entry *from,
693 struct scan_cache_entry *dst)
694 {
695 uint32_t alt_wcn_ie_len;
696
697 if (from->frm_subtype == dst->frm_subtype)
698 return;
699
700 if (!from->ie_list.wcn && !dst->ie_list.wcn)
701 return;
702
703 /* Existing WCN IE is empty. */
704 if (!from->ie_list.wcn)
705 return;
706
707 alt_wcn_ie_len = 2 + from->ie_list.wcn[1];
708 if (alt_wcn_ie_len > WLAN_MAX_IE_LEN + 2) {
709 scm_err("invalid IE len");
710 return;
711 }
712
713 if (!dst->alt_wcn_ie.ptr) {
714 /* allocate this additional buffer for alternate WCN IE */
715 dst->alt_wcn_ie.ptr =
716 qdf_mem_malloc_atomic(WLAN_MAX_IE_LEN + 2);
717 if (!dst->alt_wcn_ie.ptr) {
718 scm_err("failed to allocate memory");
719 return;
720 }
721 }
722 qdf_mem_copy(dst->alt_wcn_ie.ptr,
723 from->ie_list.wcn, alt_wcn_ie_len);
724 dst->alt_wcn_ie.len = alt_wcn_ie_len;
725 }
726
727 /**
728 * scm_update_mlme_info() - update mlme info
729 * @src: source scan entry
730 * @dest: destination scan entry
731 *
732 * Return: void
733 */
734 static inline void
scm_update_mlme_info(struct scan_cache_entry * src,struct scan_cache_entry * dest)735 scm_update_mlme_info(struct scan_cache_entry *src,
736 struct scan_cache_entry *dest)
737 {
738 qdf_mem_copy(&dest->mlme_info, &src->mlme_info,
739 sizeof(struct mlme_info));
740 }
741
742 /**
743 * scm_copy_info_from_dup_entry() - copy duplicate node info
744 * to new scan entry
745 * @pdev: pdev ptr
746 * @scan_obj: scan obj ptr
747 * @scan_db: scan database
748 * @scan_params: new entry to be added
749 * @scan_node: duplicate entry
750 *
751 * Copy duplicate node info to new entry.
752 *
753 * Return: void
754 */
755 static void
scm_copy_info_from_dup_entry(struct wlan_objmgr_pdev * pdev,struct wlan_scan_obj * scan_obj,struct scan_dbs * scan_db,struct scan_cache_entry * scan_params,struct scan_cache_node * scan_node)756 scm_copy_info_from_dup_entry(struct wlan_objmgr_pdev *pdev,
757 struct wlan_scan_obj *scan_obj,
758 struct scan_dbs *scan_db,
759 struct scan_cache_entry *scan_params,
760 struct scan_cache_node *scan_node)
761 {
762 struct scan_cache_entry *scan_entry;
763 uint64_t time_gap;
764
765 scan_entry = scan_node->entry;
766
767 /* Update probe resp entry as well if AP is in hidden mode */
768 if (scan_params->frm_subtype == MGMT_SUBTYPE_PROBE_RESP &&
769 scan_entry->is_hidden_ssid)
770 scan_params->is_hidden_ssid = true;
771
772 /*
773 * If AP changed its beacon from not having an SSID to showing it the
774 * kernel will drop the entry asumming that something is wrong with AP.
775 * This can result in connection failure while updating the bss during
776 * connection. So flush the hidden entry from kernel before indicating
777 * the new entry.
778 */
779 if (scan_entry->is_hidden_ssid &&
780 scan_params->frm_subtype == MGMT_SUBTYPE_BEACON &&
781 !util_scan_is_null_ssid(&scan_params->ssid)) {
782 if (scan_obj->cb.unlink_bss) {
783 scm_debug("Hidden AP "QDF_MAC_ADDR_FMT" switch to non-hidden SSID, So unlink the entry",
784 QDF_MAC_ADDR_REF(scan_entry->bssid.bytes));
785 scan_obj->cb.unlink_bss(pdev, scan_entry);
786 }
787 }
788
789 /* If old entry have the ssid but new entry does not */
790 if (util_scan_is_null_ssid(&scan_params->ssid) &&
791 scan_entry->ssid.length) {
792 /*
793 * New entry has a hidden SSID and old one has the SSID.
794 * Add the entry by using the ssid of the old entry
795 * only if diff of saved SSID time and current time is
796 * less than HIDDEN_SSID_TIME time.
797 * This will avoid issues in case AP changes its SSID
798 * while remain hidden.
799 */
800 time_gap =
801 qdf_mc_timer_get_system_time() -
802 scan_entry->hidden_ssid_timestamp;
803 if (time_gap <= HIDDEN_SSID_TIME) {
804 scan_params->hidden_ssid_timestamp =
805 scan_entry->hidden_ssid_timestamp;
806 scan_params->ssid.length =
807 scan_entry->ssid.length;
808 qdf_mem_copy(scan_params->ssid.ssid,
809 scan_entry->ssid.ssid,
810 scan_entry->ssid.length);
811 }
812 }
813
814 /*
815 * Due to Rx sensitivity issue, sometime beacons are seen on adjacent
816 * channel so workaround in software is needed. If DS params or HT info
817 * are present driver can get proper channel info from these IEs and set
818 * channel_mismatch so that the older RSSI values are used in new entry.
819 *
820 * For the cases where DS params and HT info is not present, driver
821 * needs to check below conditions to get proper channel and set
822 * channel_mismatch so that the older RSSI values are used in new entry:
823 * -- The old entry channel and new entry channel are not same
824 * -- RSSI is less than -80, this indicate that the signal has leaked
825 * in adjacent channel.
826 */
827 time_gap =
828 scan_params->scan_entry_time -
829 scan_entry->rssi_timestamp;
830
831 if ((scan_params->frm_subtype == MGMT_SUBTYPE_BEACON ||
832 scan_params->frm_subtype == MGMT_SUBTYPE_PROBE_RESP) &&
833 !util_scan_entry_htinfo(scan_params) &&
834 !util_scan_entry_ds_param(scan_params) &&
835 !util_scan_entry_vhtop(scan_params) &&
836 !util_scan_entry_heop(scan_params) &&
837 (scan_params->channel.chan_freq != scan_entry->channel.chan_freq) &&
838 (scan_params->rssi_raw < ADJACENT_CHANNEL_RSSI_THRESHOLD ||
839 (time_gap < WLAN_RSSI_AVERAGING_TIME &&
840 (scan_params->rssi_raw + ADJACENT_CHANNEL_RSSI_DIFF_THRESHOLD) <
841 scan_entry->rssi_raw))) {
842 scan_params->channel.chan_freq = scan_entry->channel.chan_freq;
843 scan_params->channel_mismatch = true;
844 }
845
846 /* Use old value for rssi if beacon was heard on adjacent channel. */
847 if (scan_params->channel_mismatch) {
848 scan_params->snr = scan_entry->snr;
849 scan_params->avg_snr = scan_entry->avg_snr;
850 scan_params->rssi_raw = scan_entry->rssi_raw;
851 scan_params->avg_rssi = scan_entry->avg_rssi;
852 scan_params->rssi_timestamp =
853 scan_entry->rssi_timestamp;
854 } else {
855 /* If elapsed time since last rssi and snr update for this
856 * entry is smaller than a threshold, calculate a
857 * running average of the RSSI and SNR values.
858 * Otherwise new frames RSSI and SNR are more representative
859 * of the signal strength.
860 */
861 if (time_gap > WLAN_RSSI_AVERAGING_TIME) {
862 scan_params->avg_rssi =
863 WLAN_RSSI_IN(scan_params->rssi_raw);
864 scan_params->avg_snr =
865 WLAN_SNR_IN(scan_params->snr);
866 }
867 else {
868 /* Copy previous average rssi and snr to new entry */
869 scan_params->avg_snr = scan_entry->avg_snr;
870 scan_params->avg_rssi = scan_entry->avg_rssi;
871 /* Average with previous samples */
872 WLAN_RSSI_LPF(scan_params->avg_rssi,
873 scan_params->rssi_raw);
874 WLAN_SNR_LPF(scan_params->avg_snr,
875 scan_params->snr);
876 }
877
878 scan_params->rssi_timestamp = scan_params->scan_entry_time;
879 }
880
881 /* copy wsn ie from scan_entry to scan_params*/
882 scm_update_alt_wcn_ie(scan_entry, scan_params);
883
884 /* copy mlme info from scan_entry to scan_params*/
885 scm_update_mlme_info(scan_entry, scan_params);
886 }
887
888 /**
889 * scm_find_duplicate() - find duplicate entry,
890 * if present, add input scan entry before it and delete
891 * duplicate entry. otherwise add entry to tail
892 * @pdev: pdev ptr
893 * @scan_obj: scan obj ptr
894 * @scan_db: scan db
895 * @entry: input scan cache entry
896 * @dup_node: node before which new entry to be added
897 *
898 * ref_cnt is taken for dup_node, caller should release ref taken
899 * if returns true.
900 *
901 * Return: bool
902 */
903 static bool
scm_find_duplicate(struct wlan_objmgr_pdev * pdev,struct wlan_scan_obj * scan_obj,struct scan_dbs * scan_db,struct scan_cache_entry * entry,struct scan_cache_node ** dup_node)904 scm_find_duplicate(struct wlan_objmgr_pdev *pdev,
905 struct wlan_scan_obj *scan_obj,
906 struct scan_dbs *scan_db,
907 struct scan_cache_entry *entry,
908 struct scan_cache_node **dup_node)
909 {
910 uint8_t hash_idx;
911 struct scan_cache_node *cur_node;
912 struct scan_cache_node *next_node = NULL;
913
914 hash_idx = SCAN_GET_HASH(entry->bssid.bytes);
915
916 cur_node = scm_get_next_node(scan_db,
917 &scan_db->scan_hash_tbl[hash_idx],
918 NULL);
919
920 while (cur_node) {
921 if (util_is_scan_entry_match(entry,
922 cur_node->entry)) {
923 scm_copy_info_from_dup_entry(pdev, scan_obj, scan_db,
924 entry, cur_node);
925 *dup_node = cur_node;
926 return true;
927 }
928 next_node = scm_get_next_node(scan_db,
929 &scan_db->scan_hash_tbl[hash_idx], cur_node);
930 cur_node = next_node;
931 next_node = NULL;
932 }
933
934 return false;
935 }
936
937 /*
938 * Buffer len size to add the dynamic scan frame debug info
939 * 7 (pdev id) + 21 (security info) + 8 (hidden info) + 15 (chan mismatch) +
940 * 8 (CSA IE info) + 31 (ML info) + 5 extra
941 */
942 #define SCAN_DUMP_MAX_LEN 95
943
944 #ifdef WLAN_FEATURE_11BE_MLO
945 /**
946 * scm_dump_ml_scan_info(): Dump ml scan info
947 * @scan_params: new received entry
948 * @log_str: Buffer pointer
949 * @str_len: max string length
950 * @len: already filled length in buffer
951 *
952 * Return: length filled in buffer
953 */
scm_dump_ml_scan_info(struct scan_cache_entry * scan_params,char * log_str,uint32_t str_len,uint32_t len)954 static uint32_t scm_dump_ml_scan_info(struct scan_cache_entry *scan_params,
955 char *log_str, uint32_t str_len,
956 uint32_t len)
957 {
958 /* Scenario: When both STA and AP support ML then
959 * Driver will fill ml_info structure and print the MLD address and no.
960 * of links.
961 */
962 if (qdf_is_macaddr_zero(&scan_params->ml_info.mld_mac_addr))
963 return 0;
964
965 return qdf_scnprintf(log_str + len, str_len - len,
966 ", MLD " QDF_MAC_ADDR_FMT " links %d",
967 QDF_MAC_ADDR_REF(scan_params->ml_info.mld_mac_addr.bytes),
968 scan_params->ml_info.num_links);
969 }
970 #else
scm_dump_ml_scan_info(struct scan_cache_entry * scan_params,char * log_str,uint32_t str_len,uint32_t len)971 static uint32_t scm_dump_ml_scan_info(struct scan_cache_entry *scan_params,
972 char *log_str, uint32_t str_len,
973 uint32_t len)
974 {
975 return 0;
976 }
977 #endif
978
scm_dump_scan_entry(struct wlan_objmgr_pdev * pdev,struct scan_cache_entry * scan_params)979 static void scm_dump_scan_entry(struct wlan_objmgr_pdev *pdev,
980 struct scan_cache_entry *scan_params)
981 {
982 uint8_t security_type;
983 char log_str[SCAN_DUMP_MAX_LEN] = {0};
984 uint32_t str_len = SCAN_DUMP_MAX_LEN;
985 uint8_t pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
986 uint32_t len = 0;
987
988 /* Add pdev_id if its non zero */
989 if (pdev_id)
990 len += qdf_scnprintf(log_str + len, str_len - len,
991 "pdev %d ", pdev_id);
992
993 /* Add WPA/RSN/WAPI/WEP info if its non zero */
994 security_type = scan_params->security_type;
995 if (security_type)
996 len += qdf_scnprintf(log_str + len, str_len - len,
997 "%s%s%s%s",
998 security_type & SCAN_SECURITY_TYPE_WPA ?
999 "[WPA]" : "",
1000 security_type & SCAN_SECURITY_TYPE_RSN ?
1001 "[RSN]" : "",
1002 security_type & SCAN_SECURITY_TYPE_WAPI ?
1003 "[WAPI]" : "",
1004 security_type & SCAN_SECURITY_TYPE_WEP ?
1005 "[WEP]" : "");
1006
1007 /* Add hidden info if present */
1008 if (scan_params->is_hidden_ssid)
1009 len += qdf_scnprintf(log_str + len, str_len - len, "[hidden]");
1010
1011 /* Add channel mismatch info if present */
1012 if (scan_params->channel_mismatch)
1013 len += qdf_scnprintf(log_str + len, str_len - len,
1014 "[Chan mismatch]");
1015
1016 /* Add CSA IE info if present */
1017 if (scan_params->ie_list.csa ||
1018 scan_params->ie_list.xcsa ||
1019 scan_params->ie_list.cswrp)
1020 len += qdf_scnprintf(log_str + len, str_len - len, "[CSA IE]");
1021
1022 /* Add ML info */
1023 len += scm_dump_ml_scan_info(scan_params, log_str, str_len, len);
1024
1025 scm_nofl_debug("Rcvd %s(%d): " QDF_MAC_ADDR_FMT " \"" QDF_SSID_FMT "\" freq %d rssi %d tsf %u seq %d snr %d phy %d %s",
1026 (scan_params->frm_subtype == MGMT_SUBTYPE_PROBE_RESP) ?
1027 "prb rsp" : "bcn", scan_params->raw_frame.len,
1028 QDF_MAC_ADDR_REF(scan_params->bssid.bytes),
1029 QDF_SSID_REF(scan_params->ssid.length,
1030 scan_params->ssid.ssid),
1031 scan_params->channel.chan_freq, scan_params->rssi_raw,
1032 scan_params->tsf_delta, scan_params->seq_num,
1033 scan_params->snr, scan_params->phy_mode, log_str);
1034 }
1035
1036 /**
1037 * scm_add_update_entry() - add or update scan entry
1038 * @psoc: psoc ptr
1039 * @pdev: pdev pointer
1040 * @scan_params: new received entry
1041 *
1042 * Return: QDF_STATUS
1043 */
scm_add_update_entry(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_pdev * pdev,struct scan_cache_entry * scan_params)1044 static QDF_STATUS scm_add_update_entry(struct wlan_objmgr_psoc *psoc,
1045 struct wlan_objmgr_pdev *pdev, struct scan_cache_entry *scan_params)
1046 {
1047 struct scan_cache_node *dup_node = NULL;
1048 struct scan_cache_node *scan_node = NULL;
1049 bool is_dup_found = false;
1050 QDF_STATUS status;
1051 struct scan_dbs *scan_db;
1052 struct wlan_scan_obj *scan_obj;
1053
1054 scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1055 if (!scan_db) {
1056 scm_err("scan_db is NULL");
1057 return QDF_STATUS_E_INVAL;
1058 }
1059
1060 scan_obj = wlan_psoc_get_scan_obj(psoc);
1061 if (!scan_obj) {
1062 scm_err("scan_obj is NULL");
1063 return QDF_STATUS_E_INVAL;
1064 }
1065
1066 if (scan_params->frm_subtype ==
1067 MGMT_SUBTYPE_PROBE_RESP &&
1068 !scan_params->ie_list.ssid)
1069 scm_debug("Probe resp doesn't contain SSID");
1070
1071 is_dup_found = scm_find_duplicate(pdev, scan_obj, scan_db, scan_params,
1072 &dup_node);
1073
1074 scm_dump_scan_entry(pdev, scan_params);
1075
1076 if (scan_obj->cb.inform_beacon)
1077 scan_obj->cb.inform_beacon(pdev, scan_params);
1078
1079 if (scan_db->num_entries >= MAX_SCAN_CACHE_SIZE) {
1080 status = scm_flush_oldest_entry(scan_db);
1081 if (QDF_IS_STATUS_ERROR(status)) {
1082 /* release ref taken for dup node */
1083 if (is_dup_found)
1084 scm_scan_entry_put_ref(scan_db, dup_node, true);
1085 return status;
1086 }
1087 }
1088
1089 scan_node = qdf_mem_malloc(sizeof(*scan_node));
1090 if (!scan_node) {
1091 /* release ref taken for dup node */
1092 if (is_dup_found)
1093 scm_scan_entry_put_ref(scan_db, dup_node, true);
1094 return QDF_STATUS_E_NOMEM;
1095 }
1096
1097 scan_node->entry = scan_params;
1098 qdf_spin_lock_bh(&scan_db->scan_db_lock);
1099 scm_add_scan_node(scan_db, scan_node, dup_node);
1100
1101 if (is_dup_found) {
1102 /* release ref taken for dup node and delete it */
1103 scm_scan_entry_del(scan_db, dup_node);
1104 scm_scan_entry_put_ref(scan_db, dup_node, false);
1105 }
1106 qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1107
1108 return QDF_STATUS_SUCCESS;
1109 }
1110
1111 #ifdef CONFIG_REG_CLIENT
1112 /**
1113 * scm_is_bss_allowed_for_country() - Check if bss is allowed to start for a
1114 * specific country and power mode (VLP?LPI/SP) for 6GHz.
1115 * @psoc: psoc ptr
1116 * @scan_entry: ptr to scan entry
1117 *
1118 * Return: True if allowed, False if not.
1119 */
scm_is_bss_allowed_for_country(struct wlan_objmgr_psoc * psoc,struct scan_cache_entry * scan_entry)1120 static bool scm_is_bss_allowed_for_country(struct wlan_objmgr_psoc *psoc,
1121 struct scan_cache_entry *scan_entry)
1122 {
1123 struct wlan_country_ie *cc_ie;
1124 uint8_t programmed_country[REG_ALPHA2_LEN + 1];
1125
1126 if (wlan_reg_is_6ghz_chan_freq(scan_entry->channel.chan_freq)) {
1127 cc_ie = util_scan_entry_country(scan_entry);
1128 if (!cc_ie)
1129 return false;
1130 wlan_reg_read_current_country(psoc, programmed_country);
1131 if (cc_ie && qdf_mem_cmp(cc_ie->cc, programmed_country,
1132 REG_ALPHA2_LEN)) {
1133 if (wlan_reg_is_us(programmed_country))
1134 return false;
1135 }
1136 }
1137 return true;
1138 }
1139 #else
scm_is_bss_allowed_for_country(struct wlan_objmgr_psoc * psoc,struct scan_cache_entry * scan_entry)1140 static bool scm_is_bss_allowed_for_country(struct wlan_objmgr_psoc *psoc,
1141 struct scan_cache_entry *scan_entry)
1142 {
1143 return true;
1144 }
1145 #endif
1146
1147 /**
1148 * scm_is_p2p_wildcard_ssid() - check p2p wildcard ssid or not
1149 * @scan_entry: scan entry
1150 *
1151 * Return: true if SSID is wildcard "DIRECT-" ssid
1152 */
scm_is_p2p_wildcard_ssid(struct scan_cache_entry * scan_entry)1153 static bool scm_is_p2p_wildcard_ssid(struct scan_cache_entry *scan_entry)
1154 {
1155 static const char wildcard_ssid[] = "DIRECT-";
1156 uint8_t len = sizeof(wildcard_ssid) - 1;
1157
1158 if (!scan_entry->is_p2p)
1159 return false;
1160 if (!qdf_mem_cmp(scan_entry->ssid.ssid,
1161 wildcard_ssid, len) &&
1162 (scan_entry->ssid.length == len))
1163 return true;
1164
1165 return false;
1166 }
1167
__scm_handle_bcn_probe(struct scan_bcn_probe_event * bcn)1168 QDF_STATUS __scm_handle_bcn_probe(struct scan_bcn_probe_event *bcn)
1169 {
1170 struct wlan_objmgr_psoc *psoc;
1171 struct wlan_objmgr_pdev *pdev = NULL;
1172 struct scan_cache_entry *scan_entry;
1173 struct wlan_scan_obj *scan_obj;
1174 qdf_list_t *scan_list = NULL;
1175 QDF_STATUS status = QDF_STATUS_SUCCESS;
1176 uint32_t list_count, i;
1177 qdf_list_node_t *next_node = NULL;
1178 struct scan_cache_node *scan_node;
1179 struct wlan_frame_hdr *hdr = NULL;
1180 struct wlan_crypto_params sec_params;
1181
1182 if (!bcn) {
1183 scm_err("bcn is NULL");
1184 return QDF_STATUS_E_INVAL;
1185 }
1186 if (!bcn->rx_data) {
1187 scm_err("rx_data is NULL");
1188 status = QDF_STATUS_E_INVAL;
1189 goto free_nbuf;
1190 }
1191 if (!bcn->buf) {
1192 scm_err("buf is NULL");
1193 status = QDF_STATUS_E_INVAL;
1194 goto free_nbuf;
1195 }
1196
1197 hdr = (struct wlan_frame_hdr *)qdf_nbuf_data(bcn->buf);
1198 psoc = bcn->psoc;
1199 pdev = wlan_objmgr_get_pdev_by_id(psoc,
1200 bcn->rx_data->pdev_id, WLAN_SCAN_ID);
1201 if (!pdev) {
1202 scm_err("pdev is NULL for pdev %d", bcn->rx_data->pdev_id);
1203 status = QDF_STATUS_E_INVAL;
1204 goto free_nbuf;
1205 }
1206 scan_obj = wlan_psoc_get_scan_obj(psoc);
1207 if (!scan_obj) {
1208 status = QDF_STATUS_E_INVAL;
1209 goto free_nbuf;
1210 }
1211
1212 if (qdf_nbuf_len(bcn->buf) <=
1213 (sizeof(struct wlan_frame_hdr) +
1214 offsetof(struct wlan_bcn_frame, ie))) {
1215 scm_debug("invalid beacon/probe length");
1216 status = QDF_STATUS_E_INVAL;
1217 goto free_nbuf;
1218 }
1219
1220 if (bcn->frm_type == MGMT_SUBTYPE_BEACON &&
1221 wlan_reg_is_dfs_for_freq(pdev, bcn->rx_data->chan_freq)) {
1222 util_scan_add_hidden_ssid(pdev, bcn->buf);
1223 }
1224
1225 scan_list =
1226 util_scan_unpack_beacon_frame(pdev, qdf_nbuf_data(bcn->buf),
1227 qdf_nbuf_len(bcn->buf), bcn->frm_type,
1228 bcn->rx_data);
1229 if (!scan_list || qdf_list_empty(scan_list)) {
1230 scm_debug(QDF_MAC_ADDR_FMT ": failed to unpack %d frame",
1231 QDF_MAC_ADDR_REF(hdr->i_addr3), bcn->frm_type);
1232 status = QDF_STATUS_E_INVAL;
1233 goto free_nbuf;
1234 }
1235
1236 list_count = qdf_list_size(scan_list);
1237 for (i = 0; i < list_count; i++) {
1238 status = qdf_list_remove_front(scan_list, &next_node);
1239 if (QDF_IS_STATUS_ERROR(status) || !next_node) {
1240 scm_debug(QDF_MAC_ADDR_FMT ": list remove failure i %d, lsize %d",
1241 QDF_MAC_ADDR_REF(hdr->i_addr3), i,
1242 list_count);
1243 status = QDF_STATUS_E_INVAL;
1244 goto free_nbuf;
1245 }
1246
1247 scan_node = qdf_container_of(next_node,
1248 struct scan_cache_node, node);
1249
1250 scan_entry = scan_node->entry;
1251
1252 if (scan_obj->drop_bcn_on_chan_mismatch &&
1253 scan_entry->channel_mismatch) {
1254 scm_nofl_debug(QDF_MAC_ADDR_FMT ": Drop frame(%d) for chan mismatch, seq %d frame freq %d rx data freq %d RSSI %d",
1255 QDF_MAC_ADDR_REF(
1256 scan_entry->bssid.bytes),
1257 bcn->frm_type,
1258 scan_entry->seq_num,
1259 scan_entry->channel.chan_freq,
1260 bcn->rx_data->chan_freq,
1261 scan_entry->rssi_raw);
1262 util_scan_free_cache_entry(scan_entry);
1263 qdf_mem_free(scan_node);
1264 continue;
1265 }
1266 /* Do not add invalid channel entry as kernel will reject it */
1267 if (scan_obj->drop_bcn_on_invalid_freq &&
1268 !wlan_reg_is_freq_enabled(pdev,
1269 scan_entry->channel.chan_freq,
1270 REG_BEST_PWR_MODE)) {
1271 scm_nofl_debug(QDF_MAC_ADDR_FMT ": Drop frame(%d) for invalid freq %d seq %d RSSI %d",
1272 QDF_MAC_ADDR_REF(
1273 scan_entry->bssid.bytes),
1274 bcn->frm_type,
1275 scan_entry->channel.chan_freq,
1276 scan_entry->seq_num,
1277 scan_entry->rssi_raw);
1278 util_scan_free_cache_entry(scan_entry);
1279 qdf_mem_free(scan_node);
1280 continue;
1281 }
1282 if (util_scan_entry_rsn(scan_entry)) {
1283 status = wlan_crypto_rsnie_check(
1284 &sec_params,
1285 util_scan_entry_rsn(scan_entry));
1286 if (QDF_IS_STATUS_ERROR(status) &&
1287 !scm_is_p2p_wildcard_ssid(scan_entry)) {
1288 scm_nofl_debug(QDF_MAC_ADDR_FMT ": Drop frame(%d) with invalid RSN IE freq %d, parse status %d",
1289 QDF_MAC_ADDR_REF(
1290 scan_entry->bssid.bytes),
1291 bcn->frm_type,
1292 scan_entry->channel.chan_freq,
1293 status);
1294 util_scan_free_cache_entry(scan_entry);
1295 qdf_mem_free(scan_node);
1296 continue;
1297 }
1298 }
1299 if (wlan_cm_get_check_6ghz_security(psoc) &&
1300 wlan_reg_is_6ghz_chan_freq(scan_entry->channel.chan_freq)) {
1301 if (!util_scan_entry_rsn(scan_entry)) {
1302 scm_info_rl(QDF_MAC_ADDR_FMT ": Drop frame(%d) with No RSN IE in 6GHz(%d)",
1303 QDF_MAC_ADDR_REF(
1304 scan_entry->bssid.bytes),
1305 bcn->frm_type,
1306 scan_entry->channel.chan_freq);
1307 util_scan_free_cache_entry(scan_entry);
1308 qdf_mem_free(scan_node);
1309 continue;
1310 }
1311 status = wlan_crypto_rsnie_check(&sec_params,
1312 util_scan_entry_rsn(scan_entry));
1313 if (QDF_IS_STATUS_ERROR(status)) {
1314 scm_info_rl(QDF_MAC_ADDR_FMT ": Drop frame(%d) with invalid RSN IE in 6GHz(%d), parse status %d",
1315 QDF_MAC_ADDR_REF(
1316 scan_entry->bssid.bytes),
1317 bcn->frm_type,
1318 scan_entry->channel.chan_freq,
1319 status);
1320 util_scan_free_cache_entry(scan_entry);
1321 qdf_mem_free(scan_node);
1322 continue;
1323 }
1324 if ((QDF_HAS_PARAM(sec_params.ucastcipherset,
1325 WLAN_CRYPTO_CIPHER_NONE)) ||
1326 (QDF_HAS_PARAM(sec_params.ucastcipherset,
1327 WLAN_CRYPTO_CIPHER_TKIP)) ||
1328 (QDF_HAS_PARAM(sec_params.ucastcipherset,
1329 WLAN_CRYPTO_CIPHER_WEP_40)) ||
1330 (QDF_HAS_PARAM(sec_params.ucastcipherset,
1331 WLAN_CRYPTO_CIPHER_WEP_104))) {
1332 scm_info_rl(QDF_MAC_ADDR_FMT ": Drop frame(%d) with Invalid sec type %0X for 6GHz(%d)",
1333 QDF_MAC_ADDR_REF(
1334 scan_entry->bssid.bytes),
1335 bcn->frm_type,
1336 sec_params.ucastcipherset,
1337 scan_entry->channel.chan_freq);
1338 util_scan_free_cache_entry(scan_entry);
1339 qdf_mem_free(scan_node);
1340 continue;
1341 }
1342 if (!wlan_cm_6ghz_allowed_for_akm(psoc,
1343 sec_params.key_mgmt,
1344 sec_params.rsn_caps,
1345 util_scan_entry_rsnxe(scan_entry),
1346 0, false)) {
1347 scm_info_rl(QDF_MAC_ADDR_FMT ": Drop frame(%d) with Invalid AKM suite %0X for 6GHz(%d)",
1348 QDF_MAC_ADDR_REF(
1349 scan_entry->bssid.bytes),
1350 bcn->frm_type,
1351 sec_params.key_mgmt,
1352 scan_entry->channel.chan_freq);
1353 util_scan_free_cache_entry(scan_entry);
1354 qdf_mem_free(scan_node);
1355 continue;
1356 }
1357 }
1358
1359 scan_entry->non_intersected_phymode = scan_entry->phy_mode;
1360
1361 if (scan_obj->cb.update_beacon)
1362 scan_obj->cb.update_beacon(pdev, scan_entry);
1363
1364 /**
1365 * Do not drop the frame if Wi-Fi safe mode or RF test mode is
1366 * enabled. wlan_cm_get_check_6ghz_security API returns true if
1367 * neither Safe mode nor RF test mode are enabled.
1368 */
1369 if (!wlan_cm_get_standard_6ghz_conn_policy(psoc) &&
1370 !scm_is_bss_allowed_for_country(psoc, scan_entry) &&
1371 wlan_cm_get_check_6ghz_security(psoc)) {
1372 scm_info_rl(QDF_MAC_ADDR_FMT ": Drop frame(%d) freq %d, as country not present OR VLP mode not supported for US",
1373 QDF_MAC_ADDR_REF(scan_entry->bssid.bytes),
1374 bcn->frm_type,
1375 scan_entry->channel.chan_freq);
1376 util_scan_free_cache_entry(scan_entry);
1377 qdf_mem_free(scan_node);
1378 continue;
1379 }
1380
1381 status = scm_add_update_entry(psoc, pdev, scan_entry);
1382 if (QDF_IS_STATUS_ERROR(status)) {
1383 scm_debug(QDF_MAC_ADDR_FMT ": Failed to add entry for frame(%d) seq %d freq %d",
1384 QDF_MAC_ADDR_REF(scan_entry->bssid.bytes),
1385 bcn->frm_type,
1386 scan_entry->seq_num,
1387 scan_entry->channel.chan_freq);
1388 util_scan_free_cache_entry(scan_entry);
1389 qdf_mem_free(scan_node);
1390 continue;
1391 }
1392
1393 if (bcn->save_rnr_info)
1394 scm_add_rnr_channel_db(psoc, scan_entry);
1395
1396 qdf_mem_free(scan_node);
1397 }
1398
1399 free_nbuf:
1400 if (scan_list)
1401 qdf_mem_free(scan_list);
1402 if (bcn->psoc)
1403 wlan_objmgr_psoc_release_ref(bcn->psoc, WLAN_SCAN_ID);
1404 if (pdev)
1405 wlan_objmgr_pdev_release_ref(pdev, WLAN_SCAN_ID);
1406 if (bcn->rx_data)
1407 qdf_mem_free(bcn->rx_data);
1408 if (bcn->buf)
1409 qdf_nbuf_free(bcn->buf);
1410 qdf_mem_free(bcn);
1411
1412 return status;
1413 }
1414
scm_handle_bcn_probe(struct scheduler_msg * msg)1415 QDF_STATUS scm_handle_bcn_probe(struct scheduler_msg *msg)
1416 {
1417 if (!msg) {
1418 scm_err("msg is NULL");
1419 return QDF_STATUS_E_NULL_VALUE;
1420 }
1421
1422 return __scm_handle_bcn_probe(msg->bodyptr);
1423 }
1424
1425 /**
1426 * scm_scan_apply_filter_get_entry() - apply filter and get the
1427 * scan entry
1428 * @psoc: psoc pointer
1429 * @db_entry: scan entry
1430 * @filter: filter to be applied
1431 * @scan_list: scan list to which entry is added
1432 *
1433 * Return: QDF_STATUS
1434 */
1435 static QDF_STATUS
scm_scan_apply_filter_get_entry(struct wlan_objmgr_psoc * psoc,struct scan_cache_entry * db_entry,struct scan_filter * filter,qdf_list_t * scan_list)1436 scm_scan_apply_filter_get_entry(struct wlan_objmgr_psoc *psoc,
1437 struct scan_cache_entry *db_entry,
1438 struct scan_filter *filter,
1439 qdf_list_t *scan_list)
1440 {
1441 struct scan_cache_node *scan_node = NULL;
1442 struct security_info security = {0};
1443 bool match;
1444
1445 if (!filter)
1446 match = true;
1447 else
1448 match = scm_filter_match(psoc, db_entry,
1449 filter, &security);
1450
1451 if (!match)
1452 return QDF_STATUS_SUCCESS;
1453
1454 scan_node = qdf_mem_malloc_atomic(sizeof(*scan_node));
1455 if (!scan_node)
1456 return QDF_STATUS_E_NOMEM;
1457
1458 scan_node->entry =
1459 util_scan_copy_cache_entry(db_entry);
1460
1461 if (!scan_node->entry) {
1462 qdf_mem_free(scan_node);
1463 return QDF_STATUS_E_NOMEM;
1464 }
1465
1466 qdf_mem_copy(&scan_node->entry->neg_sec_info,
1467 &security, sizeof(scan_node->entry->neg_sec_info));
1468
1469 qdf_list_insert_front(scan_list, &scan_node->node);
1470
1471 return QDF_STATUS_SUCCESS;
1472 }
1473
1474 /**
1475 * scm_get_results() - Iterate and get scan results
1476 * @psoc: psoc ptr
1477 * @scan_db: scan db
1478 * @filter: filter to be applied
1479 * @scan_list: scan list to which entry is added
1480 *
1481 * Return: void
1482 */
scm_get_results(struct wlan_objmgr_psoc * psoc,struct scan_dbs * scan_db,struct scan_filter * filter,qdf_list_t * scan_list)1483 static void scm_get_results(struct wlan_objmgr_psoc *psoc,
1484 struct scan_dbs *scan_db, struct scan_filter *filter,
1485 qdf_list_t *scan_list)
1486 {
1487 int i, count;
1488 struct scan_cache_node *cur_node;
1489 struct scan_cache_node *next_node = NULL;
1490
1491 for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1492 cur_node = scm_get_next_node(scan_db,
1493 &scan_db->scan_hash_tbl[i], NULL);
1494 count = qdf_list_size(&scan_db->scan_hash_tbl[i]);
1495 if (!count)
1496 continue;
1497 while (cur_node) {
1498 scm_scan_apply_filter_get_entry(psoc,
1499 cur_node->entry, filter, scan_list);
1500 next_node = scm_get_next_node(scan_db,
1501 &scan_db->scan_hash_tbl[i], cur_node);
1502 cur_node = next_node;
1503 }
1504 }
1505 }
1506
scm_purge_scan_results(qdf_list_t * scan_list)1507 QDF_STATUS scm_purge_scan_results(qdf_list_t *scan_list)
1508 {
1509 QDF_STATUS status;
1510 struct scan_cache_node *cur_node;
1511 qdf_list_node_t *cur_lst = NULL, *next_lst = NULL;
1512
1513 if (!scan_list) {
1514 scm_err("scan_result is NULL");
1515 return QDF_STATUS_E_INVAL;
1516 }
1517
1518 status = qdf_list_peek_front(scan_list, &cur_lst);
1519
1520 while (cur_lst) {
1521 qdf_list_peek_next(
1522 scan_list, cur_lst, &next_lst);
1523 cur_node = qdf_container_of(cur_lst,
1524 struct scan_cache_node, node);
1525 status = qdf_list_remove_node(scan_list,
1526 cur_lst);
1527 if (QDF_IS_STATUS_SUCCESS(status)) {
1528 util_scan_free_cache_entry(cur_node->entry);
1529 qdf_mem_free(cur_node);
1530 }
1531 cur_lst = next_lst;
1532 next_lst = NULL;
1533 }
1534
1535 qdf_list_destroy(scan_list);
1536 qdf_mem_free(scan_list);
1537
1538 return status;
1539 }
1540
scm_get_scan_result(struct wlan_objmgr_pdev * pdev,struct scan_filter * filter)1541 qdf_list_t *scm_get_scan_result(struct wlan_objmgr_pdev *pdev,
1542 struct scan_filter *filter)
1543 {
1544 struct wlan_objmgr_psoc *psoc;
1545 struct scan_dbs *scan_db;
1546 qdf_list_t *tmp_list;
1547
1548 if (!pdev) {
1549 scm_err("pdev is NULL");
1550 return NULL;
1551 }
1552
1553 psoc = wlan_pdev_get_psoc(pdev);
1554 if (!psoc) {
1555 scm_err("psoc is NULL");
1556 return NULL;
1557 }
1558
1559 scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1560 if (!scan_db) {
1561 scm_err("scan_db is NULL");
1562 return NULL;
1563 }
1564
1565 tmp_list = qdf_mem_malloc_atomic(sizeof(*tmp_list));
1566 if (!tmp_list) {
1567 scm_err("failed tp allocate scan_result");
1568 return NULL;
1569 }
1570 qdf_list_create(tmp_list,
1571 MAX_SCAN_CACHE_SIZE);
1572 scm_age_out_entries(psoc, scan_db);
1573 scm_get_results(psoc, scan_db, filter, tmp_list);
1574
1575 return tmp_list;
1576 }
1577
1578 /**
1579 * scm_iterate_db_and_call_func() - iterate and call the func
1580 * @scan_db: scan db
1581 * @func: func to be called
1582 * @arg: func arg
1583 *
1584 * Return: QDF_STATUS
1585 */
1586 static QDF_STATUS
scm_iterate_db_and_call_func(struct scan_dbs * scan_db,scan_iterator_func func,void * arg)1587 scm_iterate_db_and_call_func(struct scan_dbs *scan_db,
1588 scan_iterator_func func, void *arg)
1589 {
1590 int i;
1591 QDF_STATUS status = QDF_STATUS_SUCCESS;
1592 struct scan_cache_node *cur_node;
1593 struct scan_cache_node *next_node = NULL;
1594
1595 if (!func)
1596 return QDF_STATUS_E_INVAL;
1597
1598 for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1599 cur_node = scm_get_next_node(scan_db,
1600 &scan_db->scan_hash_tbl[i], NULL);
1601 while (cur_node) {
1602 status = func(arg, cur_node->entry);
1603 if (QDF_IS_STATUS_ERROR(status)) {
1604 scm_scan_entry_put_ref(scan_db,
1605 cur_node, true);
1606 return status;
1607 }
1608 next_node = scm_get_next_node(scan_db,
1609 &scan_db->scan_hash_tbl[i], cur_node);
1610 cur_node = next_node;
1611 }
1612 }
1613
1614 return status;
1615 }
1616
1617 QDF_STATUS
scm_iterate_scan_db(struct wlan_objmgr_pdev * pdev,scan_iterator_func func,void * arg)1618 scm_iterate_scan_db(struct wlan_objmgr_pdev *pdev,
1619 scan_iterator_func func, void *arg)
1620 {
1621 struct wlan_objmgr_psoc *psoc;
1622 struct scan_dbs *scan_db;
1623 QDF_STATUS status;
1624
1625 if (!func) {
1626 scm_err("func is NULL");
1627 return QDF_STATUS_E_INVAL;
1628 }
1629
1630 if (!pdev) {
1631 scm_err("pdev is NULL");
1632 return QDF_STATUS_E_INVAL;
1633 }
1634
1635 psoc = wlan_pdev_get_psoc(pdev);
1636 if (!psoc) {
1637 scm_err("psoc is NULL");
1638 return QDF_STATUS_E_INVAL;
1639 }
1640 scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1641 if (!scan_db) {
1642 scm_err("scan_db is NULL");
1643 return QDF_STATUS_E_INVAL;
1644 }
1645
1646 scm_age_out_entries(psoc, scan_db);
1647 status = scm_iterate_db_and_call_func(scan_db, func, arg);
1648
1649 return status;
1650 }
1651
1652 /**
1653 * scm_scan_apply_filter_flush_entry() -flush scan entries depending
1654 * on filter
1655 * @psoc: psoc ptr
1656 * @scan_db: scan db
1657 * @db_node: node on which filters are applied
1658 * @filter: filter to be applied
1659 *
1660 * Return: QDF_STATUS
1661 */
1662 static QDF_STATUS
scm_scan_apply_filter_flush_entry(struct wlan_objmgr_psoc * psoc,struct scan_dbs * scan_db,struct scan_cache_node * db_node,struct scan_filter * filter)1663 scm_scan_apply_filter_flush_entry(struct wlan_objmgr_psoc *psoc,
1664 struct scan_dbs *scan_db,
1665 struct scan_cache_node *db_node,
1666 struct scan_filter *filter)
1667 {
1668 struct security_info security = {0};
1669 bool match;
1670
1671 if (!filter)
1672 match = true;
1673 else
1674 match = scm_filter_match(psoc, db_node->entry,
1675 filter, &security);
1676
1677 if (!match)
1678 return QDF_STATUS_SUCCESS;
1679
1680 qdf_spin_lock_bh(&scan_db->scan_db_lock);
1681 scm_scan_entry_del(scan_db, db_node);
1682 qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1683
1684 return QDF_STATUS_SUCCESS;
1685 }
1686
1687 /**
1688 * scm_flush_scan_entries() - API to flush scan entries depending on filters
1689 * @psoc: psoc ptr
1690 * @scan_db: scan db
1691 * @filter: filter
1692 * @pdev_id: pdev id of the scan db
1693 *
1694 * Return: void
1695 */
scm_flush_scan_entries(struct wlan_objmgr_psoc * psoc,struct scan_dbs * scan_db,struct scan_filter * filter,uint8_t pdev_id)1696 static void scm_flush_scan_entries(struct wlan_objmgr_psoc *psoc,
1697 struct scan_dbs *scan_db, struct scan_filter *filter, uint8_t pdev_id)
1698 {
1699 int i;
1700 struct scan_cache_node *cur_node;
1701 struct scan_cache_node *next_node = NULL;
1702
1703 for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1704 cur_node = scm_get_next_node(scan_db,
1705 &scan_db->scan_hash_tbl[i], NULL);
1706 while (cur_node) {
1707 scm_scan_apply_filter_flush_entry(psoc, scan_db,
1708 cur_node, filter);
1709 next_node = scm_get_next_node(scan_db,
1710 &scan_db->scan_hash_tbl[i], cur_node);
1711 cur_node = next_node;
1712 }
1713 }
1714 /* if all scan results are flushed reset scan channel info as well */
1715 if (!filter)
1716 scm_reset_scan_chan_info(psoc, pdev_id);
1717 }
1718
scm_flush_results(struct wlan_objmgr_pdev * pdev,struct scan_filter * filter)1719 QDF_STATUS scm_flush_results(struct wlan_objmgr_pdev *pdev,
1720 struct scan_filter *filter)
1721 {
1722 struct wlan_objmgr_psoc *psoc;
1723 struct scan_dbs *scan_db;
1724 QDF_STATUS status = QDF_STATUS_SUCCESS;
1725
1726 if (!pdev) {
1727 scm_err("pdev is NULL");
1728 return QDF_STATUS_E_INVAL;
1729 }
1730
1731 psoc = wlan_pdev_get_psoc(pdev);
1732 if (!psoc) {
1733 scm_err("psoc is NULL");
1734 return QDF_STATUS_E_INVAL;
1735 }
1736
1737 scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1738 if (!scan_db) {
1739 scm_err("scan_db is NULL");
1740 return QDF_STATUS_E_INVAL;
1741 }
1742
1743 scm_flush_scan_entries(psoc, scan_db, filter,
1744 wlan_objmgr_pdev_get_pdev_id(pdev));
1745
1746 return status;
1747 }
1748
1749 /**
1750 * scm_filter_channels() - Remove entries not belonging to channel list
1751 * @pdev: pointer to pdev
1752 * @scan_db: scan db
1753 * @db_node: node on which filters are applied
1754 * @chan_freq_list: valid channel frequency (in MHz) list
1755 * @num_chan: number of channels
1756 *
1757 * Return: QDF_STATUS
1758 */
scm_filter_channels(struct wlan_objmgr_pdev * pdev,struct scan_dbs * scan_db,struct scan_cache_node * db_node,uint32_t * chan_freq_list,uint32_t num_chan)1759 static void scm_filter_channels(struct wlan_objmgr_pdev *pdev,
1760 struct scan_dbs *scan_db,
1761 struct scan_cache_node *db_node,
1762 uint32_t *chan_freq_list, uint32_t num_chan)
1763 {
1764 int i;
1765 bool match = false;
1766
1767 for (i = 0; i < num_chan; i++) {
1768 if (chan_freq_list[i] == util_scan_entry_channel_frequency(
1769 db_node->entry)) {
1770 match = true;
1771 break;
1772 }
1773 }
1774
1775 if (!match) {
1776 qdf_spin_lock_bh(&scan_db->scan_db_lock);
1777 scm_scan_entry_del(scan_db, db_node);
1778 qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1779 }
1780 }
1781
scm_filter_valid_channel(struct wlan_objmgr_pdev * pdev,uint32_t * chan_freq_list,uint32_t num_chan)1782 void scm_filter_valid_channel(struct wlan_objmgr_pdev *pdev,
1783 uint32_t *chan_freq_list, uint32_t num_chan)
1784 {
1785 int i;
1786 struct wlan_objmgr_psoc *psoc;
1787 struct scan_dbs *scan_db;
1788 struct scan_cache_node *cur_node;
1789 struct scan_cache_node *next_node = NULL;
1790
1791 scm_debug("num_chan = %d", num_chan);
1792
1793 if (!pdev) {
1794 scm_err("pdev is NULL");
1795 return;
1796 }
1797
1798 psoc = wlan_pdev_get_psoc(pdev);
1799 if (!psoc) {
1800 scm_err("psoc is NULL");
1801 return;
1802 }
1803
1804 scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1805 if (!scan_db) {
1806 scm_err("scan_db is NULL");
1807 return;
1808 }
1809
1810 for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1811 cur_node = scm_get_next_node(scan_db,
1812 &scan_db->scan_hash_tbl[i], NULL);
1813 while (cur_node) {
1814 scm_filter_channels(pdev, scan_db,
1815 cur_node, chan_freq_list, num_chan);
1816 next_node = scm_get_next_node(scan_db,
1817 &scan_db->scan_hash_tbl[i], cur_node);
1818 cur_node = next_node;
1819 }
1820 }
1821 }
1822
scm_scan_register_mbssid_cb(struct wlan_objmgr_psoc * psoc,update_mbssid_bcn_prb_rsp cb)1823 QDF_STATUS scm_scan_register_mbssid_cb(struct wlan_objmgr_psoc *psoc,
1824 update_mbssid_bcn_prb_rsp cb)
1825 {
1826 struct wlan_scan_obj *scan_obj;
1827
1828 scan_obj = wlan_psoc_get_scan_obj(psoc);
1829 if (!scan_obj) {
1830 scm_err("scan obj is NULL");
1831 return QDF_STATUS_E_INVAL;
1832 }
1833
1834 scan_obj->cb.inform_mbssid_bcn_prb_rsp = cb;
1835
1836 return QDF_STATUS_SUCCESS;
1837 }
1838
scm_scan_register_bcn_cb(struct wlan_objmgr_psoc * psoc,update_beacon_cb cb,enum scan_cb_type type)1839 QDF_STATUS scm_scan_register_bcn_cb(struct wlan_objmgr_psoc *psoc,
1840 update_beacon_cb cb, enum scan_cb_type type)
1841 {
1842 struct wlan_scan_obj *scan_obj;
1843
1844 scan_obj = wlan_psoc_get_scan_obj(psoc);
1845 if (!scan_obj) {
1846 scm_err("scan obj is NULL");
1847 return QDF_STATUS_E_INVAL;
1848 }
1849 switch (type) {
1850 case SCAN_CB_TYPE_INFORM_BCN:
1851 scan_obj->cb.inform_beacon = cb;
1852 break;
1853 case SCAN_CB_TYPE_UPDATE_BCN:
1854 scan_obj->cb.update_beacon = cb;
1855 break;
1856 case SCAN_CB_TYPE_UNLINK_BSS:
1857 scan_obj->cb.unlink_bss = cb;
1858 break;
1859 default:
1860 scm_err("invalid cb type %d", type);
1861 }
1862
1863 return QDF_STATUS_SUCCESS;
1864 }
1865
scm_reset_scan_chan_info(struct wlan_objmgr_psoc * psoc,uint8_t pdev_id)1866 void scm_reset_scan_chan_info(struct wlan_objmgr_psoc *psoc, uint8_t pdev_id)
1867 {
1868 struct wlan_scan_obj *scan_obj;
1869
1870 scan_obj = wlan_psoc_get_scan_obj(psoc);
1871 if (!scan_obj)
1872 return;
1873
1874 scm_debug("pdev %d, Reset all channel info", pdev_id);
1875 qdf_mem_zero(&scan_obj->pdev_info[pdev_id].chan_scan_info,
1876 sizeof(scan_obj->pdev_info[pdev_id].chan_scan_info));
1877 }
1878
scm_db_init(struct wlan_objmgr_psoc * psoc)1879 QDF_STATUS scm_db_init(struct wlan_objmgr_psoc *psoc)
1880 {
1881 int i, j;
1882 struct scan_dbs *scan_db;
1883
1884 if (!psoc) {
1885 scm_err("psoc is NULL");
1886 return QDF_STATUS_E_INVAL;
1887 }
1888
1889 /* Initialize the scan database per pdev */
1890 for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) {
1891 scan_db = wlan_pdevid_get_scan_db(psoc, i);
1892 if (!scan_db) {
1893 scm_err("scan_db is NULL %d", i);
1894 continue;
1895 }
1896 scan_db->num_entries = 0;
1897 qdf_spinlock_create(&scan_db->scan_db_lock);
1898 for (j = 0; j < SCAN_HASH_SIZE; j++)
1899 qdf_list_create(&scan_db->scan_hash_tbl[j],
1900 MAX_SCAN_CACHE_SIZE);
1901 scm_reset_scan_chan_info(psoc, i);
1902 }
1903 return QDF_STATUS_SUCCESS;
1904 }
1905
scm_db_deinit(struct wlan_objmgr_psoc * psoc)1906 QDF_STATUS scm_db_deinit(struct wlan_objmgr_psoc *psoc)
1907 {
1908 int i, j;
1909 struct scan_dbs *scan_db;
1910
1911 if (!psoc) {
1912 scm_err("scan obj is NULL");
1913 return QDF_STATUS_E_INVAL;
1914 }
1915
1916 /* Initialize the scan database per pdev */
1917 for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) {
1918 scan_db = wlan_pdevid_get_scan_db(psoc, i);
1919 if (!scan_db) {
1920 scm_err("scan_db is NULL %d", i);
1921 continue;
1922 }
1923
1924 scm_flush_scan_entries(psoc, scan_db, NULL, i);
1925 for (j = 0; j < SCAN_HASH_SIZE; j++)
1926 qdf_list_destroy(&scan_db->scan_hash_tbl[j]);
1927 qdf_spinlock_destroy(&scan_db->scan_db_lock);
1928 }
1929
1930 return QDF_STATUS_SUCCESS;
1931 }
1932
1933 #ifdef FEATURE_6G_SCAN_CHAN_SORT_ALGO
scm_channel_list_db_init(struct wlan_objmgr_psoc * psoc)1934 QDF_STATUS scm_channel_list_db_init(struct wlan_objmgr_psoc *psoc)
1935 {
1936 uint32_t i, j;
1937 uint32_t min_freq, max_freq;
1938 struct channel_list_db *rnr_channel_db;
1939
1940 min_freq = wlan_reg_min_6ghz_chan_freq();
1941 max_freq = wlan_reg_max_6ghz_chan_freq();
1942
1943 scm_info("min_freq %d max_freq %d", min_freq, max_freq);
1944 i = min_freq;
1945 rnr_channel_db = scm_get_rnr_channel_db(psoc);
1946 if (!rnr_channel_db)
1947 return QDF_STATUS_E_INVAL;
1948
1949 for (j = 0; j < QDF_ARRAY_SIZE(rnr_channel_db->channel); j++) {
1950 if (i >= min_freq && i <= max_freq)
1951 rnr_channel_db->channel[j].chan_freq = i;
1952 i += 20;
1953 /* init list for all to avoid uninitialized list */
1954 qdf_list_create(&rnr_channel_db->channel[j].rnr_list,
1955 WLAN_MAX_RNR_COUNT);
1956 }
1957 return QDF_STATUS_SUCCESS;
1958 }
1959
scm_channel_list_db_deinit(struct wlan_objmgr_psoc * psoc)1960 QDF_STATUS scm_channel_list_db_deinit(struct wlan_objmgr_psoc *psoc)
1961 {
1962 int i;
1963 qdf_list_node_t *cur_node, *next_node;
1964 struct meta_rnr_channel *channel;
1965 struct scan_rnr_node *rnr_node;
1966 struct channel_list_db *rnr_channel_db;
1967
1968 rnr_channel_db = scm_get_rnr_channel_db(psoc);
1969 if (!rnr_channel_db)
1970 return QDF_STATUS_E_INVAL;
1971
1972 for (i = 0; i < QDF_ARRAY_SIZE(rnr_channel_db->channel); i++) {
1973 channel = &rnr_channel_db->channel[i];
1974 channel->chan_freq = 0;
1975 channel->beacon_probe_last_time_found = 0;
1976 channel->bss_beacon_probe_count = 0;
1977 channel->saved_profile_count = 0;
1978 cur_node = NULL;
1979 qdf_list_peek_front(&channel->rnr_list, &cur_node);
1980 while (cur_node) {
1981 next_node = NULL;
1982 qdf_list_peek_next(&channel->rnr_list, cur_node,
1983 &next_node);
1984 rnr_node = qdf_container_of(cur_node,
1985 struct scan_rnr_node,
1986 node);
1987 qdf_list_remove_node(&channel->rnr_list,
1988 &rnr_node->node);
1989 qdf_mem_free(rnr_node);
1990 cur_node = next_node;
1991 next_node = NULL;
1992 }
1993 qdf_list_destroy(&channel->rnr_list);
1994 }
1995
1996 return QDF_STATUS_SUCCESS;
1997 }
1998
scm_rnr_db_flush(struct wlan_objmgr_psoc * psoc)1999 QDF_STATUS scm_rnr_db_flush(struct wlan_objmgr_psoc *psoc)
2000 {
2001 int i;
2002 qdf_list_node_t *cur_node, *next_node;
2003 struct meta_rnr_channel *channel;
2004 struct scan_rnr_node *rnr_node;
2005 struct channel_list_db *rnr_channel_db;
2006
2007 rnr_channel_db = scm_get_rnr_channel_db(psoc);
2008 if (!rnr_channel_db)
2009 return QDF_STATUS_E_INVAL;
2010
2011 for (i = 0; i < QDF_ARRAY_SIZE(rnr_channel_db->channel); i++) {
2012 channel = &rnr_channel_db->channel[i];
2013 cur_node = NULL;
2014 qdf_list_peek_front(&channel->rnr_list, &cur_node);
2015 while (cur_node) {
2016 next_node = NULL;
2017 qdf_list_peek_next(&channel->rnr_list, cur_node,
2018 &next_node);
2019 rnr_node = qdf_container_of(cur_node,
2020 struct scan_rnr_node,
2021 node);
2022 qdf_list_remove_node(&channel->rnr_list,
2023 &rnr_node->node);
2024 qdf_mem_free(rnr_node);
2025 cur_node = next_node;
2026 next_node = NULL;
2027 }
2028 /* Reset beacon info */
2029 channel->beacon_probe_last_time_found = 0;
2030 channel->bss_beacon_probe_count = 0;
2031 }
2032
2033 return QDF_STATUS_SUCCESS;
2034 }
2035
scm_update_rnr_from_scan_cache(struct wlan_objmgr_pdev * pdev)2036 void scm_update_rnr_from_scan_cache(struct wlan_objmgr_pdev *pdev)
2037 {
2038 uint8_t i;
2039 struct scan_dbs *scan_db;
2040 struct scan_cache_node *cur_node;
2041 struct scan_cache_node *next_node = NULL;
2042 struct wlan_objmgr_psoc *psoc;
2043 struct scan_cache_entry *entry;
2044
2045 psoc = wlan_pdev_get_psoc(pdev);
2046 if (!psoc) {
2047 scm_err("psoc is NULL");
2048 return;
2049 }
2050 scan_db = wlan_pdev_get_scan_db(psoc, pdev);
2051 if (!scan_db) {
2052 scm_err("scan_db is NULL");
2053 return;
2054 }
2055
2056 for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
2057 cur_node = scm_get_next_node(scan_db,
2058 &scan_db->scan_hash_tbl[i], NULL);
2059 while (cur_node) {
2060 entry = cur_node->entry;
2061 scm_add_rnr_channel_db(psoc, entry);
2062 next_node =
2063 scm_get_next_node(scan_db,
2064 &scan_db->scan_hash_tbl[i],
2065 cur_node);
2066 cur_node = next_node;
2067 next_node = NULL;
2068 }
2069 }
2070 }
2071 #endif
2072
scm_update_scan_mlme_info(struct wlan_objmgr_pdev * pdev,struct scan_cache_entry * entry)2073 QDF_STATUS scm_update_scan_mlme_info(struct wlan_objmgr_pdev *pdev,
2074 struct scan_cache_entry *entry)
2075 {
2076 uint8_t hash_idx;
2077 struct scan_dbs *scan_db;
2078 struct scan_cache_node *cur_node;
2079 struct scan_cache_node *next_node = NULL;
2080 struct wlan_objmgr_psoc *psoc;
2081
2082 psoc = wlan_pdev_get_psoc(pdev);
2083 if (!psoc) {
2084 scm_err("psoc is NULL");
2085 return QDF_STATUS_E_INVAL;
2086 }
2087 scan_db = wlan_pdev_get_scan_db(psoc, pdev);
2088 if (!scan_db) {
2089 scm_err("scan_db is NULL");
2090 return QDF_STATUS_E_INVAL;
2091 }
2092
2093 hash_idx = SCAN_GET_HASH(entry->bssid.bytes);
2094
2095 cur_node = scm_get_next_node(scan_db,
2096 &scan_db->scan_hash_tbl[hash_idx], NULL);
2097
2098 while (cur_node) {
2099 if (util_is_scan_entry_match(entry,
2100 cur_node->entry)) {
2101 /* Acquire db lock to prevent simultaneous update */
2102 qdf_spin_lock_bh(&scan_db->scan_db_lock);
2103 scm_update_mlme_info(entry, cur_node->entry);
2104 qdf_spin_unlock_bh(&scan_db->scan_db_lock);
2105 scm_scan_entry_put_ref(scan_db,
2106 cur_node, true);
2107 return QDF_STATUS_SUCCESS;
2108 }
2109 next_node = scm_get_next_node(scan_db,
2110 &scan_db->scan_hash_tbl[hash_idx], cur_node);
2111 cur_node = next_node;
2112 }
2113
2114 return QDF_STATUS_E_INVAL;
2115 }
2116
scm_scan_update_mlme_by_bssinfo(struct wlan_objmgr_pdev * pdev,struct bss_info * bss_info,struct mlme_info * mlme)2117 QDF_STATUS scm_scan_update_mlme_by_bssinfo(struct wlan_objmgr_pdev *pdev,
2118 struct bss_info *bss_info, struct mlme_info *mlme)
2119 {
2120 uint8_t hash_idx;
2121 struct scan_dbs *scan_db;
2122 struct scan_cache_node *cur_node;
2123 struct scan_cache_node *next_node = NULL;
2124 struct wlan_objmgr_psoc *psoc;
2125 struct scan_cache_entry *entry;
2126
2127 psoc = wlan_pdev_get_psoc(pdev);
2128 if (!psoc) {
2129 scm_err("psoc is NULL");
2130 return QDF_STATUS_E_INVAL;
2131 }
2132 scan_db = wlan_pdev_get_scan_db(psoc, pdev);
2133 if (!scan_db) {
2134 scm_err("scan_db is NULL");
2135 return QDF_STATUS_E_INVAL;
2136 }
2137
2138 hash_idx = SCAN_GET_HASH(bss_info->bssid.bytes);
2139 cur_node = scm_get_next_node(scan_db,
2140 &scan_db->scan_hash_tbl[hash_idx], NULL);
2141 while (cur_node) {
2142 entry = cur_node->entry;
2143 if (qdf_is_macaddr_equal(&bss_info->bssid, &entry->bssid) &&
2144 (util_is_ssid_match(&bss_info->ssid, &entry->ssid)) &&
2145 (bss_info->freq == entry->channel.chan_freq)) {
2146 /* Acquire db lock to prevent simultaneous update */
2147 qdf_spin_lock_bh(&scan_db->scan_db_lock);
2148 qdf_mem_copy(&entry->mlme_info, mlme,
2149 sizeof(struct mlme_info));
2150 scm_debug("BSSID: "QDF_MAC_ADDR_FMT" set assoc_state to %d with age %lu ms",
2151 QDF_MAC_ADDR_REF(entry->bssid.bytes),
2152 mlme->assoc_state,
2153 util_scan_entry_age(entry));
2154 scm_scan_entry_put_ref(scan_db,
2155 cur_node, false);
2156 qdf_spin_unlock_bh(&scan_db->scan_db_lock);
2157 return QDF_STATUS_SUCCESS;
2158 }
2159 next_node = scm_get_next_node(scan_db,
2160 &scan_db->scan_hash_tbl[hash_idx], cur_node);
2161 cur_node = next_node;
2162 }
2163
2164 return QDF_STATUS_E_INVAL;
2165 }
2166
scm_get_last_scan_time_per_channel(struct wlan_objmgr_vdev * vdev,uint32_t freq)2167 uint32_t scm_get_last_scan_time_per_channel(struct wlan_objmgr_vdev *vdev,
2168 uint32_t freq)
2169 {
2170 struct wlan_scan_obj *scan;
2171 struct chan_list_scan_info *chan_info;
2172 uint8_t pdev_id;
2173 int i;
2174
2175 scan = wlan_vdev_get_scan_obj(vdev);
2176 if (!scan)
2177 return 0;
2178
2179 pdev_id = wlan_scan_vdev_get_pdev_id(vdev);
2180 chan_info = &scan->pdev_info[pdev_id].chan_scan_info;
2181
2182 for (i = 0; i < chan_info->num_chan ; i++) {
2183 if (chan_info->ch_scan_info[i].freq == freq)
2184 return chan_info->ch_scan_info[i].last_scan_time;
2185 }
2186
2187 return 0;
2188 }
2189
2190 struct scan_cache_entry *
scm_scan_get_scan_entry_by_mac_freq(struct wlan_objmgr_pdev * pdev,struct qdf_mac_addr * bssid,uint16_t freq)2191 scm_scan_get_scan_entry_by_mac_freq(struct wlan_objmgr_pdev *pdev,
2192 struct qdf_mac_addr *bssid,
2193 uint16_t freq)
2194 {
2195 struct scan_filter *scan_filter;
2196 qdf_list_t *list = NULL;
2197 struct scan_cache_node *first_node = NULL;
2198 qdf_list_node_t *cur_node = NULL;
2199 struct scan_cache_entry *scan_entry = NULL;
2200
2201 scan_filter = qdf_mem_malloc(sizeof(*scan_filter));
2202 if (!scan_filter)
2203 return NULL;
2204 scan_filter->num_of_bssid = 1;
2205 scan_filter->chan_freq_list[0] = freq;
2206 scan_filter->num_of_channels = 1;
2207 qdf_copy_macaddr(&scan_filter->bssid_list[0], bssid);
2208
2209 list = scm_get_scan_result(pdev, scan_filter);
2210 qdf_mem_free(scan_filter);
2211 if (!list || (list && !qdf_list_size(list))) {
2212 scm_debug("Scan entry for bssid:"
2213 QDF_MAC_ADDR_FMT "and freq %d not found",
2214 QDF_MAC_ADDR_REF(bssid->bytes), freq);
2215 goto done;
2216 }
2217 /*
2218 * There might be multiple scan results in the scan db with given mac
2219 * address(e.g. SSID/some capabilities of the AP have just changed and
2220 * old entry is not aged out yet). scm_get_scan_result() inserts the
2221 * latest scan result at the front of the given list. So, it's ok to
2222 * pick scan result from the front node alone.
2223 */
2224 qdf_list_peek_front(list, &cur_node);
2225 first_node = qdf_container_of(cur_node,
2226 struct scan_cache_node,
2227 node);
2228
2229 if (first_node && first_node->entry)
2230 scan_entry = util_scan_copy_cache_entry(first_node->entry);
2231
2232 done:
2233 if (list)
2234 scm_purge_scan_results(list);
2235
2236 return scan_entry;
2237 }
2238
2239 QDF_STATUS
scm_scan_get_entry_by_mac_addr(struct wlan_objmgr_pdev * pdev,struct qdf_mac_addr * bssid,struct element_info * frame)2240 scm_scan_get_entry_by_mac_addr(struct wlan_objmgr_pdev *pdev,
2241 struct qdf_mac_addr *bssid,
2242 struct element_info *frame)
2243 {
2244 struct scan_filter *scan_filter;
2245 qdf_list_t *list = NULL;
2246 struct scan_cache_node *first_node = NULL;
2247 qdf_list_node_t *cur_node = NULL;
2248 QDF_STATUS status = QDF_STATUS_SUCCESS;
2249
2250 scan_filter = qdf_mem_malloc(sizeof(*scan_filter));
2251 if (!scan_filter)
2252 return QDF_STATUS_E_NOMEM;
2253 scan_filter->num_of_bssid = 1;
2254 qdf_copy_macaddr(&scan_filter->bssid_list[0], bssid);
2255 list = scm_get_scan_result(pdev, scan_filter);
2256 qdf_mem_free(scan_filter);
2257 if (!list || (list && !qdf_list_size(list))) {
2258 status = QDF_STATUS_E_INVAL;
2259 goto done;
2260 }
2261 /*
2262 * There might be multiple scan results in the scan db with given mac
2263 * address(e.g. SSID/some capabilities of the AP have just changed and
2264 * old entry is not aged out yet). scm_get_scan_result() inserts the
2265 * latest scan result at the front of the given list. So, it's ok to
2266 * pick scan result from the front node alone.
2267 */
2268 qdf_list_peek_front(list, &cur_node);
2269 first_node = qdf_container_of(cur_node,
2270 struct scan_cache_node,
2271 node);
2272 if (first_node && first_node->entry) {
2273 frame->len = first_node->entry->raw_frame.len;
2274 frame->ptr = qdf_mem_malloc(frame->len);
2275 if (!frame->ptr) {
2276 status = QDF_STATUS_E_NOMEM;
2277 goto done;
2278 }
2279 qdf_mem_copy(frame->ptr,
2280 first_node->entry->raw_frame.ptr,
2281 frame->len);
2282 }
2283
2284 done:
2285 if (list)
2286 scm_purge_scan_results(list);
2287
2288 return status;
2289 }
2290
2291 #ifdef WLAN_FEATURE_11BE_MLO
scm_get_mld_addr_by_link_addr(struct wlan_objmgr_pdev * pdev,struct qdf_mac_addr * link_addr,struct qdf_mac_addr * mld_mac_addr)2292 QDF_STATUS scm_get_mld_addr_by_link_addr(struct wlan_objmgr_pdev *pdev,
2293 struct qdf_mac_addr *link_addr,
2294 struct qdf_mac_addr *mld_mac_addr)
2295 {
2296 struct scan_cache_entry *entry = NULL;
2297
2298 /* For ML connection, BSSID is link address */
2299 entry = scm_scan_get_entry_by_bssid(pdev, link_addr);
2300 if (!entry) {
2301 scm_err("scan entry not found for link addr: " QDF_MAC_ADDR_FMT,
2302 QDF_MAC_ADDR_REF(link_addr->bytes));
2303 return QDF_STATUS_E_FAILURE;
2304 }
2305
2306 if (qdf_is_macaddr_zero(&entry->ml_info.mld_mac_addr)) {
2307 util_scan_free_cache_entry(entry);
2308 return QDF_STATUS_E_FAILURE;
2309 }
2310
2311 qdf_mem_copy(mld_mac_addr, &entry->ml_info.mld_mac_addr,
2312 QDF_MAC_ADDR_SIZE);
2313 util_scan_free_cache_entry(entry);
2314
2315 return QDF_STATUS_SUCCESS;
2316 }
2317 #endif
2318
2319 struct scan_cache_entry *
scm_scan_get_entry_by_bssid(struct wlan_objmgr_pdev * pdev,struct qdf_mac_addr * bssid)2320 scm_scan_get_entry_by_bssid(struct wlan_objmgr_pdev *pdev,
2321 struct qdf_mac_addr *bssid)
2322 {
2323 struct scan_filter *scan_filter;
2324 qdf_list_t *list = NULL;
2325 struct scan_cache_node *first_node = NULL;
2326 qdf_list_node_t *cur_node = NULL;
2327 struct scan_cache_entry *entry = NULL, *scan_entry = NULL;
2328
2329 if (!pdev)
2330 return NULL;
2331
2332 scan_filter = qdf_mem_malloc(sizeof(*scan_filter));
2333 if (!scan_filter)
2334 return NULL;
2335
2336 scan_filter->num_of_bssid = 1;
2337 qdf_mem_copy(scan_filter->bssid_list[0].bytes,
2338 bssid, sizeof(struct qdf_mac_addr));
2339 list = scm_get_scan_result(pdev, scan_filter);
2340 qdf_mem_free(scan_filter);
2341
2342 if (!list || (!qdf_list_size(list))) {
2343 scm_debug("Scan entry for bssid: "QDF_MAC_ADDR_FMT" not found",
2344 QDF_MAC_ADDR_REF(bssid->bytes));
2345 goto exit;
2346 }
2347
2348 qdf_list_peek_front(list, &cur_node);
2349 first_node = qdf_container_of(cur_node, struct scan_cache_node,
2350 node);
2351 if (first_node && first_node->entry) {
2352 entry = first_node->entry;
2353 scan_entry = util_scan_copy_cache_entry(entry);
2354 }
2355 exit:
2356 if (list)
2357 scm_purge_scan_results(list);
2358
2359 return scan_entry;
2360 }
2361
scm_scan_entries_contain_cmn_akm(struct scan_cache_entry * entry1,struct scan_cache_entry * entry2)2362 bool scm_scan_entries_contain_cmn_akm(struct scan_cache_entry *entry1,
2363 struct scan_cache_entry *entry2)
2364 {
2365 wlan_crypto_key_mgmt akm_type;
2366 uint32_t key_mgmt;
2367 struct security_info *entry1_sec_info, *entry2_sec_info;
2368
2369 /* For Open security, allow connection */
2370 if (!entry1->ie_list.rsn && !entry2->ie_list.rsn)
2371 return true;
2372
2373 /* If only one is open connection, remove the partner link */
2374 if (!entry1->ie_list.rsn || !entry2->ie_list.rsn)
2375 return false;
2376
2377 entry1_sec_info = &entry1->neg_sec_info;
2378 entry2_sec_info = &entry2->neg_sec_info;
2379
2380 /* Check if MFPC is equal */
2381 if ((entry1_sec_info->rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_ENABLED) ^
2382 (entry2_sec_info->rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_ENABLED)) {
2383 scm_debug("MFPC capability is not equal 0x%x, 0x%x",
2384 entry1_sec_info->rsn_caps, entry2_sec_info->rsn_caps);
2385 return false;
2386 }
2387
2388 /* Check UC cipher suite */
2389 if (!UCAST_CIPHER_MATCH(entry1_sec_info, entry2_sec_info)) {
2390 scm_debug("Intersected UC cipher bitmap NULL 0x%x, 0x%x",
2391 entry1_sec_info->ucastcipherset,
2392 entry2_sec_info->ucastcipherset);
2393 return false;
2394 }
2395
2396 /* Check MC cipher suite */
2397 if (!MCAST_CIPHER_MATCH(entry1_sec_info, entry2_sec_info)) {
2398 scm_debug("Intersected MC cipher bitmap NULL 0x%x, 0x%x",
2399 entry1_sec_info->mcastcipherset,
2400 entry2_sec_info->mcastcipherset);
2401 return false;
2402 }
2403
2404 /* Check AKM suite */
2405 key_mgmt = entry1_sec_info->key_mgmt;
2406 akm_type = wlan_crypto_get_secure_akm_available(key_mgmt);
2407 if (akm_type == WLAN_CRYPTO_KEY_MGMT_MAX) {
2408 scm_debug("No matching AKM 0x%x", key_mgmt);
2409 return false;
2410 } else if (!HAS_KEY_MGMT(entry2_sec_info, akm_type)) {
2411 scm_debug("Intersected AKM bitmap NULL 0x%x, 0x%x",
2412 entry1_sec_info->key_mgmt, entry2_sec_info->key_mgmt);
2413 return false;
2414 } else {
2415 key_mgmt = 0x0;
2416 QDF_SET_PARAM(key_mgmt, akm_type);
2417 }
2418
2419 /* If not SAE AKM no need to check H2E capability match */
2420 if (!WLAN_CRYPTO_IS_AKM_SAE(key_mgmt))
2421 return true;
2422
2423 /* If SAE_H2E capability is not equal then treat as mismatch */
2424 if (util_scan_entry_sae_h2e_capable(entry1) ^
2425 util_scan_entry_sae_h2e_capable(entry2)) {
2426 scm_debug("SAE-H2E capability mismatch");
2427 return false;
2428 }
2429
2430 return true;
2431 }
2432