xref: /wlan-dirver/qca-wifi-host-cmn/umac/scan/core/src/wlan_scan_cache_db.c (revision 1f55ed1a9f5050d8da228aa8dd3fff7c0242aa71)
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 		scm_nofl_debug("Received %s from BSSID: %pM tsf_delta = %u Seq Num: %d  ssid:%.*s, rssi: %d pdev_id = %d",
786 			       (bcn->frm_type == MGMT_SUBTYPE_PROBE_RESP) ?
787 			       "Probe Rsp" : "Beacon", scan_entry->bssid.bytes,
788 			       scan_entry->tsf_delta, scan_entry->seq_num,
789 			       scan_entry->ssid.length, scan_entry->ssid.ssid,
790 			       scan_entry->rssi_raw,
791 			       wlan_objmgr_pdev_get_pdev_id(pdev));
792 
793 		if (scan_obj->drop_bcn_on_chan_mismatch &&
794 			scan_entry->channel_mismatch) {
795 			scm_debug("Drop frame, as channel mismatch Received for from BSSID: %pM Seq Num: %d",
796 				   scan_entry->bssid.bytes,
797 				   scan_entry->seq_num);
798 			util_scan_free_cache_entry(scan_entry);
799 			qdf_mem_free(scan_node);
800 			continue;
801 		}
802 
803 		if (scan_obj->cb.update_beacon)
804 			scan_obj->cb.update_beacon(pdev, scan_entry);
805 
806 		if (wlan_reg_11d_enabled_on_host(psoc))
807 			scm_11d_handle_country_info(psoc, pdev, scan_entry);
808 
809 		status = scm_add_update_entry(psoc, pdev, scan_entry);
810 		if (QDF_IS_STATUS_ERROR(status)) {
811 			scm_debug("failed to add entry for BSSID: %pM Seq Num: %d",
812 				  scan_entry->bssid.bytes,
813 				  scan_entry->seq_num);
814 			util_scan_free_cache_entry(scan_entry);
815 			qdf_mem_free(scan_node);
816 			continue;
817 		}
818 
819 		qdf_mem_free(scan_node);
820 	}
821 
822 free_nbuf:
823 	if (scan_list)
824 		qdf_mem_free(scan_list);
825 	if (bcn->psoc)
826 		wlan_objmgr_psoc_release_ref(bcn->psoc, WLAN_SCAN_ID);
827 	if (pdev)
828 		wlan_objmgr_pdev_release_ref(pdev, WLAN_SCAN_ID);
829 	if (bcn->rx_data)
830 		qdf_mem_free(bcn->rx_data);
831 	if (bcn->buf)
832 		qdf_nbuf_free(bcn->buf);
833 	qdf_mem_free(bcn);
834 
835 	return status;
836 }
837 
838 /**
839  * scm_list_insert_sorted() - add the entries in scan_list in sorted way
840  * @psoc: psoc ptr
841  * @filter: scan filter
842  * @scan_node: node entry to be inserted
843  * @scan_list: Temp scan list
844  *
845  * Add the entries in scan_list in sorted way considering
846  * cap_val and prefer val. The node is copy of original scan entry and
847  * thus no lock is required.
848  *
849  * Return: void
850  */
851 static void scm_list_insert_sorted(struct wlan_objmgr_psoc *psoc,
852 	struct scan_filter *filter,
853 	struct scan_cache_node *scan_node,
854 	qdf_list_t *scan_list)
855 {
856 	struct scan_cache_node *cur_node;
857 	qdf_list_node_t *cur_lst = NULL, *next_lst = NULL;
858 	struct scan_default_params *params;
859 	int pcl_chan_weight = 0;
860 
861 	params = wlan_scan_psoc_get_def_params(psoc);
862 	if (!params) {
863 		scm_err("wlan_scan_psoc_get_def_params failed");
864 		return;
865 	}
866 
867 	if (filter->num_of_pcl_channels > 0 &&
868 			(scan_node->entry->rssi_raw > SCM_PCL_RSSI_THRESHOLD)) {
869 		if (scm_get_pcl_weight_of_channel(
870 					scan_node->entry->channel.chan_idx,
871 					filter, &pcl_chan_weight,
872 					filter->pcl_weight_list)) {
873 			scm_debug("pcl channel %d pcl_chan_weight %d",
874 					scan_node->entry->channel.chan_idx,
875 					pcl_chan_weight);
876 		}
877 	}
878 	if (params->is_bssid_hint_priority &&
879 	    !qdf_mem_cmp(filter->bssid_hint.bytes,
880 			 scan_node->entry->bssid.bytes,
881 			 QDF_MAC_ADDR_SIZE))
882 		scan_node->entry->bss_score = BEST_CANDIDATE_MAX_BSS_SCORE;
883 	else
884 		scm_calculate_bss_score(psoc, params,
885 					scan_node->entry, pcl_chan_weight);
886 
887 	if (qdf_list_empty(scan_list)) {
888 		qdf_list_insert_front(scan_list, &scan_node->node);
889 		return;
890 	}
891 
892 	qdf_list_peek_front(scan_list, &cur_lst);
893 
894 	while (cur_lst) {
895 		cur_node = qdf_container_of(cur_lst,
896 				struct scan_cache_node, node);
897 		if (scm_is_better_bss(params,
898 		   scan_node->entry, cur_node->entry)) {
899 			qdf_list_insert_before(scan_list,
900 				&scan_node->node,
901 				&cur_node->node);
902 			break;
903 		}
904 		qdf_list_peek_next(scan_list,
905 			cur_lst, &next_lst);
906 		cur_lst = next_lst;
907 		next_lst = NULL;
908 	}
909 
910 	if (!cur_lst)
911 		qdf_list_insert_back(scan_list,
912 			&scan_node->node);
913 
914 }
915 
916 /**
917  * scm_scan_apply_filter_get_entry() - apply filter and get the
918  * scan entry
919  * @psoc: psoc pointer
920  * @db_entry: scan entry
921  * @filter: filter to be applied
922  * @scan_list: scan list to which entry is added
923  *
924  * Return: QDF_STATUS
925  */
926 static QDF_STATUS
927 scm_scan_apply_filter_get_entry(struct wlan_objmgr_psoc *psoc,
928 	struct scan_cache_entry *db_entry,
929 	struct scan_filter *filter,
930 	qdf_list_t *scan_list)
931 {
932 	struct scan_cache_node *scan_node = NULL;
933 	struct security_info security = {0};
934 	bool match;
935 
936 	if (!filter)
937 		match = true;
938 	else
939 		match = scm_filter_match(psoc, db_entry,
940 					filter, &security);
941 
942 	if (!match)
943 		return QDF_STATUS_SUCCESS;
944 
945 	scan_node = qdf_mem_malloc_atomic(sizeof(*scan_node));
946 	if (!scan_node)
947 		return QDF_STATUS_E_NOMEM;
948 
949 	scan_node->entry =
950 		util_scan_copy_cache_entry(db_entry);
951 
952 	if (!scan_node->entry) {
953 		qdf_mem_free(scan_node);
954 		return QDF_STATUS_E_NOMEM;
955 	}
956 
957 	qdf_mem_copy(&scan_node->entry->neg_sec_info,
958 		&security, sizeof(scan_node->entry->neg_sec_info));
959 
960 	if (!filter || !filter->bss_scoring_required)
961 		qdf_list_insert_front(scan_list,
962 			&scan_node->node);
963 	else
964 		scm_list_insert_sorted(psoc, filter, scan_node, scan_list);
965 
966 	return QDF_STATUS_SUCCESS;
967 }
968 
969 /**
970  * scm_get_results() - Iterate and get scan results
971  * @psoc: psoc ptr
972  * @scan_db: scan db
973  * @filter: filter to be applied
974  * @scan_list: scan list to which entry is added
975  *
976  * Return: void
977  */
978 static void scm_get_results(struct wlan_objmgr_psoc *psoc,
979 	struct scan_dbs *scan_db, struct scan_filter *filter,
980 	qdf_list_t *scan_list)
981 {
982 	int i, count;
983 	struct scan_cache_node *cur_node;
984 	struct scan_cache_node *next_node = NULL;
985 
986 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
987 		cur_node = scm_get_next_node(scan_db,
988 			   &scan_db->scan_hash_tbl[i], NULL);
989 		count = qdf_list_size(&scan_db->scan_hash_tbl[i]);
990 		if (!count)
991 			continue;
992 		while (cur_node) {
993 			scm_scan_apply_filter_get_entry(psoc,
994 				cur_node->entry, filter, scan_list);
995 			next_node = scm_get_next_node(scan_db,
996 				&scan_db->scan_hash_tbl[i], cur_node);
997 			cur_node = next_node;
998 		}
999 	}
1000 }
1001 
1002 QDF_STATUS scm_purge_scan_results(qdf_list_t *scan_list)
1003 {
1004 	QDF_STATUS status;
1005 	struct scan_cache_node *cur_node;
1006 	qdf_list_node_t *cur_lst = NULL, *next_lst = NULL;
1007 
1008 	if (!scan_list) {
1009 		scm_err("scan_result is NULL");
1010 		return QDF_STATUS_E_INVAL;
1011 	}
1012 
1013 	status = qdf_list_peek_front(scan_list, &cur_lst);
1014 
1015 	while (cur_lst) {
1016 		qdf_list_peek_next(
1017 			scan_list, cur_lst, &next_lst);
1018 		cur_node = qdf_container_of(cur_lst,
1019 			struct scan_cache_node, node);
1020 		status = qdf_list_remove_node(scan_list,
1021 					cur_lst);
1022 		if (QDF_IS_STATUS_SUCCESS(status)) {
1023 			util_scan_free_cache_entry(cur_node->entry);
1024 			qdf_mem_free(cur_node);
1025 		}
1026 		cur_lst = next_lst;
1027 		next_lst = NULL;
1028 	}
1029 
1030 	qdf_list_destroy(scan_list);
1031 	qdf_mem_free(scan_list);
1032 
1033 	return status;
1034 }
1035 
1036 qdf_list_t *scm_get_scan_result(struct wlan_objmgr_pdev *pdev,
1037 	struct scan_filter *filter)
1038 {
1039 	struct wlan_objmgr_psoc *psoc;
1040 	struct scan_dbs *scan_db;
1041 	qdf_list_t *tmp_list;
1042 
1043 	if (!pdev) {
1044 		scm_err("pdev is NULL");
1045 		return NULL;
1046 	}
1047 
1048 	psoc = wlan_pdev_get_psoc(pdev);
1049 	if (!psoc) {
1050 		scm_err("psoc is NULL");
1051 		return NULL;
1052 	}
1053 
1054 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1055 	if (!scan_db) {
1056 		scm_err("scan_db is NULL");
1057 		return NULL;
1058 	}
1059 
1060 	tmp_list = qdf_mem_malloc_atomic(sizeof(*tmp_list));
1061 	if (!tmp_list) {
1062 		scm_err("failed tp allocate scan_result");
1063 		return NULL;
1064 	}
1065 	qdf_list_create(tmp_list,
1066 			MAX_SCAN_CACHE_SIZE);
1067 	scm_age_out_entries(psoc, scan_db);
1068 	scm_get_results(psoc, scan_db, filter, tmp_list);
1069 
1070 	return tmp_list;
1071 }
1072 
1073 /**
1074  * scm_iterate_db_and_call_func() - iterate and call the func
1075  * @scan_db: scan db
1076  * @func: func to be called
1077  * @arg: func arg
1078  *
1079  * Return: QDF_STATUS
1080  */
1081 static QDF_STATUS
1082 scm_iterate_db_and_call_func(struct scan_dbs *scan_db,
1083 	scan_iterator_func func, void *arg)
1084 {
1085 	int i;
1086 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1087 	struct scan_cache_node *cur_node;
1088 	struct scan_cache_node *next_node = NULL;
1089 
1090 	if (!func)
1091 		return QDF_STATUS_E_INVAL;
1092 
1093 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1094 		cur_node = scm_get_next_node(scan_db,
1095 			&scan_db->scan_hash_tbl[i], NULL);
1096 		while (cur_node) {
1097 			status = func(arg, cur_node->entry);
1098 			if (QDF_IS_STATUS_ERROR(status)) {
1099 				scm_scan_entry_put_ref(scan_db,
1100 					cur_node, true);
1101 				return status;
1102 			}
1103 			next_node = scm_get_next_node(scan_db,
1104 				&scan_db->scan_hash_tbl[i], cur_node);
1105 			cur_node = next_node;
1106 		}
1107 	}
1108 
1109 	return status;
1110 }
1111 
1112 QDF_STATUS
1113 scm_iterate_scan_db(struct wlan_objmgr_pdev *pdev,
1114 	scan_iterator_func func, void *arg)
1115 {
1116 	struct wlan_objmgr_psoc *psoc;
1117 	struct scan_dbs *scan_db;
1118 	QDF_STATUS status;
1119 
1120 	if (!func) {
1121 		scm_err("func is NULL");
1122 		return QDF_STATUS_E_INVAL;
1123 	}
1124 
1125 	if (!pdev) {
1126 		scm_err("pdev is NULL");
1127 		return QDF_STATUS_E_INVAL;
1128 	}
1129 
1130 	psoc = wlan_pdev_get_psoc(pdev);
1131 	if (!psoc) {
1132 		scm_err("psoc is NULL");
1133 		return QDF_STATUS_E_INVAL;
1134 	}
1135 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1136 	if (!scan_db) {
1137 		scm_err("scan_db is NULL");
1138 		return QDF_STATUS_E_INVAL;
1139 	}
1140 
1141 	scm_age_out_entries(psoc, scan_db);
1142 	status = scm_iterate_db_and_call_func(scan_db, func, arg);
1143 
1144 	return status;
1145 }
1146 
1147 /**
1148  * scm_scan_apply_filter_flush_entry() -flush scan entries depending
1149  * on filter
1150  * @psoc: psoc ptr
1151  * @scan_db: scan db
1152  * @db_node: node on which filters are applied
1153  * @filter: filter to be applied
1154  *
1155  * Return: QDF_STATUS
1156  */
1157 static QDF_STATUS
1158 scm_scan_apply_filter_flush_entry(struct wlan_objmgr_psoc *psoc,
1159 	struct scan_dbs *scan_db,
1160 	struct scan_cache_node *db_node,
1161 	struct scan_filter *filter)
1162 {
1163 	struct security_info security = {0};
1164 	bool match;
1165 
1166 	if (!filter)
1167 		match = true;
1168 	else
1169 		match = scm_filter_match(psoc, db_node->entry,
1170 					filter, &security);
1171 
1172 	if (!match)
1173 		return QDF_STATUS_SUCCESS;
1174 
1175 	qdf_spin_lock_bh(&scan_db->scan_db_lock);
1176 	scm_scan_entry_del(scan_db, db_node);
1177 	qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1178 
1179 	return QDF_STATUS_SUCCESS;
1180 }
1181 
1182 /**
1183  * scm_flush_scan_entries() - API to flush scan entries depending on filters
1184  * @psoc: psoc ptr
1185  * @scan_db: scan db
1186  * @filter: filter
1187  *
1188  * Return: void
1189  */
1190 static void scm_flush_scan_entries(struct wlan_objmgr_psoc *psoc,
1191 	struct scan_dbs *scan_db,
1192 	struct scan_filter *filter)
1193 {
1194 	int i;
1195 	struct scan_cache_node *cur_node;
1196 	struct scan_cache_node *next_node = NULL;
1197 
1198 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1199 		cur_node = scm_get_next_node(scan_db,
1200 			   &scan_db->scan_hash_tbl[i], NULL);
1201 		while (cur_node) {
1202 			scm_scan_apply_filter_flush_entry(psoc, scan_db,
1203 				cur_node, filter);
1204 			next_node = scm_get_next_node(scan_db,
1205 				&scan_db->scan_hash_tbl[i], cur_node);
1206 			cur_node = next_node;
1207 		}
1208 	}
1209 }
1210 
1211 QDF_STATUS scm_flush_results(struct wlan_objmgr_pdev *pdev,
1212 	struct scan_filter *filter)
1213 {
1214 	struct wlan_objmgr_psoc *psoc;
1215 	struct scan_dbs *scan_db;
1216 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1217 
1218 	if (!pdev) {
1219 		scm_err("pdev is NULL");
1220 		return QDF_STATUS_E_INVAL;
1221 	}
1222 
1223 	psoc = wlan_pdev_get_psoc(pdev);
1224 	if (!psoc) {
1225 		scm_err("psoc is NULL");
1226 		return QDF_STATUS_E_INVAL;
1227 	}
1228 
1229 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1230 	if (!scan_db) {
1231 		scm_err("scan_db is NULL");
1232 		return QDF_STATUS_E_INVAL;
1233 	}
1234 
1235 	scm_flush_scan_entries(psoc, scan_db, filter);
1236 
1237 	return status;
1238 }
1239 
1240 /**
1241  * scm_filter_channels() - Remove entries not belonging to channel list
1242  * @scan_db: scan db
1243  * @db_node: node on which filters are applied
1244  * @chan_list: valid channel list
1245  * @num_chan: number of channels
1246  *
1247  * Return: QDF_STATUS
1248  */
1249 static void scm_filter_channels(struct scan_dbs *scan_db,
1250 	struct scan_cache_node *db_node,
1251 	uint8_t *chan_list, uint32_t num_chan)
1252 {
1253 	int i;
1254 	bool match = false;
1255 
1256 	for (i = 0; i < num_chan; i++) {
1257 		if (chan_list[i] ==
1258 		   util_scan_entry_channel_num(db_node->entry)) {
1259 			match = true;
1260 			break;
1261 		}
1262 	}
1263 
1264 	if (!match) {
1265 		qdf_spin_lock_bh(&scan_db->scan_db_lock);
1266 		scm_scan_entry_del(scan_db, db_node);
1267 		qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1268 	}
1269 }
1270 
1271 void scm_filter_valid_channel(struct wlan_objmgr_pdev *pdev,
1272 	uint8_t *chan_list, uint32_t num_chan)
1273 {
1274 	int i;
1275 	struct wlan_objmgr_psoc *psoc;
1276 	struct scan_dbs *scan_db;
1277 	struct scan_cache_node *cur_node;
1278 	struct scan_cache_node *next_node = NULL;
1279 
1280 	scm_debug("num_chan = %d", num_chan);
1281 
1282 	if (!pdev) {
1283 		scm_err("pdev is NULL");
1284 		return;
1285 	}
1286 
1287 	psoc = wlan_pdev_get_psoc(pdev);
1288 	if (!psoc) {
1289 		scm_err("psoc is NULL");
1290 		return;
1291 	}
1292 
1293 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1294 	if (!scan_db) {
1295 		scm_err("scan_db is NULL");
1296 		return;
1297 	}
1298 
1299 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1300 		cur_node = scm_get_next_node(scan_db,
1301 			   &scan_db->scan_hash_tbl[i], NULL);
1302 		while (cur_node) {
1303 			scm_filter_channels(scan_db,
1304 				cur_node, chan_list, num_chan);
1305 			next_node = scm_get_next_node(scan_db,
1306 				&scan_db->scan_hash_tbl[i], cur_node);
1307 			cur_node = next_node;
1308 		}
1309 	}
1310 }
1311 
1312 QDF_STATUS scm_scan_register_bcn_cb(struct wlan_objmgr_psoc *psoc,
1313 	update_beacon_cb cb, enum scan_cb_type type)
1314 {
1315 	struct wlan_scan_obj *scan_obj;
1316 
1317 	scan_obj = wlan_psoc_get_scan_obj(psoc);
1318 	if (!scan_obj) {
1319 		scm_err("scan obj is NULL");
1320 		return QDF_STATUS_E_INVAL;
1321 	}
1322 	switch (type) {
1323 	case SCAN_CB_TYPE_INFORM_BCN:
1324 		scan_obj->cb.inform_beacon = cb;
1325 		break;
1326 	case SCAN_CB_TYPE_UPDATE_BCN:
1327 		scan_obj->cb.update_beacon = cb;
1328 		break;
1329 	default:
1330 		scm_err("invalid cb type %d", type);
1331 	}
1332 
1333 	return QDF_STATUS_SUCCESS;
1334 }
1335 
1336 QDF_STATUS scm_db_init(struct wlan_objmgr_psoc *psoc)
1337 {
1338 	int i, j;
1339 	struct scan_dbs *scan_db;
1340 
1341 	if (!psoc) {
1342 		scm_err("psoc is NULL");
1343 		return QDF_STATUS_E_INVAL;
1344 	}
1345 
1346 	/* Initialize the scan database per pdev */
1347 	for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) {
1348 		scan_db = wlan_pdevid_get_scan_db(psoc, i);
1349 		if (!scan_db) {
1350 			scm_err("scan_db is NULL %d", i);
1351 			continue;
1352 		}
1353 		scan_db->num_entries = 0;
1354 		qdf_spinlock_create(&scan_db->scan_db_lock);
1355 		for (j = 0; j < SCAN_HASH_SIZE; j++)
1356 			qdf_list_create(&scan_db->scan_hash_tbl[j],
1357 				MAX_SCAN_CACHE_SIZE);
1358 	}
1359 
1360 	return QDF_STATUS_SUCCESS;
1361 }
1362 
1363 QDF_STATUS scm_db_deinit(struct wlan_objmgr_psoc *psoc)
1364 {
1365 	int i, j;
1366 	struct scan_dbs *scan_db;
1367 
1368 	if (!psoc) {
1369 		scm_err("scan obj is NULL");
1370 		return QDF_STATUS_E_INVAL;
1371 	}
1372 
1373 	/* Initialize the scan database per pdev */
1374 	for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) {
1375 		scan_db = wlan_pdevid_get_scan_db(psoc, i);
1376 		if (!scan_db) {
1377 			scm_err("scan_db is NULL %d", i);
1378 			continue;
1379 		}
1380 
1381 		scm_flush_scan_entries(psoc, scan_db, NULL);
1382 		for (j = 0; j < SCAN_HASH_SIZE; j++)
1383 			qdf_list_destroy(&scan_db->scan_hash_tbl[j]);
1384 		qdf_spinlock_destroy(&scan_db->scan_db_lock);
1385 	}
1386 
1387 	return QDF_STATUS_SUCCESS;
1388 }
1389 
1390 QDF_STATUS scm_update_scan_mlme_info(struct wlan_objmgr_pdev *pdev,
1391 	struct scan_cache_entry *entry)
1392 {
1393 	uint8_t hash_idx;
1394 	struct scan_dbs *scan_db;
1395 	struct scan_cache_node *cur_node;
1396 	struct scan_cache_node *next_node = NULL;
1397 	struct wlan_objmgr_psoc *psoc;
1398 
1399 	psoc = wlan_pdev_get_psoc(pdev);
1400 	if (!psoc) {
1401 		scm_err("psoc is NULL");
1402 		return QDF_STATUS_E_INVAL;
1403 	}
1404 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1405 	if (!scan_db) {
1406 		scm_err("scan_db is NULL");
1407 		return QDF_STATUS_E_INVAL;
1408 	}
1409 
1410 	hash_idx = SCAN_GET_HASH(entry->bssid.bytes);
1411 
1412 	cur_node = scm_get_next_node(scan_db,
1413 			&scan_db->scan_hash_tbl[hash_idx], NULL);
1414 
1415 	while (cur_node) {
1416 		if (util_is_scan_entry_match(entry,
1417 					cur_node->entry)) {
1418 			/* Acquire db lock to prevent simultaneous update */
1419 			qdf_spin_lock_bh(&scan_db->scan_db_lock);
1420 			scm_update_mlme_info(entry, cur_node->entry);
1421 			qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1422 			scm_scan_entry_put_ref(scan_db,
1423 					cur_node, true);
1424 			return QDF_STATUS_SUCCESS;
1425 		}
1426 		next_node = scm_get_next_node(scan_db,
1427 				&scan_db->scan_hash_tbl[hash_idx], cur_node);
1428 		cur_node = next_node;
1429 	}
1430 
1431 	return QDF_STATUS_E_INVAL;
1432 }
1433 
1434 QDF_STATUS scm_scan_update_mlme_by_bssinfo(struct wlan_objmgr_pdev *pdev,
1435 		struct bss_info *bss_info, struct mlme_info *mlme)
1436 {
1437 	uint8_t hash_idx;
1438 	struct scan_dbs *scan_db;
1439 	struct scan_cache_node *cur_node;
1440 	struct scan_cache_node *next_node = NULL;
1441 	struct wlan_objmgr_psoc *psoc;
1442 	struct scan_cache_entry *entry;
1443 
1444 	psoc = wlan_pdev_get_psoc(pdev);
1445 	if (!psoc) {
1446 		scm_err("psoc is NULL");
1447 		return QDF_STATUS_E_INVAL;
1448 	}
1449 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1450 	if (!scan_db) {
1451 		scm_err("scan_db is NULL");
1452 		return QDF_STATUS_E_INVAL;
1453 	}
1454 
1455 	hash_idx = SCAN_GET_HASH(bss_info->bssid.bytes);
1456 	cur_node = scm_get_next_node(scan_db,
1457 			&scan_db->scan_hash_tbl[hash_idx], NULL);
1458 	while (cur_node) {
1459 		entry = cur_node->entry;
1460 		if (qdf_is_macaddr_equal(&bss_info->bssid, &entry->bssid) &&
1461 			(util_is_ssid_match(&bss_info->ssid, &entry->ssid)) &&
1462 			(bss_info->chan == entry->channel.chan_idx)) {
1463 			/* Acquire db lock to prevent simultaneous update */
1464 			qdf_spin_lock_bh(&scan_db->scan_db_lock);
1465 			qdf_mem_copy(&entry->mlme_info, mlme,
1466 					sizeof(struct mlme_info));
1467 			scm_scan_entry_put_ref(scan_db,
1468 					cur_node, false);
1469 			qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1470 			return QDF_STATUS_SUCCESS;
1471 		}
1472 		next_node = scm_get_next_node(scan_db,
1473 				&scan_db->scan_hash_tbl[hash_idx], cur_node);
1474 		cur_node = next_node;
1475 	}
1476 
1477 	return QDF_STATUS_E_INVAL;
1478 }
1479