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