xref: /wlan-dirver/qca-wifi-host-cmn/umac/scan/core/src/wlan_scan_cache_db.c (revision 1397a33f48ea6455be40871470b286e535820eb8)
1 /*
2  * Copyright (c) 2017-2019 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 (util_scan_is_null_ssid(&scan_params->ssid) &&
495 	    scan_entry->ssid.length) {
496 		/*
497 		 * New entry has a hidden SSID and old one has the SSID.
498 		 * Add the entry by using the ssid of the old entry
499 		 * only if diff of saved SSID time and current time is
500 		 * less than HIDDEN_SSID_TIME time.
501 		 * This will avoid issues in case AP changes its SSID
502 		 * while remain hidden.
503 		 */
504 		time_gap =
505 			qdf_mc_timer_get_system_time() -
506 			scan_entry->hidden_ssid_timestamp;
507 		if (time_gap <= HIDDEN_SSID_TIME) {
508 			scan_params->hidden_ssid_timestamp =
509 				scan_entry->hidden_ssid_timestamp;
510 			scan_params->ssid.length =
511 				scan_entry->ssid.length;
512 			qdf_mem_copy(scan_params->ssid.ssid,
513 				scan_entry->ssid.ssid,
514 				scan_entry->ssid.length);
515 		}
516 	}
517 
518 	/*
519 	 * Due to Rx sensitivity issue, sometime beacons are seen on adjacent
520 	 * channel so workaround in software is needed. If DS params or HT info
521 	 * are present driver can get proper channel info from these IEs and set
522 	 * channel_mismatch so that the older RSSI values are used in new entry.
523 	 *
524 	 * For the cases where DS params and HT info is not present, driver
525 	 * needs to check below conditions to get proper channel and set
526 	 * channel_mismatch so that the older RSSI values are used in new entry:
527 	 *   -- The old entry channel and new entry channel are not same
528 	 *   -- RSSI is less than -80, this indicate that the signal has leaked
529 	 *       in adjacent channel.
530 	 */
531 	if ((scan_params->frm_subtype == MGMT_SUBTYPE_BEACON) &&
532 	    !util_scan_entry_htinfo(scan_params) &&
533 	    !util_scan_entry_ds_param(scan_params) &&
534 	    (scan_params->channel.chan_idx != scan_entry->channel.chan_idx) &&
535 	    (scan_params->rssi_raw  < ADJACENT_CHANNEL_RSSI_THRESHOLD)) {
536 		scan_params->channel.chan_idx = scan_entry->channel.chan_idx;
537 		scan_params->channel_mismatch = true;
538 	}
539 
540 	/* Use old value for rssi if beacon was heard on adjacent channel. */
541 	if (scan_params->channel_mismatch) {
542 		scan_params->rssi_raw = scan_entry->rssi_raw;
543 		scan_params->avg_rssi = scan_entry->avg_rssi;
544 		scan_params->rssi_timestamp =
545 			scan_entry->rssi_timestamp;
546 	} else {
547 		/* If elapsed time since last rssi update for this
548 		 * entry is smaller than a thresold, calculate a
549 		 * running average of the RSSI values.
550 		 * Otherwise new frames RSSI is more representive
551 		 * of the signal strength.
552 		 */
553 		time_gap =
554 			scan_params->scan_entry_time -
555 			scan_entry->rssi_timestamp;
556 		if (time_gap > WLAN_RSSI_AVERAGING_TIME)
557 			scan_params->avg_rssi =
558 				WLAN_RSSI_IN(scan_params->rssi_raw);
559 		else {
560 			/* Copy previous average rssi to new entry */
561 			scan_params->avg_rssi = scan_entry->avg_rssi;
562 			/* Average with previous samples */
563 			WLAN_RSSI_LPF(scan_params->avg_rssi,
564 					scan_params->rssi_raw);
565 		}
566 
567 		scan_params->rssi_timestamp = scan_params->scan_entry_time;
568 	}
569 
570 	/* copy wsn ie from scan_entry to scan_params*/
571 	scm_update_alt_wcn_ie(scan_entry, scan_params);
572 
573 	/* copy mlme info from scan_entry to scan_params*/
574 	scm_update_mlme_info(scan_entry, scan_params);
575 }
576 
577 /**
578  * scm_find_duplicate() - find duplicate entry,
579  * if present, add input scan entry before it and delete
580  * duplicate entry. otherwise add entry to tail
581  * @scan_db: scan db
582  * @entry: input scan cache entry
583  * @dup_node: node before which new entry to be added
584  *
585  * ref_cnt is taken for dup_node, caller should release ref taken
586  * if returns true.
587  *
588  * Return: bool
589  */
590 static bool
591 scm_find_duplicate(struct scan_dbs *scan_db,
592 		   struct scan_cache_entry *entry,
593 		   struct scan_cache_node **dup_node)
594 {
595 	uint8_t hash_idx;
596 	struct scan_cache_node *cur_node;
597 	struct scan_cache_node *next_node = NULL;
598 
599 	hash_idx = SCAN_GET_HASH(entry->bssid.bytes);
600 
601 	cur_node = scm_get_next_node(scan_db,
602 				     &scan_db->scan_hash_tbl[hash_idx],
603 				     NULL);
604 
605 	while (cur_node) {
606 		if (util_is_scan_entry_match(entry,
607 		   cur_node->entry)) {
608 			scm_copy_info_from_dup_entry(scan_db, entry, cur_node);
609 			*dup_node = cur_node;
610 			return true;
611 		}
612 		next_node = scm_get_next_node(scan_db,
613 			 &scan_db->scan_hash_tbl[hash_idx], cur_node);
614 		cur_node = next_node;
615 		next_node = NULL;
616 	}
617 
618 	return false;
619 }
620 
621 /**
622  * scm_add_update_entry() - add or update scan entry
623  * @psoc: psoc ptr
624  * @pdev: pdev pointer
625  * @scan_params: new received entry
626  *
627  * Return: QDF_STATUS
628  */
629 static QDF_STATUS scm_add_update_entry(struct wlan_objmgr_psoc *psoc,
630 	struct wlan_objmgr_pdev *pdev, struct scan_cache_entry *scan_params)
631 {
632 	struct scan_cache_node *dup_node = NULL;
633 	struct scan_cache_node *scan_node = NULL;
634 	bool is_dup_found = false;
635 	QDF_STATUS status;
636 	struct scan_dbs *scan_db;
637 	struct wlan_scan_obj *scan_obj;
638 
639 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
640 	if (!scan_db) {
641 		scm_err("scan_db is NULL");
642 		return QDF_STATUS_E_INVAL;
643 	}
644 
645 	scan_obj = wlan_psoc_get_scan_obj(psoc);
646 	if (!scan_obj) {
647 		scm_err("scan_obj is NULL");
648 		return QDF_STATUS_E_INVAL;
649 	}
650 
651 	if (scan_params->frm_subtype ==
652 	   MGMT_SUBTYPE_PROBE_RESP &&
653 	   !scan_params->ie_list.ssid)
654 		scm_debug("Probe resp doesn't contain SSID");
655 
656 
657 	if (scan_params->ie_list.csa ||
658 	   scan_params->ie_list.xcsa ||
659 	   scan_params->ie_list.cswrp)
660 		scm_debug("CSA IE present for BSSID: %pM",
661 			  scan_params->bssid.bytes);
662 
663 	is_dup_found = scm_find_duplicate(scan_db, scan_params, &dup_node);
664 
665 	if (scan_obj->cb.inform_beacon)
666 		scan_obj->cb.inform_beacon(pdev, scan_params);
667 
668 	if (scan_db->num_entries >= MAX_SCAN_CACHE_SIZE) {
669 		status = scm_flush_oldest_entry(scan_db);
670 		if (QDF_IS_STATUS_ERROR(status)) {
671 			/* release ref taken for dup node */
672 			if (is_dup_found)
673 				scm_scan_entry_put_ref(scan_db, dup_node, true);
674 			return status;
675 		}
676 	}
677 
678 	scan_node = qdf_mem_malloc(sizeof(*scan_node));
679 	if (!scan_node) {
680 		/* release ref taken for dup node */
681 		if (is_dup_found)
682 			scm_scan_entry_put_ref(scan_db, dup_node, true);
683 		return QDF_STATUS_E_NOMEM;
684 	}
685 
686 	scan_node->entry = scan_params;
687 	qdf_spin_lock_bh(&scan_db->scan_db_lock);
688 	scm_add_scan_node(scan_db, scan_node, dup_node);
689 
690 	if (is_dup_found) {
691 		/* release ref taken for dup node and delete it */
692 		scm_scan_entry_del(scan_db, dup_node);
693 		scm_scan_entry_put_ref(scan_db, dup_node, false);
694 	}
695 	qdf_spin_unlock_bh(&scan_db->scan_db_lock);
696 
697 	return QDF_STATUS_SUCCESS;
698 }
699 
700 QDF_STATUS scm_handle_bcn_probe(struct scheduler_msg *msg)
701 {
702 	struct scan_bcn_probe_event *bcn;
703 	struct wlan_objmgr_psoc *psoc;
704 	struct wlan_objmgr_pdev *pdev = NULL;
705 	struct scan_cache_entry *scan_entry;
706 	struct wlan_scan_obj *scan_obj;
707 	qdf_list_t *scan_list = NULL;
708 	QDF_STATUS status = QDF_STATUS_SUCCESS;
709 	uint32_t list_count, i;
710 	qdf_list_node_t *next_node = NULL;
711 	struct scan_cache_node *scan_node;
712 	struct wlan_frame_hdr *hdr = NULL;
713 
714 	bcn = msg->bodyptr;
715 	if (!bcn) {
716 		scm_err("bcn is NULL");
717 		return QDF_STATUS_E_INVAL;
718 	}
719 	if (!bcn->rx_data) {
720 		scm_err("rx_data iS NULL");
721 		status = QDF_STATUS_E_INVAL;
722 		goto free_nbuf;
723 	}
724 	if (!bcn->buf) {
725 		scm_err("buf is NULL");
726 		status = QDF_STATUS_E_INVAL;
727 		goto free_nbuf;
728 	}
729 
730 	hdr = (struct wlan_frame_hdr *)qdf_nbuf_data(bcn->buf);
731 	psoc = bcn->psoc;
732 	pdev = wlan_objmgr_get_pdev_by_id(psoc,
733 			   bcn->rx_data->pdev_id, WLAN_SCAN_ID);
734 	if (!pdev) {
735 		scm_err("pdev is NULL");
736 		status = QDF_STATUS_E_INVAL;
737 		goto free_nbuf;
738 	}
739 	scan_obj = wlan_psoc_get_scan_obj(psoc);
740 	if (!scan_obj) {
741 		scm_err("scan_obj is NULL");
742 		status = QDF_STATUS_E_INVAL;
743 		goto free_nbuf;
744 	}
745 
746 	if (qdf_nbuf_len(bcn->buf) <=
747 	   (sizeof(struct wlan_frame_hdr) +
748 	   offsetof(struct wlan_bcn_frame, ie))) {
749 		scm_debug("invalid beacon/probe length");
750 		status = QDF_STATUS_E_INVAL;
751 		goto free_nbuf;
752 	}
753 
754 	if (bcn->frm_type == MGMT_SUBTYPE_BEACON &&
755 	    utils_is_dfs_ch(pdev, bcn->rx_data->channel)) {
756 		util_scan_add_hidden_ssid(pdev, bcn->buf);
757 	}
758 
759 	scan_list =
760 		 util_scan_unpack_beacon_frame(pdev, qdf_nbuf_data(bcn->buf),
761 			qdf_nbuf_len(bcn->buf), bcn->frm_type,
762 			bcn->rx_data);
763 	if (!scan_list || qdf_list_empty(scan_list)) {
764 		scm_debug("failed to unpack %d frame BSSID: %pM",
765 			  bcn->frm_type, hdr->i_addr3);
766 		status = QDF_STATUS_E_INVAL;
767 		goto free_nbuf;
768 	}
769 
770 	list_count = qdf_list_size(scan_list);
771 	for (i = 0; i < list_count; i++) {
772 		status = qdf_list_remove_front(scan_list, &next_node);
773 		if (QDF_IS_STATUS_ERROR(status) || next_node == NULL) {
774 			scm_debug("list remove failure i:%d, lsize:%d, BSSID: %pM",
775 				  i, list_count, hdr->i_addr3);
776 			status = QDF_STATUS_E_INVAL;
777 			goto free_nbuf;
778 		}
779 
780 		scan_node = qdf_container_of(next_node,
781 			struct scan_cache_node, node);
782 
783 		scan_entry = scan_node->entry;
784 
785 		if (scan_obj->drop_bcn_on_chan_mismatch &&
786 			scan_entry->channel_mismatch) {
787 			scm_debug("Drop frame, as channel mismatch Received for from BSSID: %pM Seq Num: %d",
788 				   scan_entry->bssid.bytes,
789 				   scan_entry->seq_num);
790 			util_scan_free_cache_entry(scan_entry);
791 			qdf_mem_free(scan_node);
792 			continue;
793 		}
794 
795 		scm_nofl_debug("Received %s from BSSID: %pM tsf_delta = %u Seq Num: %d  ssid:%.*s, rssi: %d channel %d pdev_id = %d",
796 			       (bcn->frm_type == MGMT_SUBTYPE_PROBE_RESP) ?
797 			       "Probe Rsp" : "Beacon", scan_entry->bssid.bytes,
798 			       scan_entry->tsf_delta, scan_entry->seq_num,
799 			       scan_entry->ssid.length, scan_entry->ssid.ssid,
800 			       scan_entry->rssi_raw,
801 			       scan_entry->channel.chan_idx,
802 			       wlan_objmgr_pdev_get_pdev_id(pdev));
803 
804 		if (scan_obj->cb.update_beacon)
805 			scan_obj->cb.update_beacon(pdev, scan_entry);
806 
807 		if (wlan_reg_11d_enabled_on_host(psoc))
808 			scm_11d_handle_country_info(psoc, pdev, scan_entry);
809 
810 		status = scm_add_update_entry(psoc, pdev, scan_entry);
811 		if (QDF_IS_STATUS_ERROR(status)) {
812 			scm_debug("failed to add entry for BSSID: %pM Seq Num: %d",
813 				  scan_entry->bssid.bytes,
814 				  scan_entry->seq_num);
815 			util_scan_free_cache_entry(scan_entry);
816 			qdf_mem_free(scan_node);
817 			continue;
818 		}
819 
820 		qdf_mem_free(scan_node);
821 	}
822 
823 free_nbuf:
824 	if (scan_list)
825 		qdf_mem_free(scan_list);
826 	if (bcn->psoc)
827 		wlan_objmgr_psoc_release_ref(bcn->psoc, WLAN_SCAN_ID);
828 	if (pdev)
829 		wlan_objmgr_pdev_release_ref(pdev, WLAN_SCAN_ID);
830 	if (bcn->rx_data)
831 		qdf_mem_free(bcn->rx_data);
832 	if (bcn->buf)
833 		qdf_nbuf_free(bcn->buf);
834 	qdf_mem_free(bcn);
835 
836 	return status;
837 }
838 
839 /**
840  * scm_list_insert_sorted() - add the entries in scan_list in sorted way
841  * @psoc: psoc ptr
842  * @filter: scan filter
843  * @scan_node: node entry to be inserted
844  * @scan_list: Temp scan list
845  *
846  * Add the entries in scan_list in sorted way considering
847  * cap_val and prefer val. The node is copy of original scan entry and
848  * thus no lock is required.
849  *
850  * Return: void
851  */
852 static void scm_list_insert_sorted(struct wlan_objmgr_psoc *psoc,
853 	struct scan_filter *filter,
854 	struct scan_cache_node *scan_node,
855 	qdf_list_t *scan_list)
856 {
857 	struct scan_cache_node *cur_node;
858 	qdf_list_node_t *cur_lst = NULL, *next_lst = NULL;
859 	struct scan_default_params *params;
860 	int pcl_chan_weight = 0;
861 
862 	params = wlan_scan_psoc_get_def_params(psoc);
863 	if (!params) {
864 		scm_err("wlan_scan_psoc_get_def_params failed");
865 		return;
866 	}
867 
868 	if (filter->num_of_pcl_channels > 0 &&
869 			(scan_node->entry->rssi_raw > SCM_PCL_RSSI_THRESHOLD)) {
870 		if (scm_get_pcl_weight_of_channel(
871 					scan_node->entry->channel.chan_idx,
872 					filter, &pcl_chan_weight,
873 					filter->pcl_weight_list)) {
874 			scm_debug("pcl channel %d pcl_chan_weight %d",
875 					scan_node->entry->channel.chan_idx,
876 					pcl_chan_weight);
877 		}
878 	}
879 	if (params->is_bssid_hint_priority &&
880 	    !qdf_mem_cmp(filter->bssid_hint.bytes,
881 			 scan_node->entry->bssid.bytes,
882 			 QDF_MAC_ADDR_SIZE))
883 		scan_node->entry->bss_score = BEST_CANDIDATE_MAX_BSS_SCORE;
884 	else
885 		scm_calculate_bss_score(psoc, params,
886 					scan_node->entry, pcl_chan_weight);
887 
888 	if (qdf_list_empty(scan_list)) {
889 		qdf_list_insert_front(scan_list, &scan_node->node);
890 		return;
891 	}
892 
893 	qdf_list_peek_front(scan_list, &cur_lst);
894 
895 	while (cur_lst) {
896 		cur_node = qdf_container_of(cur_lst,
897 				struct scan_cache_node, node);
898 		if (scm_is_better_bss(params,
899 		   scan_node->entry, cur_node->entry)) {
900 			qdf_list_insert_before(scan_list,
901 				&scan_node->node,
902 				&cur_node->node);
903 			break;
904 		}
905 		qdf_list_peek_next(scan_list,
906 			cur_lst, &next_lst);
907 		cur_lst = next_lst;
908 		next_lst = NULL;
909 	}
910 
911 	if (!cur_lst)
912 		qdf_list_insert_back(scan_list,
913 			&scan_node->node);
914 
915 }
916 
917 /**
918  * scm_scan_apply_filter_get_entry() - apply filter and get the
919  * scan entry
920  * @psoc: psoc pointer
921  * @db_entry: scan entry
922  * @filter: filter to be applied
923  * @scan_list: scan list to which entry is added
924  *
925  * Return: QDF_STATUS
926  */
927 static QDF_STATUS
928 scm_scan_apply_filter_get_entry(struct wlan_objmgr_psoc *psoc,
929 	struct scan_cache_entry *db_entry,
930 	struct scan_filter *filter,
931 	qdf_list_t *scan_list)
932 {
933 	struct scan_cache_node *scan_node = NULL;
934 	struct security_info security = {0};
935 	bool match;
936 
937 	if (!filter)
938 		match = true;
939 	else
940 		match = scm_filter_match(psoc, db_entry,
941 					filter, &security);
942 
943 	if (!match)
944 		return QDF_STATUS_SUCCESS;
945 
946 	scan_node = qdf_mem_malloc_atomic(sizeof(*scan_node));
947 	if (!scan_node)
948 		return QDF_STATUS_E_NOMEM;
949 
950 	scan_node->entry =
951 		util_scan_copy_cache_entry(db_entry);
952 
953 	if (!scan_node->entry) {
954 		qdf_mem_free(scan_node);
955 		return QDF_STATUS_E_NOMEM;
956 	}
957 
958 	qdf_mem_copy(&scan_node->entry->neg_sec_info,
959 		&security, sizeof(scan_node->entry->neg_sec_info));
960 
961 	if (!filter || !filter->bss_scoring_required)
962 		qdf_list_insert_front(scan_list,
963 			&scan_node->node);
964 	else
965 		scm_list_insert_sorted(psoc, filter, scan_node, scan_list);
966 
967 	return QDF_STATUS_SUCCESS;
968 }
969 
970 /**
971  * scm_get_results() - Iterate and get scan results
972  * @psoc: psoc ptr
973  * @scan_db: scan db
974  * @filter: filter to be applied
975  * @scan_list: scan list to which entry is added
976  *
977  * Return: void
978  */
979 static void scm_get_results(struct wlan_objmgr_psoc *psoc,
980 	struct scan_dbs *scan_db, struct scan_filter *filter,
981 	qdf_list_t *scan_list)
982 {
983 	int i, count;
984 	struct scan_cache_node *cur_node;
985 	struct scan_cache_node *next_node = NULL;
986 
987 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
988 		cur_node = scm_get_next_node(scan_db,
989 			   &scan_db->scan_hash_tbl[i], NULL);
990 		count = qdf_list_size(&scan_db->scan_hash_tbl[i]);
991 		if (!count)
992 			continue;
993 		while (cur_node) {
994 			scm_scan_apply_filter_get_entry(psoc,
995 				cur_node->entry, filter, scan_list);
996 			next_node = scm_get_next_node(scan_db,
997 				&scan_db->scan_hash_tbl[i], cur_node);
998 			cur_node = next_node;
999 		}
1000 	}
1001 }
1002 
1003 QDF_STATUS scm_purge_scan_results(qdf_list_t *scan_list)
1004 {
1005 	QDF_STATUS status;
1006 	struct scan_cache_node *cur_node;
1007 	qdf_list_node_t *cur_lst = NULL, *next_lst = NULL;
1008 
1009 	if (!scan_list) {
1010 		scm_err("scan_result is NULL");
1011 		return QDF_STATUS_E_INVAL;
1012 	}
1013 
1014 	status = qdf_list_peek_front(scan_list, &cur_lst);
1015 
1016 	while (cur_lst) {
1017 		qdf_list_peek_next(
1018 			scan_list, cur_lst, &next_lst);
1019 		cur_node = qdf_container_of(cur_lst,
1020 			struct scan_cache_node, node);
1021 		status = qdf_list_remove_node(scan_list,
1022 					cur_lst);
1023 		if (QDF_IS_STATUS_SUCCESS(status)) {
1024 			util_scan_free_cache_entry(cur_node->entry);
1025 			qdf_mem_free(cur_node);
1026 		}
1027 		cur_lst = next_lst;
1028 		next_lst = NULL;
1029 	}
1030 
1031 	qdf_list_destroy(scan_list);
1032 	qdf_mem_free(scan_list);
1033 
1034 	return status;
1035 }
1036 
1037 qdf_list_t *scm_get_scan_result(struct wlan_objmgr_pdev *pdev,
1038 	struct scan_filter *filter)
1039 {
1040 	struct wlan_objmgr_psoc *psoc;
1041 	struct scan_dbs *scan_db;
1042 	qdf_list_t *tmp_list;
1043 
1044 	if (!pdev) {
1045 		scm_err("pdev is NULL");
1046 		return NULL;
1047 	}
1048 
1049 	psoc = wlan_pdev_get_psoc(pdev);
1050 	if (!psoc) {
1051 		scm_err("psoc is NULL");
1052 		return NULL;
1053 	}
1054 
1055 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1056 	if (!scan_db) {
1057 		scm_err("scan_db is NULL");
1058 		return NULL;
1059 	}
1060 
1061 	tmp_list = qdf_mem_malloc_atomic(sizeof(*tmp_list));
1062 	if (!tmp_list) {
1063 		scm_err("failed tp allocate scan_result");
1064 		return NULL;
1065 	}
1066 	qdf_list_create(tmp_list,
1067 			MAX_SCAN_CACHE_SIZE);
1068 	scm_age_out_entries(psoc, scan_db);
1069 	scm_get_results(psoc, scan_db, filter, tmp_list);
1070 
1071 	return tmp_list;
1072 }
1073 
1074 /**
1075  * scm_iterate_db_and_call_func() - iterate and call the func
1076  * @scan_db: scan db
1077  * @func: func to be called
1078  * @arg: func arg
1079  *
1080  * Return: QDF_STATUS
1081  */
1082 static QDF_STATUS
1083 scm_iterate_db_and_call_func(struct scan_dbs *scan_db,
1084 	scan_iterator_func func, void *arg)
1085 {
1086 	int i;
1087 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1088 	struct scan_cache_node *cur_node;
1089 	struct scan_cache_node *next_node = NULL;
1090 
1091 	if (!func)
1092 		return QDF_STATUS_E_INVAL;
1093 
1094 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1095 		cur_node = scm_get_next_node(scan_db,
1096 			&scan_db->scan_hash_tbl[i], NULL);
1097 		while (cur_node) {
1098 			status = func(arg, cur_node->entry);
1099 			if (QDF_IS_STATUS_ERROR(status)) {
1100 				scm_scan_entry_put_ref(scan_db,
1101 					cur_node, true);
1102 				return status;
1103 			}
1104 			next_node = scm_get_next_node(scan_db,
1105 				&scan_db->scan_hash_tbl[i], cur_node);
1106 			cur_node = next_node;
1107 		}
1108 	}
1109 
1110 	return status;
1111 }
1112 
1113 QDF_STATUS
1114 scm_iterate_scan_db(struct wlan_objmgr_pdev *pdev,
1115 	scan_iterator_func func, void *arg)
1116 {
1117 	struct wlan_objmgr_psoc *psoc;
1118 	struct scan_dbs *scan_db;
1119 	QDF_STATUS status;
1120 
1121 	if (!func) {
1122 		scm_err("func is NULL");
1123 		return QDF_STATUS_E_INVAL;
1124 	}
1125 
1126 	if (!pdev) {
1127 		scm_err("pdev is NULL");
1128 		return QDF_STATUS_E_INVAL;
1129 	}
1130 
1131 	psoc = wlan_pdev_get_psoc(pdev);
1132 	if (!psoc) {
1133 		scm_err("psoc is NULL");
1134 		return QDF_STATUS_E_INVAL;
1135 	}
1136 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1137 	if (!scan_db) {
1138 		scm_err("scan_db is NULL");
1139 		return QDF_STATUS_E_INVAL;
1140 	}
1141 
1142 	scm_age_out_entries(psoc, scan_db);
1143 	status = scm_iterate_db_and_call_func(scan_db, func, arg);
1144 
1145 	return status;
1146 }
1147 
1148 /**
1149  * scm_scan_apply_filter_flush_entry() -flush scan entries depending
1150  * on filter
1151  * @psoc: psoc ptr
1152  * @scan_db: scan db
1153  * @db_node: node on which filters are applied
1154  * @filter: filter to be applied
1155  *
1156  * Return: QDF_STATUS
1157  */
1158 static QDF_STATUS
1159 scm_scan_apply_filter_flush_entry(struct wlan_objmgr_psoc *psoc,
1160 	struct scan_dbs *scan_db,
1161 	struct scan_cache_node *db_node,
1162 	struct scan_filter *filter)
1163 {
1164 	struct security_info security = {0};
1165 	bool match;
1166 
1167 	if (!filter)
1168 		match = true;
1169 	else
1170 		match = scm_filter_match(psoc, db_node->entry,
1171 					filter, &security);
1172 
1173 	if (!match)
1174 		return QDF_STATUS_SUCCESS;
1175 
1176 	qdf_spin_lock_bh(&scan_db->scan_db_lock);
1177 	scm_scan_entry_del(scan_db, db_node);
1178 	qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1179 
1180 	return QDF_STATUS_SUCCESS;
1181 }
1182 
1183 /**
1184  * scm_flush_scan_entries() - API to flush scan entries depending on filters
1185  * @psoc: psoc ptr
1186  * @scan_db: scan db
1187  * @filter: filter
1188  *
1189  * Return: void
1190  */
1191 static void scm_flush_scan_entries(struct wlan_objmgr_psoc *psoc,
1192 	struct scan_dbs *scan_db,
1193 	struct scan_filter *filter)
1194 {
1195 	int i;
1196 	struct scan_cache_node *cur_node;
1197 	struct scan_cache_node *next_node = NULL;
1198 
1199 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1200 		cur_node = scm_get_next_node(scan_db,
1201 			   &scan_db->scan_hash_tbl[i], NULL);
1202 		while (cur_node) {
1203 			scm_scan_apply_filter_flush_entry(psoc, scan_db,
1204 				cur_node, filter);
1205 			next_node = scm_get_next_node(scan_db,
1206 				&scan_db->scan_hash_tbl[i], cur_node);
1207 			cur_node = next_node;
1208 		}
1209 	}
1210 }
1211 
1212 QDF_STATUS scm_flush_results(struct wlan_objmgr_pdev *pdev,
1213 	struct scan_filter *filter)
1214 {
1215 	struct wlan_objmgr_psoc *psoc;
1216 	struct scan_dbs *scan_db;
1217 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1218 
1219 	if (!pdev) {
1220 		scm_err("pdev is NULL");
1221 		return QDF_STATUS_E_INVAL;
1222 	}
1223 
1224 	psoc = wlan_pdev_get_psoc(pdev);
1225 	if (!psoc) {
1226 		scm_err("psoc is NULL");
1227 		return QDF_STATUS_E_INVAL;
1228 	}
1229 
1230 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1231 	if (!scan_db) {
1232 		scm_err("scan_db is NULL");
1233 		return QDF_STATUS_E_INVAL;
1234 	}
1235 
1236 	scm_flush_scan_entries(psoc, scan_db, filter);
1237 
1238 	return status;
1239 }
1240 
1241 /**
1242  * scm_filter_channels() - Remove entries not belonging to channel list
1243  * @scan_db: scan db
1244  * @db_node: node on which filters are applied
1245  * @chan_list: valid channel list
1246  * @num_chan: number of channels
1247  *
1248  * Return: QDF_STATUS
1249  */
1250 static void scm_filter_channels(struct scan_dbs *scan_db,
1251 	struct scan_cache_node *db_node,
1252 	uint8_t *chan_list, uint32_t num_chan)
1253 {
1254 	int i;
1255 	bool match = false;
1256 
1257 	for (i = 0; i < num_chan; i++) {
1258 		if (chan_list[i] ==
1259 		   util_scan_entry_channel_num(db_node->entry)) {
1260 			match = true;
1261 			break;
1262 		}
1263 	}
1264 
1265 	if (!match) {
1266 		qdf_spin_lock_bh(&scan_db->scan_db_lock);
1267 		scm_scan_entry_del(scan_db, db_node);
1268 		qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1269 	}
1270 }
1271 
1272 void scm_filter_valid_channel(struct wlan_objmgr_pdev *pdev,
1273 	uint8_t *chan_list, uint32_t num_chan)
1274 {
1275 	int i;
1276 	struct wlan_objmgr_psoc *psoc;
1277 	struct scan_dbs *scan_db;
1278 	struct scan_cache_node *cur_node;
1279 	struct scan_cache_node *next_node = NULL;
1280 
1281 	scm_debug("num_chan = %d", num_chan);
1282 
1283 	if (!pdev) {
1284 		scm_err("pdev is NULL");
1285 		return;
1286 	}
1287 
1288 	psoc = wlan_pdev_get_psoc(pdev);
1289 	if (!psoc) {
1290 		scm_err("psoc is NULL");
1291 		return;
1292 	}
1293 
1294 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1295 	if (!scan_db) {
1296 		scm_err("scan_db is NULL");
1297 		return;
1298 	}
1299 
1300 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1301 		cur_node = scm_get_next_node(scan_db,
1302 			   &scan_db->scan_hash_tbl[i], NULL);
1303 		while (cur_node) {
1304 			scm_filter_channels(scan_db,
1305 				cur_node, chan_list, num_chan);
1306 			next_node = scm_get_next_node(scan_db,
1307 				&scan_db->scan_hash_tbl[i], cur_node);
1308 			cur_node = next_node;
1309 		}
1310 	}
1311 }
1312 
1313 QDF_STATUS scm_scan_register_bcn_cb(struct wlan_objmgr_psoc *psoc,
1314 	update_beacon_cb cb, enum scan_cb_type type)
1315 {
1316 	struct wlan_scan_obj *scan_obj;
1317 
1318 	scan_obj = wlan_psoc_get_scan_obj(psoc);
1319 	if (!scan_obj) {
1320 		scm_err("scan obj is NULL");
1321 		return QDF_STATUS_E_INVAL;
1322 	}
1323 	switch (type) {
1324 	case SCAN_CB_TYPE_INFORM_BCN:
1325 		scan_obj->cb.inform_beacon = cb;
1326 		break;
1327 	case SCAN_CB_TYPE_UPDATE_BCN:
1328 		scan_obj->cb.update_beacon = cb;
1329 		break;
1330 	default:
1331 		scm_err("invalid cb type %d", type);
1332 	}
1333 
1334 	return QDF_STATUS_SUCCESS;
1335 }
1336 
1337 QDF_STATUS scm_db_init(struct wlan_objmgr_psoc *psoc)
1338 {
1339 	int i, j;
1340 	struct scan_dbs *scan_db;
1341 
1342 	if (!psoc) {
1343 		scm_err("psoc is NULL");
1344 		return QDF_STATUS_E_INVAL;
1345 	}
1346 
1347 	/* Initialize the scan database per pdev */
1348 	for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) {
1349 		scan_db = wlan_pdevid_get_scan_db(psoc, i);
1350 		if (!scan_db) {
1351 			scm_err("scan_db is NULL %d", i);
1352 			continue;
1353 		}
1354 		scan_db->num_entries = 0;
1355 		qdf_spinlock_create(&scan_db->scan_db_lock);
1356 		for (j = 0; j < SCAN_HASH_SIZE; j++)
1357 			qdf_list_create(&scan_db->scan_hash_tbl[j],
1358 				MAX_SCAN_CACHE_SIZE);
1359 	}
1360 
1361 	return QDF_STATUS_SUCCESS;
1362 }
1363 
1364 QDF_STATUS scm_db_deinit(struct wlan_objmgr_psoc *psoc)
1365 {
1366 	int i, j;
1367 	struct scan_dbs *scan_db;
1368 
1369 	if (!psoc) {
1370 		scm_err("scan obj is NULL");
1371 		return QDF_STATUS_E_INVAL;
1372 	}
1373 
1374 	/* Initialize the scan database per pdev */
1375 	for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) {
1376 		scan_db = wlan_pdevid_get_scan_db(psoc, i);
1377 		if (!scan_db) {
1378 			scm_err("scan_db is NULL %d", i);
1379 			continue;
1380 		}
1381 
1382 		scm_flush_scan_entries(psoc, scan_db, NULL);
1383 		for (j = 0; j < SCAN_HASH_SIZE; j++)
1384 			qdf_list_destroy(&scan_db->scan_hash_tbl[j]);
1385 		qdf_spinlock_destroy(&scan_db->scan_db_lock);
1386 	}
1387 
1388 	return QDF_STATUS_SUCCESS;
1389 }
1390 
1391 QDF_STATUS scm_update_scan_mlme_info(struct wlan_objmgr_pdev *pdev,
1392 	struct scan_cache_entry *entry)
1393 {
1394 	uint8_t hash_idx;
1395 	struct scan_dbs *scan_db;
1396 	struct scan_cache_node *cur_node;
1397 	struct scan_cache_node *next_node = NULL;
1398 	struct wlan_objmgr_psoc *psoc;
1399 
1400 	psoc = wlan_pdev_get_psoc(pdev);
1401 	if (!psoc) {
1402 		scm_err("psoc is NULL");
1403 		return QDF_STATUS_E_INVAL;
1404 	}
1405 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1406 	if (!scan_db) {
1407 		scm_err("scan_db is NULL");
1408 		return QDF_STATUS_E_INVAL;
1409 	}
1410 
1411 	hash_idx = SCAN_GET_HASH(entry->bssid.bytes);
1412 
1413 	cur_node = scm_get_next_node(scan_db,
1414 			&scan_db->scan_hash_tbl[hash_idx], NULL);
1415 
1416 	while (cur_node) {
1417 		if (util_is_scan_entry_match(entry,
1418 					cur_node->entry)) {
1419 			/* Acquire db lock to prevent simultaneous update */
1420 			qdf_spin_lock_bh(&scan_db->scan_db_lock);
1421 			scm_update_mlme_info(entry, cur_node->entry);
1422 			qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1423 			scm_scan_entry_put_ref(scan_db,
1424 					cur_node, true);
1425 			return QDF_STATUS_SUCCESS;
1426 		}
1427 		next_node = scm_get_next_node(scan_db,
1428 				&scan_db->scan_hash_tbl[hash_idx], cur_node);
1429 		cur_node = next_node;
1430 	}
1431 
1432 	return QDF_STATUS_E_INVAL;
1433 }
1434 
1435 QDF_STATUS scm_scan_update_mlme_by_bssinfo(struct wlan_objmgr_pdev *pdev,
1436 		struct bss_info *bss_info, struct mlme_info *mlme)
1437 {
1438 	uint8_t hash_idx;
1439 	struct scan_dbs *scan_db;
1440 	struct scan_cache_node *cur_node;
1441 	struct scan_cache_node *next_node = NULL;
1442 	struct wlan_objmgr_psoc *psoc;
1443 	struct scan_cache_entry *entry;
1444 
1445 	psoc = wlan_pdev_get_psoc(pdev);
1446 	if (!psoc) {
1447 		scm_err("psoc is NULL");
1448 		return QDF_STATUS_E_INVAL;
1449 	}
1450 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1451 	if (!scan_db) {
1452 		scm_err("scan_db is NULL");
1453 		return QDF_STATUS_E_INVAL;
1454 	}
1455 
1456 	hash_idx = SCAN_GET_HASH(bss_info->bssid.bytes);
1457 	cur_node = scm_get_next_node(scan_db,
1458 			&scan_db->scan_hash_tbl[hash_idx], NULL);
1459 	while (cur_node) {
1460 		entry = cur_node->entry;
1461 		if (qdf_is_macaddr_equal(&bss_info->bssid, &entry->bssid) &&
1462 			(util_is_ssid_match(&bss_info->ssid, &entry->ssid)) &&
1463 			(bss_info->chan == entry->channel.chan_idx)) {
1464 			/* Acquire db lock to prevent simultaneous update */
1465 			qdf_spin_lock_bh(&scan_db->scan_db_lock);
1466 			qdf_mem_copy(&entry->mlme_info, mlme,
1467 					sizeof(struct mlme_info));
1468 			scm_scan_entry_put_ref(scan_db,
1469 					cur_node, false);
1470 			qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1471 			return QDF_STATUS_SUCCESS;
1472 		}
1473 		next_node = scm_get_next_node(scan_db,
1474 				&scan_db->scan_hash_tbl[hash_idx], cur_node);
1475 		cur_node = next_node;
1476 	}
1477 
1478 	return QDF_STATUS_E_INVAL;
1479 }
1480