xref: /wlan-dirver/qca-wifi-host-cmn/umac/scan/core/src/wlan_scan_cache_db.c (revision 3149adf58a329e17232a4c0e58d460d025edd55a)
1 /*
2  * Copyright (c) 2017-2018 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.
27  * - While reading the entry ref_cnt is incremented while holding the lock.
28  * - Once reading operation is done ref_cnt is decremented while holding
29  *   the lock.
30  * - Once ref_cnt become 0 the node is deleted from the scan cache.
31  */
32 #include <qdf_status.h>
33 #include <wlan_objmgr_psoc_obj.h>
34 #include <wlan_objmgr_pdev_obj.h>
35 #include <wlan_objmgr_vdev_obj.h>
36 #include <wlan_scan_public_structs.h>
37 #include <wlan_scan_utils_api.h>
38 #include "wlan_scan_main.h"
39 #include "wlan_scan_cache_db_i.h"
40 #include "wlan_reg_services_api.h"
41 #include "wlan_reg_ucfg_api.h"
42 
43 /**
44  * scm_del_scan_node() - API to remove scan node from the list
45  * @list: hash list
46  * @scan_node: node to be removed
47  *
48  * This should be called while holding scan_db_lock.
49  *
50  * Return: void
51  */
52 static void scm_del_scan_node(qdf_list_t *list,
53 	struct scan_cache_node *scan_node)
54 {
55 	QDF_STATUS status;
56 
57 	status = qdf_list_remove_node(list, &scan_node->node);
58 	if (QDF_IS_STATUS_SUCCESS(status)) {
59 		util_scan_free_cache_entry(scan_node->entry);
60 		qdf_mem_free(scan_node);
61 	}
62 }
63 
64 /**
65  * scm_del_scan_node_from_db() - API to del the scan entry
66  * @scan_db: scan database
67  * @scan_entry:entry scan_node
68  *
69  * API to flush the scan entry. This should be called while
70  * holding scan_db_lock.
71  *
72  * Return: QDF status.
73  */
74 static QDF_STATUS scm_del_scan_node_from_db(struct scan_dbs *scan_db,
75 	struct scan_cache_node *scan_node)
76 {
77 	QDF_STATUS status = QDF_STATUS_SUCCESS;
78 	uint8_t hash_idx;
79 
80 	if (!scan_node)
81 		return QDF_STATUS_E_INVAL;
82 
83 	hash_idx = SCAN_GET_HASH(scan_node->entry->bssid.bytes);
84 	scm_del_scan_node(&scan_db->scan_hash_tbl[hash_idx], scan_node);
85 	scan_db->num_entries--;
86 
87 	return status;
88 }
89 
90 /**
91  * scm_scan_entry_get_ref() - api to increase ref count of scan entry
92  * @scan_node: scan node
93  *
94  * Return: void
95  */
96 static void scm_scan_entry_get_ref(struct scan_cache_node *scan_node)
97 {
98 	if (scan_node == NULL) {
99 		scm_err("scan_node is NULL");
100 		QDF_ASSERT(0);
101 		return;
102 	}
103 	qdf_atomic_inc(&scan_node->ref_cnt);
104 }
105 
106 /**
107  * scm_scan_entry_put_ref() - Api to decrease ref count of scan entry
108  * and free if it become 0
109  * @scan_db: scan database
110  * @scan_node: scan node
111  * @lock_needed: if scan_db_lock is needed
112  * @delete: logically delete the entry
113  *
114  * Return: void
115  */
116 static void scm_scan_entry_put_ref(struct scan_dbs *scan_db,
117 	struct scan_cache_node *scan_node, bool lock_needed, bool delete)
118 {
119 
120 	if (!scan_node) {
121 		scm_err("scan_node is NULL");
122 		QDF_ASSERT(0);
123 		return;
124 	}
125 
126 	if (lock_needed)
127 		qdf_spin_lock_bh(&scan_db->scan_db_lock);
128 
129 	if (delete && !scan_node->active) {
130 		if (lock_needed)
131 			qdf_spin_unlock_bh(&scan_db->scan_db_lock);
132 		scm_warn("node is already deleted");
133 		return;
134 	}
135 
136 	if (!qdf_atomic_read(&scan_node->ref_cnt)) {
137 		if (lock_needed)
138 			qdf_spin_unlock_bh(&scan_db->scan_db_lock);
139 		scm_err("scan_node ref cnt is 0");
140 		QDF_ASSERT(0);
141 		return;
142 	}
143 
144 	if (delete)
145 		scan_node->active = false;
146 
147 	/* Decrement ref count, free scan_node, if ref count == 0 */
148 	if (qdf_atomic_dec_and_test(&scan_node->ref_cnt))
149 		scm_del_scan_node_from_db(scan_db, scan_node);
150 
151 	if (lock_needed)
152 		qdf_spin_unlock_bh(&scan_db->scan_db_lock);
153 }
154 
155 /**
156  * scm_add_scan_node() - API to add scan node
157  * @scan_db: data base
158  * @scan_node: node to be removed
159  *
160  * Return: void
161  */
162 static void scm_add_scan_node(struct scan_dbs *scan_db,
163 	struct scan_cache_node *scan_node)
164 {
165 	uint8_t hash_idx;
166 
167 	hash_idx =
168 		SCAN_GET_HASH(scan_node->entry->bssid.bytes);
169 
170 	qdf_spin_lock_bh(&scan_db->scan_db_lock);
171 	qdf_atomic_init(&scan_node->ref_cnt);
172 	scan_node->active = true;
173 	scm_scan_entry_get_ref(scan_node);
174 	qdf_list_insert_back(&scan_db->scan_hash_tbl[hash_idx],
175 			&scan_node->node);
176 	scan_db->num_entries++;
177 	qdf_spin_unlock_bh(&scan_db->scan_db_lock);
178 }
179 
180 
181 /**
182  * scm_get_next_valid_node() - API get the next valid scan node from
183  * the list
184  * @list: hash list
185  * @cur_node: current node pointer
186  *
187  * API to get next active node from the list. If cur_node is NULL
188  * it will return first node of the list.
189  * Call must be protected by scan_db->scan_db_lock
190  *
191  * Return: next scan node
192  */
193 static qdf_list_node_t *
194 scm_get_next_valid_node(qdf_list_t *list,
195 	qdf_list_node_t *cur_node)
196 {
197 	qdf_list_node_t *next_node = NULL;
198 	qdf_list_node_t *temp_node = NULL;
199 	struct scan_cache_node *scan_node;
200 
201 	if (cur_node)
202 		qdf_list_peek_next(list, cur_node, &next_node);
203 	else
204 		qdf_list_peek_front(list, &next_node);
205 
206 	while (next_node) {
207 		scan_node = qdf_container_of(next_node,
208 			struct scan_cache_node, node);
209 		if (scan_node->active)
210 			return next_node;
211 		/*
212 		 * If node is not valid check for next entry
213 		 * to get next valid node.
214 		 */
215 		qdf_list_peek_next(list, next_node, &temp_node);
216 		next_node = temp_node;
217 		temp_node = NULL;
218 	}
219 
220 	return next_node;
221 }
222 
223 /**
224  * scm_get_next_node() - API get the next scan node from
225  * the list
226  * @scan_db: scan data base
227  * @list: hash list
228  * @cur_node: current node pointer
229  *
230  * API get the next node from the list. If cur_node is NULL
231  * it will return first node of the list
232  *
233  * Return: next scan cache node
234  */
235 static struct scan_cache_node *
236 scm_get_next_node(struct scan_dbs *scan_db,
237 	qdf_list_t *list, struct scan_cache_node *cur_node)
238 {
239 	struct scan_cache_node *next_node = NULL;
240 	qdf_list_node_t *next_list = NULL;
241 
242 	qdf_spin_lock_bh(&scan_db->scan_db_lock);
243 	if (cur_node) {
244 		next_list = scm_get_next_valid_node(list, &cur_node->node);
245 		/* Decrement the ref count of the previous node */
246 		scm_scan_entry_put_ref(scan_db,
247 			cur_node, false, false);
248 	} else {
249 		next_list = scm_get_next_valid_node(list, NULL);
250 	}
251 	/* Increase the ref count of the obtained node */
252 	if (next_list) {
253 		next_node = qdf_container_of(next_list,
254 			struct scan_cache_node, node);
255 		scm_scan_entry_get_ref(next_node);
256 	}
257 	qdf_spin_unlock_bh(&scan_db->scan_db_lock);
258 
259 	return next_node;
260 }
261 
262 /**
263  * scm_check_and_age_out() - check and age out the old entries
264  * @scan_db: scan db
265  * @scan_node: node to check for age out
266  * @scan_aging_time: scan cache aging time
267  *
268  * Return: void
269  */
270 static void scm_check_and_age_out(struct scan_dbs *scan_db,
271 	struct scan_cache_node *node,
272 	uint32_t scan_aging_time)
273 {
274 	if (util_scan_entry_age(node->entry) >=
275 	   scan_aging_time) {
276 		scm_info("Aging out BSSID: %pM with age %d ms",
277 			node->entry->bssid.bytes,
278 			util_scan_entry_age(node->entry));
279 		scm_scan_entry_put_ref(scan_db, node, true, true);
280 	}
281 }
282 
283 void scm_age_out_entries(struct wlan_objmgr_psoc *psoc,
284 	struct scan_dbs *scan_db)
285 {
286 	int i;
287 	struct scan_cache_node *cur_node = NULL;
288 	struct scan_cache_node *next_node = NULL;
289 	struct scan_default_params *def_param;
290 
291 	def_param = wlan_scan_psoc_get_def_params(psoc);
292 	if (!def_param) {
293 		scm_err("wlan_scan_psoc_get_def_params failed");
294 		return;
295 	}
296 
297 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
298 		cur_node = scm_get_next_node(scan_db,
299 			&scan_db->scan_hash_tbl[i], NULL);
300 		while (cur_node) {
301 			scm_check_and_age_out(scan_db, cur_node,
302 					def_param->scan_cache_aging_time);
303 			next_node = scm_get_next_node(scan_db,
304 				&scan_db->scan_hash_tbl[i], cur_node);
305 			cur_node = next_node;
306 			next_node = NULL;
307 		}
308 	}
309 }
310 
311 /**
312  * scm_flush_oldest_entry() - flust out the oldest entry
313  * @scan_db: scan db from which oldest etry needs to be flushed
314  *
315  * Return: QDF_STATUS
316  */
317 static QDF_STATUS scm_flush_oldest_entry(struct scan_dbs *scan_db)
318 {
319 	int i;
320 	struct scan_cache_node *oldest_node = NULL;
321 	struct scan_cache_node *cur_node;
322 	qdf_list_node_t *cur_list;
323 
324 	qdf_spin_lock_bh(&scan_db->scan_db_lock);
325 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
326 		/* Get the first valid node for the hash */
327 		cur_list = scm_get_next_valid_node(&scan_db->scan_hash_tbl[i],
328 						   NULL);
329 		/*
330 		 * Check only the first valid node if present as new
331 		 * entry are added to tail and thus first valid
332 		 * node is the oldest
333 		 */
334 		if (cur_list) {
335 			cur_node = qdf_container_of(cur_list,
336 				struct scan_cache_node, node);
337 			if (!oldest_node ||
338 			   (util_scan_entry_age(oldest_node->entry) <
339 			   util_scan_entry_age(cur_node->entry)))
340 				oldest_node = cur_node;
341 		}
342 	}
343 
344 	if (oldest_node) {
345 		scm_debug("Flush oldest BSSID: %pM with age %d ms",
346 				oldest_node->entry->bssid.bytes,
347 				util_scan_entry_age(oldest_node->entry));
348 		scm_scan_entry_put_ref(scan_db, oldest_node, false, true);
349 	}
350 	qdf_spin_unlock_bh(&scan_db->scan_db_lock);
351 
352 	return QDF_STATUS_SUCCESS;
353 }
354 
355 /**
356  * scm_update_alt_wcn_ie() - update the alternate WCN IE
357  * @from: copy from
358  * @dst: copy to
359  *
360  * Return: void
361  */
362 static void scm_update_alt_wcn_ie(struct scan_cache_entry *from,
363 	struct scan_cache_entry *dst)
364 {
365 	uint32_t alt_wcn_ie_len;
366 
367 	if (from->frm_subtype == dst->frm_subtype)
368 		return;
369 
370 	if (!from->ie_list.wcn && !dst->ie_list.wcn)
371 		return;
372 
373 	/* Existing WCN IE is empty. */
374 	if (!from->ie_list.wcn)
375 		return;
376 
377 	alt_wcn_ie_len = 2 + from->ie_list.wcn[1];
378 	if (alt_wcn_ie_len > WLAN_MAX_IE_LEN + 2) {
379 		scm_err("invalid IE len");
380 		return;
381 	}
382 
383 	if (!dst->alt_wcn_ie.ptr) {
384 		/* allocate this additional buffer for alternate WCN IE */
385 		dst->alt_wcn_ie.ptr = qdf_mem_malloc(WLAN_MAX_IE_LEN + 2);
386 		if (!dst->alt_wcn_ie.ptr) {
387 			scm_err("failed to allocate memory");
388 			return;
389 		}
390 	}
391 	qdf_mem_copy(dst->alt_wcn_ie.ptr,
392 		from->ie_list.wcn, alt_wcn_ie_len);
393 	dst->alt_wcn_ie.len = alt_wcn_ie_len;
394 }
395 
396 /**
397  * scm_add_scan_entry() - add new scan entry to the database
398  * @scan_db: scan database
399  * @scan_params: new entry to be added
400  *
401  * Return: QDF_STATUS
402  */
403 static QDF_STATUS scm_add_scan_entry(struct scan_dbs *scan_db,
404 	struct scan_cache_entry *scan_params)
405 {
406 	struct scan_cache_node *scan_node;
407 	QDF_STATUS status;
408 
409 	if (scan_db->num_entries >= MAX_SCAN_CACHE_SIZE) {
410 		status = scm_flush_oldest_entry(scan_db);
411 		if (QDF_IS_STATUS_ERROR(status))
412 			return status;
413 	}
414 
415 	scan_node = qdf_mem_malloc(sizeof(*scan_node));
416 	if (!scan_node)
417 		return QDF_STATUS_E_NOMEM;
418 
419 	scan_node->entry = scan_params;
420 	scm_add_scan_node(scan_db, scan_node);
421 
422 	return QDF_STATUS_SUCCESS;
423 }
424 
425 /**
426  * scm_update_mlme_info() - update mlme info
427  * @src: source scan entry
428  * @dest: destination scan entry
429  *
430  * Return: void
431  */
432 static inline void
433 scm_update_mlme_info(struct scan_cache_entry *src,
434 	struct scan_cache_entry *dest)
435 {
436 	qdf_mem_copy(&dest->mlme_info, &src->mlme_info,
437 		sizeof(struct mlme_info));
438 }
439 
440 /**
441  * scm_delete_duplicate_entry() - remove duplicate node entry
442  * @scan_db: scan database
443  * @scan_params: new entry to be added
444  * @scan_node: old entry to removed
445  *
446  * Remove duplicate node after copying required
447  * info into new entry
448  *
449  * Return: void
450  */
451 static void scm_delete_duplicate_entry(struct scan_dbs *scan_db,
452 	struct scan_cache_entry *scan_params,
453 	struct scan_cache_node *scan_node)
454 {
455 	struct scan_cache_entry *scan_entry;
456 	uint64_t time_gap;
457 
458 	scan_entry = scan_node->entry;
459 	/* If old entry have the ssid but new entry does not */
460 	if (!scan_params->ssid.length && scan_entry->ssid.length) {
461 		/*
462 		 * New entry has a hidden SSID and old one has the SSID.
463 		 * Add the entry by using the ssid of the old entry
464 		 * only if diff of saved SSID time and current time is
465 		 * less than HIDDEN_SSID_TIME time.
466 		 * This will avoid issues in case AP changes its SSID
467 		 * while remain hidden.
468 		 */
469 		time_gap =
470 			qdf_mc_timer_get_system_time() -
471 			scan_entry->hidden_ssid_timestamp;
472 		if (time_gap <= HIDDEN_SSID_TIME) {
473 			scan_params->hidden_ssid_timestamp =
474 				scan_entry->hidden_ssid_timestamp;
475 			scan_params->ssid.length =
476 				scan_entry->ssid.length;
477 			qdf_mem_copy(scan_params->ssid.ssid,
478 				scan_entry->ssid.ssid,
479 				scan_params->ssid.length);
480 		}
481 	}
482 
483 	/*
484 	 * Due to Rx sensitivity issue, sometime beacons are seen on adjacent
485 	 * channel so workaround in software is needed. If DS params or HT info
486 	 * are present driver can get proper channel info from these IEs and set
487 	 * channel_mismatch so that the older RSSI values are used in new entry.
488 	 *
489 	 * For the cases where DS params and HT info is not present, driver
490 	 * needs to check below conditions to get proper channel and set
491 	 * channel_mismatch so that the older RSSI values are used in new entry:
492 	 *   -- The old entry channel and new entry channel are not same
493 	 *   -- RSSI is less than -80, this indicate that the signal has leaked
494 	 *       in adjacent channel.
495 	 */
496 	if ((scan_params->frm_subtype == MGMT_SUBTYPE_BEACON) &&
497 	    !util_scan_entry_htinfo(scan_params) &&
498 	    !util_scan_entry_ds_param(scan_params) &&
499 	    (scan_params->channel.chan_idx != scan_entry->channel.chan_idx) &&
500 	    (scan_params->rssi_raw  < ADJACENT_CHANNEL_RSSI_THRESHOLD)) {
501 		scan_params->channel.chan_idx = scan_entry->channel.chan_idx;
502 		scan_params->channel_mismatch = true;
503 	}
504 
505 	/* Use old value for rssi if beacon was heard on adjacent channel. */
506 	if (scan_params->channel_mismatch) {
507 		scan_params->rssi_raw = scan_entry->rssi_raw;
508 		scan_params->avg_rssi = scan_entry->avg_rssi;
509 		scan_params->rssi_timestamp =
510 			scan_entry->rssi_timestamp;
511 	} else {
512 		/* If elapsed time since last rssi update for this
513 		 * entry is smaller than a thresold, calculate a
514 		 * running average of the RSSI values.
515 		 * Otherwise new frames RSSI is more representive
516 		 * of the signal strength.
517 		 */
518 		time_gap =
519 			scan_params->scan_entry_time -
520 			scan_entry->rssi_timestamp;
521 		if (time_gap > WLAN_RSSI_AVERAGING_TIME)
522 			scan_params->avg_rssi =
523 				WLAN_RSSI_IN(scan_params->rssi_raw);
524 		else {
525 			/* Copy previous average rssi to new entry */
526 			scan_params->avg_rssi = scan_entry->avg_rssi;
527 			/* Average with previous samples */
528 			WLAN_RSSI_LPF(scan_params->avg_rssi,
529 					scan_params->rssi_raw);
530 		}
531 
532 		scan_params->rssi_timestamp = scan_params->scan_entry_time;
533 	}
534 
535 	/* copy wsn ie from scan_entry to scan_params*/
536 	scm_update_alt_wcn_ie(scan_entry, scan_params);
537 
538 	/* copy mlme info from scan_entry to scan_params*/
539 	scm_update_mlme_info(scan_entry, scan_params);
540 
541 	/* Mark delete the duplicate node */
542 	scm_scan_entry_put_ref(scan_db, scan_node, true, true);
543 }
544 
545 /**
546  * scm_find_duplicate_and_del() - find duplicate entry if present
547  * and update it
548  * @scan_db: scan db
549  * @entry: input scan cache entry
550  *
551  * Return: true if entry is found and updated else false
552  */
553 static bool
554 scm_find_duplicate_and_del(struct scan_dbs *scan_db,
555 	struct scan_cache_entry *entry)
556 {
557 	uint8_t hash_idx;
558 	struct scan_cache_node *cur_node;
559 	struct scan_cache_node *next_node = NULL;
560 
561 	hash_idx = SCAN_GET_HASH(entry->bssid.bytes);
562 
563 	cur_node = scm_get_next_node(scan_db,
564 		   &scan_db->scan_hash_tbl[hash_idx], NULL);
565 
566 	while (cur_node) {
567 		if (util_is_scan_entry_match(entry,
568 		   cur_node->entry)) {
569 			scm_delete_duplicate_entry(scan_db,
570 				entry, cur_node);
571 			scm_scan_entry_put_ref(scan_db,
572 				cur_node, true, false);
573 			return true;
574 		}
575 		next_node = scm_get_next_node(scan_db,
576 			 &scan_db->scan_hash_tbl[hash_idx], cur_node);
577 		cur_node = next_node;
578 		next_node = NULL;
579 	}
580 
581 	return false;
582 }
583 
584 /**
585  * scm_add_update_entry() - add or update scan entry
586  * @psoc: psoc ptr
587  * @pdev: pdev pointer
588  * @scan_params: new received entry
589  *
590  * Return: QDF_STATUS
591  */
592 static QDF_STATUS scm_add_update_entry(struct wlan_objmgr_psoc *psoc,
593 	struct wlan_objmgr_pdev *pdev, struct scan_cache_entry *scan_params)
594 {
595 	QDF_STATUS status;
596 	struct scan_dbs *scan_db;
597 	struct wlan_scan_obj *scan_obj;
598 
599 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
600 	if (!scan_db) {
601 		scm_err("scan_db is NULL");
602 		return QDF_STATUS_E_INVAL;
603 	}
604 
605 	scan_obj = wlan_psoc_get_scan_obj(psoc);
606 	if (!scan_obj) {
607 		scm_err("scan_obj is NULL");
608 		return QDF_STATUS_E_INVAL;
609 	}
610 
611 	if (scan_params->frm_subtype ==
612 	   MGMT_SUBTYPE_PROBE_RESP &&
613 	   !scan_params->ie_list.ssid)
614 		scm_info("Probe resp doesnt contain SSID");
615 
616 
617 	if (scan_params->ie_list.csa ||
618 	   scan_params->ie_list.xcsa ||
619 	   scan_params->ie_list.cswrp)
620 		scm_info("CSA IE present for BSSID: %pM",
621 			scan_params->bssid.bytes);
622 
623 	scm_find_duplicate_and_del(scan_db, scan_params);
624 
625 	if (scan_obj->cb.inform_beacon)
626 		scan_obj->cb.inform_beacon(pdev, scan_params);
627 
628 	status = scm_add_scan_entry(scan_db, scan_params);
629 
630 	return status;
631 }
632 
633 QDF_STATUS scm_handle_bcn_probe(struct scheduler_msg *msg)
634 {
635 	struct scan_bcn_probe_event *bcn;
636 	struct wlan_objmgr_psoc *psoc;
637 	struct wlan_objmgr_pdev *pdev = NULL;
638 	struct scan_cache_entry *scan_entry;
639 	struct wlan_scan_obj *scan_obj;
640 	qdf_list_t *scan_list = NULL;
641 	QDF_STATUS status = QDF_STATUS_SUCCESS;
642 	uint32_t list_count, i;
643 	qdf_list_node_t *next_node = NULL;
644 	struct scan_cache_node *scan_node;
645 
646 	bcn = msg->bodyptr;
647 	if (!bcn) {
648 		scm_err("bcn is NULL");
649 		return QDF_STATUS_E_INVAL;
650 	}
651 	if (!bcn->rx_data) {
652 		scm_err("rx_data iS NULL");
653 		status = QDF_STATUS_E_INVAL;
654 		goto free_nbuf;
655 	}
656 	if (!bcn->buf) {
657 		scm_err("buf is NULL");
658 		status = QDF_STATUS_E_INVAL;
659 		goto free_nbuf;
660 	}
661 
662 	psoc = bcn->psoc;
663 	pdev = wlan_objmgr_get_pdev_by_id(psoc,
664 			   bcn->rx_data->pdev_id, WLAN_SCAN_ID);
665 	if (!pdev) {
666 		scm_err("pdev is NULL");
667 		status = QDF_STATUS_E_INVAL;
668 		goto free_nbuf;
669 	}
670 	scan_obj = wlan_psoc_get_scan_obj(psoc);
671 	if (!scan_obj) {
672 		scm_err("scan_obj is NULL");
673 		status = QDF_STATUS_E_INVAL;
674 		goto free_nbuf;
675 	}
676 
677 	if (qdf_nbuf_len(bcn->buf) <=
678 	   (sizeof(struct wlan_frame_hdr) +
679 	   offsetof(struct wlan_bcn_frame, ie))) {
680 		scm_err("invalid beacon/probe length");
681 		status = QDF_STATUS_E_INVAL;
682 		goto free_nbuf;
683 	}
684 
685 	scan_list =
686 		 util_scan_unpack_beacon_frame(qdf_nbuf_data(bcn->buf),
687 			qdf_nbuf_len(bcn->buf), bcn->frm_type,
688 			bcn->rx_data);
689 	if (!scan_list || qdf_list_empty(scan_list)) {
690 		scm_err("failed to unpack frame");
691 		status = QDF_STATUS_E_INVAL;
692 		goto free_nbuf;
693 	}
694 
695 	list_count = qdf_list_size(scan_list);
696 	for (i = 0; i < list_count; i++) {
697 		status = qdf_list_remove_front(scan_list, &next_node);
698 		if (QDF_IS_STATUS_ERROR(status) || next_node == NULL) {
699 			scm_err("failed to unpack frame");
700 			status = QDF_STATUS_E_INVAL;
701 			goto free_nbuf;
702 		}
703 
704 		scan_node = qdf_container_of(next_node,
705 			struct scan_cache_node, node);
706 
707 		scan_entry = scan_node->entry;
708 
709 		scm_debug("Received %s from BSSID: %pM tsf_delta = %u Seq Num: %x  ssid:%.*s, rssi: %d",
710 			  (bcn->frm_type == MGMT_SUBTYPE_PROBE_RESP) ?
711 			  "Probe Rsp" : "Beacon", scan_entry->bssid.bytes,
712 			  scan_entry->tsf_delta, scan_entry->seq_num,
713 			  scan_entry->ssid.length, scan_entry->ssid.ssid,
714 			  scan_entry->rssi_raw);
715 
716 		if (scan_obj->drop_bcn_on_chan_mismatch &&
717 			scan_entry->channel_mismatch) {
718 			scm_debug("Drop frame, as channel mismatch Received for from BSSID: %pM ",
719 				   scan_entry->bssid.bytes);
720 			util_scan_free_cache_entry(scan_entry);
721 			qdf_mem_free(scan_node);
722 			continue;
723 		}
724 
725 		if (scan_obj->cb.update_beacon)
726 			scan_obj->cb.update_beacon(pdev, scan_entry);
727 
728 		if (wlan_reg_11d_enabled_on_host(psoc))
729 			scm_11d_handle_country_info(psoc, pdev, scan_entry);
730 
731 		status = scm_add_update_entry(psoc, pdev, scan_entry);
732 		if (QDF_IS_STATUS_ERROR(status)) {
733 			scm_debug("failed to add entry for BSSID: %pM",
734 				  scan_entry->bssid.bytes);
735 			util_scan_free_cache_entry(scan_entry);
736 			qdf_mem_free(scan_node);
737 			continue;
738 		}
739 
740 		qdf_mem_free(scan_node);
741 	}
742 
743 free_nbuf:
744 	if (scan_list)
745 		qdf_mem_free(scan_list);
746 	if (bcn->psoc)
747 		wlan_objmgr_psoc_release_ref(bcn->psoc, WLAN_SCAN_ID);
748 	if (pdev)
749 		wlan_objmgr_pdev_release_ref(pdev, WLAN_SCAN_ID);
750 	if (bcn->rx_data)
751 		qdf_mem_free(bcn->rx_data);
752 	if (bcn->buf)
753 		qdf_nbuf_free(bcn->buf);
754 	qdf_mem_free(bcn);
755 
756 	return status;
757 }
758 
759 /**
760  * scm_list_insert_sorted() - add the entries in scan_list in sorted way
761  * @psoc: psoc ptr
762  * @filter: scan filter
763  * @scan_node: node entry to be inserted
764  * @scan_list: Temp scan list
765  *
766  * Add the entries in scan_list in sorted way considering
767  * cap_val and prefer val. The node is copy of original scan entry and
768  * thus no lock is required.
769  *
770  * Return: void
771  */
772 static void scm_list_insert_sorted(struct wlan_objmgr_psoc *psoc,
773 	struct scan_filter *filter,
774 	struct scan_cache_node *scan_node,
775 	qdf_list_t *scan_list)
776 {
777 	struct scan_cache_node *cur_node;
778 	qdf_list_node_t *cur_lst = NULL, *next_lst = NULL;
779 	struct scan_default_params *params;
780 	int pcl_chan_weight = 0;
781 
782 	params = wlan_scan_psoc_get_def_params(psoc);
783 	if (!params) {
784 		scm_err("wlan_scan_psoc_get_def_params failed");
785 		return;
786 	}
787 
788 	if (filter->num_of_pcl_channels > 0 &&
789 			(scan_node->entry->rssi_raw > SCM_PCL_RSSI_THRESHOLD)) {
790 		if (scm_get_pcl_weight_of_channel(
791 					scan_node->entry->channel.chan_idx,
792 					filter, &pcl_chan_weight,
793 					filter->pcl_weight_list)) {
794 			scm_debug("pcl channel %d pcl_chan_weight %d",
795 					scan_node->entry->channel.chan_idx,
796 					pcl_chan_weight);
797 		}
798 	}
799 	if (params->is_bssid_hint_priority &&
800 	    !qdf_mem_cmp(filter->bssid_hint.bytes,
801 			 scan_node->entry->bssid.bytes,
802 			 QDF_MAC_ADDR_SIZE))
803 		scan_node->entry->bss_score = BEST_CANDIDATE_MAX_BSS_SCORE;
804 	else
805 		scm_calculate_bss_score(psoc, params,
806 					scan_node->entry, pcl_chan_weight);
807 
808 	if (qdf_list_empty(scan_list)) {
809 		qdf_list_insert_front(scan_list, &scan_node->node);
810 		return;
811 	}
812 
813 	qdf_list_peek_front(scan_list, &cur_lst);
814 
815 	while (cur_lst) {
816 		cur_node = qdf_container_of(cur_lst,
817 				struct scan_cache_node, node);
818 		if (scm_is_better_bss(params,
819 		   scan_node->entry, cur_node->entry)) {
820 			qdf_list_insert_before(scan_list,
821 				&scan_node->node,
822 				&cur_node->node);
823 			break;
824 		}
825 		qdf_list_peek_next(scan_list,
826 			cur_lst, &next_lst);
827 		cur_lst = next_lst;
828 		next_lst = NULL;
829 	}
830 
831 	if (!cur_lst)
832 		qdf_list_insert_back(scan_list,
833 			&scan_node->node);
834 
835 }
836 
837 /**
838  * scm_scan_apply_filter_get_entry() - apply filter and get the
839  * scan entry
840  * @psoc: psoc pointer
841  * @db_entry: scan entry
842  * @filter: filter to be applied
843  * @scan_list: scan list to which entry is added
844  *
845  * Return: QDF_STATUS
846  */
847 static QDF_STATUS
848 scm_scan_apply_filter_get_entry(struct wlan_objmgr_psoc *psoc,
849 	struct scan_cache_entry *db_entry,
850 	struct scan_filter *filter,
851 	qdf_list_t *scan_list)
852 {
853 	struct scan_cache_node *scan_node = NULL;
854 	struct security_info security = {0};
855 	bool match;
856 
857 	if (!filter)
858 		match = true;
859 	else
860 		match = scm_filter_match(psoc, db_entry,
861 					filter, &security);
862 
863 	if (!match)
864 		return QDF_STATUS_SUCCESS;
865 
866 	scan_node = qdf_mem_malloc(sizeof(*scan_node));
867 	if (!scan_node)
868 		return QDF_STATUS_E_NOMEM;
869 
870 	scan_node->entry =
871 		util_scan_copy_cache_entry(db_entry);
872 
873 	if (!scan_node->entry) {
874 		qdf_mem_free(scan_node);
875 		return QDF_STATUS_E_NOMEM;
876 	}
877 
878 	qdf_mem_copy(&scan_node->entry->neg_sec_info,
879 		&security, sizeof(scan_node->entry->neg_sec_info));
880 
881 	if (!filter || !filter->bss_scoring_required)
882 		qdf_list_insert_front(scan_list,
883 			&scan_node->node);
884 	else
885 		scm_list_insert_sorted(psoc, filter, scan_node, scan_list);
886 
887 	return QDF_STATUS_SUCCESS;
888 }
889 
890 /**
891  * scm_get_results() - Iterate and get scan results
892  * @psoc: psoc ptr
893  * @scan_db: scan db
894  * @filter: filter to be applied
895  * @scan_list: scan list to which entry is added
896  *
897  * Return: void
898  */
899 static void scm_get_results(struct wlan_objmgr_psoc *psoc,
900 	struct scan_dbs *scan_db, struct scan_filter *filter,
901 	qdf_list_t *scan_list)
902 {
903 	int i, count;
904 	struct scan_cache_node *cur_node;
905 	struct scan_cache_node *next_node = NULL;
906 
907 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
908 		cur_node = scm_get_next_node(scan_db,
909 			   &scan_db->scan_hash_tbl[i], NULL);
910 		count = qdf_list_size(&scan_db->scan_hash_tbl[i]);
911 		if (!count)
912 			continue;
913 		while (cur_node) {
914 			scm_scan_apply_filter_get_entry(psoc,
915 				cur_node->entry, filter, scan_list);
916 			next_node = scm_get_next_node(scan_db,
917 				&scan_db->scan_hash_tbl[i], cur_node);
918 			cur_node = next_node;
919 		}
920 	}
921 }
922 
923 QDF_STATUS scm_purge_scan_results(qdf_list_t *scan_list)
924 {
925 	QDF_STATUS status;
926 	struct scan_cache_node *cur_node;
927 	qdf_list_node_t *cur_lst = NULL, *next_lst = NULL;
928 
929 	if (!scan_list) {
930 		scm_err("scan_result is NULL");
931 		return QDF_STATUS_E_INVAL;
932 	}
933 
934 	status = qdf_list_peek_front(scan_list, &cur_lst);
935 
936 	while (cur_lst) {
937 		qdf_list_peek_next(
938 			scan_list, cur_lst, &next_lst);
939 		cur_node = qdf_container_of(cur_lst,
940 			struct scan_cache_node, node);
941 		status = qdf_list_remove_node(scan_list,
942 					cur_lst);
943 		if (QDF_IS_STATUS_SUCCESS(status)) {
944 			util_scan_free_cache_entry(cur_node->entry);
945 			qdf_mem_free(cur_node);
946 		}
947 		cur_lst = next_lst;
948 		next_lst = NULL;
949 	}
950 
951 	qdf_list_destroy(scan_list);
952 	qdf_mem_free(scan_list);
953 
954 	return status;
955 }
956 
957 qdf_list_t *scm_get_scan_result(struct wlan_objmgr_pdev *pdev,
958 	struct scan_filter *filter)
959 {
960 	struct wlan_objmgr_psoc *psoc;
961 	struct scan_dbs *scan_db;
962 	qdf_list_t *tmp_list;
963 
964 	if (!pdev) {
965 		scm_err("pdev is NULL");
966 		return NULL;
967 	}
968 
969 	psoc = wlan_pdev_get_psoc(pdev);
970 	if (!psoc) {
971 		scm_err("psoc is NULL");
972 		return NULL;
973 	}
974 
975 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
976 	if (!scan_db) {
977 		scm_err("scan_db is NULL");
978 		return NULL;
979 	}
980 
981 	tmp_list = qdf_mem_malloc(sizeof(*tmp_list));
982 	if (!tmp_list) {
983 		scm_err("failed tp allocate scan_result");
984 		return NULL;
985 	}
986 	qdf_list_create(tmp_list,
987 			MAX_SCAN_CACHE_SIZE);
988 	scm_age_out_entries(psoc, scan_db);
989 	scm_get_results(psoc, scan_db, filter, tmp_list);
990 
991 	return tmp_list;
992 }
993 
994 /**
995  * scm_iterate_db_and_call_func() - iterate and call the func
996  * @scan_db: scan db
997  * @func: func to be called
998  * @arg: func arg
999  *
1000  * Return: QDF_STATUS
1001  */
1002 static QDF_STATUS
1003 scm_iterate_db_and_call_func(struct scan_dbs *scan_db,
1004 	scan_iterator_func func, void *arg)
1005 {
1006 	int i;
1007 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1008 	struct scan_cache_node *cur_node;
1009 	struct scan_cache_node *next_node = NULL;
1010 
1011 	if (!func)
1012 		return QDF_STATUS_E_INVAL;
1013 
1014 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1015 		cur_node = scm_get_next_node(scan_db,
1016 			&scan_db->scan_hash_tbl[i], NULL);
1017 		while (cur_node) {
1018 			status = func(arg, cur_node->entry);
1019 			if (QDF_IS_STATUS_ERROR(status)) {
1020 				scm_scan_entry_put_ref(scan_db,
1021 					cur_node, true, false);
1022 				return status;
1023 			}
1024 			next_node = scm_get_next_node(scan_db,
1025 				&scan_db->scan_hash_tbl[i], cur_node);
1026 			cur_node = next_node;
1027 		}
1028 	}
1029 
1030 	return status;
1031 }
1032 
1033 QDF_STATUS
1034 scm_iterate_scan_db(struct wlan_objmgr_pdev *pdev,
1035 	scan_iterator_func func, void *arg)
1036 {
1037 	struct wlan_objmgr_psoc *psoc;
1038 	struct scan_dbs *scan_db;
1039 	QDF_STATUS status;
1040 
1041 	if (!func) {
1042 		scm_err("func is NULL");
1043 		return QDF_STATUS_E_INVAL;
1044 	}
1045 
1046 	if (!pdev) {
1047 		scm_err("pdev is NULL");
1048 		return QDF_STATUS_E_INVAL;
1049 	}
1050 
1051 	psoc = wlan_pdev_get_psoc(pdev);
1052 	if (!psoc) {
1053 		scm_err("psoc is NULL");
1054 		return QDF_STATUS_E_INVAL;
1055 	}
1056 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1057 	if (!scan_db) {
1058 		scm_err("scan_db is NULL");
1059 		return QDF_STATUS_E_INVAL;
1060 	}
1061 
1062 	scm_age_out_entries(psoc, scan_db);
1063 	status = scm_iterate_db_and_call_func(scan_db, func, arg);
1064 
1065 	return status;
1066 }
1067 
1068 /**
1069  * scm_scan_apply_filter_flush_entry() -flush scan entries depending
1070  * on filter
1071  * @psoc: psoc ptr
1072  * @scan_db: scan db
1073  * @db_node: node on which filters are applied
1074  * @filter: filter to be applied
1075  *
1076  * Return: QDF_STATUS
1077  */
1078 static QDF_STATUS
1079 scm_scan_apply_filter_flush_entry(struct wlan_objmgr_psoc *psoc,
1080 	struct scan_dbs *scan_db,
1081 	struct scan_cache_node *db_node,
1082 	struct scan_filter *filter)
1083 {
1084 	struct security_info security = {0};
1085 	bool match;
1086 
1087 	if (!filter)
1088 		match = true;
1089 	else
1090 		match = scm_filter_match(psoc, db_node->entry,
1091 					filter, &security);
1092 
1093 	if (!match)
1094 		return QDF_STATUS_SUCCESS;
1095 
1096 	scm_scan_entry_put_ref(scan_db, db_node, true, true);
1097 
1098 	return QDF_STATUS_SUCCESS;
1099 }
1100 
1101 /**
1102  * scm_flush_scan_entries() - API to flush scan entries depending on filters
1103  * @psoc: psoc ptr
1104  * @scan_db: scan db
1105  * @filter: filter
1106  *
1107  * Return: void
1108  */
1109 static void scm_flush_scan_entries(struct wlan_objmgr_psoc *psoc,
1110 	struct scan_dbs *scan_db,
1111 	struct scan_filter *filter)
1112 {
1113 	int i;
1114 	struct scan_cache_node *cur_node;
1115 	struct scan_cache_node *next_node = NULL;
1116 
1117 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1118 		cur_node = scm_get_next_node(scan_db,
1119 			   &scan_db->scan_hash_tbl[i], NULL);
1120 		while (cur_node) {
1121 			scm_scan_apply_filter_flush_entry(psoc, scan_db,
1122 				cur_node, filter);
1123 			next_node = scm_get_next_node(scan_db,
1124 				&scan_db->scan_hash_tbl[i], cur_node);
1125 			cur_node = next_node;
1126 		}
1127 	}
1128 }
1129 
1130 QDF_STATUS scm_flush_results(struct wlan_objmgr_pdev *pdev,
1131 	struct scan_filter *filter)
1132 {
1133 	struct wlan_objmgr_psoc *psoc;
1134 	struct scan_dbs *scan_db;
1135 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1136 
1137 	if (!pdev) {
1138 		scm_err("pdev is NULL");
1139 		return QDF_STATUS_E_INVAL;
1140 	}
1141 
1142 	psoc = wlan_pdev_get_psoc(pdev);
1143 	if (!psoc) {
1144 		scm_err("psoc is NULL");
1145 		return QDF_STATUS_E_INVAL;
1146 	}
1147 
1148 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1149 	if (!scan_db) {
1150 		scm_err("scan_db is NULL");
1151 		return QDF_STATUS_E_INVAL;
1152 	}
1153 
1154 	scm_flush_scan_entries(psoc, scan_db, filter);
1155 
1156 	return status;
1157 }
1158 
1159 /**
1160  * scm_filter_channels() - Remove entries not belonging to channel list
1161  * @scan_db: scan db
1162  * @db_node: node on which filters are applied
1163  * @chan_list: valid channel list
1164  * @num_chan: number of channels
1165  *
1166  * Return: QDF_STATUS
1167  */
1168 static void scm_filter_channels(struct scan_dbs *scan_db,
1169 	struct scan_cache_node *db_node,
1170 	uint8_t *chan_list, uint32_t num_chan)
1171 {
1172 	int i;
1173 	bool match = false;
1174 
1175 	for (i = 0; i < num_chan; i++) {
1176 		if (chan_list[i] ==
1177 		   util_scan_entry_channel_num(db_node->entry)) {
1178 			match = true;
1179 			break;
1180 		}
1181 	}
1182 
1183 	if (!match)
1184 		scm_scan_entry_put_ref(scan_db, db_node, true, true);
1185 
1186 }
1187 
1188 void scm_filter_valid_channel(struct wlan_objmgr_pdev *pdev,
1189 	uint8_t *chan_list, uint32_t num_chan)
1190 {
1191 	int i;
1192 	struct wlan_objmgr_psoc *psoc;
1193 	struct scan_dbs *scan_db;
1194 	struct scan_cache_node *cur_node;
1195 	struct scan_cache_node *next_node = NULL;
1196 
1197 	scm_info("num_chan = %d", num_chan);
1198 
1199 	if (!pdev) {
1200 		scm_err("pdev is NULL");
1201 		return;
1202 	}
1203 
1204 	psoc = wlan_pdev_get_psoc(pdev);
1205 	if (!psoc) {
1206 		scm_err("psoc is NULL");
1207 		return;
1208 	}
1209 
1210 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1211 	if (!scan_db) {
1212 		scm_err("scan_db is NULL");
1213 		return;
1214 	}
1215 
1216 	for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
1217 		cur_node = scm_get_next_node(scan_db,
1218 			   &scan_db->scan_hash_tbl[i], NULL);
1219 		while (cur_node) {
1220 			scm_filter_channels(scan_db,
1221 				cur_node, chan_list, num_chan);
1222 			next_node = scm_get_next_node(scan_db,
1223 				&scan_db->scan_hash_tbl[i], cur_node);
1224 			cur_node = next_node;
1225 		}
1226 	}
1227 }
1228 
1229 QDF_STATUS scm_scan_register_bcn_cb(struct wlan_objmgr_psoc *psoc,
1230 	update_beacon_cb cb, enum scan_cb_type type)
1231 {
1232 	struct wlan_scan_obj *scan_obj;
1233 
1234 	scan_obj = wlan_psoc_get_scan_obj(psoc);
1235 	if (!scan_obj) {
1236 		scm_err("scan obj is NULL");
1237 		return QDF_STATUS_E_INVAL;
1238 	}
1239 	switch (type) {
1240 	case SCAN_CB_TYPE_INFORM_BCN:
1241 		scan_obj->cb.inform_beacon = cb;
1242 		break;
1243 	case SCAN_CB_TYPE_UPDATE_BCN:
1244 		scan_obj->cb.update_beacon = cb;
1245 		break;
1246 	default:
1247 		scm_err("invalid cb type %d", type);
1248 	}
1249 
1250 	return QDF_STATUS_SUCCESS;
1251 }
1252 
1253 QDF_STATUS scm_db_init(struct wlan_objmgr_psoc *psoc)
1254 {
1255 	int i, j;
1256 	struct scan_dbs *scan_db;
1257 
1258 	if (!psoc) {
1259 		scm_err("psoc is NULL");
1260 		return QDF_STATUS_E_INVAL;
1261 	}
1262 
1263 	/* Initialize the scan database per pdev */
1264 	for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) {
1265 		scan_db = wlan_pdevid_get_scan_db(psoc, i);
1266 		if (!scan_db) {
1267 			scm_err("scan_db is NULL %d", i);
1268 			continue;
1269 		}
1270 		scan_db->num_entries = 0;
1271 		qdf_spinlock_create(&scan_db->scan_db_lock);
1272 		for (j = 0; j < SCAN_HASH_SIZE; j++)
1273 			qdf_list_create(&scan_db->scan_hash_tbl[j],
1274 				MAX_SCAN_CACHE_SIZE);
1275 	}
1276 
1277 	return QDF_STATUS_SUCCESS;
1278 }
1279 
1280 QDF_STATUS scm_db_deinit(struct wlan_objmgr_psoc *psoc)
1281 {
1282 	int i, j;
1283 	struct scan_dbs *scan_db;
1284 
1285 	if (!psoc) {
1286 		scm_err("scan obj is NULL");
1287 		return QDF_STATUS_E_INVAL;
1288 	}
1289 
1290 	/* Initialize the scan database per pdev */
1291 	for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) {
1292 		scan_db = wlan_pdevid_get_scan_db(psoc, i);
1293 		if (!scan_db) {
1294 			scm_err("scan_db is NULL %d", i);
1295 			continue;
1296 		}
1297 
1298 		scm_flush_scan_entries(psoc, scan_db, NULL);
1299 		for (j = 0; j < SCAN_HASH_SIZE; j++)
1300 			qdf_list_destroy(&scan_db->scan_hash_tbl[j]);
1301 		qdf_spinlock_destroy(&scan_db->scan_db_lock);
1302 	}
1303 
1304 	return QDF_STATUS_SUCCESS;
1305 }
1306 
1307 QDF_STATUS scm_update_scan_mlme_info(struct wlan_objmgr_pdev *pdev,
1308 	struct scan_cache_entry *entry)
1309 {
1310 	uint8_t hash_idx;
1311 	struct scan_dbs *scan_db;
1312 	struct scan_cache_node *cur_node;
1313 	struct scan_cache_node *next_node = NULL;
1314 	struct wlan_objmgr_psoc *psoc;
1315 
1316 	psoc = wlan_pdev_get_psoc(pdev);
1317 	if (!psoc) {
1318 		scm_err("psoc is NULL");
1319 		return QDF_STATUS_E_INVAL;
1320 	}
1321 	scan_db = wlan_pdev_get_scan_db(psoc, pdev);
1322 	if (!scan_db) {
1323 		scm_err("scan_db is NULL");
1324 		return QDF_STATUS_E_INVAL;
1325 	}
1326 
1327 	hash_idx = SCAN_GET_HASH(entry->bssid.bytes);
1328 
1329 	cur_node = scm_get_next_node(scan_db,
1330 			&scan_db->scan_hash_tbl[hash_idx], NULL);
1331 
1332 	while (cur_node) {
1333 		if (util_is_scan_entry_match(entry,
1334 					cur_node->entry)) {
1335 			/* Acquire db lock to prevent simultaneous update */
1336 			qdf_spin_lock_bh(&scan_db->scan_db_lock);
1337 			scm_update_mlme_info(entry, cur_node->entry);
1338 			qdf_spin_unlock_bh(&scan_db->scan_db_lock);
1339 			scm_scan_entry_put_ref(scan_db,
1340 					cur_node, true, false);
1341 			return QDF_STATUS_SUCCESS;
1342 		}
1343 		next_node = scm_get_next_node(scan_db,
1344 				&scan_db->scan_hash_tbl[hash_idx], cur_node);
1345 		cur_node = next_node;
1346 	}
1347 
1348 	return QDF_STATUS_E_INVAL;
1349 }
1350