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