xref: /wlan-dirver/qca-wifi-host-cmn/umac/scan/core/src/wlan_scan_cache_db.c (revision 1b9674e21e24478fba4530f5ae7396b9555e9c6a)
1 /*
2  * Copyright (c) 2017-2018 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_dfs_utils_api.h>
54 
55 /**
56  * scm_del_scan_node() - API to remove scan node from the list
57  * @list: hash list
58  * @scan_node: node to be removed
59  *
60  * This should be called while holding scan_db_lock.
61  *
62  * Return: void
63  */
64 static void scm_del_scan_node(qdf_list_t *list,
65 	struct scan_cache_node *scan_node)
66 {
67 	QDF_STATUS status;
68 
69 	status = qdf_list_remove_node(list, &scan_node->node);
70 	if (QDF_IS_STATUS_SUCCESS(status)) {
71 		util_scan_free_cache_entry(scan_node->entry);
72 		qdf_mem_free(scan_node);
73 	}
74 }
75 
76 /**
77  * scm_del_scan_node_from_db() - API to del the scan entry
78  * @scan_db: scan database
79  * @scan_entry:entry scan_node
80  *
81  * API to flush the scan entry. This should be called while
82  * holding scan_db_lock.
83  *
84  * Return: QDF status.
85  */
86 static QDF_STATUS scm_del_scan_node_from_db(struct scan_dbs *scan_db,
87 	struct scan_cache_node *scan_node)
88 {
89 	QDF_STATUS status = QDF_STATUS_SUCCESS;
90 	uint8_t hash_idx;
91 
92 	if (!scan_node)
93 		return QDF_STATUS_E_INVAL;
94 
95 	hash_idx = SCAN_GET_HASH(scan_node->entry->bssid.bytes);
96 	scm_del_scan_node(&scan_db->scan_hash_tbl[hash_idx], scan_node);
97 	scan_db->num_entries--;
98 
99 	return status;
100 }
101 
102 /**
103  * scm_scan_entry_get_ref() - api to increase ref count of scan entry
104  * @scan_node: scan node
105  *
106  * Return: void
107  */
108 static void scm_scan_entry_get_ref(struct scan_cache_node *scan_node)
109 {
110 	if (scan_node == NULL) {
111 		scm_err("scan_node is NULL");
112 		QDF_ASSERT(0);
113 		return;
114 	}
115 	qdf_atomic_inc(&scan_node->ref_cnt);
116 }
117 
118 /**
119  * scm_scan_entry_put_ref() - Api to decrease ref count of scan entry
120  * and free if it become 0
121  * @scan_db: scan database
122  * @scan_node: scan node
123  * @lock_needed: if scan_db_lock is needed
124  *
125  * Return: void
126  */
127 static void scm_scan_entry_put_ref(struct scan_dbs *scan_db,
128 	struct scan_cache_node *scan_node, bool lock_needed)
129 {
130 
131 	if (!scan_node) {
132 		scm_err("scan_node is NULL");
133 		QDF_ASSERT(0);
134 		return;
135 	}
136 
137 	if (lock_needed)
138 		qdf_spin_lock_bh(&scan_db->scan_db_lock);
139 
140 	if (!qdf_atomic_read(&scan_node->ref_cnt)) {
141 		if (lock_needed)
142 			qdf_spin_unlock_bh(&scan_db->scan_db_lock);
143 		scm_err("scan_node ref cnt is 0");
144 		QDF_ASSERT(0);
145 		return;
146 	}
147 
148 	/* Decrement ref count, free scan_node, if ref count == 0 */
149 	if (qdf_atomic_dec_and_test(&scan_node->ref_cnt))
150 		scm_del_scan_node_from_db(scan_db, scan_node);
151 
152 	if (lock_needed)
153 		qdf_spin_unlock_bh(&scan_db->scan_db_lock);
154 }
155 
156 /**
157  * scm_scan_entry_del() - API to delete scan node
158  * @scan_db: data base
159  * @scan_node: node to be deleted
160  *
161  * Call must be protected by scan_db->scan_db_lock
162  *
163  * Return: void
164  */
165 
166 static void scm_scan_entry_del(struct scan_dbs *scan_db,
167 			       struct scan_cache_node *scan_node)
168 {
169 	if (!scan_node) {
170 		scm_err("scan node is NULL");
171 		QDF_ASSERT(0);
172 		return;
173 	}
174 
175 	if (scan_node->cookie != SCAN_NODE_ACTIVE_COOKIE) {
176 		scm_debug("node is already deleted");
177 		return;
178 	}
179 	/* Seems node is already deleted */
180 	if (!qdf_atomic_read(&scan_node->ref_cnt)) {
181 		scm_debug("node is already deleted ref 0");
182 		return;
183 	}
184 	scan_node->cookie = 0;
185 
186 	scm_scan_entry_put_ref(scan_db, scan_node, false);
187 }
188 
189 /**
190  * scm_add_scan_node() - API to add scan node
191  * @scan_db: data base
192  * @scan_node: node to be added
193  * @dup_node: node before which new node to be added
194  * if it's not NULL, otherwise add node to tail
195  *
196  * Call must be protected by scan_db->scan_db_lock
197  *
198  * Return: void
199  */
200 static void scm_add_scan_node(struct scan_dbs *scan_db,
201 	struct scan_cache_node *scan_node,
202 	struct scan_cache_node *dup_node)
203 {
204 	uint8_t hash_idx;
205 
206 	hash_idx =
207 		SCAN_GET_HASH(scan_node->entry->bssid.bytes);
208 
209 	qdf_atomic_init(&scan_node->ref_cnt);
210 	scan_node->cookie = SCAN_NODE_ACTIVE_COOKIE;
211 	scm_scan_entry_get_ref(scan_node);
212 	if (!dup_node)
213 		qdf_list_insert_back(&scan_db->scan_hash_tbl[hash_idx],
214 				     &scan_node->node);
215 	else
216 		qdf_list_insert_before(&scan_db->scan_hash_tbl[hash_idx],
217 				       &scan_node->node, &dup_node->node);
218 
219 	scan_db->num_entries++;
220 }
221 
222 
223 /**
224  * scm_get_next_valid_node() - API get the next valid scan node from
225  * the list
226  * @list: hash list
227  * @cur_node: current node pointer
228  *
229  * API to get next active node from the list. If cur_node is NULL
230  * it will return first node of the list.
231  * Call must be protected by scan_db->scan_db_lock
232  *
233  * Return: next scan node
234  */
235 static qdf_list_node_t *
236 scm_get_next_valid_node(qdf_list_t *list,
237 	qdf_list_node_t *cur_node)
238 {
239 	qdf_list_node_t *next_node = NULL;
240 	qdf_list_node_t *temp_node = NULL;
241 	struct scan_cache_node *scan_node;
242 
243 	if (cur_node)
244 		qdf_list_peek_next(list, cur_node, &next_node);
245 	else
246 		qdf_list_peek_front(list, &next_node);
247 
248 	while (next_node) {
249 		scan_node = qdf_container_of(next_node,
250 			struct scan_cache_node, node);
251 		if (scan_node->cookie == SCAN_NODE_ACTIVE_COOKIE)
252 			return next_node;
253 		/*
254 		 * If node is not valid check for next entry
255 		 * to get next valid node.
256 		 */
257 		qdf_list_peek_next(list, next_node, &temp_node);
258 		next_node = temp_node;
259 		temp_node = NULL;
260 	}
261 
262 	return next_node;
263 }
264 
265 /**
266  * scm_get_next_node() - API get the next scan node from
267  * the list
268  * @scan_db: scan data base
269  * @list: hash list
270  * @cur_node: current node pointer
271  *
272  * API get the next node from the list. If cur_node is NULL
273  * it will return first node of the list
274  *
275  * Return: next scan cache node
276  */
277 static struct scan_cache_node *
278 scm_get_next_node(struct scan_dbs *scan_db,
279 	qdf_list_t *list, struct scan_cache_node *cur_node)
280 {
281 	struct scan_cache_node *next_node = NULL;
282 	qdf_list_node_t *next_list = NULL;
283 
284 	qdf_spin_lock_bh(&scan_db->scan_db_lock);
285 	if (cur_node) {
286 		next_list = scm_get_next_valid_node(list, &cur_node->node);
287 		/* Decrement the ref count of the previous node */
288 		scm_scan_entry_put_ref(scan_db,
289 			cur_node, false);
290 	} else {
291 		next_list = scm_get_next_valid_node(list, NULL);
292 	}
293 	/* Increase the ref count of the obtained node */
294 	if (next_list) {
295 		next_node = qdf_container_of(next_list,
296 			struct scan_cache_node, node);
297 		scm_scan_entry_get_ref(next_node);
298 	}
299 	qdf_spin_unlock_bh(&scan_db->scan_db_lock);
300 
301 	return next_node;
302 }
303 
304 /**
305  * scm_check_and_age_out() - check and age out the old entries
306  * @scan_db: scan db
307  * @scan_node: node to check for age out
308  * @scan_aging_time: scan cache aging time
309  *
310  * Return: void
311  */
312 static void scm_check_and_age_out(struct scan_dbs *scan_db,
313 	struct scan_cache_node *node,
314 	uint32_t scan_aging_time)
315 {
316 	if (util_scan_entry_age(node->entry) >=
317 	   scan_aging_time) {
318 		scm_debug("Aging out BSSID: %pM with age %d ms",
319 			  node->entry->bssid.bytes,
320 			  util_scan_entry_age(node->entry));
321 		qdf_spin_lock_bh(&scan_db->scan_db_lock);
322 		scm_scan_entry_del(scan_db, node);
323 		qdf_spin_unlock_bh(&scan_db->scan_db_lock);
324 	}
325 }
326 
327 static bool scm_bss_is_connected(struct scan_cache_entry *entry)
328 {
329 	if (entry->mlme_info.assoc_state == SCAN_ENTRY_CON_STATE_ASSOC)
330 		return true;
331 	return false;
332 }
333 void scm_age_out_entries(struct wlan_objmgr_psoc *psoc,
334 	struct scan_dbs *scan_db)
335 {
336 	int i;
337 	struct scan_cache_node *cur_node = NULL;
338 	struct scan_cache_node *next_node = NULL;
339 	struct scan_default_params *def_param;
340 
341 	def_param = wlan_scan_psoc_get_def_params(psoc);
342 	if (!def_param) {
343 		scm_err("wlan_scan_psoc_get_def_params failed");
344 		return;
345 	}
346 
347 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
348 		cur_node = scm_get_next_node(scan_db,
349 			&scan_db->scan_hash_tbl[i], NULL);
350 		while (cur_node) {
351 			if (!scm_bss_is_connected(cur_node->entry))
352 				scm_check_and_age_out(scan_db, cur_node,
353 					def_param->scan_cache_aging_time);
354 			next_node = scm_get_next_node(scan_db,
355 				&scan_db->scan_hash_tbl[i], cur_node);
356 			cur_node = next_node;
357 			next_node = NULL;
358 		}
359 	}
360 }
361 
362 /**
363  * scm_flush_oldest_entry() - Iterate over scan db and flust out the
364  *  oldest entry
365  * @scan_db: scan db from which oldest entry needs to be flushed
366  *
367  * Return: QDF_STATUS
368  */
369 static QDF_STATUS scm_flush_oldest_entry(struct scan_dbs *scan_db)
370 {
371 	int i;
372 	struct scan_cache_node *oldest_node = NULL;
373 	struct scan_cache_node *cur_node;
374 
375 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
376 		/* Get the first valid node for the hash */
377 		cur_node = scm_get_next_node(scan_db,
378 					     &scan_db->scan_hash_tbl[i],
379 					     NULL);
380 		 /* Iterate scan db and flush out oldest node
381 		  * take ref_cnt for oldest_node
382 		  */
383 
384 		while (cur_node) {
385 			if (!oldest_node ||
386 			   (util_scan_entry_age(oldest_node->entry) <
387 			    util_scan_entry_age(cur_node->entry))) {
388 				if (oldest_node)
389 					scm_scan_entry_put_ref(scan_db,
390 							       oldest_node,
391 							       true);
392 				oldest_node = cur_node;
393 				scm_scan_entry_get_ref(oldest_node);
394 			}
395 
396 			cur_node = scm_get_next_node(scan_db,
397 					&scan_db->scan_hash_tbl[i],
398 					cur_node);
399 		};
400 	}
401 
402 	if (oldest_node) {
403 		scm_debug("Flush oldest BSSID: %pM with age %d ms",
404 				oldest_node->entry->bssid.bytes,
405 				util_scan_entry_age(oldest_node->entry));
406 		/* Release ref_cnt taken for oldest_node and delete it */
407 		qdf_spin_lock_bh(&scan_db->scan_db_lock);
408 		scm_scan_entry_del(scan_db, oldest_node);
409 		scm_scan_entry_put_ref(scan_db, oldest_node, false);
410 		qdf_spin_unlock_bh(&scan_db->scan_db_lock);
411 	}
412 
413 	return QDF_STATUS_SUCCESS;
414 }
415 
416 /**
417  * scm_update_alt_wcn_ie() - update the alternate WCN IE
418  * @from: copy from
419  * @dst: copy to
420  *
421  * Return: void
422  */
423 static void scm_update_alt_wcn_ie(struct scan_cache_entry *from,
424 	struct scan_cache_entry *dst)
425 {
426 	uint32_t alt_wcn_ie_len;
427 
428 	if (from->frm_subtype == dst->frm_subtype)
429 		return;
430 
431 	if (!from->ie_list.wcn && !dst->ie_list.wcn)
432 		return;
433 
434 	/* Existing WCN IE is empty. */
435 	if (!from->ie_list.wcn)
436 		return;
437 
438 	alt_wcn_ie_len = 2 + from->ie_list.wcn[1];
439 	if (alt_wcn_ie_len > WLAN_MAX_IE_LEN + 2) {
440 		scm_err("invalid IE len");
441 		return;
442 	}
443 
444 	if (!dst->alt_wcn_ie.ptr) {
445 		/* allocate this additional buffer for alternate WCN IE */
446 		dst->alt_wcn_ie.ptr =
447 			qdf_mem_malloc_atomic(WLAN_MAX_IE_LEN + 2);
448 		if (!dst->alt_wcn_ie.ptr) {
449 			scm_err("failed to allocate memory");
450 			return;
451 		}
452 	}
453 	qdf_mem_copy(dst->alt_wcn_ie.ptr,
454 		from->ie_list.wcn, alt_wcn_ie_len);
455 	dst->alt_wcn_ie.len = alt_wcn_ie_len;
456 }
457 
458 /**
459  * scm_update_mlme_info() - update mlme info
460  * @src: source scan entry
461  * @dest: destination scan entry
462  *
463  * Return: void
464  */
465 static inline void
466 scm_update_mlme_info(struct scan_cache_entry *src,
467 	struct scan_cache_entry *dest)
468 {
469 	qdf_mem_copy(&dest->mlme_info, &src->mlme_info,
470 		sizeof(struct mlme_info));
471 }
472 
473 /**
474  * scm_copy_info_from_dup_entry() - copy duplicate node info
475  * to new scan entry
476  * @scan_db: scan database
477  * @scan_params: new entry to be added
478  * @scan_node: duplicate entry
479  *
480  * Copy duplicate node info to new entry.
481  *
482  * Return: void
483  */
484 static void
485 scm_copy_info_from_dup_entry(struct scan_dbs *scan_db,
486 			     struct scan_cache_entry *scan_params,
487 			     struct scan_cache_node *scan_node)
488 {
489 	struct scan_cache_entry *scan_entry;
490 	uint64_t time_gap;
491 
492 	scan_entry = scan_node->entry;
493 	/* If old entry have the ssid but new entry does not */
494 	if (!scan_params->ssid.length && scan_entry->ssid.length) {
495 		/*
496 		 * New entry has a hidden SSID and old one has the SSID.
497 		 * Add the entry by using the ssid of the old entry
498 		 * only if diff of saved SSID time and current time is
499 		 * less than HIDDEN_SSID_TIME time.
500 		 * This will avoid issues in case AP changes its SSID
501 		 * while remain hidden.
502 		 */
503 		time_gap =
504 			qdf_mc_timer_get_system_time() -
505 			scan_entry->hidden_ssid_timestamp;
506 		if (time_gap <= HIDDEN_SSID_TIME) {
507 			scan_params->hidden_ssid_timestamp =
508 				scan_entry->hidden_ssid_timestamp;
509 			scan_params->ssid.length =
510 				scan_entry->ssid.length;
511 			qdf_mem_copy(scan_params->ssid.ssid,
512 				scan_entry->ssid.ssid,
513 				scan_params->ssid.length);
514 		}
515 	}
516 
517 	/*
518 	 * Due to Rx sensitivity issue, sometime beacons are seen on adjacent
519 	 * channel so workaround in software is needed. If DS params or HT info
520 	 * are present driver can get proper channel info from these IEs and set
521 	 * channel_mismatch so that the older RSSI values are used in new entry.
522 	 *
523 	 * For the cases where DS params and HT info is not present, driver
524 	 * needs to check below conditions to get proper channel and set
525 	 * channel_mismatch so that the older RSSI values are used in new entry:
526 	 *   -- The old entry channel and new entry channel are not same
527 	 *   -- RSSI is less than -80, this indicate that the signal has leaked
528 	 *       in adjacent channel.
529 	 */
530 	if ((scan_params->frm_subtype == MGMT_SUBTYPE_BEACON) &&
531 	    !util_scan_entry_htinfo(scan_params) &&
532 	    !util_scan_entry_ds_param(scan_params) &&
533 	    (scan_params->channel.chan_idx != scan_entry->channel.chan_idx) &&
534 	    (scan_params->rssi_raw  < ADJACENT_CHANNEL_RSSI_THRESHOLD)) {
535 		scan_params->channel.chan_idx = scan_entry->channel.chan_idx;
536 		scan_params->channel_mismatch = true;
537 	}
538 
539 	/* Use old value for rssi if beacon was heard on adjacent channel. */
540 	if (scan_params->channel_mismatch) {
541 		scan_params->rssi_raw = scan_entry->rssi_raw;
542 		scan_params->avg_rssi = scan_entry->avg_rssi;
543 		scan_params->rssi_timestamp =
544 			scan_entry->rssi_timestamp;
545 	} else {
546 		/* If elapsed time since last rssi update for this
547 		 * entry is smaller than a thresold, calculate a
548 		 * running average of the RSSI values.
549 		 * Otherwise new frames RSSI is more representive
550 		 * of the signal strength.
551 		 */
552 		time_gap =
553 			scan_params->scan_entry_time -
554 			scan_entry->rssi_timestamp;
555 		if (time_gap > WLAN_RSSI_AVERAGING_TIME)
556 			scan_params->avg_rssi =
557 				WLAN_RSSI_IN(scan_params->rssi_raw);
558 		else {
559 			/* Copy previous average rssi to new entry */
560 			scan_params->avg_rssi = scan_entry->avg_rssi;
561 			/* Average with previous samples */
562 			WLAN_RSSI_LPF(scan_params->avg_rssi,
563 					scan_params->rssi_raw);
564 		}
565 
566 		scan_params->rssi_timestamp = scan_params->scan_entry_time;
567 	}
568 
569 	/* copy wsn ie from scan_entry to scan_params*/
570 	scm_update_alt_wcn_ie(scan_entry, scan_params);
571 
572 	/* copy mlme info from scan_entry to scan_params*/
573 	scm_update_mlme_info(scan_entry, scan_params);
574 }
575 
576 /**
577  * scm_find_duplicate() - find duplicate entry,
578  * if present, add input scan entry before it and delete
579  * duplicate entry. otherwise add entry to tail
580  * @scan_db: scan db
581  * @entry: input scan cache entry
582  * @dup_node: node before which new entry to be added
583  *
584  * ref_cnt is taken for dup_node, caller should release ref taken
585  * if returns true.
586  *
587  * Return: bool
588  */
589 static bool
590 scm_find_duplicate(struct scan_dbs *scan_db,
591 		   struct scan_cache_entry *entry,
592 		   struct scan_cache_node **dup_node)
593 {
594 	uint8_t hash_idx;
595 	struct scan_cache_node *cur_node;
596 	struct scan_cache_node *next_node = NULL;
597 
598 	hash_idx = SCAN_GET_HASH(entry->bssid.bytes);
599 
600 	cur_node = scm_get_next_node(scan_db,
601 				     &scan_db->scan_hash_tbl[hash_idx],
602 				     NULL);
603 
604 	while (cur_node) {
605 		if (util_is_scan_entry_match(entry,
606 		   cur_node->entry)) {
607 			scm_copy_info_from_dup_entry(scan_db, entry, cur_node);
608 			*dup_node = cur_node;
609 			return true;
610 		}
611 		next_node = scm_get_next_node(scan_db,
612 			 &scan_db->scan_hash_tbl[hash_idx], cur_node);
613 		cur_node = next_node;
614 		next_node = NULL;
615 	}
616 
617 	return false;
618 }
619 
620 /**
621  * scm_add_update_entry() - add or update scan entry
622  * @psoc: psoc ptr
623  * @pdev: pdev pointer
624  * @scan_params: new received entry
625  *
626  * Return: QDF_STATUS
627  */
628 static QDF_STATUS scm_add_update_entry(struct wlan_objmgr_psoc *psoc,
629 	struct wlan_objmgr_pdev *pdev, struct scan_cache_entry *scan_params)
630 {
631 	struct scan_cache_node *dup_node = NULL;
632 	struct scan_cache_node *scan_node = NULL;
633 	bool is_dup_found = false;
634 	QDF_STATUS status;
635 	struct scan_dbs *scan_db;
636 	struct wlan_scan_obj *scan_obj;
637 
638 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
639 	if (!scan_db) {
640 		scm_err("scan_db is NULL");
641 		return QDF_STATUS_E_INVAL;
642 	}
643 
644 	scan_obj = wlan_psoc_get_scan_obj(psoc);
645 	if (!scan_obj) {
646 		scm_err("scan_obj is NULL");
647 		return QDF_STATUS_E_INVAL;
648 	}
649 
650 	if (scan_params->frm_subtype ==
651 	   MGMT_SUBTYPE_PROBE_RESP &&
652 	   !scan_params->ie_list.ssid)
653 		scm_debug("Probe resp doesn't contain SSID");
654 
655 
656 	if (scan_params->ie_list.csa ||
657 	   scan_params->ie_list.xcsa ||
658 	   scan_params->ie_list.cswrp)
659 		scm_debug("CSA IE present for BSSID: %pM",
660 			  scan_params->bssid.bytes);
661 
662 	is_dup_found = scm_find_duplicate(scan_db, scan_params, &dup_node);
663 
664 	if (scan_obj->cb.inform_beacon)
665 		scan_obj->cb.inform_beacon(pdev, scan_params);
666 
667 	if (scan_db->num_entries >= MAX_SCAN_CACHE_SIZE) {
668 		status = scm_flush_oldest_entry(scan_db);
669 		if (QDF_IS_STATUS_ERROR(status)) {
670 			/* release ref taken for dup node */
671 			if (is_dup_found)
672 				scm_scan_entry_put_ref(scan_db, dup_node, true);
673 			return status;
674 		}
675 	}
676 
677 	scan_node = qdf_mem_malloc(sizeof(*scan_node));
678 	if (!scan_node) {
679 		/* release ref taken for dup node */
680 		if (is_dup_found)
681 			scm_scan_entry_put_ref(scan_db, dup_node, true);
682 		return QDF_STATUS_E_NOMEM;
683 	}
684 
685 	scan_node->entry = scan_params;
686 	qdf_spin_lock_bh(&scan_db->scan_db_lock);
687 	scm_add_scan_node(scan_db, scan_node, dup_node);
688 
689 	if (is_dup_found) {
690 		/* release ref taken for dup node and delete it */
691 		scm_scan_entry_del(scan_db, dup_node);
692 		scm_scan_entry_put_ref(scan_db, dup_node, false);
693 	}
694 	qdf_spin_unlock_bh(&scan_db->scan_db_lock);
695 
696 	return QDF_STATUS_SUCCESS;
697 }
698 
699 QDF_STATUS scm_handle_bcn_probe(struct scheduler_msg *msg)
700 {
701 	struct scan_bcn_probe_event *bcn;
702 	struct wlan_objmgr_psoc *psoc;
703 	struct wlan_objmgr_pdev *pdev = NULL;
704 	struct scan_cache_entry *scan_entry;
705 	struct wlan_scan_obj *scan_obj;
706 	qdf_list_t *scan_list = NULL;
707 	QDF_STATUS status = QDF_STATUS_SUCCESS;
708 	uint32_t list_count, i;
709 	qdf_list_node_t *next_node = NULL;
710 	struct scan_cache_node *scan_node;
711 
712 	bcn = msg->bodyptr;
713 	if (!bcn) {
714 		scm_err("bcn is NULL");
715 		return QDF_STATUS_E_INVAL;
716 	}
717 	if (!bcn->rx_data) {
718 		scm_err("rx_data iS NULL");
719 		status = QDF_STATUS_E_INVAL;
720 		goto free_nbuf;
721 	}
722 	if (!bcn->buf) {
723 		scm_err("buf is NULL");
724 		status = QDF_STATUS_E_INVAL;
725 		goto free_nbuf;
726 	}
727 
728 	psoc = bcn->psoc;
729 	pdev = wlan_objmgr_get_pdev_by_id(psoc,
730 			   bcn->rx_data->pdev_id, WLAN_SCAN_ID);
731 	if (!pdev) {
732 		scm_err("pdev is NULL");
733 		status = QDF_STATUS_E_INVAL;
734 		goto free_nbuf;
735 	}
736 	scan_obj = wlan_psoc_get_scan_obj(psoc);
737 	if (!scan_obj) {
738 		scm_err("scan_obj is NULL");
739 		status = QDF_STATUS_E_INVAL;
740 		goto free_nbuf;
741 	}
742 
743 	if (qdf_nbuf_len(bcn->buf) <=
744 	   (sizeof(struct wlan_frame_hdr) +
745 	   offsetof(struct wlan_bcn_frame, ie))) {
746 		scm_debug("invalid beacon/probe length");
747 		status = QDF_STATUS_E_INVAL;
748 		goto free_nbuf;
749 	}
750 
751 	if (bcn->frm_type == MGMT_SUBTYPE_BEACON &&
752 	    utils_is_dfs_ch(pdev, bcn->rx_data->channel)) {
753 		util_scan_add_hidden_ssid(pdev, bcn->buf);
754 	}
755 
756 	scan_list =
757 		 util_scan_unpack_beacon_frame(pdev, qdf_nbuf_data(bcn->buf),
758 			qdf_nbuf_len(bcn->buf), bcn->frm_type,
759 			bcn->rx_data);
760 	if (!scan_list || qdf_list_empty(scan_list)) {
761 		scm_debug("failed to unpack frame");
762 		status = QDF_STATUS_E_INVAL;
763 		goto free_nbuf;
764 	}
765 
766 	list_count = qdf_list_size(scan_list);
767 	for (i = 0; i < list_count; i++) {
768 		status = qdf_list_remove_front(scan_list, &next_node);
769 		if (QDF_IS_STATUS_ERROR(status) || next_node == NULL) {
770 			scm_debug("failed to unpack frame");
771 			status = QDF_STATUS_E_INVAL;
772 			goto free_nbuf;
773 		}
774 
775 		scan_node = qdf_container_of(next_node,
776 			struct scan_cache_node, node);
777 
778 		scan_entry = scan_node->entry;
779 
780 		scm_debug("Received %s from BSSID: %pM tsf_delta = %u Seq Num: %x  ssid:%.*s, rssi: %d",
781 			  (bcn->frm_type == MGMT_SUBTYPE_PROBE_RESP) ?
782 			  "Probe Rsp" : "Beacon", scan_entry->bssid.bytes,
783 			  scan_entry->tsf_delta, scan_entry->seq_num,
784 			  scan_entry->ssid.length, scan_entry->ssid.ssid,
785 			  scan_entry->rssi_raw);
786 
787 		if (scan_obj->drop_bcn_on_chan_mismatch &&
788 			scan_entry->channel_mismatch) {
789 			scm_debug("Drop frame, as channel mismatch Received for from BSSID: %pM ",
790 				   scan_entry->bssid.bytes);
791 			util_scan_free_cache_entry(scan_entry);
792 			qdf_mem_free(scan_node);
793 			continue;
794 		}
795 
796 		if (scan_obj->cb.update_beacon)
797 			scan_obj->cb.update_beacon(pdev, scan_entry);
798 
799 		if (wlan_reg_11d_enabled_on_host(psoc))
800 			scm_11d_handle_country_info(psoc, pdev, scan_entry);
801 
802 		status = scm_add_update_entry(psoc, pdev, scan_entry);
803 		if (QDF_IS_STATUS_ERROR(status)) {
804 			scm_debug("failed to add entry for BSSID: %pM",
805 				  scan_entry->bssid.bytes);
806 			util_scan_free_cache_entry(scan_entry);
807 			qdf_mem_free(scan_node);
808 			continue;
809 		}
810 
811 		qdf_mem_free(scan_node);
812 	}
813 
814 free_nbuf:
815 	if (scan_list)
816 		qdf_mem_free(scan_list);
817 	if (bcn->psoc)
818 		wlan_objmgr_psoc_release_ref(bcn->psoc, WLAN_SCAN_ID);
819 	if (pdev)
820 		wlan_objmgr_pdev_release_ref(pdev, WLAN_SCAN_ID);
821 	if (bcn->rx_data)
822 		qdf_mem_free(bcn->rx_data);
823 	if (bcn->buf)
824 		qdf_nbuf_free(bcn->buf);
825 	qdf_mem_free(bcn);
826 
827 	return status;
828 }
829 
830 /**
831  * scm_list_insert_sorted() - add the entries in scan_list in sorted way
832  * @psoc: psoc ptr
833  * @filter: scan filter
834  * @scan_node: node entry to be inserted
835  * @scan_list: Temp scan list
836  *
837  * Add the entries in scan_list in sorted way considering
838  * cap_val and prefer val. The node is copy of original scan entry and
839  * thus no lock is required.
840  *
841  * Return: void
842  */
843 static void scm_list_insert_sorted(struct wlan_objmgr_psoc *psoc,
844 	struct scan_filter *filter,
845 	struct scan_cache_node *scan_node,
846 	qdf_list_t *scan_list)
847 {
848 	struct scan_cache_node *cur_node;
849 	qdf_list_node_t *cur_lst = NULL, *next_lst = NULL;
850 	struct scan_default_params *params;
851 	int pcl_chan_weight = 0;
852 
853 	params = wlan_scan_psoc_get_def_params(psoc);
854 	if (!params) {
855 		scm_err("wlan_scan_psoc_get_def_params failed");
856 		return;
857 	}
858 
859 	if (filter->num_of_pcl_channels > 0 &&
860 			(scan_node->entry->rssi_raw > SCM_PCL_RSSI_THRESHOLD)) {
861 		if (scm_get_pcl_weight_of_channel(
862 					scan_node->entry->channel.chan_idx,
863 					filter, &pcl_chan_weight,
864 					filter->pcl_weight_list)) {
865 			scm_debug("pcl channel %d pcl_chan_weight %d",
866 					scan_node->entry->channel.chan_idx,
867 					pcl_chan_weight);
868 		}
869 	}
870 	if (params->is_bssid_hint_priority &&
871 	    !qdf_mem_cmp(filter->bssid_hint.bytes,
872 			 scan_node->entry->bssid.bytes,
873 			 QDF_MAC_ADDR_SIZE))
874 		scan_node->entry->bss_score = BEST_CANDIDATE_MAX_BSS_SCORE;
875 	else
876 		scm_calculate_bss_score(psoc, params,
877 					scan_node->entry, pcl_chan_weight);
878 
879 	if (qdf_list_empty(scan_list)) {
880 		qdf_list_insert_front(scan_list, &scan_node->node);
881 		return;
882 	}
883 
884 	qdf_list_peek_front(scan_list, &cur_lst);
885 
886 	while (cur_lst) {
887 		cur_node = qdf_container_of(cur_lst,
888 				struct scan_cache_node, node);
889 		if (scm_is_better_bss(params,
890 		   scan_node->entry, cur_node->entry)) {
891 			qdf_list_insert_before(scan_list,
892 				&scan_node->node,
893 				&cur_node->node);
894 			break;
895 		}
896 		qdf_list_peek_next(scan_list,
897 			cur_lst, &next_lst);
898 		cur_lst = next_lst;
899 		next_lst = NULL;
900 	}
901 
902 	if (!cur_lst)
903 		qdf_list_insert_back(scan_list,
904 			&scan_node->node);
905 
906 }
907 
908 /**
909  * scm_scan_apply_filter_get_entry() - apply filter and get the
910  * scan entry
911  * @psoc: psoc pointer
912  * @db_entry: scan entry
913  * @filter: filter to be applied
914  * @scan_list: scan list to which entry is added
915  *
916  * Return: QDF_STATUS
917  */
918 static QDF_STATUS
919 scm_scan_apply_filter_get_entry(struct wlan_objmgr_psoc *psoc,
920 	struct scan_cache_entry *db_entry,
921 	struct scan_filter *filter,
922 	qdf_list_t *scan_list)
923 {
924 	struct scan_cache_node *scan_node = NULL;
925 	struct security_info security = {0};
926 	bool match;
927 
928 	if (!filter)
929 		match = true;
930 	else
931 		match = scm_filter_match(psoc, db_entry,
932 					filter, &security);
933 
934 	if (!match)
935 		return QDF_STATUS_SUCCESS;
936 
937 	scan_node = qdf_mem_malloc_atomic(sizeof(*scan_node));
938 	if (!scan_node)
939 		return QDF_STATUS_E_NOMEM;
940 
941 	scan_node->entry =
942 		util_scan_copy_cache_entry(db_entry);
943 
944 	if (!scan_node->entry) {
945 		qdf_mem_free(scan_node);
946 		return QDF_STATUS_E_NOMEM;
947 	}
948 
949 	qdf_mem_copy(&scan_node->entry->neg_sec_info,
950 		&security, sizeof(scan_node->entry->neg_sec_info));
951 
952 	if (!filter || !filter->bss_scoring_required)
953 		qdf_list_insert_front(scan_list,
954 			&scan_node->node);
955 	else
956 		scm_list_insert_sorted(psoc, filter, scan_node, scan_list);
957 
958 	return QDF_STATUS_SUCCESS;
959 }
960 
961 /**
962  * scm_get_results() - Iterate and get scan results
963  * @psoc: psoc ptr
964  * @scan_db: scan db
965  * @filter: filter to be applied
966  * @scan_list: scan list to which entry is added
967  *
968  * Return: void
969  */
970 static void scm_get_results(struct wlan_objmgr_psoc *psoc,
971 	struct scan_dbs *scan_db, struct scan_filter *filter,
972 	qdf_list_t *scan_list)
973 {
974 	int i, count;
975 	struct scan_cache_node *cur_node;
976 	struct scan_cache_node *next_node = NULL;
977 
978 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
979 		cur_node = scm_get_next_node(scan_db,
980 			   &scan_db->scan_hash_tbl[i], NULL);
981 		count = qdf_list_size(&scan_db->scan_hash_tbl[i]);
982 		if (!count)
983 			continue;
984 		while (cur_node) {
985 			scm_scan_apply_filter_get_entry(psoc,
986 				cur_node->entry, filter, scan_list);
987 			next_node = scm_get_next_node(scan_db,
988 				&scan_db->scan_hash_tbl[i], cur_node);
989 			cur_node = next_node;
990 		}
991 	}
992 }
993 
994 QDF_STATUS scm_purge_scan_results(qdf_list_t *scan_list)
995 {
996 	QDF_STATUS status;
997 	struct scan_cache_node *cur_node;
998 	qdf_list_node_t *cur_lst = NULL, *next_lst = NULL;
999 
1000 	if (!scan_list) {
1001 		scm_err("scan_result is NULL");
1002 		return QDF_STATUS_E_INVAL;
1003 	}
1004 
1005 	status = qdf_list_peek_front(scan_list, &cur_lst);
1006 
1007 	while (cur_lst) {
1008 		qdf_list_peek_next(
1009 			scan_list, cur_lst, &next_lst);
1010 		cur_node = qdf_container_of(cur_lst,
1011 			struct scan_cache_node, node);
1012 		status = qdf_list_remove_node(scan_list,
1013 					cur_lst);
1014 		if (QDF_IS_STATUS_SUCCESS(status)) {
1015 			util_scan_free_cache_entry(cur_node->entry);
1016 			qdf_mem_free(cur_node);
1017 		}
1018 		cur_lst = next_lst;
1019 		next_lst = NULL;
1020 	}
1021 
1022 	qdf_list_destroy(scan_list);
1023 	qdf_mem_free(scan_list);
1024 
1025 	return status;
1026 }
1027 
1028 qdf_list_t *scm_get_scan_result(struct wlan_objmgr_pdev *pdev,
1029 	struct scan_filter *filter)
1030 {
1031 	struct wlan_objmgr_psoc *psoc;
1032 	struct scan_dbs *scan_db;
1033 	qdf_list_t *tmp_list;
1034 
1035 	if (!pdev) {
1036 		scm_err("pdev is NULL");
1037 		return NULL;
1038 	}
1039 
1040 	psoc = wlan_pdev_get_psoc(pdev);
1041 	if (!psoc) {
1042 		scm_err("psoc is NULL");
1043 		return NULL;
1044 	}
1045 
1046 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1047 	if (!scan_db) {
1048 		scm_err("scan_db is NULL");
1049 		return NULL;
1050 	}
1051 
1052 	tmp_list = qdf_mem_malloc_atomic(sizeof(*tmp_list));
1053 	if (!tmp_list) {
1054 		scm_err("failed tp allocate scan_result");
1055 		return NULL;
1056 	}
1057 	qdf_list_create(tmp_list,
1058 			MAX_SCAN_CACHE_SIZE);
1059 	scm_age_out_entries(psoc, scan_db);
1060 	scm_get_results(psoc, scan_db, filter, tmp_list);
1061 
1062 	return tmp_list;
1063 }
1064 
1065 /**
1066  * scm_iterate_db_and_call_func() - iterate and call the func
1067  * @scan_db: scan db
1068  * @func: func to be called
1069  * @arg: func arg
1070  *
1071  * Return: QDF_STATUS
1072  */
1073 static QDF_STATUS
1074 scm_iterate_db_and_call_func(struct scan_dbs *scan_db,
1075 	scan_iterator_func func, void *arg)
1076 {
1077 	int i;
1078 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1079 	struct scan_cache_node *cur_node;
1080 	struct scan_cache_node *next_node = NULL;
1081 
1082 	if (!func)
1083 		return QDF_STATUS_E_INVAL;
1084 
1085 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1086 		cur_node = scm_get_next_node(scan_db,
1087 			&scan_db->scan_hash_tbl[i], NULL);
1088 		while (cur_node) {
1089 			status = func(arg, cur_node->entry);
1090 			if (QDF_IS_STATUS_ERROR(status)) {
1091 				scm_scan_entry_put_ref(scan_db,
1092 					cur_node, true);
1093 				return status;
1094 			}
1095 			next_node = scm_get_next_node(scan_db,
1096 				&scan_db->scan_hash_tbl[i], cur_node);
1097 			cur_node = next_node;
1098 		}
1099 	}
1100 
1101 	return status;
1102 }
1103 
1104 QDF_STATUS
1105 scm_iterate_scan_db(struct wlan_objmgr_pdev *pdev,
1106 	scan_iterator_func func, void *arg)
1107 {
1108 	struct wlan_objmgr_psoc *psoc;
1109 	struct scan_dbs *scan_db;
1110 	QDF_STATUS status;
1111 
1112 	if (!func) {
1113 		scm_err("func is NULL");
1114 		return QDF_STATUS_E_INVAL;
1115 	}
1116 
1117 	if (!pdev) {
1118 		scm_err("pdev is NULL");
1119 		return QDF_STATUS_E_INVAL;
1120 	}
1121 
1122 	psoc = wlan_pdev_get_psoc(pdev);
1123 	if (!psoc) {
1124 		scm_err("psoc is NULL");
1125 		return QDF_STATUS_E_INVAL;
1126 	}
1127 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1128 	if (!scan_db) {
1129 		scm_err("scan_db is NULL");
1130 		return QDF_STATUS_E_INVAL;
1131 	}
1132 
1133 	scm_age_out_entries(psoc, scan_db);
1134 	status = scm_iterate_db_and_call_func(scan_db, func, arg);
1135 
1136 	return status;
1137 }
1138 
1139 /**
1140  * scm_scan_apply_filter_flush_entry() -flush scan entries depending
1141  * on filter
1142  * @psoc: psoc ptr
1143  * @scan_db: scan db
1144  * @db_node: node on which filters are applied
1145  * @filter: filter to be applied
1146  *
1147  * Return: QDF_STATUS
1148  */
1149 static QDF_STATUS
1150 scm_scan_apply_filter_flush_entry(struct wlan_objmgr_psoc *psoc,
1151 	struct scan_dbs *scan_db,
1152 	struct scan_cache_node *db_node,
1153 	struct scan_filter *filter)
1154 {
1155 	struct security_info security = {0};
1156 	bool match;
1157 
1158 	if (!filter)
1159 		match = true;
1160 	else
1161 		match = scm_filter_match(psoc, db_node->entry,
1162 					filter, &security);
1163 
1164 	if (!match)
1165 		return QDF_STATUS_SUCCESS;
1166 
1167 	qdf_spin_lock_bh(&scan_db->scan_db_lock);
1168 	scm_scan_entry_del(scan_db, db_node);
1169 	qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1170 
1171 	return QDF_STATUS_SUCCESS;
1172 }
1173 
1174 /**
1175  * scm_flush_scan_entries() - API to flush scan entries depending on filters
1176  * @psoc: psoc ptr
1177  * @scan_db: scan db
1178  * @filter: filter
1179  *
1180  * Return: void
1181  */
1182 static void scm_flush_scan_entries(struct wlan_objmgr_psoc *psoc,
1183 	struct scan_dbs *scan_db,
1184 	struct scan_filter *filter)
1185 {
1186 	int i;
1187 	struct scan_cache_node *cur_node;
1188 	struct scan_cache_node *next_node = NULL;
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 			scm_scan_apply_filter_flush_entry(psoc, scan_db,
1195 				cur_node, filter);
1196 			next_node = scm_get_next_node(scan_db,
1197 				&scan_db->scan_hash_tbl[i], cur_node);
1198 			cur_node = next_node;
1199 		}
1200 	}
1201 }
1202 
1203 QDF_STATUS scm_flush_results(struct wlan_objmgr_pdev *pdev,
1204 	struct scan_filter *filter)
1205 {
1206 	struct wlan_objmgr_psoc *psoc;
1207 	struct scan_dbs *scan_db;
1208 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1209 
1210 	if (!pdev) {
1211 		scm_err("pdev is NULL");
1212 		return QDF_STATUS_E_INVAL;
1213 	}
1214 
1215 	psoc = wlan_pdev_get_psoc(pdev);
1216 	if (!psoc) {
1217 		scm_err("psoc is NULL");
1218 		return QDF_STATUS_E_INVAL;
1219 	}
1220 
1221 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1222 	if (!scan_db) {
1223 		scm_err("scan_db is NULL");
1224 		return QDF_STATUS_E_INVAL;
1225 	}
1226 
1227 	scm_flush_scan_entries(psoc, scan_db, filter);
1228 
1229 	return status;
1230 }
1231 
1232 /**
1233  * scm_filter_channels() - Remove entries not belonging to channel list
1234  * @scan_db: scan db
1235  * @db_node: node on which filters are applied
1236  * @chan_list: valid channel list
1237  * @num_chan: number of channels
1238  *
1239  * Return: QDF_STATUS
1240  */
1241 static void scm_filter_channels(struct scan_dbs *scan_db,
1242 	struct scan_cache_node *db_node,
1243 	uint8_t *chan_list, uint32_t num_chan)
1244 {
1245 	int i;
1246 	bool match = false;
1247 
1248 	for (i = 0; i < num_chan; i++) {
1249 		if (chan_list[i] ==
1250 		   util_scan_entry_channel_num(db_node->entry)) {
1251 			match = true;
1252 			break;
1253 		}
1254 	}
1255 
1256 	if (!match) {
1257 		qdf_spin_lock_bh(&scan_db->scan_db_lock);
1258 		scm_scan_entry_del(scan_db, db_node);
1259 		qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1260 	}
1261 }
1262 
1263 void scm_filter_valid_channel(struct wlan_objmgr_pdev *pdev,
1264 	uint8_t *chan_list, uint32_t num_chan)
1265 {
1266 	int i;
1267 	struct wlan_objmgr_psoc *psoc;
1268 	struct scan_dbs *scan_db;
1269 	struct scan_cache_node *cur_node;
1270 	struct scan_cache_node *next_node = NULL;
1271 
1272 	scm_debug("num_chan = %d", num_chan);
1273 
1274 	if (!pdev) {
1275 		scm_err("pdev is NULL");
1276 		return;
1277 	}
1278 
1279 	psoc = wlan_pdev_get_psoc(pdev);
1280 	if (!psoc) {
1281 		scm_err("psoc is NULL");
1282 		return;
1283 	}
1284 
1285 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1286 	if (!scan_db) {
1287 		scm_err("scan_db is NULL");
1288 		return;
1289 	}
1290 
1291 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1292 		cur_node = scm_get_next_node(scan_db,
1293 			   &scan_db->scan_hash_tbl[i], NULL);
1294 		while (cur_node) {
1295 			scm_filter_channels(scan_db,
1296 				cur_node, chan_list, num_chan);
1297 			next_node = scm_get_next_node(scan_db,
1298 				&scan_db->scan_hash_tbl[i], cur_node);
1299 			cur_node = next_node;
1300 		}
1301 	}
1302 }
1303 
1304 QDF_STATUS scm_scan_register_bcn_cb(struct wlan_objmgr_psoc *psoc,
1305 	update_beacon_cb cb, enum scan_cb_type type)
1306 {
1307 	struct wlan_scan_obj *scan_obj;
1308 
1309 	scan_obj = wlan_psoc_get_scan_obj(psoc);
1310 	if (!scan_obj) {
1311 		scm_err("scan obj is NULL");
1312 		return QDF_STATUS_E_INVAL;
1313 	}
1314 	switch (type) {
1315 	case SCAN_CB_TYPE_INFORM_BCN:
1316 		scan_obj->cb.inform_beacon = cb;
1317 		break;
1318 	case SCAN_CB_TYPE_UPDATE_BCN:
1319 		scan_obj->cb.update_beacon = cb;
1320 		break;
1321 	default:
1322 		scm_err("invalid cb type %d", type);
1323 	}
1324 
1325 	return QDF_STATUS_SUCCESS;
1326 }
1327 
1328 QDF_STATUS scm_db_init(struct wlan_objmgr_psoc *psoc)
1329 {
1330 	int i, j;
1331 	struct scan_dbs *scan_db;
1332 
1333 	if (!psoc) {
1334 		scm_err("psoc is NULL");
1335 		return QDF_STATUS_E_INVAL;
1336 	}
1337 
1338 	/* Initialize the scan database per pdev */
1339 	for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) {
1340 		scan_db = wlan_pdevid_get_scan_db(psoc, i);
1341 		if (!scan_db) {
1342 			scm_err("scan_db is NULL %d", i);
1343 			continue;
1344 		}
1345 		scan_db->num_entries = 0;
1346 		qdf_spinlock_create(&scan_db->scan_db_lock);
1347 		for (j = 0; j < SCAN_HASH_SIZE; j++)
1348 			qdf_list_create(&scan_db->scan_hash_tbl[j],
1349 				MAX_SCAN_CACHE_SIZE);
1350 	}
1351 
1352 	return QDF_STATUS_SUCCESS;
1353 }
1354 
1355 QDF_STATUS scm_db_deinit(struct wlan_objmgr_psoc *psoc)
1356 {
1357 	int i, j;
1358 	struct scan_dbs *scan_db;
1359 
1360 	if (!psoc) {
1361 		scm_err("scan obj is NULL");
1362 		return QDF_STATUS_E_INVAL;
1363 	}
1364 
1365 	/* Initialize the scan database per pdev */
1366 	for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) {
1367 		scan_db = wlan_pdevid_get_scan_db(psoc, i);
1368 		if (!scan_db) {
1369 			scm_err("scan_db is NULL %d", i);
1370 			continue;
1371 		}
1372 
1373 		scm_flush_scan_entries(psoc, scan_db, NULL);
1374 		for (j = 0; j < SCAN_HASH_SIZE; j++)
1375 			qdf_list_destroy(&scan_db->scan_hash_tbl[j]);
1376 		qdf_spinlock_destroy(&scan_db->scan_db_lock);
1377 	}
1378 
1379 	return QDF_STATUS_SUCCESS;
1380 }
1381 
1382 QDF_STATUS scm_update_scan_mlme_info(struct wlan_objmgr_pdev *pdev,
1383 	struct scan_cache_entry *entry)
1384 {
1385 	uint8_t hash_idx;
1386 	struct scan_dbs *scan_db;
1387 	struct scan_cache_node *cur_node;
1388 	struct scan_cache_node *next_node = NULL;
1389 	struct wlan_objmgr_psoc *psoc;
1390 
1391 	psoc = wlan_pdev_get_psoc(pdev);
1392 	if (!psoc) {
1393 		scm_err("psoc is NULL");
1394 		return QDF_STATUS_E_INVAL;
1395 	}
1396 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1397 	if (!scan_db) {
1398 		scm_err("scan_db is NULL");
1399 		return QDF_STATUS_E_INVAL;
1400 	}
1401 
1402 	hash_idx = SCAN_GET_HASH(entry->bssid.bytes);
1403 
1404 	cur_node = scm_get_next_node(scan_db,
1405 			&scan_db->scan_hash_tbl[hash_idx], NULL);
1406 
1407 	while (cur_node) {
1408 		if (util_is_scan_entry_match(entry,
1409 					cur_node->entry)) {
1410 			/* Acquire db lock to prevent simultaneous update */
1411 			qdf_spin_lock_bh(&scan_db->scan_db_lock);
1412 			scm_update_mlme_info(entry, cur_node->entry);
1413 			qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1414 			scm_scan_entry_put_ref(scan_db,
1415 					cur_node, true);
1416 			return QDF_STATUS_SUCCESS;
1417 		}
1418 		next_node = scm_get_next_node(scan_db,
1419 				&scan_db->scan_hash_tbl[hash_idx], cur_node);
1420 		cur_node = next_node;
1421 	}
1422 
1423 	return QDF_STATUS_E_INVAL;
1424 }
1425 
1426 QDF_STATUS scm_scan_update_mlme_by_bssinfo(struct wlan_objmgr_pdev *pdev,
1427 		struct bss_info *bss_info, struct mlme_info *mlme)
1428 {
1429 	uint8_t hash_idx;
1430 	struct scan_dbs *scan_db;
1431 	struct scan_cache_node *cur_node;
1432 	struct scan_cache_node *next_node = NULL;
1433 	struct wlan_objmgr_psoc *psoc;
1434 	struct scan_cache_entry *entry;
1435 
1436 	psoc = wlan_pdev_get_psoc(pdev);
1437 	if (!psoc) {
1438 		scm_err("psoc is NULL");
1439 		return QDF_STATUS_E_INVAL;
1440 	}
1441 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1442 	if (!scan_db) {
1443 		scm_err("scan_db is NULL");
1444 		return QDF_STATUS_E_INVAL;
1445 	}
1446 
1447 	hash_idx = SCAN_GET_HASH(bss_info->bssid.bytes);
1448 	cur_node = scm_get_next_node(scan_db,
1449 			&scan_db->scan_hash_tbl[hash_idx], NULL);
1450 	while (cur_node) {
1451 		entry = cur_node->entry;
1452 		if (qdf_is_macaddr_equal(&bss_info->bssid, &entry->bssid) &&
1453 			(util_is_ssid_match(&bss_info->ssid, &entry->ssid)) &&
1454 			(bss_info->chan == entry->channel.chan_idx)) {
1455 			/* Acquire db lock to prevent simultaneous update */
1456 			qdf_spin_lock_bh(&scan_db->scan_db_lock);
1457 			qdf_mem_copy(&entry->mlme_info, mlme,
1458 					sizeof(struct mlme_info));
1459 			scm_scan_entry_put_ref(scan_db,
1460 					cur_node, false);
1461 			qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1462 			return QDF_STATUS_SUCCESS;
1463 		}
1464 		next_node = scm_get_next_node(scan_db,
1465 				&scan_db->scan_hash_tbl[hash_idx], cur_node);
1466 		cur_node = next_node;
1467 	}
1468 
1469 	return QDF_STATUS_E_INVAL;
1470 }
1471