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