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