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