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