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