xref: /wlan-dirver/qca-wifi-host-cmn/umac/scan/core/src/wlan_scan_cache_db.c (revision f4b29f3ad5284b62be9a856132a100beee3c6a6a)
1 /*
2  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * DOC: contains scan cache api and functionality
21  * The Scan entries are protected by scan_db_lock. Holding the lock
22  * for whole scan operation during get/flush scan results may take
23  * more than 5 ms and thus ref count is used along with scan_db_lock.
24  * Below are the operation on scan cache entry:
25  * - While adding new node to the entry scan_db_lock is taken and ref_cnt
26  *   is initialized and incremented. Also the cookie will be set to valid value.
27  * - The ref count incremented during adding new node should be decremented only
28  *   by a delete operation on the node. But there can be multiple concurrent
29  *   delete operations on a node from different threads which may lead to ref
30  *   count being decremented multiple time and freeing the node even if node
31  *   is in use. So to maintain atomicity between multiple delete operations
32  *   on a same node from different threads, a cookie is used to check if node is
33  *   logically deleted or not. A delete operation will set the cookie to 0
34  *   making it invalid. So if the 2nd thread find the cookie as invalid it will
35  *   not try to delete and decrement the ref count of the node again.
36  * - This Cookie is also used to check if node is valid while iterating through
37  *   the scan cache to avoid duplicate entries.
38  * - Once ref_cnt become 0, i.e. it is logically deleted and no thread is using
39  *   it the node is physically deleted from the scan cache.
40  * - While reading the node the ref_cnt should be incremented. Once reading
41  *   operation is done ref_cnt is decremented.
42  */
43 #include <qdf_status.h>
44 #include <wlan_objmgr_psoc_obj.h>
45 #include <wlan_objmgr_pdev_obj.h>
46 #include <wlan_objmgr_vdev_obj.h>
47 #include <wlan_scan_public_structs.h>
48 #include <wlan_scan_utils_api.h>
49 #include "wlan_scan_main.h"
50 #include "wlan_scan_cache_db_i.h"
51 #include "wlan_reg_services_api.h"
52 #include "wlan_reg_ucfg_api.h"
53 #include <wlan_objmgr_vdev_obj.h>
54 #include <wlan_dfs_utils_api.h>
55 #include "wlan_crypto_global_def.h"
56 #include "wlan_crypto_global_api.h"
57 #include "wlan_cm_bss_score_param.h"
58 
59 #ifdef FEATURE_6G_SCAN_CHAN_SORT_ALGO
60 
61 struct channel_list_db *scm_get_rnr_channel_db(struct wlan_objmgr_psoc *psoc)
62 {
63 	struct wlan_scan_obj *scan_obj = NULL;
64 
65 	scan_obj = wlan_psoc_get_scan_obj(psoc);
66 
67 	if (!scan_obj)
68 		return NULL;
69 
70 	return &scan_obj->rnr_channel_db;
71 }
72 
73 struct meta_rnr_channel *scm_get_chan_meta(struct wlan_objmgr_psoc *psoc,
74 					   uint32_t chan_freq)
75 {
76 	int i;
77 	struct channel_list_db *rnr_channel_db;
78 
79 	if (!psoc || !chan_freq || !wlan_reg_is_6ghz_chan_freq(chan_freq))
80 		return NULL;
81 
82 	rnr_channel_db = scm_get_rnr_channel_db(psoc);
83 	if (!rnr_channel_db)
84 		return NULL;
85 
86 	for (i = 0; i < QDF_ARRAY_SIZE(rnr_channel_db->channel); i++)
87 		if (rnr_channel_db->channel[i].chan_freq == chan_freq)
88 			return &rnr_channel_db->channel[i];
89 
90 	return NULL;
91 }
92 
93 static void scm_add_rnr_channel_db(struct wlan_objmgr_psoc *psoc,
94 				   struct scan_cache_entry *entry)
95 {
96 	uint32_t chan_freq;
97 	uint8_t is_6g_bss, i;
98 	struct meta_rnr_channel *channel;
99 	struct rnr_bss_info *rnr_bss;
100 	struct scan_rnr_node *rnr_node;
101 
102 	chan_freq = entry->channel.chan_freq;
103 	is_6g_bss = wlan_reg_is_6ghz_chan_freq(chan_freq);
104 
105 	/* Return if the BSS is not 6G and RNR IE is not present */
106 	if (!(is_6g_bss || entry->ie_list.rnrie))
107 		return;
108 
109 	scm_debug("BSS freq %d BSSID: "QDF_MAC_ADDR_FMT, chan_freq,
110 		  QDF_MAC_ADDR_REF(entry->bssid.bytes));
111 	if (is_6g_bss) {
112 		channel = scm_get_chan_meta(psoc, chan_freq);
113 		if (!channel) {
114 			scm_debug("Failed to get chan Meta freq %d", chan_freq);
115 			return;
116 		}
117 		channel->bss_beacon_probe_count++;
118 		channel->beacon_probe_last_time_found = entry->scan_entry_time;
119 	}
120 
121 	/*
122 	 * If scan entry got RNR IE then loop through all
123 	 * entries and increase the BSS count in respective channels
124 	 */
125 	if (!entry->ie_list.rnrie)
126 		return;
127 
128 	for (i = 0; i < MAX_RNR_BSS; i++) {
129 		rnr_bss = &entry->rnr.bss_info[i];
130 		/* Skip if entry is not valid */
131 		if (!rnr_bss->channel_number)
132 			continue;
133 		chan_freq = wlan_reg_chan_opclass_to_freq(rnr_bss->channel_number,
134 							  rnr_bss->operating_class,
135 							  false);
136 		channel = scm_get_chan_meta(psoc, chan_freq);
137 		if (!channel) {
138 			scm_debug("Failed to get chan Meta freq %d", chan_freq);
139 			continue;
140 		}
141 		channel->bss_beacon_probe_count++;
142 		/* Don't add RNR entry if list is full */
143 		if (qdf_list_size(&channel->rnr_list) >= WLAN_MAX_RNR_COUNT) {
144 			scm_debug("List is full");
145 			return;
146 		}
147 
148 		rnr_node = qdf_mem_malloc(sizeof(struct scan_rnr_node));
149 		if (!rnr_node)
150 			return;
151 		rnr_node->entry.timestamp = entry->scan_entry_time;
152 		if (!qdf_is_macaddr_zero(&rnr_bss->bssid))
153 			qdf_mem_copy(&rnr_node->entry.bssid,
154 				     &rnr_bss->bssid,
155 				     QDF_MAC_ADDR_SIZE);
156 		if (rnr_bss->short_ssid)
157 			rnr_node->entry.short_ssid = rnr_bss->short_ssid;
158 		scm_debug("Add freq %d: "QDF_MAC_ADDR_FMT" short ssid %x", chan_freq,
159 			  QDF_MAC_ADDR_REF(rnr_bss->bssid.bytes),
160 			  rnr_bss->short_ssid);
161 		qdf_list_insert_back(&channel->rnr_list,
162 				     &rnr_node->node);
163 	}
164 }
165 #endif
166 
167 /**
168  * scm_del_scan_node() - API to remove scan node from the list
169  * @list: hash list
170  * @scan_node: node to be removed
171  *
172  * This should be called while holding scan_db_lock.
173  *
174  * Return: void
175  */
176 static void scm_del_scan_node(qdf_list_t *list,
177 	struct scan_cache_node *scan_node)
178 {
179 	QDF_STATUS status;
180 
181 	status = qdf_list_remove_node(list, &scan_node->node);
182 	if (QDF_IS_STATUS_SUCCESS(status)) {
183 		util_scan_free_cache_entry(scan_node->entry);
184 		qdf_mem_free(scan_node);
185 	}
186 }
187 
188 /**
189  * scm_del_scan_node_from_db() - API to del the scan entry
190  * @scan_db: scan database
191  * @scan_entry:entry scan_node
192  *
193  * API to flush the scan entry. This should be called while
194  * holding scan_db_lock.
195  *
196  * Return: QDF status.
197  */
198 static QDF_STATUS scm_del_scan_node_from_db(struct scan_dbs *scan_db,
199 	struct scan_cache_node *scan_node)
200 {
201 	QDF_STATUS status = QDF_STATUS_SUCCESS;
202 	uint8_t hash_idx;
203 
204 	if (!scan_node)
205 		return QDF_STATUS_E_INVAL;
206 
207 	hash_idx = SCAN_GET_HASH(scan_node->entry->bssid.bytes);
208 	scm_del_scan_node(&scan_db->scan_hash_tbl[hash_idx], scan_node);
209 	scan_db->num_entries--;
210 
211 	return status;
212 }
213 
214 /**
215  * scm_scan_entry_get_ref() - api to increase ref count of scan entry
216  * @scan_node: scan node
217  *
218  * Return: void
219  */
220 static void scm_scan_entry_get_ref(struct scan_cache_node *scan_node)
221 {
222 	if (!scan_node) {
223 		scm_err("scan_node is NULL");
224 		QDF_ASSERT(0);
225 		return;
226 	}
227 	qdf_atomic_inc(&scan_node->ref_cnt);
228 }
229 
230 /**
231  * scm_scan_entry_put_ref() - Api to decrease ref count of scan entry
232  * and free if it become 0
233  * @scan_db: scan database
234  * @scan_node: scan node
235  * @lock_needed: if scan_db_lock is needed
236  *
237  * Return: void
238  */
239 static void scm_scan_entry_put_ref(struct scan_dbs *scan_db,
240 	struct scan_cache_node *scan_node, bool lock_needed)
241 {
242 
243 	if (!scan_node) {
244 		scm_err("scan_node is NULL");
245 		QDF_ASSERT(0);
246 		return;
247 	}
248 
249 	if (lock_needed)
250 		qdf_spin_lock_bh(&scan_db->scan_db_lock);
251 
252 	if (!qdf_atomic_read(&scan_node->ref_cnt)) {
253 		if (lock_needed)
254 			qdf_spin_unlock_bh(&scan_db->scan_db_lock);
255 		scm_err("scan_node ref cnt is 0");
256 		QDF_ASSERT(0);
257 		return;
258 	}
259 
260 	/* Decrement ref count, free scan_node, if ref count == 0 */
261 	if (qdf_atomic_dec_and_test(&scan_node->ref_cnt))
262 		scm_del_scan_node_from_db(scan_db, scan_node);
263 
264 	if (lock_needed)
265 		qdf_spin_unlock_bh(&scan_db->scan_db_lock);
266 }
267 
268 /**
269  * scm_scan_entry_del() - API to delete scan node
270  * @scan_db: data base
271  * @scan_node: node to be deleted
272  *
273  * Call must be protected by scan_db->scan_db_lock
274  *
275  * Return: void
276  */
277 
278 static void scm_scan_entry_del(struct scan_dbs *scan_db,
279 			       struct scan_cache_node *scan_node)
280 {
281 	if (!scan_node) {
282 		scm_err("scan node is NULL");
283 		QDF_ASSERT(0);
284 		return;
285 	}
286 
287 	if (scan_node->cookie != SCAN_NODE_ACTIVE_COOKIE) {
288 		scm_debug("node is already deleted");
289 		return;
290 	}
291 	/* Seems node is already deleted */
292 	if (!qdf_atomic_read(&scan_node->ref_cnt)) {
293 		scm_debug("node is already deleted ref 0");
294 		return;
295 	}
296 	scan_node->cookie = 0;
297 	scm_scan_entry_put_ref(scan_db, scan_node, false);
298 }
299 
300 /**
301  * scm_add_scan_node() - API to add scan node
302  * @scan_db: data base
303  * @scan_node: node to be added
304  * @dup_node: node before which new node to be added
305  * if it's not NULL, otherwise add node to tail
306  *
307  * Call must be protected by scan_db->scan_db_lock
308  *
309  * Return: void
310  */
311 static void scm_add_scan_node(struct scan_dbs *scan_db,
312 	struct scan_cache_node *scan_node,
313 	struct scan_cache_node *dup_node)
314 {
315 	uint8_t hash_idx;
316 
317 	hash_idx =
318 		SCAN_GET_HASH(scan_node->entry->bssid.bytes);
319 
320 	qdf_atomic_init(&scan_node->ref_cnt);
321 	scan_node->cookie = SCAN_NODE_ACTIVE_COOKIE;
322 	scm_scan_entry_get_ref(scan_node);
323 	if (!dup_node)
324 		qdf_list_insert_back(&scan_db->scan_hash_tbl[hash_idx],
325 				     &scan_node->node);
326 	else
327 		qdf_list_insert_before(&scan_db->scan_hash_tbl[hash_idx],
328 				       &scan_node->node, &dup_node->node);
329 
330 	scan_db->num_entries++;
331 }
332 
333 
334 /**
335  * scm_get_next_valid_node() - API get the next valid scan node from
336  * the list
337  * @list: hash list
338  * @cur_node: current node pointer
339  *
340  * API to get next active node from the list. If cur_node is NULL
341  * it will return first node of the list.
342  * Call must be protected by scan_db->scan_db_lock
343  *
344  * Return: next scan node
345  */
346 static qdf_list_node_t *
347 scm_get_next_valid_node(qdf_list_t *list,
348 	qdf_list_node_t *cur_node)
349 {
350 	qdf_list_node_t *next_node = NULL;
351 	qdf_list_node_t *temp_node = NULL;
352 	struct scan_cache_node *scan_node;
353 
354 	if (cur_node)
355 		qdf_list_peek_next(list, cur_node, &next_node);
356 	else
357 		qdf_list_peek_front(list, &next_node);
358 
359 	while (next_node) {
360 		scan_node = qdf_container_of(next_node,
361 			struct scan_cache_node, node);
362 		if (scan_node->cookie == SCAN_NODE_ACTIVE_COOKIE)
363 			return next_node;
364 		/*
365 		 * If node is not valid check for next entry
366 		 * to get next valid node.
367 		 */
368 		qdf_list_peek_next(list, next_node, &temp_node);
369 		next_node = temp_node;
370 		temp_node = NULL;
371 	}
372 
373 	return next_node;
374 }
375 
376 /**
377  * scm_get_next_node() - API get the next scan node from
378  * the list
379  * @scan_db: scan data base
380  * @list: hash list
381  * @cur_node: current node pointer
382  *
383  * API get the next node from the list. If cur_node is NULL
384  * it will return first node of the list
385  *
386  * Return: next scan cache node
387  */
388 static struct scan_cache_node *
389 scm_get_next_node(struct scan_dbs *scan_db,
390 	qdf_list_t *list, struct scan_cache_node *cur_node)
391 {
392 	struct scan_cache_node *next_node = NULL;
393 	qdf_list_node_t *next_list = NULL;
394 
395 	qdf_spin_lock_bh(&scan_db->scan_db_lock);
396 	if (cur_node) {
397 		next_list = scm_get_next_valid_node(list, &cur_node->node);
398 		/* Decrement the ref count of the previous node */
399 		scm_scan_entry_put_ref(scan_db,
400 			cur_node, false);
401 	} else {
402 		next_list = scm_get_next_valid_node(list, NULL);
403 	}
404 	/* Increase the ref count of the obtained node */
405 	if (next_list) {
406 		next_node = qdf_container_of(next_list,
407 			struct scan_cache_node, node);
408 		scm_scan_entry_get_ref(next_node);
409 	}
410 	qdf_spin_unlock_bh(&scan_db->scan_db_lock);
411 
412 	return next_node;
413 }
414 
415 /**
416  * scm_check_and_age_out() - check and age out the old entries
417  * @scan_db: scan db
418  * @scan_node: node to check for age out
419  * @scan_aging_time: scan cache aging time
420  *
421  * Return: void
422  */
423 static void scm_check_and_age_out(struct scan_dbs *scan_db,
424 	struct scan_cache_node *node,
425 	qdf_time_t scan_aging_time)
426 {
427 	if (util_scan_entry_age(node->entry) >=
428 	   scan_aging_time) {
429 		scm_debug("Aging out BSSID: "QDF_MAC_ADDR_FMT" with age %lu ms",
430 			  QDF_MAC_ADDR_REF(node->entry->bssid.bytes),
431 			  util_scan_entry_age(node->entry));
432 		qdf_spin_lock_bh(&scan_db->scan_db_lock);
433 		scm_scan_entry_del(scan_db, node);
434 		qdf_spin_unlock_bh(&scan_db->scan_db_lock);
435 	}
436 }
437 
438 static bool scm_bss_is_connected(struct scan_cache_entry *entry)
439 {
440 	if (entry->mlme_info.assoc_state == SCAN_ENTRY_CON_STATE_ASSOC)
441 		return true;
442 	return false;
443 }
444 
445 /**
446  * scm_get_conn_node() - Get the scan cache entry node of the connected BSS
447  * @scan_db: scan DB pointer
448  *
449  * Return: scan cache entry node of connected BSS if exists, NULL otherwise
450  */
451 static
452 struct scan_cache_node *scm_get_conn_node(struct scan_dbs *scan_db)
453 {
454 	int i;
455 	struct scan_cache_node *cur_node = NULL;
456 	struct scan_cache_node *next_node = NULL;
457 
458 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
459 		cur_node = scm_get_next_node(scan_db,
460 			&scan_db->scan_hash_tbl[i], NULL);
461 		while (cur_node) {
462 			if (scm_bss_is_connected(cur_node->entry))
463 				return cur_node;
464 			next_node = scm_get_next_node(scan_db,
465 				&scan_db->scan_hash_tbl[i], cur_node);
466 			cur_node = next_node;
467 			next_node = NULL;
468 		}
469 	}
470 
471 	return NULL;
472 }
473 
474 void scm_age_out_entries(struct wlan_objmgr_psoc *psoc,
475 	struct scan_dbs *scan_db)
476 {
477 	int i;
478 	struct scan_cache_node *cur_node = NULL;
479 	struct scan_cache_node *next_node = NULL;
480 	struct scan_cache_node *conn_node = NULL;
481 	struct scan_default_params *def_param;
482 
483 	def_param = wlan_scan_psoc_get_def_params(psoc);
484 	if (!def_param) {
485 		scm_err("wlan_scan_psoc_get_def_params failed");
486 		return;
487 	}
488 
489 	conn_node = scm_get_conn_node(scan_db);
490 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
491 		cur_node = scm_get_next_node(scan_db,
492 			&scan_db->scan_hash_tbl[i], NULL);
493 		while (cur_node) {
494 			if (!conn_node /* if there is no connected node */ ||
495 			    /* OR cur_node is not part of the MBSSID of the
496 			     * connected node
497 			     */
498 			    memcmp(conn_node->entry->mbssid_info.trans_bssid,
499 				   cur_node->entry->mbssid_info.trans_bssid,
500 				   QDF_MAC_ADDR_SIZE)
501 			   ) {
502 				scm_check_and_age_out(scan_db, cur_node,
503 					def_param->scan_cache_aging_time);
504 			}
505 			next_node = scm_get_next_node(scan_db,
506 				&scan_db->scan_hash_tbl[i], cur_node);
507 			cur_node = next_node;
508 			next_node = NULL;
509 		}
510 	}
511 
512 	if (conn_node)
513 		scm_scan_entry_put_ref(scan_db, conn_node, true);
514 }
515 
516 /**
517  * scm_flush_oldest_entry() - Iterate over scan db and flust out the
518  *  oldest entry
519  * @scan_db: scan db from which oldest entry needs to be flushed
520  *
521  * Return: QDF_STATUS
522  */
523 static QDF_STATUS scm_flush_oldest_entry(struct scan_dbs *scan_db)
524 {
525 	int i;
526 	struct scan_cache_node *oldest_node = NULL;
527 	struct scan_cache_node *cur_node;
528 
529 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
530 		/* Get the first valid node for the hash */
531 		cur_node = scm_get_next_node(scan_db,
532 					     &scan_db->scan_hash_tbl[i],
533 					     NULL);
534 		 /* Iterate scan db and flush out oldest node
535 		  * take ref_cnt for oldest_node
536 		  */
537 
538 		while (cur_node) {
539 			if (!oldest_node ||
540 			   (util_scan_entry_age(oldest_node->entry) <
541 			    util_scan_entry_age(cur_node->entry))) {
542 				if (oldest_node)
543 					scm_scan_entry_put_ref(scan_db,
544 							       oldest_node,
545 							       true);
546 				qdf_spin_lock_bh(&scan_db->scan_db_lock);
547 				oldest_node = cur_node;
548 				scm_scan_entry_get_ref(oldest_node);
549 				qdf_spin_unlock_bh(&scan_db->scan_db_lock);
550 			}
551 
552 			cur_node = scm_get_next_node(scan_db,
553 					&scan_db->scan_hash_tbl[i],
554 					cur_node);
555 		};
556 	}
557 
558 	if (oldest_node) {
559 		scm_debug("Flush oldest BSSID: "QDF_MAC_ADDR_FMT" with age %lu ms",
560 			  QDF_MAC_ADDR_REF(oldest_node->entry->bssid.bytes),
561 			  util_scan_entry_age(oldest_node->entry));
562 		/* Release ref_cnt taken for oldest_node and delete it */
563 		qdf_spin_lock_bh(&scan_db->scan_db_lock);
564 		scm_scan_entry_del(scan_db, oldest_node);
565 		scm_scan_entry_put_ref(scan_db, oldest_node, false);
566 		qdf_spin_unlock_bh(&scan_db->scan_db_lock);
567 	}
568 
569 	return QDF_STATUS_SUCCESS;
570 }
571 
572 /**
573  * scm_update_alt_wcn_ie() - update the alternate WCN IE
574  * @from: copy from
575  * @dst: copy to
576  *
577  * Return: void
578  */
579 static void scm_update_alt_wcn_ie(struct scan_cache_entry *from,
580 	struct scan_cache_entry *dst)
581 {
582 	uint32_t alt_wcn_ie_len;
583 
584 	if (from->frm_subtype == dst->frm_subtype)
585 		return;
586 
587 	if (!from->ie_list.wcn && !dst->ie_list.wcn)
588 		return;
589 
590 	/* Existing WCN IE is empty. */
591 	if (!from->ie_list.wcn)
592 		return;
593 
594 	alt_wcn_ie_len = 2 + from->ie_list.wcn[1];
595 	if (alt_wcn_ie_len > WLAN_MAX_IE_LEN + 2) {
596 		scm_err("invalid IE len");
597 		return;
598 	}
599 
600 	if (!dst->alt_wcn_ie.ptr) {
601 		/* allocate this additional buffer for alternate WCN IE */
602 		dst->alt_wcn_ie.ptr =
603 			qdf_mem_malloc_atomic(WLAN_MAX_IE_LEN + 2);
604 		if (!dst->alt_wcn_ie.ptr) {
605 			scm_err("failed to allocate memory");
606 			return;
607 		}
608 	}
609 	qdf_mem_copy(dst->alt_wcn_ie.ptr,
610 		from->ie_list.wcn, alt_wcn_ie_len);
611 	dst->alt_wcn_ie.len = alt_wcn_ie_len;
612 }
613 
614 /**
615  * scm_update_mlme_info() - update mlme info
616  * @src: source scan entry
617  * @dest: destination scan entry
618  *
619  * Return: void
620  */
621 static inline void
622 scm_update_mlme_info(struct scan_cache_entry *src,
623 	struct scan_cache_entry *dest)
624 {
625 	qdf_mem_copy(&dest->mlme_info, &src->mlme_info,
626 		sizeof(struct mlme_info));
627 }
628 
629 /**
630  * scm_copy_info_from_dup_entry() - copy duplicate node info
631  * to new scan entry
632  * @pdev: pdev ptr
633  * @scan_obj: scan obj ptr
634  * @scan_db: scan database
635  * @scan_params: new entry to be added
636  * @scan_node: duplicate entry
637  *
638  * Copy duplicate node info to new entry.
639  *
640  * Return: void
641  */
642 static void
643 scm_copy_info_from_dup_entry(struct wlan_objmgr_pdev *pdev,
644 			     struct wlan_scan_obj *scan_obj,
645 			     struct scan_dbs *scan_db,
646 			     struct scan_cache_entry *scan_params,
647 			     struct scan_cache_node *scan_node)
648 {
649 	struct scan_cache_entry *scan_entry;
650 	uint64_t time_gap;
651 
652 	scan_entry = scan_node->entry;
653 
654 	/* Update probe resp entry as well if AP is in hidden mode */
655 	if (scan_params->frm_subtype == MGMT_SUBTYPE_PROBE_RESP &&
656 	    scan_entry->is_hidden_ssid)
657 		scan_params->is_hidden_ssid = true;
658 
659 	/*
660 	 * If AP changed its beacon from not having an SSID to showing it the
661 	 * kernel will drop the entry asumming that something is wrong with AP.
662 	 * This can result in connection failure while updating the bss during
663 	 * connection. So flush the hidden entry from kernel before indicating
664 	 * the new entry.
665 	 */
666 	if (scan_entry->is_hidden_ssid &&
667 	    scan_params->frm_subtype == MGMT_SUBTYPE_BEACON &&
668 	    !util_scan_is_null_ssid(&scan_params->ssid)) {
669 		if (scan_obj->cb.unlink_bss) {
670 			scm_debug("Hidden AP "QDF_MAC_ADDR_FMT" switch to non-hidden SSID, So unlink the entry",
671 				  QDF_MAC_ADDR_REF(scan_entry->bssid.bytes));
672 			scan_obj->cb.unlink_bss(pdev, scan_entry);
673 		}
674 	}
675 
676 	/* If old entry have the ssid but new entry does not */
677 	if (util_scan_is_null_ssid(&scan_params->ssid) &&
678 	    scan_entry->ssid.length) {
679 		/*
680 		 * New entry has a hidden SSID and old one has the SSID.
681 		 * Add the entry by using the ssid of the old entry
682 		 * only if diff of saved SSID time and current time is
683 		 * less than HIDDEN_SSID_TIME time.
684 		 * This will avoid issues in case AP changes its SSID
685 		 * while remain hidden.
686 		 */
687 		time_gap =
688 			qdf_mc_timer_get_system_time() -
689 			scan_entry->hidden_ssid_timestamp;
690 		if (time_gap <= HIDDEN_SSID_TIME) {
691 			scan_params->hidden_ssid_timestamp =
692 				scan_entry->hidden_ssid_timestamp;
693 			scan_params->ssid.length =
694 				scan_entry->ssid.length;
695 			qdf_mem_copy(scan_params->ssid.ssid,
696 				scan_entry->ssid.ssid,
697 				scan_entry->ssid.length);
698 		}
699 	}
700 
701 	/*
702 	 * Due to Rx sensitivity issue, sometime beacons are seen on adjacent
703 	 * channel so workaround in software is needed. If DS params or HT info
704 	 * are present driver can get proper channel info from these IEs and set
705 	 * channel_mismatch so that the older RSSI values are used in new entry.
706 	 *
707 	 * For the cases where DS params and HT info is not present, driver
708 	 * needs to check below conditions to get proper channel and set
709 	 * channel_mismatch so that the older RSSI values are used in new entry:
710 	 *   -- The old entry channel and new entry channel are not same
711 	 *   -- RSSI is less than -80, this indicate that the signal has leaked
712 	 *       in adjacent channel.
713 	 */
714 	if ((scan_params->frm_subtype == MGMT_SUBTYPE_BEACON) &&
715 	    !util_scan_entry_htinfo(scan_params) &&
716 	    !util_scan_entry_ds_param(scan_params) &&
717 	    (scan_params->channel.chan_freq != scan_entry->channel.chan_freq) &&
718 	    (scan_params->rssi_raw  < ADJACENT_CHANNEL_RSSI_THRESHOLD)) {
719 		scan_params->channel.chan_freq = scan_entry->channel.chan_freq;
720 		scan_params->channel_mismatch = true;
721 	}
722 
723 	/* Use old value for rssi if beacon was heard on adjacent channel. */
724 	if (scan_params->channel_mismatch) {
725 		scan_params->snr = scan_entry->snr;
726 		scan_params->avg_snr = scan_entry->avg_snr;
727 		scan_params->rssi_raw = scan_entry->rssi_raw;
728 		scan_params->avg_rssi = scan_entry->avg_rssi;
729 		scan_params->rssi_timestamp =
730 			scan_entry->rssi_timestamp;
731 	} else {
732 		/* If elapsed time since last rssi and snr update for this
733 		 * entry is smaller than a thresold, calculate a
734 		 * running average of the RSSI and SNR values.
735 		 * Otherwise new frames RSSI and SNR are more representive
736 		 * of the signal strength.
737 		 */
738 		time_gap =
739 			scan_params->scan_entry_time -
740 			scan_entry->rssi_timestamp;
741 		if (time_gap > WLAN_RSSI_AVERAGING_TIME) {
742 			scan_params->avg_rssi =
743 				WLAN_RSSI_IN(scan_params->rssi_raw);
744 			scan_params->avg_snr =
745 				WLAN_SNR_IN(scan_params->snr);
746 		}
747 		else {
748 			/* Copy previous average rssi and snr to new entry */
749 			scan_params->avg_snr = scan_entry->avg_snr;
750 			scan_params->avg_rssi = scan_entry->avg_rssi;
751 			/* Average with previous samples */
752 			WLAN_RSSI_LPF(scan_params->avg_rssi,
753 				      scan_params->rssi_raw);
754 			WLAN_SNR_LPF(scan_params->avg_snr,
755 				     scan_params->snr);
756 		}
757 
758 		scan_params->rssi_timestamp = scan_params->scan_entry_time;
759 	}
760 
761 	/* copy wsn ie from scan_entry to scan_params*/
762 	scm_update_alt_wcn_ie(scan_entry, scan_params);
763 
764 	/* copy mlme info from scan_entry to scan_params*/
765 	scm_update_mlme_info(scan_entry, scan_params);
766 }
767 
768 /**
769  * scm_find_duplicate() - find duplicate entry,
770  * if present, add input scan entry before it and delete
771  * duplicate entry. otherwise add entry to tail
772  * @pdev: pdev ptr
773  * @scan_obj: scan obj ptr
774  * @scan_db: scan db
775  * @entry: input scan cache entry
776  * @dup_node: node before which new entry to be added
777  *
778  * ref_cnt is taken for dup_node, caller should release ref taken
779  * if returns true.
780  *
781  * Return: bool
782  */
783 static bool
784 scm_find_duplicate(struct wlan_objmgr_pdev *pdev,
785 		   struct wlan_scan_obj *scan_obj,
786 		   struct scan_dbs *scan_db,
787 		   struct scan_cache_entry *entry,
788 		   struct scan_cache_node **dup_node)
789 {
790 	uint8_t hash_idx;
791 	struct scan_cache_node *cur_node;
792 	struct scan_cache_node *next_node = NULL;
793 
794 	hash_idx = SCAN_GET_HASH(entry->bssid.bytes);
795 
796 	cur_node = scm_get_next_node(scan_db,
797 				     &scan_db->scan_hash_tbl[hash_idx],
798 				     NULL);
799 
800 	while (cur_node) {
801 		if (util_is_scan_entry_match(entry,
802 		   cur_node->entry)) {
803 			scm_copy_info_from_dup_entry(pdev, scan_obj, scan_db,
804 						     entry, cur_node);
805 			*dup_node = cur_node;
806 			return true;
807 		}
808 		next_node = scm_get_next_node(scan_db,
809 			 &scan_db->scan_hash_tbl[hash_idx], cur_node);
810 		cur_node = next_node;
811 		next_node = NULL;
812 	}
813 
814 	return false;
815 }
816 
817 /**
818  * scm_add_update_entry() - add or update scan entry
819  * @psoc: psoc ptr
820  * @pdev: pdev pointer
821  * @scan_params: new received entry
822  *
823  * Return: QDF_STATUS
824  */
825 static QDF_STATUS scm_add_update_entry(struct wlan_objmgr_psoc *psoc,
826 	struct wlan_objmgr_pdev *pdev, struct scan_cache_entry *scan_params)
827 {
828 	struct scan_cache_node *dup_node = NULL;
829 	struct scan_cache_node *scan_node = NULL;
830 	bool is_dup_found = false;
831 	QDF_STATUS status;
832 	struct scan_dbs *scan_db;
833 	struct wlan_scan_obj *scan_obj;
834 	uint8_t security_type;
835 
836 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
837 	if (!scan_db) {
838 		scm_err("scan_db is NULL");
839 		return QDF_STATUS_E_INVAL;
840 	}
841 
842 	scan_obj = wlan_psoc_get_scan_obj(psoc);
843 	if (!scan_obj) {
844 		scm_err("scan_obj is NULL");
845 		return QDF_STATUS_E_INVAL;
846 	}
847 
848 	if (scan_params->frm_subtype ==
849 	   MGMT_SUBTYPE_PROBE_RESP &&
850 	   !scan_params->ie_list.ssid)
851 		scm_debug("Probe resp doesn't contain SSID");
852 
853 
854 	if (scan_params->ie_list.csa ||
855 	   scan_params->ie_list.xcsa ||
856 	   scan_params->ie_list.cswrp)
857 		scm_debug("CSA IE present for BSSID: "QDF_MAC_ADDR_FMT,
858 			  QDF_MAC_ADDR_REF(scan_params->bssid.bytes));
859 
860 	is_dup_found = scm_find_duplicate(pdev, scan_obj, scan_db, scan_params,
861 					  &dup_node);
862 
863 	security_type = scan_params->security_type;
864 	scm_nofl_debug("Received %s: "QDF_MAC_ADDR_FMT" \"%.*s\" freq %d rssi %d tsf_delta %u seq %d snr %d phy %d hidden %d mismatch %d %s%s%s%s pdev %d boot_time %llu ns",
865 		       (scan_params->frm_subtype == MGMT_SUBTYPE_PROBE_RESP) ?
866 		       "prb rsp" : "bcn",
867 		       QDF_MAC_ADDR_REF(scan_params->bssid.bytes),
868 		       scan_params->ssid.length, scan_params->ssid.ssid,
869 		       scan_params->channel.chan_freq, scan_params->rssi_raw,
870 		       scan_params->tsf_delta, scan_params->seq_num,
871 		       scan_params->snr, scan_params->phy_mode,
872 		       scan_params->is_hidden_ssid,
873 		       scan_params->channel_mismatch,
874 		       security_type & SCAN_SECURITY_TYPE_WPA ? "[WPA]" : "",
875 		       security_type & SCAN_SECURITY_TYPE_RSN ? "[RSN]" : "",
876 		       security_type & SCAN_SECURITY_TYPE_WAPI ? "[WAPI]" : "",
877 		       security_type & SCAN_SECURITY_TYPE_WEP ? "[WEP]" : "",
878 		       wlan_objmgr_pdev_get_pdev_id(pdev),
879 		       scan_params->boottime_ns);
880 
881 	if (scan_obj->cb.inform_beacon)
882 		scan_obj->cb.inform_beacon(pdev, scan_params);
883 
884 	if (scan_db->num_entries >= MAX_SCAN_CACHE_SIZE) {
885 		status = scm_flush_oldest_entry(scan_db);
886 		if (QDF_IS_STATUS_ERROR(status)) {
887 			/* release ref taken for dup node */
888 			if (is_dup_found)
889 				scm_scan_entry_put_ref(scan_db, dup_node, true);
890 			return status;
891 		}
892 	}
893 
894 	scan_node = qdf_mem_malloc(sizeof(*scan_node));
895 	if (!scan_node) {
896 		/* release ref taken for dup node */
897 		if (is_dup_found)
898 			scm_scan_entry_put_ref(scan_db, dup_node, true);
899 		return QDF_STATUS_E_NOMEM;
900 	}
901 
902 	scan_node->entry = scan_params;
903 	qdf_spin_lock_bh(&scan_db->scan_db_lock);
904 	scm_add_scan_node(scan_db, scan_node, dup_node);
905 
906 	if (is_dup_found) {
907 		/* release ref taken for dup node and delete it */
908 		scm_scan_entry_del(scan_db, dup_node);
909 		scm_scan_entry_put_ref(scan_db, dup_node, false);
910 	}
911 	qdf_spin_unlock_bh(&scan_db->scan_db_lock);
912 
913 	return QDF_STATUS_SUCCESS;
914 }
915 
916 #ifdef CONFIG_REG_CLIENT
917 /**
918  * scm_is_bss_allowed_for_country() - Check if bss is allowed to start for a
919  * specific country and power mode (VLP?LPI/SP) for 6GHz.
920  * @psoc: psoc ptr
921  * @scan_entry: ptr to scan entry
922  *
923  * Return: True if allowed, False if not.
924  */
925 static bool scm_is_bss_allowed_for_country(struct wlan_objmgr_psoc *psoc,
926 					   struct scan_cache_entry *scan_entry)
927 {
928 	struct wlan_country_ie *cc_ie;
929 	uint8_t programmed_country[REG_ALPHA2_LEN + 1];
930 
931 	if (wlan_reg_is_6ghz_chan_freq(scan_entry->channel.chan_freq)) {
932 		cc_ie = util_scan_entry_country(scan_entry);
933 		wlan_reg_read_current_country(psoc, programmed_country);
934 		if (cc_ie && qdf_mem_cmp(cc_ie->cc, programmed_country,
935 					 REG_ALPHA2_LEN)) {
936 			if (wlan_reg_is_us(programmed_country))
937 				return false;
938 		}
939 	}
940 	return true;
941 }
942 #else
943 static bool scm_is_bss_allowed_for_country(struct wlan_objmgr_psoc *psoc,
944 					   struct scan_cache_entry *scan_entry)
945 {
946 	return true;
947 }
948 #endif
949 
950 QDF_STATUS __scm_handle_bcn_probe(struct scan_bcn_probe_event *bcn)
951 {
952 	struct wlan_objmgr_psoc *psoc;
953 	struct wlan_objmgr_pdev *pdev = NULL;
954 	struct scan_cache_entry *scan_entry;
955 	struct wlan_scan_obj *scan_obj;
956 	qdf_list_t *scan_list = NULL;
957 	QDF_STATUS status = QDF_STATUS_SUCCESS;
958 	uint32_t list_count, i;
959 	qdf_list_node_t *next_node = NULL;
960 	struct scan_cache_node *scan_node;
961 	struct wlan_frame_hdr *hdr = NULL;
962 	struct wlan_crypto_params sec_params;
963 
964 	if (!bcn) {
965 		scm_err("bcn is NULL");
966 		return QDF_STATUS_E_INVAL;
967 	}
968 	if (!bcn->rx_data) {
969 		scm_err("rx_data iS NULL");
970 		status = QDF_STATUS_E_INVAL;
971 		goto free_nbuf;
972 	}
973 	if (!bcn->buf) {
974 		scm_err("buf is NULL");
975 		status = QDF_STATUS_E_INVAL;
976 		goto free_nbuf;
977 	}
978 
979 	hdr = (struct wlan_frame_hdr *)qdf_nbuf_data(bcn->buf);
980 	psoc = bcn->psoc;
981 	pdev = wlan_objmgr_get_pdev_by_id(psoc,
982 			   bcn->rx_data->pdev_id, WLAN_SCAN_ID);
983 	if (!pdev) {
984 		scm_err("pdev is NULL");
985 		status = QDF_STATUS_E_INVAL;
986 		goto free_nbuf;
987 	}
988 	scan_obj = wlan_psoc_get_scan_obj(psoc);
989 	if (!scan_obj) {
990 		scm_err("scan_obj is NULL");
991 		status = QDF_STATUS_E_INVAL;
992 		goto free_nbuf;
993 	}
994 
995 	if (qdf_nbuf_len(bcn->buf) <=
996 	   (sizeof(struct wlan_frame_hdr) +
997 	   offsetof(struct wlan_bcn_frame, ie))) {
998 		scm_debug("invalid beacon/probe length");
999 		status = QDF_STATUS_E_INVAL;
1000 		goto free_nbuf;
1001 	}
1002 
1003 	if (bcn->frm_type == MGMT_SUBTYPE_BEACON &&
1004 	    wlan_reg_is_dfs_for_freq(pdev, bcn->rx_data->chan_freq)) {
1005 		util_scan_add_hidden_ssid(pdev, bcn->buf);
1006 	}
1007 
1008 	scan_list =
1009 		 util_scan_unpack_beacon_frame(pdev, qdf_nbuf_data(bcn->buf),
1010 			qdf_nbuf_len(bcn->buf), bcn->frm_type,
1011 			bcn->rx_data);
1012 	if (!scan_list || qdf_list_empty(scan_list)) {
1013 		scm_debug("failed to unpack %d frame BSSID: "QDF_MAC_ADDR_FMT,
1014 			  bcn->frm_type, QDF_MAC_ADDR_REF(hdr->i_addr3));
1015 		status = QDF_STATUS_E_INVAL;
1016 		goto free_nbuf;
1017 	}
1018 
1019 	list_count = qdf_list_size(scan_list);
1020 	for (i = 0; i < list_count; i++) {
1021 		status = qdf_list_remove_front(scan_list, &next_node);
1022 		if (QDF_IS_STATUS_ERROR(status) || !next_node) {
1023 			scm_debug("list remove failure i:%d, lsize:%d, BSSID: "QDF_MAC_ADDR_FMT,
1024 				  i, list_count, QDF_MAC_ADDR_REF(hdr->i_addr3));
1025 			status = QDF_STATUS_E_INVAL;
1026 			goto free_nbuf;
1027 		}
1028 
1029 		scan_node = qdf_container_of(next_node,
1030 			struct scan_cache_node, node);
1031 
1032 		scan_entry = scan_node->entry;
1033 
1034 		if (scan_obj->drop_bcn_on_chan_mismatch &&
1035 		    scan_entry->channel_mismatch) {
1036 			scm_nofl_debug("Drop frame for chan mismatch "QDF_MAC_ADDR_FMT" Seq Num: %d freq %d RSSI %d",
1037 				       QDF_MAC_ADDR_REF(scan_entry->bssid.bytes),
1038 				       scan_entry->seq_num,
1039 				       scan_entry->channel.chan_freq,
1040 				       scan_entry->rssi_raw);
1041 			util_scan_free_cache_entry(scan_entry);
1042 			qdf_mem_free(scan_node);
1043 			continue;
1044 		}
1045 		/* Do not add invalid channel entry as kernel will reject it */
1046 		if (scan_obj->drop_bcn_on_invalid_freq &&
1047 		    wlan_reg_is_disable_for_freq(pdev,
1048 					scan_entry->channel.chan_freq)) {
1049 			scm_nofl_debug("Drop frame for invalid freq %d: "QDF_MAC_ADDR_FMT" Seq Num: %d RSSI %d",
1050 				       scan_entry->channel.chan_freq,
1051 				       QDF_MAC_ADDR_REF(scan_entry->bssid.bytes),
1052 				       scan_entry->seq_num,
1053 				       scan_entry->rssi_raw);
1054 			util_scan_free_cache_entry(scan_entry);
1055 			qdf_mem_free(scan_node);
1056 			continue;
1057 		}
1058 		if (wlan_cm_get_check_6ghz_security(psoc) &&
1059 		    wlan_reg_is_6ghz_chan_freq(scan_entry->channel.chan_freq)) {
1060 			if (!util_scan_entry_rsn(scan_entry)) {
1061 				scm_info("Drop frame from "QDF_MAC_ADDR_FMT
1062 					 ": No RSN IE for 6GHz AP",
1063 					 QDF_MAC_ADDR_REF(
1064 						 scan_entry->bssid.bytes));
1065 				util_scan_free_cache_entry(scan_entry);
1066 				qdf_mem_free(scan_node);
1067 				continue;
1068 			}
1069 			status = wlan_crypto_rsnie_check(&sec_params,
1070 					util_scan_entry_rsn(scan_entry));
1071 			if (QDF_IS_STATUS_ERROR(status)) {
1072 				scm_info("Drop frame from 6GHz AP "
1073 					 QDF_MAC_ADDR_FMT
1074 					 ": RSN IE parse failed, status %d",
1075 					 QDF_MAC_ADDR_REF(
1076 						 scan_entry->bssid.bytes),
1077 					 status);
1078 				util_scan_free_cache_entry(scan_entry);
1079 				qdf_mem_free(scan_node);
1080 				continue;
1081 			}
1082 			if ((QDF_HAS_PARAM(sec_params.ucastcipherset,
1083 					   WLAN_CRYPTO_CIPHER_NONE)) ||
1084 			    (QDF_HAS_PARAM(sec_params.ucastcipherset,
1085 					   WLAN_CRYPTO_CIPHER_TKIP)) ||
1086 			    (QDF_HAS_PARAM(sec_params.ucastcipherset,
1087 					   WLAN_CRYPTO_CIPHER_WEP_40)) ||
1088 			    (QDF_HAS_PARAM(sec_params.ucastcipherset,
1089 					   WLAN_CRYPTO_CIPHER_WEP_104))) {
1090 				scm_info("Drop frame from "QDF_MAC_ADDR_FMT
1091 					 ": Invalid sec type %0X for 6GHz AP",
1092 					 QDF_MAC_ADDR_REF(
1093 						 scan_entry->bssid.bytes),
1094 					 sec_params.ucastcipherset);
1095 				continue;
1096 			}
1097 			if (!wlan_cm_6ghz_allowed_for_akm(psoc,
1098 					sec_params.key_mgmt,
1099 					sec_params.rsn_caps,
1100 					util_scan_entry_rsnxe(scan_entry),
1101 					0, false)) {
1102 				scm_info("Drop frame from "QDF_MAC_ADDR_FMT
1103 					 ": Invalid AKM suite %0X for 6GHz AP",
1104 					 QDF_MAC_ADDR_REF(
1105 						scan_entry->bssid.bytes),
1106 					 sec_params.key_mgmt);
1107 				util_scan_free_cache_entry(scan_entry);
1108 				qdf_mem_free(scan_node);
1109 				continue;
1110 			}
1111 		}
1112 		if (scan_obj->cb.update_beacon)
1113 			scan_obj->cb.update_beacon(pdev, scan_entry);
1114 
1115 		if (!scm_is_bss_allowed_for_country(psoc, scan_entry)) {
1116 			scm_info("Drop frame from "QDF_MAC_ADDR_FMT
1117 				 ": AP in VLP mode not supported for US",
1118 				 QDF_MAC_ADDR_REF(scan_entry->bssid.bytes));
1119 			util_scan_free_cache_entry(scan_entry);
1120 			qdf_mem_free(scan_node);
1121 			continue;
1122 		}
1123 
1124 		status = scm_add_update_entry(psoc, pdev, scan_entry);
1125 		if (QDF_IS_STATUS_ERROR(status)) {
1126 			scm_debug("failed to add entry for BSSID: "QDF_MAC_ADDR_FMT" Seq Num: %d",
1127 				  QDF_MAC_ADDR_REF(scan_entry->bssid.bytes),
1128 				  scan_entry->seq_num);
1129 			util_scan_free_cache_entry(scan_entry);
1130 			qdf_mem_free(scan_node);
1131 			continue;
1132 		}
1133 
1134 		qdf_mem_free(scan_node);
1135 	}
1136 
1137 free_nbuf:
1138 	if (scan_list)
1139 		qdf_mem_free(scan_list);
1140 	if (bcn->psoc)
1141 		wlan_objmgr_psoc_release_ref(bcn->psoc, WLAN_SCAN_ID);
1142 	if (pdev)
1143 		wlan_objmgr_pdev_release_ref(pdev, WLAN_SCAN_ID);
1144 	if (bcn->rx_data)
1145 		qdf_mem_free(bcn->rx_data);
1146 	if (bcn->buf)
1147 		qdf_nbuf_free(bcn->buf);
1148 	qdf_mem_free(bcn);
1149 
1150 	return status;
1151 }
1152 
1153 QDF_STATUS scm_handle_bcn_probe(struct scheduler_msg *msg)
1154 {
1155 	if (!msg) {
1156 		scm_err("msg is NULL");
1157 		return QDF_STATUS_E_NULL_VALUE;
1158 	}
1159 
1160 	return __scm_handle_bcn_probe(msg->bodyptr);
1161 }
1162 
1163 /**
1164  * scm_scan_apply_filter_get_entry() - apply filter and get the
1165  * scan entry
1166  * @psoc: psoc pointer
1167  * @db_entry: scan entry
1168  * @filter: filter to be applied
1169  * @scan_list: scan list to which entry is added
1170  *
1171  * Return: QDF_STATUS
1172  */
1173 static QDF_STATUS
1174 scm_scan_apply_filter_get_entry(struct wlan_objmgr_psoc *psoc,
1175 	struct scan_cache_entry *db_entry,
1176 	struct scan_filter *filter,
1177 	qdf_list_t *scan_list)
1178 {
1179 	struct scan_cache_node *scan_node = NULL;
1180 	struct security_info security = {0};
1181 	bool match;
1182 
1183 	if (!filter)
1184 		match = true;
1185 	else
1186 		match = scm_filter_match(psoc, db_entry,
1187 					filter, &security);
1188 
1189 	if (!match)
1190 		return QDF_STATUS_SUCCESS;
1191 
1192 	scan_node = qdf_mem_malloc_atomic(sizeof(*scan_node));
1193 	if (!scan_node)
1194 		return QDF_STATUS_E_NOMEM;
1195 
1196 	scan_node->entry =
1197 		util_scan_copy_cache_entry(db_entry);
1198 
1199 	if (!scan_node->entry) {
1200 		qdf_mem_free(scan_node);
1201 		return QDF_STATUS_E_NOMEM;
1202 	}
1203 
1204 	qdf_mem_copy(&scan_node->entry->neg_sec_info,
1205 		&security, sizeof(scan_node->entry->neg_sec_info));
1206 
1207 	qdf_list_insert_front(scan_list, &scan_node->node);
1208 
1209 	return QDF_STATUS_SUCCESS;
1210 }
1211 
1212 /**
1213  * scm_get_results() - Iterate and get scan results
1214  * @psoc: psoc ptr
1215  * @scan_db: scan db
1216  * @filter: filter to be applied
1217  * @scan_list: scan list to which entry is added
1218  *
1219  * Return: void
1220  */
1221 static void scm_get_results(struct wlan_objmgr_psoc *psoc,
1222 	struct scan_dbs *scan_db, struct scan_filter *filter,
1223 	qdf_list_t *scan_list)
1224 {
1225 	int i, count;
1226 	struct scan_cache_node *cur_node;
1227 	struct scan_cache_node *next_node = NULL;
1228 
1229 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1230 		cur_node = scm_get_next_node(scan_db,
1231 			   &scan_db->scan_hash_tbl[i], NULL);
1232 		count = qdf_list_size(&scan_db->scan_hash_tbl[i]);
1233 		if (!count)
1234 			continue;
1235 		while (cur_node) {
1236 			scm_scan_apply_filter_get_entry(psoc,
1237 				cur_node->entry, filter, scan_list);
1238 			next_node = scm_get_next_node(scan_db,
1239 				&scan_db->scan_hash_tbl[i], cur_node);
1240 			cur_node = next_node;
1241 		}
1242 	}
1243 }
1244 
1245 QDF_STATUS scm_purge_scan_results(qdf_list_t *scan_list)
1246 {
1247 	QDF_STATUS status;
1248 	struct scan_cache_node *cur_node;
1249 	qdf_list_node_t *cur_lst = NULL, *next_lst = NULL;
1250 
1251 	if (!scan_list) {
1252 		scm_err("scan_result is NULL");
1253 		return QDF_STATUS_E_INVAL;
1254 	}
1255 
1256 	status = qdf_list_peek_front(scan_list, &cur_lst);
1257 
1258 	while (cur_lst) {
1259 		qdf_list_peek_next(
1260 			scan_list, cur_lst, &next_lst);
1261 		cur_node = qdf_container_of(cur_lst,
1262 			struct scan_cache_node, node);
1263 		status = qdf_list_remove_node(scan_list,
1264 					cur_lst);
1265 		if (QDF_IS_STATUS_SUCCESS(status)) {
1266 			util_scan_free_cache_entry(cur_node->entry);
1267 			qdf_mem_free(cur_node);
1268 		}
1269 		cur_lst = next_lst;
1270 		next_lst = NULL;
1271 	}
1272 
1273 	qdf_list_destroy(scan_list);
1274 	qdf_mem_free(scan_list);
1275 
1276 	return status;
1277 }
1278 
1279 qdf_list_t *scm_get_scan_result(struct wlan_objmgr_pdev *pdev,
1280 	struct scan_filter *filter)
1281 {
1282 	struct wlan_objmgr_psoc *psoc;
1283 	struct scan_dbs *scan_db;
1284 	qdf_list_t *tmp_list;
1285 
1286 	if (!pdev) {
1287 		scm_err("pdev is NULL");
1288 		return NULL;
1289 	}
1290 
1291 	psoc = wlan_pdev_get_psoc(pdev);
1292 	if (!psoc) {
1293 		scm_err("psoc is NULL");
1294 		return NULL;
1295 	}
1296 
1297 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1298 	if (!scan_db) {
1299 		scm_err("scan_db is NULL");
1300 		return NULL;
1301 	}
1302 
1303 	tmp_list = qdf_mem_malloc_atomic(sizeof(*tmp_list));
1304 	if (!tmp_list) {
1305 		scm_err("failed tp allocate scan_result");
1306 		return NULL;
1307 	}
1308 	qdf_list_create(tmp_list,
1309 			MAX_SCAN_CACHE_SIZE);
1310 	scm_age_out_entries(psoc, scan_db);
1311 	scm_get_results(psoc, scan_db, filter, tmp_list);
1312 
1313 	return tmp_list;
1314 }
1315 
1316 /**
1317  * scm_iterate_db_and_call_func() - iterate and call the func
1318  * @scan_db: scan db
1319  * @func: func to be called
1320  * @arg: func arg
1321  *
1322  * Return: QDF_STATUS
1323  */
1324 static QDF_STATUS
1325 scm_iterate_db_and_call_func(struct scan_dbs *scan_db,
1326 	scan_iterator_func func, void *arg)
1327 {
1328 	int i;
1329 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1330 	struct scan_cache_node *cur_node;
1331 	struct scan_cache_node *next_node = NULL;
1332 
1333 	if (!func)
1334 		return QDF_STATUS_E_INVAL;
1335 
1336 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1337 		cur_node = scm_get_next_node(scan_db,
1338 			&scan_db->scan_hash_tbl[i], NULL);
1339 		while (cur_node) {
1340 			status = func(arg, cur_node->entry);
1341 			if (QDF_IS_STATUS_ERROR(status)) {
1342 				scm_scan_entry_put_ref(scan_db,
1343 					cur_node, true);
1344 				return status;
1345 			}
1346 			next_node = scm_get_next_node(scan_db,
1347 				&scan_db->scan_hash_tbl[i], cur_node);
1348 			cur_node = next_node;
1349 		}
1350 	}
1351 
1352 	return status;
1353 }
1354 
1355 QDF_STATUS
1356 scm_iterate_scan_db(struct wlan_objmgr_pdev *pdev,
1357 	scan_iterator_func func, void *arg)
1358 {
1359 	struct wlan_objmgr_psoc *psoc;
1360 	struct scan_dbs *scan_db;
1361 	QDF_STATUS status;
1362 
1363 	if (!func) {
1364 		scm_err("func is NULL");
1365 		return QDF_STATUS_E_INVAL;
1366 	}
1367 
1368 	if (!pdev) {
1369 		scm_err("pdev is NULL");
1370 		return QDF_STATUS_E_INVAL;
1371 	}
1372 
1373 	psoc = wlan_pdev_get_psoc(pdev);
1374 	if (!psoc) {
1375 		scm_err("psoc is NULL");
1376 		return QDF_STATUS_E_INVAL;
1377 	}
1378 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1379 	if (!scan_db) {
1380 		scm_err("scan_db is NULL");
1381 		return QDF_STATUS_E_INVAL;
1382 	}
1383 
1384 	scm_age_out_entries(psoc, scan_db);
1385 	status = scm_iterate_db_and_call_func(scan_db, func, arg);
1386 
1387 	return status;
1388 }
1389 
1390 /**
1391  * scm_scan_apply_filter_flush_entry() -flush scan entries depending
1392  * on filter
1393  * @psoc: psoc ptr
1394  * @scan_db: scan db
1395  * @db_node: node on which filters are applied
1396  * @filter: filter to be applied
1397  *
1398  * Return: QDF_STATUS
1399  */
1400 static QDF_STATUS
1401 scm_scan_apply_filter_flush_entry(struct wlan_objmgr_psoc *psoc,
1402 	struct scan_dbs *scan_db,
1403 	struct scan_cache_node *db_node,
1404 	struct scan_filter *filter)
1405 {
1406 	struct security_info security = {0};
1407 	bool match;
1408 
1409 	if (!filter)
1410 		match = true;
1411 	else
1412 		match = scm_filter_match(psoc, db_node->entry,
1413 					filter, &security);
1414 
1415 	if (!match)
1416 		return QDF_STATUS_SUCCESS;
1417 
1418 	qdf_spin_lock_bh(&scan_db->scan_db_lock);
1419 	scm_scan_entry_del(scan_db, db_node);
1420 	qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1421 
1422 	return QDF_STATUS_SUCCESS;
1423 }
1424 
1425 /**
1426  * scm_flush_scan_entries() - API to flush scan entries depending on filters
1427  * @psoc: psoc ptr
1428  * @scan_db: scan db
1429  * @filter: filter
1430  *
1431  * Return: void
1432  */
1433 static void scm_flush_scan_entries(struct wlan_objmgr_psoc *psoc,
1434 	struct scan_dbs *scan_db,
1435 	struct scan_filter *filter)
1436 {
1437 	int i;
1438 	struct scan_cache_node *cur_node;
1439 	struct scan_cache_node *next_node = NULL;
1440 
1441 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1442 		cur_node = scm_get_next_node(scan_db,
1443 			   &scan_db->scan_hash_tbl[i], NULL);
1444 		while (cur_node) {
1445 			scm_scan_apply_filter_flush_entry(psoc, scan_db,
1446 				cur_node, filter);
1447 			next_node = scm_get_next_node(scan_db,
1448 				&scan_db->scan_hash_tbl[i], cur_node);
1449 			cur_node = next_node;
1450 		}
1451 	}
1452 }
1453 
1454 QDF_STATUS scm_flush_results(struct wlan_objmgr_pdev *pdev,
1455 	struct scan_filter *filter)
1456 {
1457 	struct wlan_objmgr_psoc *psoc;
1458 	struct scan_dbs *scan_db;
1459 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1460 
1461 	if (!pdev) {
1462 		scm_err("pdev is NULL");
1463 		return QDF_STATUS_E_INVAL;
1464 	}
1465 
1466 	psoc = wlan_pdev_get_psoc(pdev);
1467 	if (!psoc) {
1468 		scm_err("psoc is NULL");
1469 		return QDF_STATUS_E_INVAL;
1470 	}
1471 
1472 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1473 	if (!scan_db) {
1474 		scm_err("scan_db is NULL");
1475 		return QDF_STATUS_E_INVAL;
1476 	}
1477 
1478 	scm_flush_scan_entries(psoc, scan_db, filter);
1479 
1480 	return status;
1481 }
1482 
1483 /**
1484  * scm_filter_channels() - Remove entries not belonging to channel list
1485  * @scan_db: scan db
1486  * @db_node: node on which filters are applied
1487  * @chan_freq_list: valid channel frequency (in MHz) list
1488  * @num_chan: number of channels
1489  *
1490  * Return: QDF_STATUS
1491  */
1492 static void scm_filter_channels(struct wlan_objmgr_pdev *pdev,
1493 				struct scan_dbs *scan_db,
1494 				struct scan_cache_node *db_node,
1495 				uint32_t *chan_freq_list, uint32_t num_chan)
1496 {
1497 	int i;
1498 	bool match = false;
1499 
1500 	for (i = 0; i < num_chan; i++) {
1501 		if (chan_freq_list[i] == util_scan_entry_channel_frequency(
1502 							db_node->entry)) {
1503 			match = true;
1504 			break;
1505 		}
1506 	}
1507 
1508 	if (!match) {
1509 		qdf_spin_lock_bh(&scan_db->scan_db_lock);
1510 		scm_scan_entry_del(scan_db, db_node);
1511 		qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1512 	}
1513 }
1514 
1515 void scm_filter_valid_channel(struct wlan_objmgr_pdev *pdev,
1516 	uint32_t *chan_freq_list, uint32_t num_chan)
1517 {
1518 	int i;
1519 	struct wlan_objmgr_psoc *psoc;
1520 	struct scan_dbs *scan_db;
1521 	struct scan_cache_node *cur_node;
1522 	struct scan_cache_node *next_node = NULL;
1523 
1524 	scm_debug("num_chan = %d", num_chan);
1525 
1526 	if (!pdev) {
1527 		scm_err("pdev is NULL");
1528 		return;
1529 	}
1530 
1531 	psoc = wlan_pdev_get_psoc(pdev);
1532 	if (!psoc) {
1533 		scm_err("psoc is NULL");
1534 		return;
1535 	}
1536 
1537 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1538 	if (!scan_db) {
1539 		scm_err("scan_db is NULL");
1540 		return;
1541 	}
1542 
1543 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1544 		cur_node = scm_get_next_node(scan_db,
1545 			   &scan_db->scan_hash_tbl[i], NULL);
1546 		while (cur_node) {
1547 			scm_filter_channels(pdev, scan_db,
1548 					    cur_node, chan_freq_list, num_chan);
1549 			next_node = scm_get_next_node(scan_db,
1550 				&scan_db->scan_hash_tbl[i], cur_node);
1551 			cur_node = next_node;
1552 		}
1553 	}
1554 }
1555 
1556 QDF_STATUS scm_scan_register_bcn_cb(struct wlan_objmgr_psoc *psoc,
1557 	update_beacon_cb cb, enum scan_cb_type type)
1558 {
1559 	struct wlan_scan_obj *scan_obj;
1560 
1561 	scan_obj = wlan_psoc_get_scan_obj(psoc);
1562 	if (!scan_obj) {
1563 		scm_err("scan obj is NULL");
1564 		return QDF_STATUS_E_INVAL;
1565 	}
1566 	switch (type) {
1567 	case SCAN_CB_TYPE_INFORM_BCN:
1568 		scan_obj->cb.inform_beacon = cb;
1569 		break;
1570 	case SCAN_CB_TYPE_UPDATE_BCN:
1571 		scan_obj->cb.update_beacon = cb;
1572 		break;
1573 	case SCAN_CB_TYPE_UNLINK_BSS:
1574 		scan_obj->cb.unlink_bss = cb;
1575 		break;
1576 	default:
1577 		scm_err("invalid cb type %d", type);
1578 	}
1579 
1580 	return QDF_STATUS_SUCCESS;
1581 }
1582 
1583 QDF_STATUS scm_db_init(struct wlan_objmgr_psoc *psoc)
1584 {
1585 	int i, j;
1586 	struct scan_dbs *scan_db;
1587 
1588 	if (!psoc) {
1589 		scm_err("psoc is NULL");
1590 		return QDF_STATUS_E_INVAL;
1591 	}
1592 
1593 	/* Initialize the scan database per pdev */
1594 	for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) {
1595 		scan_db = wlan_pdevid_get_scan_db(psoc, i);
1596 		if (!scan_db) {
1597 			scm_err("scan_db is NULL %d", i);
1598 			continue;
1599 		}
1600 		scan_db->num_entries = 0;
1601 		qdf_spinlock_create(&scan_db->scan_db_lock);
1602 		for (j = 0; j < SCAN_HASH_SIZE; j++)
1603 			qdf_list_create(&scan_db->scan_hash_tbl[j],
1604 				MAX_SCAN_CACHE_SIZE);
1605 	}
1606 	return QDF_STATUS_SUCCESS;
1607 }
1608 
1609 QDF_STATUS scm_db_deinit(struct wlan_objmgr_psoc *psoc)
1610 {
1611 	int i, j;
1612 	struct scan_dbs *scan_db;
1613 
1614 	if (!psoc) {
1615 		scm_err("scan obj is NULL");
1616 		return QDF_STATUS_E_INVAL;
1617 	}
1618 
1619 	/* Initialize the scan database per pdev */
1620 	for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) {
1621 		scan_db = wlan_pdevid_get_scan_db(psoc, i);
1622 		if (!scan_db) {
1623 			scm_err("scan_db is NULL %d", i);
1624 			continue;
1625 		}
1626 
1627 		scm_flush_scan_entries(psoc, scan_db, NULL);
1628 		for (j = 0; j < SCAN_HASH_SIZE; j++)
1629 			qdf_list_destroy(&scan_db->scan_hash_tbl[j]);
1630 		qdf_spinlock_destroy(&scan_db->scan_db_lock);
1631 	}
1632 
1633 	return QDF_STATUS_SUCCESS;
1634 }
1635 
1636 #ifdef FEATURE_6G_SCAN_CHAN_SORT_ALGO
1637 QDF_STATUS scm_channel_list_db_init(struct wlan_objmgr_psoc *psoc)
1638 {
1639 	uint32_t i, j;
1640 	uint32_t min_freq, max_freq;
1641 	struct channel_list_db *rnr_channel_db;
1642 
1643 	min_freq = wlan_reg_min_6ghz_chan_freq();
1644 	max_freq = wlan_reg_max_6ghz_chan_freq();
1645 
1646 	scm_info("min_freq %d max_freq %d", min_freq, max_freq);
1647 	i = min_freq;
1648 	rnr_channel_db = scm_get_rnr_channel_db(psoc);
1649 	if (!rnr_channel_db)
1650 		return QDF_STATUS_E_INVAL;
1651 
1652 	for (j = 0; j < QDF_ARRAY_SIZE(rnr_channel_db->channel); j++) {
1653 		if (i >= min_freq && i <= max_freq)
1654 			rnr_channel_db->channel[j].chan_freq = i;
1655 		i += 20;
1656 		/* init list for all to avoid uninitialized list */
1657 		qdf_list_create(&rnr_channel_db->channel[j].rnr_list,
1658 				WLAN_MAX_RNR_COUNT);
1659 	}
1660 	return QDF_STATUS_SUCCESS;
1661 }
1662 
1663 QDF_STATUS scm_channel_list_db_deinit(struct wlan_objmgr_psoc *psoc)
1664 {
1665 	int i;
1666 	qdf_list_node_t *cur_node, *next_node;
1667 	struct meta_rnr_channel *channel;
1668 	struct scan_rnr_node *rnr_node;
1669 	struct channel_list_db *rnr_channel_db;
1670 
1671 	rnr_channel_db = scm_get_rnr_channel_db(psoc);
1672 	if (!rnr_channel_db)
1673 		return QDF_STATUS_E_INVAL;
1674 
1675 	for (i = 0; i < QDF_ARRAY_SIZE(rnr_channel_db->channel); i++) {
1676 		channel = &rnr_channel_db->channel[i];
1677 		channel->chan_freq = 0;
1678 		channel->beacon_probe_last_time_found = 0;
1679 		channel->bss_beacon_probe_count = 0;
1680 		channel->saved_profile_count = 0;
1681 		cur_node = NULL;
1682 		qdf_list_peek_front(&channel->rnr_list, &cur_node);
1683 		while (cur_node) {
1684 			next_node = NULL;
1685 			qdf_list_peek_next(&channel->rnr_list, cur_node,
1686 					   &next_node);
1687 			rnr_node = qdf_container_of(cur_node,
1688 						    struct scan_rnr_node,
1689 						    node);
1690 			qdf_list_remove_node(&channel->rnr_list,
1691 					     &rnr_node->node);
1692 			qdf_mem_free(rnr_node);
1693 			cur_node = next_node;
1694 			next_node = NULL;
1695 		}
1696 		qdf_list_destroy(&channel->rnr_list);
1697 	}
1698 
1699 	return QDF_STATUS_SUCCESS;
1700 }
1701 
1702 QDF_STATUS scm_rnr_db_flush(struct wlan_objmgr_psoc *psoc)
1703 {
1704 	int i;
1705 	qdf_list_node_t *cur_node, *next_node;
1706 	struct meta_rnr_channel *channel;
1707 	struct scan_rnr_node *rnr_node;
1708 	struct channel_list_db *rnr_channel_db;
1709 
1710 	rnr_channel_db = scm_get_rnr_channel_db(psoc);
1711 	if (!rnr_channel_db)
1712 		return QDF_STATUS_E_INVAL;
1713 
1714 	for (i = 0; i < QDF_ARRAY_SIZE(rnr_channel_db->channel); i++) {
1715 		channel = &rnr_channel_db->channel[i];
1716 		cur_node = NULL;
1717 		qdf_list_peek_front(&channel->rnr_list, &cur_node);
1718 		while (cur_node) {
1719 			next_node = NULL;
1720 			qdf_list_peek_next(&channel->rnr_list, cur_node,
1721 					   &next_node);
1722 			rnr_node = qdf_container_of(cur_node,
1723 						    struct scan_rnr_node,
1724 						    node);
1725 			qdf_list_remove_node(&channel->rnr_list,
1726 					     &rnr_node->node);
1727 			qdf_mem_free(rnr_node);
1728 			cur_node = next_node;
1729 			next_node = NULL;
1730 		}
1731 		/* Reset beacon info */
1732 		channel->beacon_probe_last_time_found = 0;
1733 		channel->bss_beacon_probe_count = 0;
1734 	}
1735 
1736 	return QDF_STATUS_SUCCESS;
1737 }
1738 
1739 void scm_update_rnr_from_scan_cache(struct wlan_objmgr_pdev *pdev)
1740 {
1741 	uint8_t i;
1742 	struct scan_dbs *scan_db;
1743 	struct scan_cache_node *cur_node;
1744 	struct scan_cache_node *next_node = NULL;
1745 	struct wlan_objmgr_psoc *psoc;
1746 	struct scan_cache_entry *entry;
1747 
1748 	psoc = wlan_pdev_get_psoc(pdev);
1749 	if (!psoc) {
1750 		scm_err("psoc is NULL");
1751 		return;
1752 	}
1753 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1754 	if (!scan_db) {
1755 		scm_err("scan_db is NULL");
1756 		return;
1757 	}
1758 
1759 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1760 		cur_node = scm_get_next_node(scan_db,
1761 					     &scan_db->scan_hash_tbl[i], NULL);
1762 		while (cur_node) {
1763 			entry = cur_node->entry;
1764 			scm_add_rnr_channel_db(psoc, entry);
1765 			next_node =
1766 				scm_get_next_node(scan_db,
1767 						  &scan_db->scan_hash_tbl[i],
1768 						  cur_node);
1769 			cur_node = next_node;
1770 			next_node = NULL;
1771 		}
1772 	}
1773 }
1774 #endif
1775 
1776 QDF_STATUS scm_update_scan_mlme_info(struct wlan_objmgr_pdev *pdev,
1777 	struct scan_cache_entry *entry)
1778 {
1779 	uint8_t hash_idx;
1780 	struct scan_dbs *scan_db;
1781 	struct scan_cache_node *cur_node;
1782 	struct scan_cache_node *next_node = NULL;
1783 	struct wlan_objmgr_psoc *psoc;
1784 
1785 	psoc = wlan_pdev_get_psoc(pdev);
1786 	if (!psoc) {
1787 		scm_err("psoc is NULL");
1788 		return QDF_STATUS_E_INVAL;
1789 	}
1790 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1791 	if (!scan_db) {
1792 		scm_err("scan_db is NULL");
1793 		return QDF_STATUS_E_INVAL;
1794 	}
1795 
1796 	hash_idx = SCAN_GET_HASH(entry->bssid.bytes);
1797 
1798 	cur_node = scm_get_next_node(scan_db,
1799 			&scan_db->scan_hash_tbl[hash_idx], NULL);
1800 
1801 	while (cur_node) {
1802 		if (util_is_scan_entry_match(entry,
1803 					cur_node->entry)) {
1804 			/* Acquire db lock to prevent simultaneous update */
1805 			qdf_spin_lock_bh(&scan_db->scan_db_lock);
1806 			scm_update_mlme_info(entry, cur_node->entry);
1807 			qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1808 			scm_scan_entry_put_ref(scan_db,
1809 					cur_node, true);
1810 			return QDF_STATUS_SUCCESS;
1811 		}
1812 		next_node = scm_get_next_node(scan_db,
1813 				&scan_db->scan_hash_tbl[hash_idx], cur_node);
1814 		cur_node = next_node;
1815 	}
1816 
1817 	return QDF_STATUS_E_INVAL;
1818 }
1819 
1820 QDF_STATUS scm_scan_update_mlme_by_bssinfo(struct wlan_objmgr_pdev *pdev,
1821 		struct bss_info *bss_info, struct mlme_info *mlme)
1822 {
1823 	uint8_t hash_idx;
1824 	struct scan_dbs *scan_db;
1825 	struct scan_cache_node *cur_node;
1826 	struct scan_cache_node *next_node = NULL;
1827 	struct wlan_objmgr_psoc *psoc;
1828 	struct scan_cache_entry *entry;
1829 
1830 	psoc = wlan_pdev_get_psoc(pdev);
1831 	if (!psoc) {
1832 		scm_err("psoc is NULL");
1833 		return QDF_STATUS_E_INVAL;
1834 	}
1835 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1836 	if (!scan_db) {
1837 		scm_err("scan_db is NULL");
1838 		return QDF_STATUS_E_INVAL;
1839 	}
1840 
1841 	hash_idx = SCAN_GET_HASH(bss_info->bssid.bytes);
1842 	cur_node = scm_get_next_node(scan_db,
1843 			&scan_db->scan_hash_tbl[hash_idx], NULL);
1844 	while (cur_node) {
1845 		entry = cur_node->entry;
1846 		if (qdf_is_macaddr_equal(&bss_info->bssid, &entry->bssid) &&
1847 			(util_is_ssid_match(&bss_info->ssid, &entry->ssid)) &&
1848 			(bss_info->freq == entry->channel.chan_freq)) {
1849 			/* Acquire db lock to prevent simultaneous update */
1850 			qdf_spin_lock_bh(&scan_db->scan_db_lock);
1851 			qdf_mem_copy(&entry->mlme_info, mlme,
1852 					sizeof(struct mlme_info));
1853 			scm_scan_entry_put_ref(scan_db,
1854 					cur_node, false);
1855 			qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1856 			return QDF_STATUS_SUCCESS;
1857 		}
1858 		next_node = scm_get_next_node(scan_db,
1859 				&scan_db->scan_hash_tbl[hash_idx], cur_node);
1860 		cur_node = next_node;
1861 	}
1862 
1863 	return QDF_STATUS_E_INVAL;
1864 }
1865