xref: /wlan-dirver/qca-wifi-host-cmn/umac/scan/core/src/wlan_scan_cache_db.c (revision 836d95ed6fcf0fa09ba8e4d4edc144823f97ae11)
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 
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 
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 
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 
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 
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
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  */
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  */
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  */
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  */
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 
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  */
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 *
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 *
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  */
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 
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
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
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 
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  */
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  */
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
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
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
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  */
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
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 
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  */
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  */
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
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  */
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 
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 
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
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  */
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 
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 
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
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
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
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  */
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 
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  */
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 
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 
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 
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 
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 
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 
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
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 
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 
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 
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 
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 
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 
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 *
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
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
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 *
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 
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