xref: /wlan-dirver/qca-wifi-host-cmn/umac/scan/core/src/wlan_scan_cache_db.c (revision a86b23ee68a2491aede2e03991f3fb37046f4e41)
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 void scm_age_out_entries(struct wlan_objmgr_psoc *psoc,
440 	struct scan_dbs *scan_db)
441 {
442 	int i;
443 	struct scan_cache_node *cur_node = NULL;
444 	struct scan_cache_node *next_node = NULL;
445 	struct scan_default_params *def_param;
446 
447 	def_param = wlan_scan_psoc_get_def_params(psoc);
448 	if (!def_param) {
449 		scm_err("wlan_scan_psoc_get_def_params failed");
450 		return;
451 	}
452 
453 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
454 		cur_node = scm_get_next_node(scan_db,
455 			&scan_db->scan_hash_tbl[i], NULL);
456 		while (cur_node) {
457 			if (!scm_bss_is_connected(cur_node->entry))
458 				scm_check_and_age_out(scan_db, cur_node,
459 					def_param->scan_cache_aging_time);
460 			next_node = scm_get_next_node(scan_db,
461 				&scan_db->scan_hash_tbl[i], cur_node);
462 			cur_node = next_node;
463 			next_node = NULL;
464 		}
465 	}
466 }
467 
468 /**
469  * scm_flush_oldest_entry() - Iterate over scan db and flust out the
470  *  oldest entry
471  * @scan_db: scan db from which oldest entry needs to be flushed
472  *
473  * Return: QDF_STATUS
474  */
475 static QDF_STATUS scm_flush_oldest_entry(struct scan_dbs *scan_db)
476 {
477 	int i;
478 	struct scan_cache_node *oldest_node = NULL;
479 	struct scan_cache_node *cur_node;
480 
481 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
482 		/* Get the first valid node for the hash */
483 		cur_node = scm_get_next_node(scan_db,
484 					     &scan_db->scan_hash_tbl[i],
485 					     NULL);
486 		 /* Iterate scan db and flush out oldest node
487 		  * take ref_cnt for oldest_node
488 		  */
489 
490 		while (cur_node) {
491 			if (!oldest_node ||
492 			   (util_scan_entry_age(oldest_node->entry) <
493 			    util_scan_entry_age(cur_node->entry))) {
494 				if (oldest_node)
495 					scm_scan_entry_put_ref(scan_db,
496 							       oldest_node,
497 							       true);
498 				oldest_node = cur_node;
499 				scm_scan_entry_get_ref(oldest_node);
500 			}
501 
502 			cur_node = scm_get_next_node(scan_db,
503 					&scan_db->scan_hash_tbl[i],
504 					cur_node);
505 		};
506 	}
507 
508 	if (oldest_node) {
509 		scm_debug("Flush oldest BSSID: %pM with age %lu ms",
510 				oldest_node->entry->bssid.bytes,
511 				util_scan_entry_age(oldest_node->entry));
512 		/* Release ref_cnt taken for oldest_node and delete it */
513 		qdf_spin_lock_bh(&scan_db->scan_db_lock);
514 		scm_scan_entry_del(scan_db, oldest_node);
515 		scm_scan_entry_put_ref(scan_db, oldest_node, false);
516 		qdf_spin_unlock_bh(&scan_db->scan_db_lock);
517 	}
518 
519 	return QDF_STATUS_SUCCESS;
520 }
521 
522 /**
523  * scm_update_alt_wcn_ie() - update the alternate WCN IE
524  * @from: copy from
525  * @dst: copy to
526  *
527  * Return: void
528  */
529 static void scm_update_alt_wcn_ie(struct scan_cache_entry *from,
530 	struct scan_cache_entry *dst)
531 {
532 	uint32_t alt_wcn_ie_len;
533 
534 	if (from->frm_subtype == dst->frm_subtype)
535 		return;
536 
537 	if (!from->ie_list.wcn && !dst->ie_list.wcn)
538 		return;
539 
540 	/* Existing WCN IE is empty. */
541 	if (!from->ie_list.wcn)
542 		return;
543 
544 	alt_wcn_ie_len = 2 + from->ie_list.wcn[1];
545 	if (alt_wcn_ie_len > WLAN_MAX_IE_LEN + 2) {
546 		scm_err("invalid IE len");
547 		return;
548 	}
549 
550 	if (!dst->alt_wcn_ie.ptr) {
551 		/* allocate this additional buffer for alternate WCN IE */
552 		dst->alt_wcn_ie.ptr =
553 			qdf_mem_malloc_atomic(WLAN_MAX_IE_LEN + 2);
554 		if (!dst->alt_wcn_ie.ptr) {
555 			scm_err("failed to allocate memory");
556 			return;
557 		}
558 	}
559 	qdf_mem_copy(dst->alt_wcn_ie.ptr,
560 		from->ie_list.wcn, alt_wcn_ie_len);
561 	dst->alt_wcn_ie.len = alt_wcn_ie_len;
562 }
563 
564 /**
565  * scm_update_mlme_info() - update mlme info
566  * @src: source scan entry
567  * @dest: destination scan entry
568  *
569  * Return: void
570  */
571 static inline void
572 scm_update_mlme_info(struct scan_cache_entry *src,
573 	struct scan_cache_entry *dest)
574 {
575 	qdf_mem_copy(&dest->mlme_info, &src->mlme_info,
576 		sizeof(struct mlme_info));
577 }
578 
579 /**
580  * scm_copy_info_from_dup_entry() - copy duplicate node info
581  * to new scan entry
582  * @pdev: pdev ptr
583  * @scan_obj: scan obj ptr
584  * @scan_db: scan database
585  * @scan_params: new entry to be added
586  * @scan_node: duplicate entry
587  *
588  * Copy duplicate node info to new entry.
589  *
590  * Return: void
591  */
592 static void
593 scm_copy_info_from_dup_entry(struct wlan_objmgr_pdev *pdev,
594 			     struct wlan_scan_obj *scan_obj,
595 			     struct scan_dbs *scan_db,
596 			     struct scan_cache_entry *scan_params,
597 			     struct scan_cache_node *scan_node)
598 {
599 	struct scan_cache_entry *scan_entry;
600 	uint64_t time_gap;
601 
602 	scan_entry = scan_node->entry;
603 
604 	/* Update probe resp entry as well if AP is in hidden mode */
605 	if (scan_params->frm_subtype == MGMT_SUBTYPE_PROBE_RESP &&
606 	    scan_entry->is_hidden_ssid)
607 		scan_params->is_hidden_ssid = true;
608 
609 	/*
610 	 * If AP changed its beacon from not having an SSID to showing it the
611 	 * kernel will drop the entry asumming that something is wrong with AP.
612 	 * This can result in connection failure while updating the bss during
613 	 * connection. So flush the hidden entry from kernel before indicating
614 	 * the new entry.
615 	 */
616 	if (scan_entry->is_hidden_ssid &&
617 	    scan_params->frm_subtype == MGMT_SUBTYPE_BEACON &&
618 	    !util_scan_is_null_ssid(&scan_params->ssid)) {
619 		if (scan_obj->cb.unlink_bss) {
620 			scm_debug("Hidden AP %pM switch to non-hidden SSID, So unlink the entry",
621 				  scan_entry->bssid.bytes);
622 			scan_obj->cb.unlink_bss(pdev, scan_entry);
623 		}
624 	}
625 
626 	/* If old entry have the ssid but new entry does not */
627 	if (util_scan_is_null_ssid(&scan_params->ssid) &&
628 	    scan_entry->ssid.length) {
629 		/*
630 		 * New entry has a hidden SSID and old one has the SSID.
631 		 * Add the entry by using the ssid of the old entry
632 		 * only if diff of saved SSID time and current time is
633 		 * less than HIDDEN_SSID_TIME time.
634 		 * This will avoid issues in case AP changes its SSID
635 		 * while remain hidden.
636 		 */
637 		time_gap =
638 			qdf_mc_timer_get_system_time() -
639 			scan_entry->hidden_ssid_timestamp;
640 		if (time_gap <= HIDDEN_SSID_TIME) {
641 			scan_params->hidden_ssid_timestamp =
642 				scan_entry->hidden_ssid_timestamp;
643 			scan_params->ssid.length =
644 				scan_entry->ssid.length;
645 			qdf_mem_copy(scan_params->ssid.ssid,
646 				scan_entry->ssid.ssid,
647 				scan_entry->ssid.length);
648 		}
649 	}
650 
651 	/*
652 	 * Due to Rx sensitivity issue, sometime beacons are seen on adjacent
653 	 * channel so workaround in software is needed. If DS params or HT info
654 	 * are present driver can get proper channel info from these IEs and set
655 	 * channel_mismatch so that the older RSSI values are used in new entry.
656 	 *
657 	 * For the cases where DS params and HT info is not present, driver
658 	 * needs to check below conditions to get proper channel and set
659 	 * channel_mismatch so that the older RSSI values are used in new entry:
660 	 *   -- The old entry channel and new entry channel are not same
661 	 *   -- RSSI is less than -80, this indicate that the signal has leaked
662 	 *       in adjacent channel.
663 	 */
664 	if ((scan_params->frm_subtype == MGMT_SUBTYPE_BEACON) &&
665 	    !util_scan_entry_htinfo(scan_params) &&
666 	    !util_scan_entry_ds_param(scan_params) &&
667 	    (scan_params->channel.chan_freq != scan_entry->channel.chan_freq) &&
668 	    (scan_params->rssi_raw  < ADJACENT_CHANNEL_RSSI_THRESHOLD)) {
669 		scan_params->channel.chan_freq = scan_entry->channel.chan_freq;
670 		scan_params->channel_mismatch = true;
671 	}
672 
673 	/* Use old value for rssi if beacon was heard on adjacent channel. */
674 	if (scan_params->channel_mismatch) {
675 		scan_params->snr = scan_entry->snr;
676 		scan_params->avg_snr = scan_entry->avg_snr;
677 		scan_params->rssi_raw = scan_entry->rssi_raw;
678 		scan_params->avg_rssi = scan_entry->avg_rssi;
679 		scan_params->rssi_timestamp =
680 			scan_entry->rssi_timestamp;
681 	} else {
682 		/* If elapsed time since last rssi and snr update for this
683 		 * entry is smaller than a thresold, calculate a
684 		 * running average of the RSSI and SNR values.
685 		 * Otherwise new frames RSSI and SNR are more representive
686 		 * of the signal strength.
687 		 */
688 		time_gap =
689 			scan_params->scan_entry_time -
690 			scan_entry->rssi_timestamp;
691 		if (time_gap > WLAN_RSSI_AVERAGING_TIME) {
692 			scan_params->avg_rssi =
693 				WLAN_RSSI_IN(scan_params->rssi_raw);
694 			scan_params->avg_snr =
695 				WLAN_SNR_IN(scan_params->snr);
696 		}
697 		else {
698 			/* Copy previous average rssi and snr to new entry */
699 			scan_params->avg_snr = scan_entry->avg_snr;
700 			scan_params->avg_rssi = scan_entry->avg_rssi;
701 			/* Average with previous samples */
702 			WLAN_RSSI_LPF(scan_params->avg_rssi,
703 				      scan_params->rssi_raw);
704 			WLAN_SNR_LPF(scan_params->avg_snr,
705 				     scan_params->snr);
706 		}
707 
708 		scan_params->rssi_timestamp = scan_params->scan_entry_time;
709 	}
710 
711 	/* copy wsn ie from scan_entry to scan_params*/
712 	scm_update_alt_wcn_ie(scan_entry, scan_params);
713 
714 	/* copy mlme info from scan_entry to scan_params*/
715 	scm_update_mlme_info(scan_entry, scan_params);
716 }
717 
718 /**
719  * scm_find_duplicate() - find duplicate entry,
720  * if present, add input scan entry before it and delete
721  * duplicate entry. otherwise add entry to tail
722  * @pdev: pdev ptr
723  * @scan_obj: scan obj ptr
724  * @scan_db: scan db
725  * @entry: input scan cache entry
726  * @dup_node: node before which new entry to be added
727  *
728  * ref_cnt is taken for dup_node, caller should release ref taken
729  * if returns true.
730  *
731  * Return: bool
732  */
733 static bool
734 scm_find_duplicate(struct wlan_objmgr_pdev *pdev,
735 		   struct wlan_scan_obj *scan_obj,
736 		   struct scan_dbs *scan_db,
737 		   struct scan_cache_entry *entry,
738 		   struct scan_cache_node **dup_node)
739 {
740 	uint8_t hash_idx;
741 	struct scan_cache_node *cur_node;
742 	struct scan_cache_node *next_node = NULL;
743 
744 	hash_idx = SCAN_GET_HASH(entry->bssid.bytes);
745 
746 	cur_node = scm_get_next_node(scan_db,
747 				     &scan_db->scan_hash_tbl[hash_idx],
748 				     NULL);
749 
750 	while (cur_node) {
751 		if (util_is_scan_entry_match(entry,
752 		   cur_node->entry)) {
753 			scm_copy_info_from_dup_entry(pdev, scan_obj, scan_db,
754 						     entry, cur_node);
755 			*dup_node = cur_node;
756 			return true;
757 		}
758 		next_node = scm_get_next_node(scan_db,
759 			 &scan_db->scan_hash_tbl[hash_idx], cur_node);
760 		cur_node = next_node;
761 		next_node = NULL;
762 	}
763 
764 	return false;
765 }
766 
767 /**
768  * scm_add_update_entry() - add or update scan entry
769  * @psoc: psoc ptr
770  * @pdev: pdev pointer
771  * @scan_params: new received entry
772  *
773  * Return: QDF_STATUS
774  */
775 static QDF_STATUS scm_add_update_entry(struct wlan_objmgr_psoc *psoc,
776 	struct wlan_objmgr_pdev *pdev, struct scan_cache_entry *scan_params)
777 {
778 	struct scan_cache_node *dup_node = NULL;
779 	struct scan_cache_node *scan_node = NULL;
780 	bool is_dup_found = false;
781 	QDF_STATUS status;
782 	struct scan_dbs *scan_db;
783 	struct wlan_scan_obj *scan_obj;
784 	uint8_t security_type;
785 
786 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
787 	if (!scan_db) {
788 		scm_err("scan_db is NULL");
789 		return QDF_STATUS_E_INVAL;
790 	}
791 
792 	scan_obj = wlan_psoc_get_scan_obj(psoc);
793 	if (!scan_obj) {
794 		scm_err("scan_obj is NULL");
795 		return QDF_STATUS_E_INVAL;
796 	}
797 
798 	if (scan_params->frm_subtype ==
799 	   MGMT_SUBTYPE_PROBE_RESP &&
800 	   !scan_params->ie_list.ssid)
801 		scm_debug("Probe resp doesn't contain SSID");
802 
803 
804 	if (scan_params->ie_list.csa ||
805 	   scan_params->ie_list.xcsa ||
806 	   scan_params->ie_list.cswrp)
807 		scm_debug("CSA IE present for BSSID: %pM",
808 			  scan_params->bssid.bytes);
809 
810 	is_dup_found = scm_find_duplicate(pdev, scan_obj, scan_db, scan_params,
811 					  &dup_node);
812 
813 	security_type = scan_params->security_type;
814 	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",
815 		       (scan_params->frm_subtype == MGMT_SUBTYPE_PROBE_RESP) ?
816 		       "prb rsp" : "bcn", scan_params->bssid.bytes,
817 		       scan_params->ssid.length, scan_params->ssid.ssid,
818 		       scan_params->channel.chan_freq, scan_params->rssi_raw,
819 		       scan_params->tsf_delta, scan_params->seq_num,
820 		       scan_params->snr, scan_params->phy_mode,
821 		       scan_params->is_hidden_ssid,
822 		       scan_params->channel_mismatch,
823 		       security_type & SCAN_SECURITY_TYPE_WPA ? "[WPA]" : "",
824 		       security_type & SCAN_SECURITY_TYPE_RSN ? "[RSN]" : "",
825 		       security_type & SCAN_SECURITY_TYPE_WAPI ? "[WAPI]" : "",
826 		       security_type & SCAN_SECURITY_TYPE_WEP ? "[WEP]" : "",
827 		       wlan_objmgr_pdev_get_pdev_id(pdev),
828 		       scan_params->boottime_ns);
829 
830 	if (scan_obj->cb.inform_beacon)
831 		scan_obj->cb.inform_beacon(pdev, scan_params);
832 
833 	if (scan_db->num_entries >= MAX_SCAN_CACHE_SIZE) {
834 		status = scm_flush_oldest_entry(scan_db);
835 		if (QDF_IS_STATUS_ERROR(status)) {
836 			/* release ref taken for dup node */
837 			if (is_dup_found)
838 				scm_scan_entry_put_ref(scan_db, dup_node, true);
839 			return status;
840 		}
841 	}
842 
843 	scan_node = qdf_mem_malloc(sizeof(*scan_node));
844 	if (!scan_node) {
845 		/* release ref taken for dup node */
846 		if (is_dup_found)
847 			scm_scan_entry_put_ref(scan_db, dup_node, true);
848 		return QDF_STATUS_E_NOMEM;
849 	}
850 
851 	scan_node->entry = scan_params;
852 	qdf_spin_lock_bh(&scan_db->scan_db_lock);
853 	scm_add_scan_node(scan_db, scan_node, dup_node);
854 
855 	if (is_dup_found) {
856 		/* release ref taken for dup node and delete it */
857 		scm_scan_entry_del(scan_db, dup_node);
858 		scm_scan_entry_put_ref(scan_db, dup_node, false);
859 	}
860 	qdf_spin_unlock_bh(&scan_db->scan_db_lock);
861 
862 	return QDF_STATUS_SUCCESS;
863 }
864 
865 QDF_STATUS __scm_handle_bcn_probe(struct scan_bcn_probe_event *bcn)
866 {
867 	struct wlan_objmgr_psoc *psoc;
868 	struct wlan_objmgr_pdev *pdev = NULL;
869 	struct scan_cache_entry *scan_entry;
870 	struct wlan_scan_obj *scan_obj;
871 	qdf_list_t *scan_list = NULL;
872 	QDF_STATUS status = QDF_STATUS_SUCCESS;
873 	uint32_t list_count, i;
874 	qdf_list_node_t *next_node = NULL;
875 	struct scan_cache_node *scan_node;
876 	struct wlan_frame_hdr *hdr = NULL;
877 
878 	if (!bcn) {
879 		scm_err("bcn is NULL");
880 		return QDF_STATUS_E_INVAL;
881 	}
882 	if (!bcn->rx_data) {
883 		scm_err("rx_data iS NULL");
884 		status = QDF_STATUS_E_INVAL;
885 		goto free_nbuf;
886 	}
887 	if (!bcn->buf) {
888 		scm_err("buf is NULL");
889 		status = QDF_STATUS_E_INVAL;
890 		goto free_nbuf;
891 	}
892 
893 	hdr = (struct wlan_frame_hdr *)qdf_nbuf_data(bcn->buf);
894 	psoc = bcn->psoc;
895 	pdev = wlan_objmgr_get_pdev_by_id(psoc,
896 			   bcn->rx_data->pdev_id, WLAN_SCAN_ID);
897 	if (!pdev) {
898 		scm_err("pdev is NULL");
899 		status = QDF_STATUS_E_INVAL;
900 		goto free_nbuf;
901 	}
902 	scan_obj = wlan_psoc_get_scan_obj(psoc);
903 	if (!scan_obj) {
904 		scm_err("scan_obj is NULL");
905 		status = QDF_STATUS_E_INVAL;
906 		goto free_nbuf;
907 	}
908 
909 	if (qdf_nbuf_len(bcn->buf) <=
910 	   (sizeof(struct wlan_frame_hdr) +
911 	   offsetof(struct wlan_bcn_frame, ie))) {
912 		scm_debug("invalid beacon/probe length");
913 		status = QDF_STATUS_E_INVAL;
914 		goto free_nbuf;
915 	}
916 
917 	if (bcn->frm_type == MGMT_SUBTYPE_BEACON &&
918 	    wlan_reg_is_dfs_for_freq(pdev, bcn->rx_data->chan_freq)) {
919 		util_scan_add_hidden_ssid(pdev, bcn->buf);
920 	}
921 
922 	scan_list =
923 		 util_scan_unpack_beacon_frame(pdev, qdf_nbuf_data(bcn->buf),
924 			qdf_nbuf_len(bcn->buf), bcn->frm_type,
925 			bcn->rx_data);
926 	if (!scan_list || qdf_list_empty(scan_list)) {
927 		scm_debug("failed to unpack %d frame BSSID: %pM",
928 			  bcn->frm_type, hdr->i_addr3);
929 		status = QDF_STATUS_E_INVAL;
930 		goto free_nbuf;
931 	}
932 
933 	list_count = qdf_list_size(scan_list);
934 	for (i = 0; i < list_count; i++) {
935 		status = qdf_list_remove_front(scan_list, &next_node);
936 		if (QDF_IS_STATUS_ERROR(status) || !next_node) {
937 			scm_debug("list remove failure i:%d, lsize:%d, BSSID: %pM",
938 				  i, list_count, hdr->i_addr3);
939 			status = QDF_STATUS_E_INVAL;
940 			goto free_nbuf;
941 		}
942 
943 		scan_node = qdf_container_of(next_node,
944 			struct scan_cache_node, node);
945 
946 		scan_entry = scan_node->entry;
947 
948 		if (scan_obj->drop_bcn_on_chan_mismatch &&
949 		    scan_entry->channel_mismatch) {
950 			scm_nofl_debug("Drop frame for chan mismatch %pM Seq Num: %d freq %d RSSI %d",
951 				       scan_entry->bssid.bytes,
952 				       scan_entry->seq_num,
953 				       scan_entry->channel.chan_freq,
954 				       scan_entry->rssi_raw);
955 			util_scan_free_cache_entry(scan_entry);
956 			qdf_mem_free(scan_node);
957 			continue;
958 		}
959 		/* Do not add invalid channel entry as kernel will reject it */
960 		if (scan_obj->drop_bcn_on_invalid_freq &&
961 		    wlan_reg_is_disable_for_freq(pdev,
962 					scan_entry->channel.chan_freq)) {
963 			scm_nofl_debug("Drop frame for invalid freq %d: %pM Seq Num: %d RSSI %d",
964 				       scan_entry->channel.chan_freq,
965 				       scan_entry->bssid.bytes,
966 				       scan_entry->seq_num,
967 				       scan_entry->rssi_raw);
968 			util_scan_free_cache_entry(scan_entry);
969 			qdf_mem_free(scan_node);
970 			continue;
971 		}
972 		if (scan_obj->cb.update_beacon)
973 			scan_obj->cb.update_beacon(pdev, scan_entry);
974 
975 		if (wlan_reg_11d_enabled_on_host(psoc))
976 			scm_11d_handle_country_info(psoc, pdev, scan_entry);
977 
978 		status = scm_add_update_entry(psoc, pdev, scan_entry);
979 		if (QDF_IS_STATUS_ERROR(status)) {
980 			scm_debug("failed to add entry for BSSID: %pM Seq Num: %d",
981 				  scan_entry->bssid.bytes,
982 				  scan_entry->seq_num);
983 			util_scan_free_cache_entry(scan_entry);
984 			qdf_mem_free(scan_node);
985 			continue;
986 		}
987 
988 		qdf_mem_free(scan_node);
989 	}
990 
991 free_nbuf:
992 	if (scan_list)
993 		qdf_mem_free(scan_list);
994 	if (bcn->psoc)
995 		wlan_objmgr_psoc_release_ref(bcn->psoc, WLAN_SCAN_ID);
996 	if (pdev)
997 		wlan_objmgr_pdev_release_ref(pdev, WLAN_SCAN_ID);
998 	if (bcn->rx_data)
999 		qdf_mem_free(bcn->rx_data);
1000 	if (bcn->buf)
1001 		qdf_nbuf_free(bcn->buf);
1002 	qdf_mem_free(bcn);
1003 
1004 	return status;
1005 }
1006 
1007 QDF_STATUS scm_handle_bcn_probe(struct scheduler_msg *msg)
1008 {
1009 	if (!msg) {
1010 		scm_err("msg is NULL");
1011 		return QDF_STATUS_E_NULL_VALUE;
1012 	}
1013 
1014 	return __scm_handle_bcn_probe(msg->bodyptr);
1015 }
1016 
1017 /**
1018  * scm_scan_apply_filter_get_entry() - apply filter and get the
1019  * scan entry
1020  * @psoc: psoc pointer
1021  * @db_entry: scan entry
1022  * @filter: filter to be applied
1023  * @scan_list: scan list to which entry is added
1024  *
1025  * Return: QDF_STATUS
1026  */
1027 static QDF_STATUS
1028 scm_scan_apply_filter_get_entry(struct wlan_objmgr_psoc *psoc,
1029 	struct scan_cache_entry *db_entry,
1030 	struct scan_filter *filter,
1031 	qdf_list_t *scan_list)
1032 {
1033 	struct scan_cache_node *scan_node = NULL;
1034 	struct security_info security = {0};
1035 	bool match;
1036 
1037 	if (!filter)
1038 		match = true;
1039 	else
1040 		match = scm_filter_match(psoc, db_entry,
1041 					filter, &security);
1042 
1043 	if (!match)
1044 		return QDF_STATUS_SUCCESS;
1045 
1046 	scan_node = qdf_mem_malloc_atomic(sizeof(*scan_node));
1047 	if (!scan_node)
1048 		return QDF_STATUS_E_NOMEM;
1049 
1050 	scan_node->entry =
1051 		util_scan_copy_cache_entry(db_entry);
1052 
1053 	if (!scan_node->entry) {
1054 		qdf_mem_free(scan_node);
1055 		return QDF_STATUS_E_NOMEM;
1056 	}
1057 
1058 	qdf_mem_copy(&scan_node->entry->neg_sec_info,
1059 		&security, sizeof(scan_node->entry->neg_sec_info));
1060 
1061 	qdf_list_insert_front(scan_list, &scan_node->node);
1062 
1063 	return QDF_STATUS_SUCCESS;
1064 }
1065 
1066 /**
1067  * scm_get_results() - Iterate and get scan results
1068  * @psoc: psoc ptr
1069  * @scan_db: scan db
1070  * @filter: filter to be applied
1071  * @scan_list: scan list to which entry is added
1072  *
1073  * Return: void
1074  */
1075 static void scm_get_results(struct wlan_objmgr_psoc *psoc,
1076 	struct scan_dbs *scan_db, struct scan_filter *filter,
1077 	qdf_list_t *scan_list)
1078 {
1079 	int i, count;
1080 	struct scan_cache_node *cur_node;
1081 	struct scan_cache_node *next_node = NULL;
1082 
1083 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1084 		cur_node = scm_get_next_node(scan_db,
1085 			   &scan_db->scan_hash_tbl[i], NULL);
1086 		count = qdf_list_size(&scan_db->scan_hash_tbl[i]);
1087 		if (!count)
1088 			continue;
1089 		while (cur_node) {
1090 			scm_scan_apply_filter_get_entry(psoc,
1091 				cur_node->entry, filter, scan_list);
1092 			next_node = scm_get_next_node(scan_db,
1093 				&scan_db->scan_hash_tbl[i], cur_node);
1094 			cur_node = next_node;
1095 		}
1096 	}
1097 }
1098 
1099 QDF_STATUS scm_purge_scan_results(qdf_list_t *scan_list)
1100 {
1101 	QDF_STATUS status;
1102 	struct scan_cache_node *cur_node;
1103 	qdf_list_node_t *cur_lst = NULL, *next_lst = NULL;
1104 
1105 	if (!scan_list) {
1106 		scm_err("scan_result is NULL");
1107 		return QDF_STATUS_E_INVAL;
1108 	}
1109 
1110 	status = qdf_list_peek_front(scan_list, &cur_lst);
1111 
1112 	while (cur_lst) {
1113 		qdf_list_peek_next(
1114 			scan_list, cur_lst, &next_lst);
1115 		cur_node = qdf_container_of(cur_lst,
1116 			struct scan_cache_node, node);
1117 		status = qdf_list_remove_node(scan_list,
1118 					cur_lst);
1119 		if (QDF_IS_STATUS_SUCCESS(status)) {
1120 			util_scan_free_cache_entry(cur_node->entry);
1121 			qdf_mem_free(cur_node);
1122 		}
1123 		cur_lst = next_lst;
1124 		next_lst = NULL;
1125 	}
1126 
1127 	qdf_list_destroy(scan_list);
1128 	qdf_mem_free(scan_list);
1129 
1130 	return status;
1131 }
1132 
1133 qdf_list_t *scm_get_scan_result(struct wlan_objmgr_pdev *pdev,
1134 	struct scan_filter *filter)
1135 {
1136 	struct wlan_objmgr_psoc *psoc;
1137 	struct scan_dbs *scan_db;
1138 	qdf_list_t *tmp_list;
1139 
1140 	if (!pdev) {
1141 		scm_err("pdev is NULL");
1142 		return NULL;
1143 	}
1144 
1145 	psoc = wlan_pdev_get_psoc(pdev);
1146 	if (!psoc) {
1147 		scm_err("psoc is NULL");
1148 		return NULL;
1149 	}
1150 
1151 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1152 	if (!scan_db) {
1153 		scm_err("scan_db is NULL");
1154 		return NULL;
1155 	}
1156 
1157 	tmp_list = qdf_mem_malloc_atomic(sizeof(*tmp_list));
1158 	if (!tmp_list) {
1159 		scm_err("failed tp allocate scan_result");
1160 		return NULL;
1161 	}
1162 	qdf_list_create(tmp_list,
1163 			MAX_SCAN_CACHE_SIZE);
1164 	scm_age_out_entries(psoc, scan_db);
1165 	scm_get_results(psoc, scan_db, filter, tmp_list);
1166 
1167 	return tmp_list;
1168 }
1169 
1170 /**
1171  * scm_iterate_db_and_call_func() - iterate and call the func
1172  * @scan_db: scan db
1173  * @func: func to be called
1174  * @arg: func arg
1175  *
1176  * Return: QDF_STATUS
1177  */
1178 static QDF_STATUS
1179 scm_iterate_db_and_call_func(struct scan_dbs *scan_db,
1180 	scan_iterator_func func, void *arg)
1181 {
1182 	int i;
1183 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1184 	struct scan_cache_node *cur_node;
1185 	struct scan_cache_node *next_node = NULL;
1186 
1187 	if (!func)
1188 		return QDF_STATUS_E_INVAL;
1189 
1190 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1191 		cur_node = scm_get_next_node(scan_db,
1192 			&scan_db->scan_hash_tbl[i], NULL);
1193 		while (cur_node) {
1194 			status = func(arg, cur_node->entry);
1195 			if (QDF_IS_STATUS_ERROR(status)) {
1196 				scm_scan_entry_put_ref(scan_db,
1197 					cur_node, true);
1198 				return status;
1199 			}
1200 			next_node = scm_get_next_node(scan_db,
1201 				&scan_db->scan_hash_tbl[i], cur_node);
1202 			cur_node = next_node;
1203 		}
1204 	}
1205 
1206 	return status;
1207 }
1208 
1209 QDF_STATUS
1210 scm_iterate_scan_db(struct wlan_objmgr_pdev *pdev,
1211 	scan_iterator_func func, void *arg)
1212 {
1213 	struct wlan_objmgr_psoc *psoc;
1214 	struct scan_dbs *scan_db;
1215 	QDF_STATUS status;
1216 
1217 	if (!func) {
1218 		scm_err("func is NULL");
1219 		return QDF_STATUS_E_INVAL;
1220 	}
1221 
1222 	if (!pdev) {
1223 		scm_err("pdev is NULL");
1224 		return QDF_STATUS_E_INVAL;
1225 	}
1226 
1227 	psoc = wlan_pdev_get_psoc(pdev);
1228 	if (!psoc) {
1229 		scm_err("psoc is NULL");
1230 		return QDF_STATUS_E_INVAL;
1231 	}
1232 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1233 	if (!scan_db) {
1234 		scm_err("scan_db is NULL");
1235 		return QDF_STATUS_E_INVAL;
1236 	}
1237 
1238 	scm_age_out_entries(psoc, scan_db);
1239 	status = scm_iterate_db_and_call_func(scan_db, func, arg);
1240 
1241 	return status;
1242 }
1243 
1244 /**
1245  * scm_scan_apply_filter_flush_entry() -flush scan entries depending
1246  * on filter
1247  * @psoc: psoc ptr
1248  * @scan_db: scan db
1249  * @db_node: node on which filters are applied
1250  * @filter: filter to be applied
1251  *
1252  * Return: QDF_STATUS
1253  */
1254 static QDF_STATUS
1255 scm_scan_apply_filter_flush_entry(struct wlan_objmgr_psoc *psoc,
1256 	struct scan_dbs *scan_db,
1257 	struct scan_cache_node *db_node,
1258 	struct scan_filter *filter)
1259 {
1260 	struct security_info security = {0};
1261 	bool match;
1262 
1263 	if (!filter)
1264 		match = true;
1265 	else
1266 		match = scm_filter_match(psoc, db_node->entry,
1267 					filter, &security);
1268 
1269 	if (!match)
1270 		return QDF_STATUS_SUCCESS;
1271 
1272 	qdf_spin_lock_bh(&scan_db->scan_db_lock);
1273 	scm_scan_entry_del(scan_db, db_node);
1274 	qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1275 
1276 	return QDF_STATUS_SUCCESS;
1277 }
1278 
1279 /**
1280  * scm_flush_scan_entries() - API to flush scan entries depending on filters
1281  * @psoc: psoc ptr
1282  * @scan_db: scan db
1283  * @filter: filter
1284  *
1285  * Return: void
1286  */
1287 static void scm_flush_scan_entries(struct wlan_objmgr_psoc *psoc,
1288 	struct scan_dbs *scan_db,
1289 	struct scan_filter *filter)
1290 {
1291 	int i;
1292 	struct scan_cache_node *cur_node;
1293 	struct scan_cache_node *next_node = NULL;
1294 
1295 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1296 		cur_node = scm_get_next_node(scan_db,
1297 			   &scan_db->scan_hash_tbl[i], NULL);
1298 		while (cur_node) {
1299 			scm_scan_apply_filter_flush_entry(psoc, scan_db,
1300 				cur_node, filter);
1301 			next_node = scm_get_next_node(scan_db,
1302 				&scan_db->scan_hash_tbl[i], cur_node);
1303 			cur_node = next_node;
1304 		}
1305 	}
1306 }
1307 
1308 QDF_STATUS scm_flush_results(struct wlan_objmgr_pdev *pdev,
1309 	struct scan_filter *filter)
1310 {
1311 	struct wlan_objmgr_psoc *psoc;
1312 	struct scan_dbs *scan_db;
1313 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1314 
1315 	if (!pdev) {
1316 		scm_err("pdev is NULL");
1317 		return QDF_STATUS_E_INVAL;
1318 	}
1319 
1320 	psoc = wlan_pdev_get_psoc(pdev);
1321 	if (!psoc) {
1322 		scm_err("psoc is NULL");
1323 		return QDF_STATUS_E_INVAL;
1324 	}
1325 
1326 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1327 	if (!scan_db) {
1328 		scm_err("scan_db is NULL");
1329 		return QDF_STATUS_E_INVAL;
1330 	}
1331 
1332 	scm_flush_scan_entries(psoc, scan_db, filter);
1333 
1334 	return status;
1335 }
1336 
1337 /**
1338  * scm_filter_channels() - Remove entries not belonging to channel list
1339  * @scan_db: scan db
1340  * @db_node: node on which filters are applied
1341  * @chan_freq_list: valid channel frequency (in MHz) list
1342  * @num_chan: number of channels
1343  *
1344  * Return: QDF_STATUS
1345  */
1346 static void scm_filter_channels(struct wlan_objmgr_pdev *pdev,
1347 				struct scan_dbs *scan_db,
1348 				struct scan_cache_node *db_node,
1349 				uint32_t *chan_freq_list, uint32_t num_chan)
1350 {
1351 	int i;
1352 	bool match = false;
1353 
1354 	for (i = 0; i < num_chan; i++) {
1355 		if (chan_freq_list[i] == util_scan_entry_channel_frequency(
1356 							db_node->entry)) {
1357 			match = true;
1358 			break;
1359 		}
1360 	}
1361 
1362 	if (!match) {
1363 		qdf_spin_lock_bh(&scan_db->scan_db_lock);
1364 		scm_scan_entry_del(scan_db, db_node);
1365 		qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1366 	}
1367 }
1368 
1369 void scm_filter_valid_channel(struct wlan_objmgr_pdev *pdev,
1370 	uint32_t *chan_freq_list, uint32_t num_chan)
1371 {
1372 	int i;
1373 	struct wlan_objmgr_psoc *psoc;
1374 	struct scan_dbs *scan_db;
1375 	struct scan_cache_node *cur_node;
1376 	struct scan_cache_node *next_node = NULL;
1377 
1378 	scm_debug("num_chan = %d", num_chan);
1379 
1380 	if (!pdev) {
1381 		scm_err("pdev is NULL");
1382 		return;
1383 	}
1384 
1385 	psoc = wlan_pdev_get_psoc(pdev);
1386 	if (!psoc) {
1387 		scm_err("psoc is NULL");
1388 		return;
1389 	}
1390 
1391 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1392 	if (!scan_db) {
1393 		scm_err("scan_db is NULL");
1394 		return;
1395 	}
1396 
1397 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1398 		cur_node = scm_get_next_node(scan_db,
1399 			   &scan_db->scan_hash_tbl[i], NULL);
1400 		while (cur_node) {
1401 			scm_filter_channels(pdev, scan_db,
1402 					    cur_node, chan_freq_list, num_chan);
1403 			next_node = scm_get_next_node(scan_db,
1404 				&scan_db->scan_hash_tbl[i], cur_node);
1405 			cur_node = next_node;
1406 		}
1407 	}
1408 }
1409 
1410 QDF_STATUS scm_scan_register_bcn_cb(struct wlan_objmgr_psoc *psoc,
1411 	update_beacon_cb cb, enum scan_cb_type type)
1412 {
1413 	struct wlan_scan_obj *scan_obj;
1414 
1415 	scan_obj = wlan_psoc_get_scan_obj(psoc);
1416 	if (!scan_obj) {
1417 		scm_err("scan obj is NULL");
1418 		return QDF_STATUS_E_INVAL;
1419 	}
1420 	switch (type) {
1421 	case SCAN_CB_TYPE_INFORM_BCN:
1422 		scan_obj->cb.inform_beacon = cb;
1423 		break;
1424 	case SCAN_CB_TYPE_UPDATE_BCN:
1425 		scan_obj->cb.update_beacon = cb;
1426 		break;
1427 	case SCAN_CB_TYPE_UNLINK_BSS:
1428 		scan_obj->cb.unlink_bss = cb;
1429 		break;
1430 	default:
1431 		scm_err("invalid cb type %d", type);
1432 	}
1433 
1434 	return QDF_STATUS_SUCCESS;
1435 }
1436 
1437 QDF_STATUS scm_db_init(struct wlan_objmgr_psoc *psoc)
1438 {
1439 	int i, j;
1440 	struct scan_dbs *scan_db;
1441 
1442 	if (!psoc) {
1443 		scm_err("psoc is NULL");
1444 		return QDF_STATUS_E_INVAL;
1445 	}
1446 
1447 	/* Initialize the scan database per pdev */
1448 	for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) {
1449 		scan_db = wlan_pdevid_get_scan_db(psoc, i);
1450 		if (!scan_db) {
1451 			scm_err("scan_db is NULL %d", i);
1452 			continue;
1453 		}
1454 		scan_db->num_entries = 0;
1455 		qdf_spinlock_create(&scan_db->scan_db_lock);
1456 		for (j = 0; j < SCAN_HASH_SIZE; j++)
1457 			qdf_list_create(&scan_db->scan_hash_tbl[j],
1458 				MAX_SCAN_CACHE_SIZE);
1459 	}
1460 	return QDF_STATUS_SUCCESS;
1461 }
1462 
1463 QDF_STATUS scm_db_deinit(struct wlan_objmgr_psoc *psoc)
1464 {
1465 	int i, j;
1466 	struct scan_dbs *scan_db;
1467 
1468 	if (!psoc) {
1469 		scm_err("scan obj is NULL");
1470 		return QDF_STATUS_E_INVAL;
1471 	}
1472 
1473 	/* Initialize the scan database per pdev */
1474 	for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) {
1475 		scan_db = wlan_pdevid_get_scan_db(psoc, i);
1476 		if (!scan_db) {
1477 			scm_err("scan_db is NULL %d", i);
1478 			continue;
1479 		}
1480 
1481 		scm_flush_scan_entries(psoc, scan_db, NULL);
1482 		for (j = 0; j < SCAN_HASH_SIZE; j++)
1483 			qdf_list_destroy(&scan_db->scan_hash_tbl[j]);
1484 		qdf_spinlock_destroy(&scan_db->scan_db_lock);
1485 	}
1486 
1487 	return QDF_STATUS_SUCCESS;
1488 }
1489 
1490 #ifdef FEATURE_6G_SCAN_CHAN_SORT_ALGO
1491 QDF_STATUS scm_channel_list_db_init(struct wlan_objmgr_psoc *psoc)
1492 {
1493 	uint32_t i, j;
1494 	uint32_t min_freq, max_freq;
1495 	struct channel_list_db *rnr_channel_db;
1496 
1497 	min_freq = wlan_reg_min_6ghz_chan_freq();
1498 	max_freq = wlan_reg_max_6ghz_chan_freq();
1499 
1500 	scm_info("min_freq %d max_freq %d", min_freq, max_freq);
1501 	i = min_freq;
1502 	rnr_channel_db = scm_get_rnr_channel_db(psoc);
1503 	if (!rnr_channel_db)
1504 		return QDF_STATUS_E_INVAL;
1505 
1506 	for (j = 0; j < QDF_ARRAY_SIZE(rnr_channel_db->channel); j++) {
1507 		if (i >= min_freq && i <= max_freq)
1508 			rnr_channel_db->channel[j].chan_freq = i;
1509 		i += 20;
1510 		/* init list for all to avoid uninitialized list */
1511 		qdf_list_create(&rnr_channel_db->channel[j].rnr_list,
1512 				WLAN_MAX_RNR_COUNT);
1513 	}
1514 	return QDF_STATUS_SUCCESS;
1515 }
1516 
1517 QDF_STATUS scm_channel_list_db_deinit(struct wlan_objmgr_psoc *psoc)
1518 {
1519 	int i;
1520 	qdf_list_node_t *cur_node, *next_node;
1521 	struct meta_rnr_channel *channel;
1522 	struct scan_rnr_node *rnr_node;
1523 	struct channel_list_db *rnr_channel_db;
1524 
1525 	rnr_channel_db = scm_get_rnr_channel_db(psoc);
1526 	if (!rnr_channel_db)
1527 		return QDF_STATUS_E_INVAL;
1528 
1529 	for (i = 0; i < QDF_ARRAY_SIZE(rnr_channel_db->channel); i++) {
1530 		channel = &rnr_channel_db->channel[i];
1531 		channel->chan_freq = 0;
1532 		channel->beacon_probe_last_time_found = 0;
1533 		channel->bss_beacon_probe_count = 0;
1534 		channel->saved_profile_count = 0;
1535 		cur_node = NULL;
1536 		qdf_list_peek_front(&channel->rnr_list, &cur_node);
1537 		while (cur_node) {
1538 			next_node = NULL;
1539 			qdf_list_peek_next(&channel->rnr_list, cur_node,
1540 					   &next_node);
1541 			rnr_node = qdf_container_of(cur_node,
1542 						    struct scan_rnr_node,
1543 						    node);
1544 			qdf_list_remove_node(&channel->rnr_list,
1545 					     &rnr_node->node);
1546 			qdf_mem_free(rnr_node);
1547 			cur_node = next_node;
1548 			next_node = NULL;
1549 		}
1550 		qdf_list_destroy(&channel->rnr_list);
1551 	}
1552 
1553 	return QDF_STATUS_SUCCESS;
1554 }
1555 
1556 QDF_STATUS scm_rnr_db_flush(struct wlan_objmgr_psoc *psoc)
1557 {
1558 	int i;
1559 	qdf_list_node_t *cur_node, *next_node;
1560 	struct meta_rnr_channel *channel;
1561 	struct scan_rnr_node *rnr_node;
1562 	struct channel_list_db *rnr_channel_db;
1563 
1564 	rnr_channel_db = scm_get_rnr_channel_db(psoc);
1565 	if (!rnr_channel_db)
1566 		return QDF_STATUS_E_INVAL;
1567 
1568 	for (i = 0; i < QDF_ARRAY_SIZE(rnr_channel_db->channel); i++) {
1569 		channel = &rnr_channel_db->channel[i];
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 		/* Reset beacon info */
1586 		channel->beacon_probe_last_time_found = 0;
1587 		channel->bss_beacon_probe_count = 0;
1588 	}
1589 
1590 	return QDF_STATUS_SUCCESS;
1591 }
1592 
1593 void scm_update_rnr_from_scan_cache(struct wlan_objmgr_pdev *pdev)
1594 {
1595 	uint8_t i;
1596 	struct scan_dbs *scan_db;
1597 	struct scan_cache_node *cur_node;
1598 	struct scan_cache_node *next_node = NULL;
1599 	struct wlan_objmgr_psoc *psoc;
1600 	struct scan_cache_entry *entry;
1601 
1602 	psoc = wlan_pdev_get_psoc(pdev);
1603 	if (!psoc) {
1604 		scm_err("psoc is NULL");
1605 		return;
1606 	}
1607 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1608 	if (!scan_db) {
1609 		scm_err("scan_db is NULL");
1610 		return;
1611 	}
1612 
1613 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1614 		cur_node = scm_get_next_node(scan_db,
1615 					     &scan_db->scan_hash_tbl[i], NULL);
1616 		while (cur_node) {
1617 			entry = cur_node->entry;
1618 			scm_add_rnr_channel_db(psoc, entry);
1619 			next_node =
1620 				scm_get_next_node(scan_db,
1621 						  &scan_db->scan_hash_tbl[i],
1622 						  cur_node);
1623 			cur_node = next_node;
1624 			next_node = NULL;
1625 		}
1626 	}
1627 }
1628 #endif
1629 
1630 QDF_STATUS scm_update_scan_mlme_info(struct wlan_objmgr_pdev *pdev,
1631 	struct scan_cache_entry *entry)
1632 {
1633 	uint8_t hash_idx;
1634 	struct scan_dbs *scan_db;
1635 	struct scan_cache_node *cur_node;
1636 	struct scan_cache_node *next_node = NULL;
1637 	struct wlan_objmgr_psoc *psoc;
1638 
1639 	psoc = wlan_pdev_get_psoc(pdev);
1640 	if (!psoc) {
1641 		scm_err("psoc is NULL");
1642 		return QDF_STATUS_E_INVAL;
1643 	}
1644 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1645 	if (!scan_db) {
1646 		scm_err("scan_db is NULL");
1647 		return QDF_STATUS_E_INVAL;
1648 	}
1649 
1650 	hash_idx = SCAN_GET_HASH(entry->bssid.bytes);
1651 
1652 	cur_node = scm_get_next_node(scan_db,
1653 			&scan_db->scan_hash_tbl[hash_idx], NULL);
1654 
1655 	while (cur_node) {
1656 		if (util_is_scan_entry_match(entry,
1657 					cur_node->entry)) {
1658 			/* Acquire db lock to prevent simultaneous update */
1659 			qdf_spin_lock_bh(&scan_db->scan_db_lock);
1660 			scm_update_mlme_info(entry, cur_node->entry);
1661 			qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1662 			scm_scan_entry_put_ref(scan_db,
1663 					cur_node, true);
1664 			return QDF_STATUS_SUCCESS;
1665 		}
1666 		next_node = scm_get_next_node(scan_db,
1667 				&scan_db->scan_hash_tbl[hash_idx], cur_node);
1668 		cur_node = next_node;
1669 	}
1670 
1671 	return QDF_STATUS_E_INVAL;
1672 }
1673 
1674 QDF_STATUS scm_scan_update_mlme_by_bssinfo(struct wlan_objmgr_pdev *pdev,
1675 		struct bss_info *bss_info, struct mlme_info *mlme)
1676 {
1677 	uint8_t hash_idx;
1678 	struct scan_dbs *scan_db;
1679 	struct scan_cache_node *cur_node;
1680 	struct scan_cache_node *next_node = NULL;
1681 	struct wlan_objmgr_psoc *psoc;
1682 	struct scan_cache_entry *entry;
1683 
1684 	psoc = wlan_pdev_get_psoc(pdev);
1685 	if (!psoc) {
1686 		scm_err("psoc is NULL");
1687 		return QDF_STATUS_E_INVAL;
1688 	}
1689 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1690 	if (!scan_db) {
1691 		scm_err("scan_db is NULL");
1692 		return QDF_STATUS_E_INVAL;
1693 	}
1694 
1695 	hash_idx = SCAN_GET_HASH(bss_info->bssid.bytes);
1696 	cur_node = scm_get_next_node(scan_db,
1697 			&scan_db->scan_hash_tbl[hash_idx], NULL);
1698 	while (cur_node) {
1699 		entry = cur_node->entry;
1700 		if (qdf_is_macaddr_equal(&bss_info->bssid, &entry->bssid) &&
1701 			(util_is_ssid_match(&bss_info->ssid, &entry->ssid)) &&
1702 			(bss_info->freq == entry->channel.chan_freq)) {
1703 			/* Acquire db lock to prevent simultaneous update */
1704 			qdf_spin_lock_bh(&scan_db->scan_db_lock);
1705 			qdf_mem_copy(&entry->mlme_info, mlme,
1706 					sizeof(struct mlme_info));
1707 			scm_scan_entry_put_ref(scan_db,
1708 					cur_node, false);
1709 			qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1710 			return QDF_STATUS_SUCCESS;
1711 		}
1712 		next_node = scm_get_next_node(scan_db,
1713 				&scan_db->scan_hash_tbl[hash_idx], cur_node);
1714 		cur_node = next_node;
1715 	}
1716 
1717 	return QDF_STATUS_E_INVAL;
1718 }
1719