xref: /wlan-dirver/qca-wifi-host-cmn/umac/scan/dispatcher/src/wlan_scan_utils_api.c (revision 901120c066e139c7f8a2c8e4820561fdd83c67ef)
1 /*
2  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /*
21  * DOC: Defines scan utility functions
22  */
23 
24 #include <wlan_cmn.h>
25 #include <wlan_scan_ucfg_api.h>
26 #include <wlan_scan_utils_api.h>
27 #include <../../core/src/wlan_scan_cache_db.h>
28 #include <../../core/src/wlan_scan_main.h>
29 #include <wlan_reg_services_api.h>
30 #if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD)
31 #include <wlan_mlme_api.h>
32 #endif
33 #ifdef WLAN_FEATURE_11BE_MLO
34 #include <wlan_utility.h>
35 #endif
36 #include "wlan_psoc_mlme_api.h"
37 #include "reg_services_public_struct.h"
38 
39 #define MAX_IE_LEN 1024
40 #define SHORT_SSID_LEN 4
41 #define NEIGHBOR_AP_LEN 1
42 #define BSS_PARAMS_LEN 1
43 
44 const char*
45 util_scan_get_ev_type_name(enum scan_event_type type)
46 {
47 	static const char * const event_name[] = {
48 		[SCAN_EVENT_TYPE_STARTED] = "STARTED",
49 		[SCAN_EVENT_TYPE_COMPLETED] = "COMPLETED",
50 		[SCAN_EVENT_TYPE_BSS_CHANNEL] = "HOME_CHANNEL",
51 		[SCAN_EVENT_TYPE_FOREIGN_CHANNEL] = "FOREIGN_CHANNEL",
52 		[SCAN_EVENT_TYPE_DEQUEUED] = "DEQUEUED",
53 		[SCAN_EVENT_TYPE_PREEMPTED] = "PREEMPTED",
54 		[SCAN_EVENT_TYPE_START_FAILED] = "START_FAILED",
55 		[SCAN_EVENT_TYPE_RESTARTED] = "RESTARTED",
56 		[SCAN_EVENT_TYPE_FOREIGN_CHANNEL_EXIT] = "FOREIGN_CHANNEL_EXIT",
57 		[SCAN_EVENT_TYPE_SUSPENDED] = "SUSPENDED",
58 		[SCAN_EVENT_TYPE_RESUMED] = "RESUMED",
59 		[SCAN_EVENT_TYPE_NLO_COMPLETE] = "NLO_COMPLETE",
60 		[SCAN_EVENT_TYPE_NLO_MATCH] = "NLO_MATCH",
61 		[SCAN_EVENT_TYPE_INVALID] = "INVALID",
62 		[SCAN_EVENT_TYPE_GPIO_TIMEOUT] = "GPIO_TIMEOUT",
63 		[SCAN_EVENT_TYPE_RADIO_MEASUREMENT_START] =
64 			"RADIO_MEASUREMENT_START",
65 		[SCAN_EVENT_TYPE_RADIO_MEASUREMENT_END] =
66 			"RADIO_MEASUREMENT_END",
67 		[SCAN_EVENT_TYPE_BSSID_MATCH] = "BSSID_MATCH",
68 		[SCAN_EVENT_TYPE_FOREIGN_CHANNEL_GET_NF] =
69 			"FOREIGN_CHANNEL_GET_NF",
70 	};
71 
72 	if (type >= SCAN_EVENT_TYPE_MAX)
73 		return "UNKNOWN";
74 
75 	return event_name[type];
76 }
77 
78 
79 const char*
80 util_scan_get_ev_reason_name(enum scan_completion_reason reason)
81 {
82 	static const char * const reason_name[] = {
83 		[SCAN_REASON_NONE] = "NONE",
84 		[SCAN_REASON_COMPLETED] = "COMPLETED",
85 		[SCAN_REASON_CANCELLED] = "CANCELLED",
86 		[SCAN_REASON_PREEMPTED] = "PREEMPTED",
87 		[SCAN_REASON_TIMEDOUT] = "TIMEDOUT",
88 		[SCAN_REASON_INTERNAL_FAILURE] = "INTERNAL_FAILURE",
89 		[SCAN_REASON_SUSPENDED] = "SUSPENDED",
90 		[SCAN_REASON_RUN_FAILED] = "RUN_FAILED",
91 		[SCAN_REASON_TERMINATION_FUNCTION] = "TERMINATION_FUNCTION",
92 		[SCAN_REASON_MAX_OFFCHAN_RETRIES] = "MAX_OFFCHAN_RETRIES",
93 		[SCAN_REASON_DFS_VIOLATION] = "DFS_NOL_VIOLATION",
94 	};
95 
96 	if (reason >= SCAN_REASON_MAX)
97 		return "UNKNOWN";
98 
99 	return reason_name[reason];
100 }
101 
102 qdf_time_t
103 util_get_last_scan_time(struct wlan_objmgr_vdev *vdev)
104 {
105 	uint8_t pdev_id;
106 	struct wlan_scan_obj *scan_obj;
107 
108 	if (!vdev) {
109 		scm_warn("null vdev");
110 		QDF_ASSERT(0);
111 		return 0;
112 	}
113 	pdev_id = wlan_scan_vdev_get_pdev_id(vdev);
114 	scan_obj = wlan_vdev_get_scan_obj(vdev);
115 
116 	if (scan_obj)
117 		return scan_obj->pdev_info[pdev_id].last_scan_time;
118 	else
119 		return 0;
120 }
121 
122 enum wlan_band util_scan_scm_freq_to_band(uint16_t freq)
123 {
124 	if (WLAN_REG_IS_24GHZ_CH_FREQ(freq))
125 		return WLAN_BAND_2_4_GHZ;
126 
127 	return WLAN_BAND_5_GHZ;
128 }
129 
130 bool util_is_scan_entry_match(
131 	struct scan_cache_entry *entry1,
132 	struct scan_cache_entry *entry2)
133 {
134 
135 	if (entry1->cap_info.wlan_caps.ess !=
136 	   entry2->cap_info.wlan_caps.ess)
137 		return false;
138 
139 	if (entry1->cap_info.wlan_caps.ess &&
140 	   !qdf_mem_cmp(entry1->bssid.bytes,
141 	   entry2->bssid.bytes, QDF_MAC_ADDR_SIZE)) {
142 		/* Check for BSS */
143 		if (util_is_ssid_match(&entry1->ssid, &entry2->ssid) ||
144 		    util_scan_is_null_ssid(&entry1->ssid) ||
145 		    util_scan_is_null_ssid(&entry2->ssid))
146 			return true;
147 	} else if (entry1->cap_info.wlan_caps.ibss &&
148 	   (entry1->channel.chan_freq ==
149 	   entry2->channel.chan_freq)) {
150 		/*
151 		 * Same channel cannot have same SSID for
152 		 * different IBSS, so no need to check BSSID
153 		 */
154 		if (util_is_ssid_match(
155 		   &entry1->ssid, &entry2->ssid))
156 			return true;
157 	} else if (!entry1->cap_info.wlan_caps.ibss &&
158 	   !entry1->cap_info.wlan_caps.ess &&
159 	   !qdf_mem_cmp(entry1->bssid.bytes,
160 	   entry2->bssid.bytes, QDF_MAC_ADDR_SIZE)) {
161 		/* In case of P2P devices, ess and ibss will be set to zero */
162 		return true;
163 	}
164 
165 	return false;
166 }
167 
168 static bool util_is_pureg_rate(uint8_t *rates, uint8_t nrates)
169 {
170 	static const uint8_t g_rates[] = {12, 18, 24, 36, 48, 72, 96, 108};
171 	bool pureg = false;
172 	uint8_t i, j;
173 
174 	for (i = 0; i < nrates; i++) {
175 		for (j = 0; j < QDF_ARRAY_SIZE(g_rates); j++) {
176 			if (WLAN_RV(rates[i]) == g_rates[j]) {
177 				pureg = true;
178 				break;
179 			}
180 		}
181 		if (pureg)
182 			break;
183 	}
184 
185 	return pureg;
186 }
187 
188 #ifdef WLAN_FEATURE_11BE
189 static enum wlan_phymode
190 util_scan_get_phymode_11be(struct wlan_objmgr_pdev *pdev,
191 			   struct scan_cache_entry *scan_params,
192 			   enum wlan_phymode phymode,
193 			   uint8_t band_mask)
194 {
195 	struct wlan_ie_ehtops *eht_ops;
196 	uint8_t width;
197 
198 	eht_ops = (struct wlan_ie_ehtops *)util_scan_entry_ehtop(scan_params);
199 	if (!util_scan_entry_ehtcap(scan_params) || !eht_ops)
200 		return phymode;
201 
202 	if (QDF_GET_BITS(eht_ops->ehtop_param,
203 			 EHTOP_INFO_PRESENT_IDX, EHTOP_INFO_PRESENT_BITS)) {
204 		width = QDF_GET_BITS(eht_ops->control,
205 				     EHTOP_INFO_CHAN_WIDTH_IDX,
206 				     EHTOP_INFO_CHAN_WIDTH_BITS);
207 		switch (width) {
208 		case WLAN_EHT_CHWIDTH_20:
209 			phymode = WLAN_PHYMODE_11BEA_EHT20;
210 			break;
211 		case WLAN_EHT_CHWIDTH_40:
212 			phymode = WLAN_PHYMODE_11BEA_EHT40;
213 			break;
214 		case WLAN_EHT_CHWIDTH_80:
215 			phymode = WLAN_PHYMODE_11BEA_EHT80;
216 			break;
217 		case WLAN_EHT_CHWIDTH_160:
218 			phymode = WLAN_PHYMODE_11BEA_EHT160;
219 			break;
220 		case WLAN_EHT_CHWIDTH_320:
221 			phymode = WLAN_PHYMODE_11BEA_EHT320;
222 			break;
223 		default:
224 			scm_debug("Invalid eht_ops width: %d", width);
225 			phymode = WLAN_PHYMODE_11BEA_EHT20;
226 			break;
227 		}
228 	} else {
229 		switch (phymode) {
230 		case WLAN_PHYMODE_11AXA_HE20:
231 			phymode = WLAN_PHYMODE_11BEA_EHT20;
232 			break;
233 		case WLAN_PHYMODE_11AXG_HE20:
234 			phymode = WLAN_PHYMODE_11BEG_EHT20;
235 			break;
236 		case WLAN_PHYMODE_11AXA_HE40:
237 			phymode = WLAN_PHYMODE_11BEA_EHT40;
238 			break;
239 		case WLAN_PHYMODE_11AXG_HE40:
240 			phymode = WLAN_PHYMODE_11BEG_EHT40;
241 			break;
242 		case WLAN_PHYMODE_11AXA_HE80:
243 			phymode = WLAN_PHYMODE_11BEA_EHT80;
244 			break;
245 		case WLAN_PHYMODE_11AXA_HE160:
246 			phymode = WLAN_PHYMODE_11BEA_EHT160;
247 			break;
248 		default:
249 			break;
250 		}
251 	}
252 
253 	if (QDF_GET_BITS(eht_ops->ehtop_param,
254 			 EHTOP_INFO_PRESENT_IDX, EHTOP_INFO_PRESENT_BITS)) {
255 		scan_params->channel.cfreq0 =
256 			wlan_reg_chan_band_to_freq(pdev,
257 						   eht_ops->ccfs0,
258 						   band_mask);
259 		scan_params->channel.cfreq1 =
260 			wlan_reg_chan_band_to_freq(pdev,
261 						   eht_ops->ccfs1,
262 						   band_mask);
263 	}
264 
265 	if (QDF_GET_BITS(eht_ops->ehtop_param,
266 			 EHTOP_PARAM_DISABLED_SC_BITMAP_PRESENT_IDX,
267 			 EHTOP_PARAM_DISABLED_SC_BITMAP_PRESENT_BITS)) {
268 		scan_params->channel.puncture_bitmap =
269 			QDF_GET_BITS(eht_ops->disabled_sub_chan_bitmap[0],
270 				     0, 8);
271 		scan_params->channel.puncture_bitmap |=
272 			QDF_GET_BITS(eht_ops->disabled_sub_chan_bitmap[1],
273 				     0, 8) << 8;
274 	} else {
275 		scan_params->channel.puncture_bitmap = 0;
276 	}
277 
278 	return phymode;
279 }
280 #else
281 static enum wlan_phymode
282 util_scan_get_phymode_11be(struct wlan_objmgr_pdev *pdev,
283 			   struct scan_cache_entry *scan_params,
284 			   enum wlan_phymode phymode,
285 			   uint8_t band_mask)
286 {
287 	return phymode;
288 }
289 #endif
290 
291 #ifdef CONFIG_BAND_6GHZ
292 static struct he_oper_6g_param *util_scan_get_he_6g_params(uint8_t *he_ops)
293 {
294 	uint8_t len;
295 	uint32_t he_oper_params;
296 
297 	if (!he_ops)
298 		return NULL;
299 
300 	len = he_ops[1];
301 	he_ops += sizeof(struct ie_header);
302 
303 	if (len < WLAN_HEOP_FIXED_PARAM_LENGTH)
304 		return NULL;
305 
306 	/* element id extension */
307 	he_ops++;
308 	len--;
309 
310 	he_oper_params = LE_READ_4(he_ops);
311 	if (!(he_oper_params & WLAN_HEOP_6GHZ_INFO_PRESENT_MASK))
312 		return NULL;
313 
314 	/* fixed params - element id extension */
315 	he_ops += WLAN_HEOP_FIXED_PARAM_LENGTH - 1;
316 	len -= WLAN_HEOP_FIXED_PARAM_LENGTH - 1;
317 
318 	if (!len)
319 		return NULL;
320 
321 	/* vht oper params */
322 	if (he_oper_params & WLAN_HEOP_VHTOP_PRESENT_MASK) {
323 		if (len < WLAN_HEOP_VHTOP_LENGTH)
324 			return NULL;
325 		he_ops += WLAN_HEOP_VHTOP_LENGTH;
326 		len -= WLAN_HEOP_VHTOP_LENGTH;
327 	}
328 
329 	if (!len)
330 		return NULL;
331 
332 	if (he_oper_params & WLAN_HEOP_CO_LOCATED_BSS_MASK) {
333 		he_ops += WLAN_HEOP_CO_LOCATED_BSS_LENGTH;
334 		len -= WLAN_HEOP_CO_LOCATED_BSS_LENGTH;
335 	}
336 
337 	if (len < sizeof(struct he_oper_6g_param))
338 		return NULL;
339 
340 	return (struct he_oper_6g_param *)he_ops;
341 }
342 
343 #ifdef WLAN_FEATURE_11BE
344 /*
345  * util_scan_is_out_of_band_leak_eht() - Check if eht beacon out of BSS BW
346  * @pdev: pointer to pdev.
347  * @scan_params: scan entry generated by beacon/probe rsp
348  * @band_mask: band mask of frequency beacon/probe rsp received
349  * @current_freq: frequency beacon/probe rsp received
350  *
351  * 1. If BSS BW <= 80MHz
352  * If Absolute value of (Current Channel Channel Center Frequency Segment 0) <=
353  * BSS BW/2 then eht beacon in BSS operating BW
354  * else eht beacon out of BSS operating BW
355  *
356  * 2. If BSS BW > 80MHz
357  * If Absolute value of (Current Channel Channel Center Frequency Segment 1) <=
358  * BSS BW/2 then eht beacon in BSS operating BW
359  * else eht beacon out of BSS operating BW
360  *
361  * Return: bool, whether eht beacon out of BSS operating BW
362  */
363 static bool
364 util_scan_is_out_of_band_leak_eht(struct wlan_objmgr_pdev *pdev,
365 				  struct scan_cache_entry *scan_params,
366 				  uint8_t band_mask,
367 				  qdf_freq_t current_freq)
368 {
369 	struct wlan_ie_ehtops *eht_ops;
370 	uint8_t ch_width;
371 	uint32_t bw;
372 	uint32_t freq_diff;
373 	qdf_freq_t freq_seg0;
374 	qdf_freq_t freq_seg1;
375 
376 	eht_ops = (struct wlan_ie_ehtops *)util_scan_entry_ehtop(scan_params);
377 	if (!util_scan_entry_ehtcap(scan_params) || !eht_ops)
378 		return false;
379 
380 	if (!QDF_GET_BITS(eht_ops->ehtop_param,
381 			  EHTOP_INFO_PRESENT_IDX, EHTOP_INFO_PRESENT_BITS))
382 		return false;
383 
384 	ch_width = QDF_GET_BITS(eht_ops->control,
385 				EHTOP_INFO_CHAN_WIDTH_IDX,
386 				EHTOP_INFO_CHAN_WIDTH_BITS);
387 	freq_seg0 = wlan_reg_chan_band_to_freq(pdev, eht_ops->ccfs0,
388 					       band_mask);
389 	freq_seg1 = wlan_reg_chan_band_to_freq(pdev, eht_ops->ccfs1,
390 					       band_mask);
391 	if (ch_width == WLAN_EHT_CHWIDTH_320)
392 		bw = BW_320_MHZ;
393 	else if (ch_width == WLAN_EHT_CHWIDTH_160)
394 		bw = BW_160_MHZ;
395 	else if (ch_width == WLAN_EHT_CHWIDTH_80)
396 		bw = BW_80_MHZ;
397 	else  if (ch_width == WLAN_EHT_CHWIDTH_40)
398 		bw = BW_40_MHZ;
399 	else  if (ch_width == WLAN_EHT_CHWIDTH_20)
400 		bw = BW_20_MHZ;
401 	else
402 		bw = BW_20_MHZ;
403 
404 	if (bw <= BW_80_MHZ)
405 		freq_diff = abs(freq_seg0 - current_freq);
406 	else
407 		freq_diff = abs(freq_seg1 - current_freq);
408 	if (freq_diff <= bw / 2)
409 		return false;
410 
411 	scm_debug("Leaked freq:%u ch width:%u freq0:%u freq1:%u",
412 		  current_freq, bw, freq_seg0, freq_seg1);
413 	return true;
414 }
415 #else
416 static bool
417 util_scan_is_out_of_band_leak_eht(struct wlan_objmgr_pdev *pdev,
418 				  struct scan_cache_entry *scan_params,
419 				  uint8_t band_mask,
420 				  qdf_freq_t current_freq)
421 {
422 	return false;
423 }
424 #endif
425 
426 /*
427  * util_scan_is_out_of_band_leak_he() - Check if HE beacon out of BSS BW
428  * @pdev: pointer to pdev.
429  * @he_6g_params: HE 6 GHz params
430  * @band_mask: band mask of frequency beacon/probe rsp received
431  * @current_freq: frequency beacon/probe rsp received
432  *
433  * 1. If BSS BW <= 80MHz
434  * If Absolute value of (Current Channel Channel Center Frequency Segment 0) <=
435  * BSS BW/2 then HE beacon in BSS operating BW
436  *
437  * 2. If BSS BW is 160MHz
438  * If Absolute value of (Current Channel Channel Center Frequency Segment 1) <=
439  * BSS BW/2 then HE beacon in BSS operating BW
440  *
441  * 3. If BSS BW is 80+80MHz
442  * If absolute value of (Current Channel - Channel Center Frequency Segment 0)
443  * <= 40 or absolute value of (Current Channel - Channel Center Frequency
444  *  Segment 1) <= 40, then HE beacon in BSS operating BW
445  *
446  * Return: bool, whether HE beacon out of BSS operating BW
447  */
448 static bool
449 util_scan_is_out_of_band_leak_he(struct wlan_objmgr_pdev *pdev,
450 				 struct he_oper_6g_param *he_6g_params,
451 				 uint8_t band_mask,
452 				 qdf_freq_t current_freq)
453 {
454 	uint8_t ch_width;
455 	uint32_t bw;
456 	uint32_t freq_diff;
457 	qdf_freq_t freq_seg0;
458 	qdf_freq_t freq_seg1;
459 
460 	ch_width = he_6g_params->width;
461 	freq_seg0 = wlan_reg_chan_band_to_freq(pdev,
462 					       he_6g_params->chan_freq_seg0,
463 					       band_mask);
464 	freq_seg1 = wlan_reg_chan_band_to_freq(pdev,
465 					       he_6g_params->chan_freq_seg1,
466 					       band_mask);
467 	if (ch_width == WLAN_HE_6GHZ_CHWIDTH_160_80_80)
468 		bw = BW_160_MHZ;
469 	else if (ch_width == WLAN_HE_6GHZ_CHWIDTH_80)
470 		bw = BW_80_MHZ;
471 	else  if (ch_width == WLAN_HE_6GHZ_CHWIDTH_40)
472 		bw = BW_40_MHZ;
473 	else  if (ch_width == WLAN_HE_6GHZ_CHWIDTH_20)
474 		bw = BW_20_MHZ;
475 	else
476 		bw = BW_20_MHZ;
477 
478 	if (bw <= BW_80_MHZ) {
479 		freq_diff = abs(freq_seg0 - current_freq);
480 		if (freq_diff <= bw / 2)
481 			return false;
482 	} else if (WLAN_IS_HE160(he_6g_params)) {
483 		freq_diff = abs(freq_seg1 - current_freq);
484 		if (freq_diff <= bw / 2)
485 			return false;
486 	} else if (WLAN_IS_HE80_80(he_6g_params)) {
487 		freq_diff = abs(freq_seg0 - current_freq);
488 		if (freq_diff <= BW_40_MHZ)
489 			return false;
490 		freq_diff = abs(freq_seg1 - current_freq);
491 		if (freq_diff <= BW_40_MHZ)
492 			return false;
493 	}
494 
495 	scm_debug("Leaked freq:%u ch width:%u freq0:%u freq1:%u",
496 		  current_freq, bw, freq_seg0, freq_seg1);
497 
498 	return true;
499 }
500 
501 /*
502  * util_scan_get_chan_from_he_6g_params() - Get chan info from 6 GHz param
503  * @pdev: pointer to pdev.
504  * @scan_params: scan entry generated by beacon/probe rsp
505  * @chan_freq: output parameter, primary freq from 6 GHz he params
506  * @is_6g_dup_bcon: output parameter, bool, if false, invalid 6g duplicated
507 	beacon out of BSS operating BW or not duplicated beacon, can drop if
508 	channel mismatch
509  * @band_mask: band mask of frequency beacon/probe rsp received
510  * @current_freq: frequency beacon/probe rsp received
511  *
512  * Return: QDF_STATUS
513  */
514 static QDF_STATUS
515 util_scan_get_chan_from_he_6g_params(struct wlan_objmgr_pdev *pdev,
516 				     struct scan_cache_entry *scan_params,
517 				     qdf_freq_t *chan_freq,
518 				     bool *is_6g_dup_bcon, uint8_t band_mask,
519 				     qdf_freq_t current_freq)
520 {
521 	struct he_oper_6g_param *he_6g_params;
522 	uint8_t *he_ops;
523 	struct wlan_scan_obj *scan_obj;
524 	struct wlan_objmgr_psoc *psoc;
525 	bool is_out_of_band_leak = true;
526 
527 	psoc = wlan_pdev_get_psoc(pdev);
528 	if (!psoc) {
529 		scm_err("psoc is NULL");
530 		return QDF_STATUS_E_INVAL;
531 	}
532 
533 	scan_obj = wlan_psoc_get_scan_obj(psoc);
534 	if (!scan_obj) {
535 		scm_err("scan_obj is NULL");
536 		return QDF_STATUS_E_INVAL;
537 	}
538 
539 	*is_6g_dup_bcon = false;
540 
541 	he_ops = util_scan_entry_heop(scan_params);
542 	if (!util_scan_entry_hecap(scan_params) || !he_ops)
543 		return QDF_STATUS_SUCCESS;
544 
545 	he_6g_params = util_scan_get_he_6g_params(he_ops);
546 	if (!he_6g_params)
547 		return QDF_STATUS_SUCCESS;
548 
549 	*chan_freq = wlan_reg_chan_band_to_freq(pdev,
550 						he_6g_params->primary_channel,
551 						band_mask);
552 	if (scan_obj->drop_bcn_on_invalid_freq &&
553 	    wlan_reg_is_disable_for_pwrmode(pdev, *chan_freq,
554 					    REG_BEST_PWR_MODE)) {
555 		scm_debug_rl(QDF_MAC_ADDR_FMT": Drop as invalid channel %d freq %d in HE 6Ghz params",
556 			     QDF_MAC_ADDR_REF(scan_params->bssid.bytes),
557 			     he_6g_params->primary_channel, *chan_freq);
558 		return QDF_STATUS_E_INVAL;
559 	}
560 
561 	if (!he_6g_params->duplicate_beacon) {
562 		*is_6g_dup_bcon = false;
563 		return QDF_STATUS_SUCCESS;
564 	}
565 	is_out_of_band_leak =
566 		util_scan_is_out_of_band_leak_eht(pdev, scan_params, band_mask,
567 						  current_freq);
568 	if (is_out_of_band_leak) {
569 		*is_6g_dup_bcon = false;
570 		return QDF_STATUS_SUCCESS;
571 	}
572 	is_out_of_band_leak =
573 		util_scan_is_out_of_band_leak_he(pdev, he_6g_params, band_mask,
574 						 current_freq);
575 	if (is_out_of_band_leak) {
576 		*is_6g_dup_bcon = false;
577 		return QDF_STATUS_SUCCESS;
578 	}
579 
580 	*is_6g_dup_bcon = true;
581 
582 	return QDF_STATUS_SUCCESS;
583 }
584 
585 static enum wlan_phymode
586 util_scan_get_phymode_6g(struct wlan_objmgr_pdev *pdev,
587 			 struct scan_cache_entry *scan_params)
588 {
589 	struct he_oper_6g_param *he_6g_params;
590 	enum wlan_phymode phymode = WLAN_PHYMODE_11AXA_HE20;
591 	uint8_t *he_ops;
592 	uint8_t band_mask = BIT(REG_BAND_6G);
593 
594 	he_ops = util_scan_entry_heop(scan_params);
595 	if (!util_scan_entry_hecap(scan_params) || !he_ops)
596 		return phymode;
597 
598 	he_6g_params = util_scan_get_he_6g_params(he_ops);
599 	if (!he_6g_params)
600 		return phymode;
601 
602 	switch (he_6g_params->width) {
603 	case WLAN_HE_6GHZ_CHWIDTH_20:
604 		phymode = WLAN_PHYMODE_11AXA_HE20;
605 		break;
606 	case WLAN_HE_6GHZ_CHWIDTH_40:
607 		phymode = WLAN_PHYMODE_11AXA_HE40;
608 		break;
609 	case WLAN_HE_6GHZ_CHWIDTH_80:
610 		phymode = WLAN_PHYMODE_11AXA_HE80;
611 		break;
612 	case WLAN_HE_6GHZ_CHWIDTH_160_80_80:
613 		if (WLAN_IS_HE80_80(he_6g_params))
614 			phymode = WLAN_PHYMODE_11AXA_HE80_80;
615 		else if (WLAN_IS_HE160(he_6g_params))
616 			phymode = WLAN_PHYMODE_11AXA_HE160;
617 		else
618 			phymode = WLAN_PHYMODE_11AXA_HE80;
619 		break;
620 	default:
621 		scm_err("Invalid he_6g_params width: %d", he_6g_params->width);
622 		phymode = WLAN_PHYMODE_11AXA_HE20;
623 		break;
624 	}
625 
626 	if (he_6g_params->chan_freq_seg0)
627 		scan_params->channel.cfreq0 =
628 			wlan_reg_chan_band_to_freq(pdev,
629 					he_6g_params->chan_freq_seg0,
630 					band_mask);
631 	if (he_6g_params->chan_freq_seg1)
632 		scan_params->channel.cfreq1 =
633 			wlan_reg_chan_band_to_freq(pdev,
634 					he_6g_params->chan_freq_seg1,
635 					band_mask);
636 
637 	phymode = util_scan_get_phymode_11be(pdev, scan_params,
638 					     phymode, band_mask);
639 
640 	return phymode;
641 }
642 
643 uint8_t
644 util_scan_get_6g_oper_channel(uint8_t *he_op_ie)
645 {
646 	struct he_oper_6g_param *he_6g_params;
647 
648 	he_6g_params = util_scan_get_he_6g_params(he_op_ie);
649 	if (!he_6g_params)
650 		return 0;
651 
652 	return he_6g_params->primary_channel;
653 }
654 
655 #else
656 static QDF_STATUS
657 util_scan_get_chan_from_he_6g_params(struct wlan_objmgr_pdev *pdev,
658 				     struct scan_cache_entry *scan_params,
659 				     qdf_freq_t *chan_freq,
660 				     bool *is_6g_dup_bcon,
661 				     uint8_t band_mask,
662 				     qdf_freq_t current_freq)
663 {
664 	return QDF_STATUS_SUCCESS;
665 }
666 static inline enum wlan_phymode
667 util_scan_get_phymode_6g(struct wlan_objmgr_pdev *pdev,
668 			 struct scan_cache_entry *scan_params)
669 {
670 	return WLAN_PHYMODE_AUTO;
671 }
672 #endif
673 
674 static inline
675 uint32_t util_scan_sec_chan_freq_from_htinfo(struct wlan_ie_htinfo_cmn *htinfo,
676 					     uint32_t primary_chan_freq)
677 {
678 	if (htinfo->hi_extchoff == WLAN_HTINFO_EXTOFFSET_ABOVE)
679 		return primary_chan_freq + WLAN_CHAN_SPACING_20MHZ;
680 	else if (htinfo->hi_extchoff == WLAN_HTINFO_EXTOFFSET_BELOW)
681 		return primary_chan_freq - WLAN_CHAN_SPACING_20MHZ;
682 
683 	return 0;
684 }
685 
686 static enum wlan_phymode
687 util_scan_get_phymode_5g(struct wlan_objmgr_pdev *pdev,
688 			 struct scan_cache_entry *scan_params)
689 {
690 	enum wlan_phymode phymode = WLAN_PHYMODE_AUTO;
691 	uint16_t ht_cap = 0;
692 	struct htcap_cmn_ie *htcap;
693 	struct wlan_ie_htinfo_cmn *htinfo;
694 	struct wlan_ie_vhtop *vhtop;
695 	uint8_t band_mask = BIT(REG_BAND_5G);
696 
697 	htcap = (struct htcap_cmn_ie *)
698 		util_scan_entry_htcap(scan_params);
699 	htinfo = (struct wlan_ie_htinfo_cmn *)
700 		util_scan_entry_htinfo(scan_params);
701 	vhtop = (struct wlan_ie_vhtop *)
702 		util_scan_entry_vhtop(scan_params);
703 
704 	if (!(htcap && htinfo))
705 		return WLAN_PHYMODE_11A;
706 
707 	if (htcap)
708 		ht_cap = le16toh(htcap->hc_cap);
709 
710 	if (ht_cap & WLAN_HTCAP_C_CHWIDTH40)
711 		phymode = WLAN_PHYMODE_11NA_HT40;
712 	else
713 		phymode = WLAN_PHYMODE_11NA_HT20;
714 
715 	scan_params->channel.cfreq0 =
716 		util_scan_sec_chan_freq_from_htinfo(htinfo,
717 						scan_params->channel.chan_freq);
718 
719 	if (util_scan_entry_vhtcap(scan_params) && vhtop) {
720 		switch (vhtop->vht_op_chwidth) {
721 		case WLAN_VHTOP_CHWIDTH_2040:
722 			if (ht_cap & WLAN_HTCAP_C_CHWIDTH40)
723 				phymode = WLAN_PHYMODE_11AC_VHT40;
724 			else
725 				phymode = WLAN_PHYMODE_11AC_VHT20;
726 			break;
727 		case WLAN_VHTOP_CHWIDTH_80:
728 			if (WLAN_IS_REVSIG_VHT80_80(vhtop))
729 				phymode = WLAN_PHYMODE_11AC_VHT80_80;
730 			else if (WLAN_IS_REVSIG_VHT160(vhtop))
731 				phymode = WLAN_PHYMODE_11AC_VHT160;
732 			else
733 				phymode = WLAN_PHYMODE_11AC_VHT80;
734 			break;
735 		case WLAN_VHTOP_CHWIDTH_160:
736 			phymode = WLAN_PHYMODE_11AC_VHT160;
737 			break;
738 		case WLAN_VHTOP_CHWIDTH_80_80:
739 			phymode = WLAN_PHYMODE_11AC_VHT80_80;
740 			break;
741 		default:
742 			scm_debug("bad channel: %d",
743 				  vhtop->vht_op_chwidth);
744 			phymode = WLAN_PHYMODE_11AC_VHT20;
745 			break;
746 		}
747 		if (vhtop->vht_op_ch_freq_seg1)
748 			scan_params->channel.cfreq0 =
749 				wlan_reg_chan_band_to_freq(pdev,
750 						vhtop->vht_op_ch_freq_seg1,
751 						band_mask);
752 		if (vhtop->vht_op_ch_freq_seg2)
753 			scan_params->channel.cfreq1 =
754 				wlan_reg_chan_band_to_freq(pdev,
755 						vhtop->vht_op_ch_freq_seg2,
756 						band_mask);
757 	}
758 
759 	if (!util_scan_entry_hecap(scan_params))
760 		return phymode;
761 
762 	/* for 5Ghz Check for HE, only if VHT cap and HE cap are present */
763 	if (!IS_WLAN_PHYMODE_VHT(phymode))
764 		return phymode;
765 
766 	switch (phymode) {
767 	case WLAN_PHYMODE_11AC_VHT20:
768 		phymode = WLAN_PHYMODE_11AXA_HE20;
769 		break;
770 	case WLAN_PHYMODE_11AC_VHT40:
771 		phymode = WLAN_PHYMODE_11AXA_HE40;
772 		break;
773 	case WLAN_PHYMODE_11AC_VHT80:
774 		phymode = WLAN_PHYMODE_11AXA_HE80;
775 		break;
776 	case WLAN_PHYMODE_11AC_VHT160:
777 		phymode = WLAN_PHYMODE_11AXA_HE160;
778 		break;
779 	case WLAN_PHYMODE_11AC_VHT80_80:
780 		phymode = WLAN_PHYMODE_11AXA_HE80_80;
781 		break;
782 	default:
783 		phymode = WLAN_PHYMODE_11AXA_HE20;
784 		break;
785 	}
786 
787 	phymode = util_scan_get_phymode_11be(pdev, scan_params,
788 					     phymode, band_mask);
789 
790 	return phymode;
791 }
792 
793 #ifdef WLAN_FEATURE_11BE
794 static enum wlan_phymode
795 util_scan_get_phymode_2g_11be(struct scan_cache_entry *scan_params,
796 			      enum wlan_phymode  phymode)
797 {
798 	if (!util_scan_entry_ehtcap(scan_params))
799 		return phymode;
800 
801 	if (phymode == WLAN_PHYMODE_11AXG_HE40PLUS)
802 		phymode = WLAN_PHYMODE_11BEG_EHT40PLUS;
803 	else if (phymode == WLAN_PHYMODE_11AXG_HE40MINUS)
804 		phymode = WLAN_PHYMODE_11BEG_EHT40MINUS;
805 	else
806 		phymode = WLAN_PHYMODE_11BEG_EHT20;
807 
808 	return phymode;
809 }
810 #else
811 static enum wlan_phymode
812 util_scan_get_phymode_2g_11be(struct scan_cache_entry *scan_params,
813 			      enum wlan_phymode  phymode)
814 {
815 	return phymode;
816 }
817 #endif
818 
819 static enum wlan_phymode
820 util_scan_get_phymode_2g(struct scan_cache_entry *scan_params)
821 {
822 	enum wlan_phymode phymode = WLAN_PHYMODE_AUTO;
823 	uint16_t ht_cap = 0;
824 	struct htcap_cmn_ie *htcap;
825 	struct wlan_ie_htinfo_cmn *htinfo;
826 	struct wlan_ie_vhtop *vhtop;
827 
828 	htcap = (struct htcap_cmn_ie *)
829 		util_scan_entry_htcap(scan_params);
830 	htinfo = (struct wlan_ie_htinfo_cmn *)
831 		util_scan_entry_htinfo(scan_params);
832 	vhtop = (struct wlan_ie_vhtop *)
833 		util_scan_entry_vhtop(scan_params);
834 
835 	if (htcap)
836 		ht_cap = le16toh(htcap->hc_cap);
837 
838 	if (htcap && htinfo) {
839 		if ((ht_cap & WLAN_HTCAP_C_CHWIDTH40) &&
840 		   (htinfo->hi_extchoff == WLAN_HTINFO_EXTOFFSET_ABOVE))
841 			phymode = WLAN_PHYMODE_11NG_HT40PLUS;
842 		else if ((ht_cap & WLAN_HTCAP_C_CHWIDTH40) &&
843 		   (htinfo->hi_extchoff == WLAN_HTINFO_EXTOFFSET_BELOW))
844 			phymode = WLAN_PHYMODE_11NG_HT40MINUS;
845 		else
846 			phymode = WLAN_PHYMODE_11NG_HT20;
847 	} else if (util_scan_entry_xrates(scan_params)) {
848 		/* only 11G stations will have more than 8 rates */
849 		phymode = WLAN_PHYMODE_11G;
850 	} else {
851 		/* Some mischievous g-only APs do not set extended rates */
852 		if (util_scan_entry_rates(scan_params)) {
853 			if (util_is_pureg_rate(&scan_params->ie_list.rates[2],
854 			   scan_params->ie_list.rates[1]))
855 				phymode = WLAN_PHYMODE_11G;
856 			else
857 				phymode = WLAN_PHYMODE_11B;
858 		} else {
859 			phymode = WLAN_PHYMODE_11B;
860 		}
861 	}
862 
863 	/* Check for VHT only if HT cap is present */
864 	if (!IS_WLAN_PHYMODE_HT(phymode))
865 		return phymode;
866 
867 	scan_params->channel.cfreq0 =
868 		util_scan_sec_chan_freq_from_htinfo(htinfo,
869 						scan_params->channel.chan_freq);
870 
871 	if (util_scan_entry_vhtcap(scan_params) && vhtop) {
872 		switch (vhtop->vht_op_chwidth) {
873 		case WLAN_VHTOP_CHWIDTH_2040:
874 			if (phymode == WLAN_PHYMODE_11NG_HT40PLUS)
875 				phymode = WLAN_PHYMODE_11AC_VHT40PLUS_2G;
876 			else if (phymode == WLAN_PHYMODE_11NG_HT40MINUS)
877 				phymode = WLAN_PHYMODE_11AC_VHT40MINUS_2G;
878 			else
879 				phymode = WLAN_PHYMODE_11AC_VHT20_2G;
880 
881 			break;
882 		default:
883 			scm_info("bad vht_op_chwidth: %d",
884 				 vhtop->vht_op_chwidth);
885 			phymode = WLAN_PHYMODE_11AC_VHT20_2G;
886 			break;
887 		}
888 	}
889 
890 	if (!util_scan_entry_hecap(scan_params))
891 		return phymode;
892 
893 	if (phymode == WLAN_PHYMODE_11AC_VHT40PLUS_2G ||
894 	    phymode == WLAN_PHYMODE_11NG_HT40PLUS)
895 		phymode = WLAN_PHYMODE_11AXG_HE40PLUS;
896 	else if (phymode == WLAN_PHYMODE_11AC_VHT40MINUS_2G ||
897 		 phymode == WLAN_PHYMODE_11NG_HT40MINUS)
898 		phymode = WLAN_PHYMODE_11AXG_HE40MINUS;
899 	else
900 		phymode = WLAN_PHYMODE_11AXG_HE20;
901 
902 	phymode = util_scan_get_phymode_2g_11be(scan_params, phymode);
903 
904 	return phymode;
905 }
906 
907 static enum wlan_phymode
908 util_scan_get_phymode(struct wlan_objmgr_pdev *pdev,
909 		      struct scan_cache_entry *scan_params)
910 {
911 	if (WLAN_REG_IS_24GHZ_CH_FREQ(scan_params->channel.chan_freq))
912 		return util_scan_get_phymode_2g(scan_params);
913 	else if (WLAN_REG_IS_6GHZ_CHAN_FREQ(scan_params->channel.chan_freq))
914 		return util_scan_get_phymode_6g(pdev, scan_params);
915 	else
916 		return util_scan_get_phymode_5g(pdev, scan_params);
917 }
918 
919 static QDF_STATUS
920 util_scan_parse_chan_switch_wrapper_ie(struct scan_cache_entry *scan_params,
921 	struct ie_header *sub_ie, qdf_size_t sub_ie_len)
922 {
923 	/* Walk through to check nothing is malformed */
924 	while (sub_ie_len >= sizeof(struct ie_header)) {
925 		/* At least one more header is present */
926 		sub_ie_len -= sizeof(struct ie_header);
927 
928 		if (sub_ie->ie_len == 0) {
929 			sub_ie += 1;
930 			continue;
931 		}
932 		if (sub_ie_len < sub_ie->ie_len) {
933 			scm_debug_rl(QDF_MAC_ADDR_FMT": Incomplete corrupted IE:%x",
934 				     QDF_MAC_ADDR_REF(scan_params->bssid.bytes),
935 				     WLAN_ELEMID_CHAN_SWITCH_WRAP);
936 			return QDF_STATUS_E_INVAL;
937 		}
938 		switch (sub_ie->ie_id) {
939 		case WLAN_ELEMID_COUNTRY:
940 			if (sub_ie->ie_len < WLAN_COUNTRY_IE_MIN_LEN)
941 				return QDF_STATUS_E_INVAL;
942 			scan_params->ie_list.country = (uint8_t *)sub_ie;
943 			break;
944 		case WLAN_ELEMID_WIDE_BAND_CHAN_SWITCH:
945 			if (sub_ie->ie_len < WLAN_WIDE_BW_CHAN_SWITCH_IE_LEN)
946 				return QDF_STATUS_E_INVAL;
947 			scan_params->ie_list.widebw = (uint8_t *)sub_ie;
948 			break;
949 		case WLAN_ELEMID_VHT_TX_PWR_ENVLP:
950 			if (sub_ie->ie_len > WLAN_TPE_IE_MAX_LEN)
951 				return QDF_STATUS_E_INVAL;
952 			scan_params->ie_list.txpwrenvlp = (uint8_t *)sub_ie;
953 			break;
954 		}
955 		/* Consume sub info element */
956 		sub_ie_len -= sub_ie->ie_len;
957 		/* go to next Sub IE */
958 		sub_ie = (struct ie_header *)
959 			(((uint8_t *) sub_ie) +
960 			sizeof(struct ie_header) + sub_ie->ie_len);
961 	}
962 
963 	return QDF_STATUS_SUCCESS;
964 }
965 
966 bool
967 util_scan_is_hidden_ssid(struct ie_ssid *ssid)
968 {
969 	uint8_t i;
970 
971 	/*
972 	 * We flag this as Hidden SSID if the Length is 0
973 	 * of the SSID only contains 0's
974 	 */
975 	if (!ssid || !ssid->ssid_len)
976 		return true;
977 
978 	for (i = 0; i < ssid->ssid_len; i++)
979 		if (ssid->ssid[i] != 0)
980 			return false;
981 
982 	/* All 0's */
983 	return true;
984 }
985 
986 #ifdef WLAN_FEATURE_11BE_MLO
987 static void
988 util_scan_update_rnr_mld(struct rnr_bss_info *rnr,
989 			 struct neighbor_ap_info_field *ap_info, uint8_t *data)
990 {
991 	uint8_t tbtt_info_length;
992 	bool mld_info_present = false;
993 
994 	tbtt_info_length = ap_info->tbtt_header.tbtt_info_length;
995 	if (tbtt_info_length >=
996 		TBTT_NEIGHBOR_AP_BSSID_S_SSID_BSS_PARAM_20MHZ_PSD_MLD_PARAM)
997 		tbtt_info_length =
998 		   TBTT_NEIGHBOR_AP_BSSID_S_SSID_BSS_PARAM_20MHZ_PSD_MLD_PARAM;
999 
1000 	switch (tbtt_info_length) {
1001 	case TBTT_NEIGHBOR_AP_BSSID_S_SSID_BSS_PARAM_20MHZ_PSD_MLD_PARAM:
1002 		rnr->channel_number = ap_info->channel_number;
1003 		rnr->operating_class = ap_info->operting_class;
1004 		qdf_mem_copy(&rnr->bssid, &data[1], QDF_MAC_ADDR_SIZE);
1005 		qdf_mem_copy(&rnr->short_ssid, &data[7], SHORT_SSID_LEN);
1006 		rnr->bss_params = data[11];
1007 		rnr->psd_20mhz = data[12];
1008 		qdf_mem_copy(&rnr->mld_info, &data[13],
1009 			     sizeof(struct rnr_mld_info));
1010 		mld_info_present = true;
1011 		break;
1012 	};
1013 
1014 	rnr->mld_info_valid = mld_info_present;
1015 }
1016 #else
1017 static void
1018 util_scan_update_rnr_mld(struct rnr_bss_info *rnr,
1019 			 struct neighbor_ap_info_field *ap_info, uint8_t *data)
1020 {
1021 	scm_debug("Wrong fieldtype");
1022 }
1023 #endif
1024 
1025 static QDF_STATUS
1026 util_scan_update_rnr(struct rnr_bss_info *rnr,
1027 		     struct neighbor_ap_info_field *ap_info,
1028 		     uint8_t *data)
1029 {
1030 	uint8_t tbtt_info_length;
1031 
1032 	tbtt_info_length = ap_info->tbtt_header.tbtt_info_length;
1033 
1034 	switch (tbtt_info_length) {
1035 	case TBTT_NEIGHBOR_AP_OFFSET_ONLY:
1036 		/* Dont store it skip*/
1037 		break;
1038 
1039 	case TBTT_NEIGHBOR_AP_BSS_PARAM:
1040 		/* Dont store it skip*/
1041 		break;
1042 
1043 	case TBTT_NEIGHBOR_AP_SHORTSSID:
1044 		rnr->channel_number = ap_info->channel_number;
1045 		rnr->operating_class = ap_info->operting_class;
1046 		qdf_mem_copy(&rnr->short_ssid, &data[1], SHORT_SSID_LEN);
1047 		break;
1048 
1049 	case TBTT_NEIGHBOR_AP_S_SSID_BSS_PARAM:
1050 		rnr->channel_number = ap_info->channel_number;
1051 		rnr->operating_class = ap_info->operting_class;
1052 		qdf_mem_copy(&rnr->short_ssid, &data[1], SHORT_SSID_LEN);
1053 		rnr->bss_params = data[5];
1054 		break;
1055 
1056 	case TBTT_NEIGHBOR_AP_BSSID:
1057 		rnr->channel_number = ap_info->channel_number;
1058 		rnr->operating_class = ap_info->operting_class;
1059 		qdf_mem_copy(&rnr->bssid, &data[1], QDF_MAC_ADDR_SIZE);
1060 		break;
1061 
1062 	case TBTT_NEIGHBOR_AP_BSSID_BSS_PARAM:
1063 		rnr->channel_number = ap_info->channel_number;
1064 		rnr->operating_class = ap_info->operting_class;
1065 		qdf_mem_copy(&rnr->bssid, &data[1], QDF_MAC_ADDR_SIZE);
1066 		rnr->bss_params = data[7];
1067 		break;
1068 
1069 	case TBTT_NEIGHBOR_AP_BSSID_BSS_PARAM_20MHZ_PSD:
1070 		rnr->channel_number = ap_info->channel_number;
1071 		rnr->operating_class = ap_info->operting_class;
1072 		qdf_mem_copy(&rnr->bssid, &data[1], QDF_MAC_ADDR_SIZE);
1073 		rnr->bss_params = data[7];
1074 		rnr->psd_20mhz = data[8];
1075 		break;
1076 
1077 	case TBTT_NEIGHBOR_AP_BSSSID_S_SSID:
1078 		rnr->channel_number = ap_info->channel_number;
1079 		rnr->operating_class = ap_info->operting_class;
1080 		qdf_mem_copy(&rnr->bssid, &data[1], QDF_MAC_ADDR_SIZE);
1081 		qdf_mem_copy(&rnr->short_ssid, &data[7], SHORT_SSID_LEN);
1082 		break;
1083 
1084 	case TBTT_NEIGHBOR_AP_BSSID_S_SSID_BSS_PARAM:
1085 		rnr->channel_number = ap_info->channel_number;
1086 		rnr->operating_class = ap_info->operting_class;
1087 		qdf_mem_copy(&rnr->bssid, &data[1], QDF_MAC_ADDR_SIZE);
1088 		qdf_mem_copy(&rnr->short_ssid, &data[7], SHORT_SSID_LEN);
1089 		rnr->bss_params = data[11];
1090 		break;
1091 
1092 	case TBTT_NEIGHBOR_AP_BSSID_S_SSID_BSS_PARAM_20MHZ_PSD:
1093 		rnr->channel_number = ap_info->channel_number;
1094 		rnr->operating_class = ap_info->operting_class;
1095 		qdf_mem_copy(&rnr->bssid, &data[1], QDF_MAC_ADDR_SIZE);
1096 		qdf_mem_copy(&rnr->short_ssid, &data[7], SHORT_SSID_LEN);
1097 		rnr->bss_params = data[11];
1098 		rnr->psd_20mhz = data[12];
1099 		break;
1100 
1101 	default:
1102 		util_scan_update_rnr_mld(rnr, ap_info, data);
1103 	}
1104 
1105 	return QDF_STATUS_SUCCESS;
1106 }
1107 
1108 static QDF_STATUS
1109 util_scan_parse_rnr_ie(struct scan_cache_entry *scan_entry,
1110 		       struct ie_header *ie)
1111 {
1112 	uint32_t rnr_ie_len;
1113 	uint16_t tbtt_count, tbtt_length, i, fieldtype, idx;
1114 	uint8_t *data;
1115 	struct neighbor_ap_info_field *neighbor_ap_info;
1116 
1117 	rnr_ie_len = ie->ie_len;
1118 	data = (uint8_t *)ie + sizeof(struct ie_header);
1119 	idx = scan_entry->rnr.count;
1120 
1121 	while (data < ((uint8_t *)ie + rnr_ie_len + 2)) {
1122 		neighbor_ap_info = (struct neighbor_ap_info_field *)data;
1123 		tbtt_count = neighbor_ap_info->tbtt_header.tbtt_info_count;
1124 		tbtt_length = neighbor_ap_info->tbtt_header.tbtt_info_length;
1125 		fieldtype = neighbor_ap_info->tbtt_header.tbbt_info_fieldtype;
1126 		scm_debug("channel number %d, op class %d",
1127 			  neighbor_ap_info->channel_number,
1128 			  neighbor_ap_info->operting_class);
1129 		scm_debug("tbtt_count %d, tbtt_length %d, fieldtype %d",
1130 			  tbtt_count, tbtt_length, fieldtype);
1131 		data += sizeof(struct neighbor_ap_info_field);
1132 
1133 		if (tbtt_count > TBTT_INFO_COUNT)
1134 			break;
1135 
1136 		for (i = 0; i < (tbtt_count + 1) &&
1137 		     data < ((uint8_t *)ie + rnr_ie_len + 2); i++) {
1138 			if ((i < MAX_RNR_BSS) && (idx < MAX_RNR_BSS))
1139 				util_scan_update_rnr(
1140 					&scan_entry->rnr.bss_info[idx++],
1141 					neighbor_ap_info,
1142 					data);
1143 			data += tbtt_length;
1144 		}
1145 	}
1146 
1147 	scan_entry->rnr.count = idx;
1148 
1149 	return QDF_STATUS_SUCCESS;
1150 }
1151 
1152 #ifdef WLAN_FEATURE_11BE
1153 #ifdef WLAN_FEATURE_11BE_MLO
1154 static void util_scan_parse_ml_ie(struct scan_cache_entry *scan_params,
1155 				  struct extn_ie_header *extn_ie)
1156 {
1157 	if (extn_ie->ie_extn_id == WLAN_EXTN_ELEMID_MULTI_LINK)
1158 		scan_params->ie_list.multi_link = (uint8_t *)extn_ie;
1159 }
1160 #else
1161 static void util_scan_parse_ml_ie(struct scan_cache_entry *scan_params,
1162 				  struct extn_ie_header *extn_ie)
1163 {
1164 }
1165 #endif
1166 static void util_scan_parse_eht_ie(struct scan_cache_entry *scan_params,
1167 				   struct extn_ie_header *extn_ie)
1168 {
1169 	switch (extn_ie->ie_extn_id) {
1170 	case WLAN_EXTN_ELEMID_EHTCAP:
1171 		scan_params->ie_list.ehtcap = (uint8_t *)extn_ie;
1172 		break;
1173 	case WLAN_EXTN_ELEMID_EHTOP:
1174 		scan_params->ie_list.ehtop  = (uint8_t *)extn_ie;
1175 		break;
1176 	default:
1177 		break;
1178 	}
1179 
1180 	util_scan_parse_ml_ie(scan_params, extn_ie);
1181 }
1182 #else
1183 static void util_scan_parse_eht_ie(struct scan_cache_entry *scan_params,
1184 				   struct extn_ie_header *extn_ie)
1185 {
1186 }
1187 #endif
1188 
1189 static QDF_STATUS
1190 util_scan_parse_extn_ie(struct wlan_objmgr_psoc *psoc,
1191 			struct scan_cache_entry *scan_params,
1192 			struct ie_header *ie)
1193 {
1194 	struct extn_ie_header *extn_ie = (struct extn_ie_header *) ie;
1195 	bool eht_capab;
1196 
1197 	wlan_psoc_mlme_get_11be_capab(psoc, &eht_capab);
1198 
1199 	switch (extn_ie->ie_extn_id) {
1200 	case WLAN_EXTN_ELEMID_MAX_CHAN_SWITCH_TIME:
1201 		if (extn_ie->ie_len != WLAN_MAX_CHAN_SWITCH_TIME_IE_LEN)
1202 			return QDF_STATUS_E_INVAL;
1203 		scan_params->ie_list.mcst  = (uint8_t *)ie;
1204 		break;
1205 	case WLAN_EXTN_ELEMID_SRP:
1206 		if (extn_ie->ie_len > WLAN_MAX_SRP_IE_LEN)
1207 			return QDF_STATUS_E_INVAL;
1208 		scan_params->ie_list.srp   = (uint8_t *)ie;
1209 		break;
1210 	case WLAN_EXTN_ELEMID_HECAP:
1211 		scan_params->ie_list.hecap = (uint8_t *)ie;
1212 		break;
1213 	case WLAN_EXTN_ELEMID_HEOP:
1214 		if (extn_ie->ie_len > WLAN_MAX_HEOP_IE_LEN)
1215 			return QDF_STATUS_E_INVAL;
1216 		scan_params->ie_list.heop  = (uint8_t *)ie;
1217 		break;
1218 	case WLAN_EXTN_ELEMID_ESP:
1219 		scan_params->ie_list.esp = (uint8_t *)ie;
1220 		break;
1221 	case WLAN_EXTN_ELEMID_MUEDCA:
1222 		if (extn_ie->ie_len > WLAN_MAX_MUEDCA_IE_LEN)
1223 			return QDF_STATUS_E_INVAL;
1224 		scan_params->ie_list.muedca = (uint8_t *)ie;
1225 		break;
1226 	case WLAN_EXTN_ELEMID_HE_6G_CAP:
1227 		if (extn_ie->ie_len > WLAN_MAX_HE_6G_CAP_IE_LEN)
1228 			return QDF_STATUS_E_INVAL;
1229 		scan_params->ie_list.hecap_6g = (uint8_t *)ie;
1230 		break;
1231 	default:
1232 		break;
1233 	}
1234 	if (eht_capab)
1235 		util_scan_parse_eht_ie(scan_params, extn_ie);
1236 
1237 	return QDF_STATUS_SUCCESS;
1238 }
1239 
1240 static QDF_STATUS
1241 util_scan_parse_vendor_ie(struct scan_cache_entry *scan_params,
1242 	struct ie_header *ie)
1243 {
1244 	if (!scan_params->ie_list.vendor)
1245 		scan_params->ie_list.vendor = (uint8_t *)ie;
1246 
1247 	if (is_wpa_oui((uint8_t *)ie)) {
1248 		scan_params->ie_list.wpa = (uint8_t *)ie;
1249 	} else if (is_wps_oui((uint8_t *)ie)) {
1250 		scan_params->ie_list.wps = (uint8_t *)ie;
1251 		/* WCN IE should be a subset of WPS IE */
1252 		if (is_wcn_oui((uint8_t *)ie))
1253 			scan_params->ie_list.wcn = (uint8_t *)ie;
1254 	} else if (is_wme_param((uint8_t *)ie)) {
1255 		if (ie->ie_len > WLAN_VENDOR_WME_IE_LEN)
1256 			return QDF_STATUS_E_INVAL;
1257 
1258 		scan_params->ie_list.wmeparam = (uint8_t *)ie;
1259 	} else if (is_wme_info((uint8_t *)ie)) {
1260 		scan_params->ie_list.wmeinfo = (uint8_t *)ie;
1261 	} else if (is_atheros_oui((uint8_t *)ie)) {
1262 		if (ie->ie_len > WLAN_VENDOR_ATHCAPS_IE_LEN)
1263 			return QDF_STATUS_E_INVAL;
1264 
1265 		scan_params->ie_list.athcaps = (uint8_t *)ie;
1266 	} else if (is_atheros_extcap_oui((uint8_t *)ie)) {
1267 		if (ie->ie_len > WLAN_VENDOR_ATH_EXTCAP_IE_LEN)
1268 			return QDF_STATUS_E_INVAL;
1269 
1270 		scan_params->ie_list.athextcaps = (uint8_t *)ie;
1271 	} else if (is_sfa_oui((uint8_t *)ie)) {
1272 		if (ie->ie_len > WLAN_VENDOR_SFA_IE_LEN)
1273 			return QDF_STATUS_E_INVAL;
1274 
1275 		scan_params->ie_list.sfa = (uint8_t *)ie;
1276 	} else if (is_p2p_oui((uint8_t *)ie)) {
1277 		scan_params->ie_list.p2p = (uint8_t *)ie;
1278 	} else if (is_qca_son_oui((uint8_t *)ie,
1279 				  QCA_OUI_WHC_AP_INFO_SUBTYPE)) {
1280 		if (ie->ie_len > WLAN_VENDOR_SON_IE_LEN)
1281 			return QDF_STATUS_E_INVAL;
1282 
1283 		scan_params->ie_list.sonadv = (uint8_t *)ie;
1284 	} else if (is_ht_cap((uint8_t *)ie)) {
1285 		/* we only care if there isn't already an HT IE (ANA) */
1286 		if (!scan_params->ie_list.htcap) {
1287 			if (ie->ie_len != (WLAN_VENDOR_HT_IE_OFFSET_LEN +
1288 					   sizeof(struct htcap_cmn_ie)))
1289 				return QDF_STATUS_E_INVAL;
1290 			scan_params->ie_list.htcap =
1291 			 (uint8_t *)&(((struct wlan_vendor_ie_htcap *)ie)->ie);
1292 		}
1293 	} else if (is_ht_info((uint8_t *)ie)) {
1294 		/* we only care if there isn't already an HT IE (ANA) */
1295 		if (!scan_params->ie_list.htinfo) {
1296 			if (ie->ie_len != WLAN_VENDOR_HT_IE_OFFSET_LEN +
1297 					  sizeof(struct wlan_ie_htinfo_cmn))
1298 				return QDF_STATUS_E_INVAL;
1299 			scan_params->ie_list.htinfo =
1300 			  (uint8_t *)&(((struct wlan_vendor_ie_htinfo *)
1301 			  ie)->hi_ie);
1302 		}
1303 	} else if (is_interop_vht((uint8_t *)ie) &&
1304 	    !(scan_params->ie_list.vhtcap)) {
1305 		uint8_t *vendor_ie = (uint8_t *)(ie);
1306 
1307 		if (ie->ie_len < ((WLAN_VENDOR_VHTCAP_IE_OFFSET +
1308 				 sizeof(struct wlan_ie_vhtcaps)) -
1309 				 sizeof(struct ie_header)))
1310 			return QDF_STATUS_E_INVAL;
1311 		vendor_ie = ((uint8_t *)(ie)) + WLAN_VENDOR_VHTCAP_IE_OFFSET;
1312 		if (vendor_ie[1] != (sizeof(struct wlan_ie_vhtcaps)) -
1313 				      sizeof(struct ie_header))
1314 			return QDF_STATUS_E_INVAL;
1315 		/* location where Interop Vht Cap IE and VHT OP IE Present */
1316 		scan_params->ie_list.vhtcap = (((uint8_t *)(ie)) +
1317 						WLAN_VENDOR_VHTCAP_IE_OFFSET);
1318 		if (ie->ie_len > ((WLAN_VENDOR_VHTCAP_IE_OFFSET +
1319 				 sizeof(struct wlan_ie_vhtcaps)) -
1320 				 sizeof(struct ie_header))) {
1321 			if (ie->ie_len < ((WLAN_VENDOR_VHTOP_IE_OFFSET +
1322 					  sizeof(struct wlan_ie_vhtop)) -
1323 					  sizeof(struct ie_header)))
1324 				return QDF_STATUS_E_INVAL;
1325 			vendor_ie = ((uint8_t *)(ie)) +
1326 				    WLAN_VENDOR_VHTOP_IE_OFFSET;
1327 			if (vendor_ie[1] != (sizeof(struct wlan_ie_vhtop) -
1328 					     sizeof(struct ie_header)))
1329 				return QDF_STATUS_E_INVAL;
1330 			scan_params->ie_list.vhtop = (((uint8_t *)(ie)) +
1331 						   WLAN_VENDOR_VHTOP_IE_OFFSET);
1332 		}
1333 	} else if (is_bwnss_oui((uint8_t *)ie)) {
1334 		/*
1335 		 * Bandwidth-NSS map has sub-type & version.
1336 		 * hence copy data just after version byte
1337 		 */
1338 		if (ie->ie_len > WLAN_BWNSS_MAP_OFFSET)
1339 			scan_params->ie_list.bwnss_map = (((uint8_t *)ie) + 8);
1340 	} else if (is_mbo_oce_oui((uint8_t *)ie)) {
1341 		scan_params->ie_list.mbo_oce = (uint8_t *)ie;
1342 	} else if (is_extender_oui((uint8_t *)ie)) {
1343 		scan_params->ie_list.extender = (uint8_t *)ie;
1344 	} else if (is_adaptive_11r_oui((uint8_t *)ie)) {
1345 		if ((ie->ie_len < OUI_LENGTH) ||
1346 		    (ie->ie_len > MAX_ADAPTIVE_11R_IE_LEN))
1347 			return QDF_STATUS_E_INVAL;
1348 
1349 		scan_params->ie_list.adaptive_11r = (uint8_t *)ie +
1350 						sizeof(struct ie_header);
1351 	} else if (is_sae_single_pmk_oui((uint8_t *)ie)) {
1352 		if ((ie->ie_len < OUI_LENGTH) ||
1353 		    (ie->ie_len > MAX_SAE_SINGLE_PMK_IE_LEN)) {
1354 			scm_debug("Invalid sae single pmk OUI");
1355 			return QDF_STATUS_E_INVAL;
1356 		}
1357 		scan_params->ie_list.single_pmk = (uint8_t *)ie +
1358 						sizeof(struct ie_header);
1359 	} else if (is_qcn_oui((uint8_t *)ie)) {
1360 		scan_params->ie_list.qcn = (uint8_t *)ie;
1361 	}
1362 
1363 	return QDF_STATUS_SUCCESS;
1364 }
1365 
1366 static QDF_STATUS
1367 util_scan_populate_bcn_ie_list(struct wlan_objmgr_pdev *pdev,
1368 			       struct scan_cache_entry *scan_params,
1369 			       qdf_freq_t *chan_freq, uint8_t band_mask)
1370 {
1371 	struct ie_header *ie, *sub_ie;
1372 	uint32_t ie_len, sub_ie_len;
1373 	QDF_STATUS status;
1374 	uint8_t chan_idx;
1375 	struct wlan_scan_obj *scan_obj;
1376 	struct wlan_objmgr_psoc *psoc;
1377 	uint8_t tpe_idx = 0;
1378 
1379 	psoc = wlan_pdev_get_psoc(pdev);
1380 	if (!psoc) {
1381 		scm_err("psoc is NULL");
1382 		return QDF_STATUS_E_INVAL;
1383 	}
1384 
1385 	scan_obj = wlan_psoc_get_scan_obj(psoc);
1386 	if (!scan_obj) {
1387 		scm_err("scan_obj is NULL");
1388 		return QDF_STATUS_E_INVAL;
1389 	}
1390 
1391 	ie_len = util_scan_entry_ie_len(scan_params);
1392 	ie = (struct ie_header *)
1393 		  util_scan_entry_ie_data(scan_params);
1394 
1395 	while (ie_len >= sizeof(struct ie_header)) {
1396 		ie_len -= sizeof(struct ie_header);
1397 
1398 		if (!ie->ie_len) {
1399 			ie += 1;
1400 			continue;
1401 		}
1402 
1403 		if (ie_len < ie->ie_len) {
1404 			if (scan_obj->allow_bss_with_incomplete_ie) {
1405 				scm_debug(QDF_MAC_ADDR_FMT": Scan allowed with incomplete corrupted IE:%x, ie_len: %d, ie->ie_len: %d, stop processing further",
1406 					  QDF_MAC_ADDR_REF(scan_params->bssid.bytes),
1407 					  ie->ie_id, ie_len, ie->ie_len);
1408 				break;
1409 			}
1410 			scm_debug(QDF_MAC_ADDR_FMT": Scan not allowed with incomplete corrupted IE:%x, ie_len: %d, ie->ie_len: %d, stop processing further",
1411 				  QDF_MAC_ADDR_REF(scan_params->bssid.bytes),
1412 				  ie->ie_id, ie_len, ie->ie_len);
1413 			return QDF_STATUS_E_INVAL;
1414 		}
1415 
1416 		switch (ie->ie_id) {
1417 		case WLAN_ELEMID_SSID:
1418 			if (ie->ie_len > (sizeof(struct ie_ssid) -
1419 					  sizeof(struct ie_header)))
1420 				goto err;
1421 			scan_params->ie_list.ssid = (uint8_t *)ie;
1422 			break;
1423 		case WLAN_ELEMID_RATES:
1424 			if (ie->ie_len > WLAN_SUPPORTED_RATES_IE_MAX_LEN)
1425 				goto err;
1426 			scan_params->ie_list.rates = (uint8_t *)ie;
1427 			break;
1428 		case WLAN_ELEMID_DSPARMS:
1429 			if (ie->ie_len != WLAN_DS_PARAM_IE_MAX_LEN)
1430 				return QDF_STATUS_E_INVAL;
1431 			scan_params->ie_list.ds_param = (uint8_t *)ie;
1432 			chan_idx = ((struct ds_ie *)ie)->cur_chan;
1433 			*chan_freq = wlan_reg_chan_band_to_freq(pdev, chan_idx,
1434 								band_mask);
1435 			/* Drop if invalid freq */
1436 			if (scan_obj->drop_bcn_on_invalid_freq &&
1437 			    !wlan_reg_is_freq_present_in_cur_chan_list(pdev,
1438 								*chan_freq)) {
1439 				scm_debug(QDF_MAC_ADDR_FMT": Drop as invalid chan %d in DS IE, freq %d, band_mask %d",
1440 					  QDF_MAC_ADDR_REF(
1441 						  scan_params->bssid.bytes),
1442 					  chan_idx, *chan_freq, band_mask);
1443 				return QDF_STATUS_E_INVAL;
1444 			}
1445 			break;
1446 		case WLAN_ELEMID_TIM:
1447 			if (ie->ie_len < WLAN_TIM_IE_MIN_LENGTH)
1448 				goto err;
1449 			scan_params->ie_list.tim = (uint8_t *)ie;
1450 			scan_params->dtim_period =
1451 				((struct wlan_tim_ie *)ie)->tim_period;
1452 			break;
1453 		case WLAN_ELEMID_COUNTRY:
1454 			if (ie->ie_len < WLAN_COUNTRY_IE_MIN_LEN)
1455 				goto err;
1456 			scan_params->ie_list.country = (uint8_t *)ie;
1457 			break;
1458 		case WLAN_ELEMID_QBSS_LOAD:
1459 			if (ie->ie_len != sizeof(struct qbss_load_ie) -
1460 					  sizeof(struct ie_header)) {
1461 				/*
1462 				 * Expected QBSS IE length is 5Bytes; For some
1463 				 * old cisco AP, QBSS IE length is 4Bytes, which
1464 				 * doesn't match with latest spec, So ignore
1465 				 * QBSS IE in such case.
1466 				 */
1467 				break;
1468 			}
1469 			scan_params->ie_list.qbssload = (uint8_t *)ie;
1470 			break;
1471 		case WLAN_ELEMID_CHANSWITCHANN:
1472 			if (ie->ie_len != WLAN_CSA_IE_MAX_LEN)
1473 				goto err;
1474 			scan_params->ie_list.csa = (uint8_t *)ie;
1475 			break;
1476 		case WLAN_ELEMID_IBSSDFS:
1477 			if (ie->ie_len < WLAN_IBSSDFS_IE_MIN_LEN)
1478 				goto err;
1479 			scan_params->ie_list.ibssdfs = (uint8_t *)ie;
1480 			break;
1481 		case WLAN_ELEMID_QUIET:
1482 			if (ie->ie_len != WLAN_QUIET_IE_MAX_LEN)
1483 				goto err;
1484 			scan_params->ie_list.quiet = (uint8_t *)ie;
1485 			break;
1486 		case WLAN_ELEMID_ERP:
1487 			if (ie->ie_len != (sizeof(struct erp_ie) -
1488 					    sizeof(struct ie_header)))
1489 				goto err;
1490 			scan_params->erp = ((struct erp_ie *)ie)->value;
1491 			break;
1492 		case WLAN_ELEMID_HTCAP_ANA:
1493 			if (ie->ie_len == sizeof(struct htcap_cmn_ie)) {
1494 				scan_params->ie_list.htcap =
1495 				(uint8_t *)&(((struct htcap_ie *)ie)->ie);
1496 			}
1497 			break;
1498 		case WLAN_ELEMID_RSN:
1499 			/*
1500 			 * For security cert TC, RSNIE length can be 1 but if
1501 			 * beacon is dropped, old entry will remain in scan
1502 			 * cache and cause cert TC failure as connection with
1503 			 * old entry with valid RSN IE will pass.
1504 			 * So instead of dropping the frame, do not store the
1505 			 * RSN pointer so that old entry is overwritten.
1506 			 */
1507 			if (ie->ie_len >= WLAN_RSN_IE_MIN_LEN)
1508 				scan_params->ie_list.rsn = (uint8_t *)ie;
1509 			break;
1510 		case WLAN_ELEMID_XRATES:
1511 			if (ie->ie_len > WLAN_EXT_SUPPORTED_RATES_IE_MAX_LEN)
1512 				goto err;
1513 			scan_params->ie_list.xrates = (uint8_t *)ie;
1514 			break;
1515 		case WLAN_ELEMID_EXTCHANSWITCHANN:
1516 			if (ie->ie_len != WLAN_XCSA_IE_MAX_LEN)
1517 				goto err;
1518 			scan_params->ie_list.xcsa = (uint8_t *)ie;
1519 			break;
1520 		case WLAN_ELEMID_SECCHANOFFSET:
1521 			if (ie->ie_len != WLAN_SECCHANOFF_IE_MAX_LEN)
1522 				goto err;
1523 			scan_params->ie_list.secchanoff = (uint8_t *)ie;
1524 			break;
1525 		case WLAN_ELEMID_HTINFO_ANA:
1526 			if (ie->ie_len != sizeof(struct wlan_ie_htinfo_cmn))
1527 				goto err;
1528 			scan_params->ie_list.htinfo =
1529 			  (uint8_t *)&(((struct wlan_ie_htinfo *) ie)->hi_ie);
1530 			chan_idx = ((struct wlan_ie_htinfo_cmn *)
1531 				 (scan_params->ie_list.htinfo))->hi_ctrlchannel;
1532 			*chan_freq = wlan_reg_chan_band_to_freq(pdev, chan_idx,
1533 								band_mask);
1534 			/* Drop if invalid freq */
1535 			if (scan_obj->drop_bcn_on_invalid_freq &&
1536 			    wlan_reg_is_disable_for_pwrmode(
1537 						pdev, *chan_freq,
1538 						REG_CURRENT_PWR_MODE)) {
1539 				scm_debug_rl(QDF_MAC_ADDR_FMT": Drop as invalid channel %d freq %d in HT_INFO IE",
1540 					     QDF_MAC_ADDR_REF(scan_params->bssid.bytes),
1541 					     chan_idx, *chan_freq);
1542 				return QDF_STATUS_E_INVAL;
1543 			}
1544 			break;
1545 		case WLAN_ELEMID_WAPI:
1546 			if (ie->ie_len < WLAN_WAPI_IE_MIN_LEN)
1547 				goto err;
1548 			scan_params->ie_list.wapi = (uint8_t *)ie;
1549 			break;
1550 		case WLAN_ELEMID_XCAPS:
1551 			if (ie->ie_len > WLAN_EXTCAP_IE_MAX_LEN)
1552 				goto err;
1553 			scan_params->ie_list.extcaps = (uint8_t *)ie;
1554 			break;
1555 		case WLAN_ELEMID_VHTCAP:
1556 			if (ie->ie_len != (sizeof(struct wlan_ie_vhtcaps) -
1557 					   sizeof(struct ie_header)))
1558 				goto err;
1559 			scan_params->ie_list.vhtcap = (uint8_t *)ie;
1560 			break;
1561 		case WLAN_ELEMID_VHTOP:
1562 			if (ie->ie_len != (sizeof(struct wlan_ie_vhtop) -
1563 					   sizeof(struct ie_header)))
1564 				goto err;
1565 			scan_params->ie_list.vhtop = (uint8_t *)ie;
1566 			break;
1567 		case WLAN_ELEMID_OP_MODE_NOTIFY:
1568 			if (ie->ie_len != WLAN_OPMODE_IE_MAX_LEN)
1569 				goto err;
1570 			scan_params->ie_list.opmode = (uint8_t *)ie;
1571 			break;
1572 		case WLAN_ELEMID_MOBILITY_DOMAIN:
1573 			if (ie->ie_len != WLAN_MOBILITY_DOMAIN_IE_MAX_LEN)
1574 				goto err;
1575 			scan_params->ie_list.mdie = (uint8_t *)ie;
1576 			break;
1577 		case WLAN_ELEMID_VENDOR:
1578 			status = util_scan_parse_vendor_ie(scan_params,
1579 							   ie);
1580 			if (QDF_IS_STATUS_ERROR(status))
1581 				goto err_status;
1582 			break;
1583 		case WLAN_ELEMID_VHT_TX_PWR_ENVLP:
1584 			if (ie->ie_len < WLAN_TPE_IE_MIN_LEN)
1585 				goto err;
1586 			if (tpe_idx >= WLAN_MAX_NUM_TPE_IE)
1587 				goto err;
1588 			scan_params->ie_list.tpe[tpe_idx++] = (uint8_t *)ie;
1589 			break;
1590 		case WLAN_ELEMID_CHAN_SWITCH_WRAP:
1591 			scan_params->ie_list.cswrp = (uint8_t *)ie;
1592 			/* Go to next sub IE */
1593 			sub_ie = (struct ie_header *)
1594 			(((uint8_t *)ie) + sizeof(struct ie_header));
1595 			sub_ie_len = ie->ie_len;
1596 			status =
1597 				util_scan_parse_chan_switch_wrapper_ie(
1598 					scan_params, sub_ie, sub_ie_len);
1599 			if (QDF_IS_STATUS_ERROR(status)) {
1600 				goto err_status;
1601 			}
1602 			break;
1603 		case WLAN_ELEMID_FILS_INDICATION:
1604 			if (ie->ie_len < WLAN_FILS_INDICATION_IE_MIN_LEN)
1605 				goto err;
1606 			scan_params->ie_list.fils_indication = (uint8_t *)ie;
1607 			break;
1608 		case WLAN_ELEMID_RSNXE:
1609 			if (!ie->ie_len)
1610 				goto err;
1611 			scan_params->ie_list.rsnxe = (uint8_t *)ie;
1612 			break;
1613 		case WLAN_ELEMID_EXTN_ELEM:
1614 			status = util_scan_parse_extn_ie(psoc, scan_params, ie);
1615 			if (QDF_IS_STATUS_ERROR(status))
1616 				goto err_status;
1617 			break;
1618 		case WLAN_ELEMID_REDUCED_NEIGHBOR_REPORT:
1619 			if (ie->ie_len < WLAN_RNR_IE_MIN_LEN)
1620 				goto err;
1621 			scan_params->ie_list.rnrie = (uint8_t *)ie;
1622 			status = util_scan_parse_rnr_ie(scan_params, ie);
1623 			if (QDF_IS_STATUS_ERROR(status))
1624 				goto err_status;
1625 			break;
1626 		default:
1627 			break;
1628 		}
1629 
1630 		/* Consume info element */
1631 		ie_len -= ie->ie_len;
1632 		/* Go to next IE */
1633 		ie = (struct ie_header *)
1634 			(((uint8_t *) ie) +
1635 			sizeof(struct ie_header) +
1636 			ie->ie_len);
1637 	}
1638 
1639 	return QDF_STATUS_SUCCESS;
1640 
1641 err:
1642 	status = QDF_STATUS_E_INVAL;
1643 err_status:
1644 	scm_debug("failed to parse IE - id: %d, len: %d",
1645 		  ie->ie_id, ie->ie_len);
1646 
1647 	return status;
1648 }
1649 
1650 /**
1651  * util_scan_update_esp_data: update ESP params from beacon/probe response
1652  * @esp_information: pointer to wlan_esp_information
1653  * @scan_entry: new received entry
1654  *
1655  * The Estimated Service Parameters element is
1656  * used by a AP to provide information to another STA which
1657  * can then use the information as input to an algorithm to
1658  * generate an estimate of throughput between the two STAs.
1659  * The ESP Information List field contains from 1 to 4 ESP
1660  * Information fields(each field 24 bits), each corresponding
1661  * to an access category for which estimated service parameters
1662  * information is provided.
1663  *
1664  * Return: None
1665  */
1666 static void util_scan_update_esp_data(struct wlan_esp_ie *esp_information,
1667 		struct scan_cache_entry *scan_entry)
1668 {
1669 
1670 	uint8_t *data;
1671 	int i = 0;
1672 	uint64_t total_elements;
1673 	struct wlan_esp_info *esp_info;
1674 	struct wlan_esp_ie *esp_ie;
1675 
1676 	esp_ie = (struct wlan_esp_ie *)
1677 		util_scan_entry_esp_info(scan_entry);
1678 
1679 	total_elements  = esp_ie->esp_len;
1680 	data = (uint8_t *)esp_ie + 3;
1681 	do_div(total_elements, ESP_INFORMATION_LIST_LENGTH);
1682 
1683 	if (total_elements > MAX_ESP_INFORMATION_FIELD) {
1684 		scm_err("No of Air time fractions are greater than supported");
1685 		return;
1686 	}
1687 
1688 	for (i = 0; i < total_elements &&
1689 	     data < ((uint8_t *)esp_ie + esp_ie->esp_len + 3); i++) {
1690 		esp_info = (struct wlan_esp_info *)data;
1691 		if (esp_info->access_category == ESP_AC_BK) {
1692 			qdf_mem_copy(&esp_information->esp_info_AC_BK,
1693 					data, 3);
1694 			data = data + ESP_INFORMATION_LIST_LENGTH;
1695 			continue;
1696 		}
1697 		if (esp_info->access_category == ESP_AC_BE) {
1698 			qdf_mem_copy(&esp_information->esp_info_AC_BE,
1699 					data, 3);
1700 			data = data + ESP_INFORMATION_LIST_LENGTH;
1701 			continue;
1702 		}
1703 		if (esp_info->access_category == ESP_AC_VI) {
1704 			qdf_mem_copy(&esp_information->esp_info_AC_VI,
1705 					data, 3);
1706 			data = data + ESP_INFORMATION_LIST_LENGTH;
1707 			continue;
1708 		}
1709 		if (esp_info->access_category == ESP_AC_VO) {
1710 			qdf_mem_copy(&esp_information->esp_info_AC_VO,
1711 					data, 3);
1712 			data = data + ESP_INFORMATION_LIST_LENGTH;
1713 			break;
1714 		}
1715 	}
1716 }
1717 
1718 /**
1719  * util_scan_scm_update_bss_with_esp_dataa: calculate estimated air time
1720  * fraction
1721  * @scan_entry: new received entry
1722  *
1723  * This function process all Access category ESP params and provide
1724  * best effort air time fraction.
1725  * If best effort is not available, it will choose VI, VO and BK in sequence
1726  *
1727  */
1728 static void util_scan_scm_update_bss_with_esp_data(
1729 		struct scan_cache_entry *scan_entry)
1730 {
1731 	uint8_t air_time_fraction = 0;
1732 	struct wlan_esp_ie esp_information;
1733 
1734 	if (!scan_entry->ie_list.esp)
1735 		return;
1736 
1737 	util_scan_update_esp_data(&esp_information, scan_entry);
1738 
1739 	/*
1740 	 * If the ESP metric is transmitting multiple airtime fractions, then
1741 	 * follow the sequence AC_BE, AC_VI, AC_VO, AC_BK and pick whichever is
1742 	 * the first one available
1743 	 */
1744 	if (esp_information.esp_info_AC_BE.access_category
1745 			== ESP_AC_BE)
1746 		air_time_fraction =
1747 			esp_information.esp_info_AC_BE.
1748 			estimated_air_fraction;
1749 	else if (esp_information.esp_info_AC_VI.access_category
1750 			== ESP_AC_VI)
1751 		air_time_fraction =
1752 			esp_information.esp_info_AC_VI.
1753 			estimated_air_fraction;
1754 	else if (esp_information.esp_info_AC_VO.access_category
1755 			== ESP_AC_VO)
1756 		air_time_fraction =
1757 			esp_information.esp_info_AC_VO.
1758 			estimated_air_fraction;
1759 	else if (esp_information.esp_info_AC_BK.access_category
1760 			== ESP_AC_BK)
1761 		air_time_fraction =
1762 			esp_information.esp_info_AC_BK.
1763 				estimated_air_fraction;
1764 	scan_entry->air_time_fraction = air_time_fraction;
1765 }
1766 
1767 /**
1768  * util_scan_scm_calc_nss_supported_by_ap() - finds out nss from AP
1769  * @scan_entry: new received entry
1770  *
1771  * Return: number of nss advertised by AP
1772  */
1773 static int util_scan_scm_calc_nss_supported_by_ap(
1774 		struct scan_cache_entry *scan_params)
1775 {
1776 	struct htcap_cmn_ie *htcap;
1777 	struct wlan_ie_vhtcaps *vhtcaps;
1778 	struct wlan_ie_hecaps *hecaps;
1779 	uint16_t rx_mcs_map = 0;
1780 
1781 	htcap = (struct htcap_cmn_ie *)
1782 		util_scan_entry_htcap(scan_params);
1783 	vhtcaps = (struct wlan_ie_vhtcaps *)
1784 		util_scan_entry_vhtcap(scan_params);
1785 	hecaps = (struct wlan_ie_hecaps *)
1786 		util_scan_entry_hecap(scan_params);
1787 
1788 	if (hecaps) {
1789 		/* Using rx mcs map related to 80MHz or lower as in some
1790 		 * cases higher mcs may support lesser NSS than that
1791 		 * of lowe mcs. Thus giving max NSS capability.
1792 		 */
1793 		rx_mcs_map =
1794 			qdf_cpu_to_le16(hecaps->mcs_bw_map[0].rx_mcs_map);
1795 	} else if (vhtcaps) {
1796 		rx_mcs_map = vhtcaps->rx_mcs_map;
1797 	}
1798 
1799 	if (hecaps || vhtcaps) {
1800 		if ((rx_mcs_map & 0xC000) != 0xC000)
1801 			return 8;
1802 
1803 		if ((rx_mcs_map & 0x3000) != 0x3000)
1804 			return 7;
1805 
1806 		if ((rx_mcs_map & 0x0C00) != 0x0C00)
1807 			return 6;
1808 
1809 		if ((rx_mcs_map & 0x0300) != 0x0300)
1810 			return 5;
1811 
1812 		if ((rx_mcs_map & 0x00C0) != 0x00C0)
1813 			return 4;
1814 
1815 		if ((rx_mcs_map & 0x0030) != 0x0030)
1816 			return 3;
1817 
1818 		if ((rx_mcs_map & 0x000C) != 0x000C)
1819 			return 2;
1820 	} else if (htcap) {
1821 		if (htcap->mcsset[3])
1822 			return 4;
1823 
1824 		if (htcap->mcsset[2])
1825 			return 3;
1826 
1827 		if (htcap->mcsset[1])
1828 			return 2;
1829 
1830 	}
1831 	return 1;
1832 }
1833 
1834 #ifdef WLAN_DFS_CHAN_HIDDEN_SSID
1835 QDF_STATUS
1836 util_scan_add_hidden_ssid(struct wlan_objmgr_pdev *pdev, qdf_nbuf_t bcnbuf)
1837 {
1838 	struct wlan_frame_hdr *hdr;
1839 	struct wlan_bcn_frame *bcn;
1840 	struct wlan_scan_obj *scan_obj;
1841 	struct wlan_ssid *conf_ssid;
1842 	struct  ie_header *ie;
1843 	uint32_t frame_len = qdf_nbuf_len(bcnbuf);
1844 	uint16_t bcn_ie_offset, ssid_ie_start_offset, ssid_ie_end_offset;
1845 	uint16_t tmplen, ie_length;
1846 	uint8_t *pbeacon, *tmp;
1847 	bool     set_ssid_flag = false;
1848 	struct ie_ssid ssid = {0};
1849 	uint8_t pdev_id;
1850 
1851 	if (!pdev) {
1852 		scm_warn("pdev: 0x%pK is NULL", pdev);
1853 		return QDF_STATUS_E_NULL_VALUE;
1854 	}
1855 	pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
1856 	scan_obj = wlan_pdev_get_scan_obj(pdev);
1857 	if (!scan_obj) {
1858 		scm_warn("null scan_obj");
1859 		return QDF_STATUS_E_NULL_VALUE;
1860 	}
1861 
1862 	conf_ssid = &scan_obj->pdev_info[pdev_id].conf_ssid;
1863 
1864 	hdr = (struct wlan_frame_hdr *)qdf_nbuf_data(bcnbuf);
1865 
1866 	/* received bssid does not match configured bssid */
1867 	if (qdf_mem_cmp(hdr->i_addr3, scan_obj->pdev_info[pdev_id].conf_bssid,
1868 			QDF_MAC_ADDR_SIZE) ||
1869 			conf_ssid->length == 0) {
1870 		return QDF_STATUS_SUCCESS;
1871 	}
1872 
1873 	bcn = (struct wlan_bcn_frame *)(qdf_nbuf_data(bcnbuf) + sizeof(*hdr));
1874 	pbeacon = (uint8_t *)bcn;
1875 
1876 	ie = (struct ie_header *)(pbeacon +
1877 				  offsetof(struct wlan_bcn_frame, ie));
1878 
1879 	bcn_ie_offset = offsetof(struct wlan_bcn_frame, ie);
1880 	ie_length = (uint16_t)(frame_len - sizeof(*hdr) -
1881 			       bcn_ie_offset);
1882 
1883 	while (ie_length >=  sizeof(struct ie_header)) {
1884 		ie_length -= sizeof(struct ie_header);
1885 
1886 		bcn_ie_offset += sizeof(struct ie_header);
1887 
1888 		if (ie_length < ie->ie_len) {
1889 			scm_debug("Incomplete corrupted IE:%x", ie->ie_id);
1890 			return QDF_STATUS_E_INVAL;
1891 		}
1892 		if (ie->ie_id == WLAN_ELEMID_SSID) {
1893 			if (ie->ie_len > (sizeof(struct ie_ssid) -
1894 						 sizeof(struct ie_header))) {
1895 				return QDF_STATUS_E_INVAL;
1896 			}
1897 			ssid.ssid_id = ie->ie_id;
1898 			ssid.ssid_len = ie->ie_len;
1899 
1900 			if (ssid.ssid_len)
1901 				qdf_mem_copy(ssid.ssid,
1902 					     ie + sizeof(struct ie_header),
1903 					     ssid.ssid_len);
1904 
1905 			if (util_scan_is_hidden_ssid(&ssid)) {
1906 				set_ssid_flag  = true;
1907 				ssid_ie_start_offset = bcn_ie_offset -
1908 					sizeof(struct ie_header);
1909 				ssid_ie_end_offset = bcn_ie_offset +
1910 					ie->ie_len;
1911 			}
1912 		}
1913 		if (ie->ie_len == 0) {
1914 			ie += 1;    /* next IE */
1915 			continue;
1916 		}
1917 		if (ie->ie_id == WLAN_ELEMID_VENDOR &&
1918 		    is_wps_oui((uint8_t *)ie)) {
1919 			set_ssid_flag = false;
1920 			break;
1921 		}
1922 		/* Consume info element */
1923 		ie_length -=  ie->ie_len;
1924 		/* Go to next IE */
1925 		ie = (struct ie_header *)(((uint8_t *)ie) +
1926 				sizeof(struct ie_header) +
1927 				ie->ie_len);
1928 	}
1929 
1930 	if (set_ssid_flag) {
1931 		/* Hidden SSID if the Length is 0 */
1932 		if (!ssid.ssid_len) {
1933 			/* increase the taillength by length of ssid */
1934 			if (qdf_nbuf_put_tail(bcnbuf,
1935 					      conf_ssid->length) == NULL) {
1936 				scm_debug("No enough tailroom");
1937 				return  QDF_STATUS_E_NOMEM;
1938 			}
1939 			/*
1940 			 * "qdf_nbuf_put_tail" might change the data pointer of
1941 			 * the skb. Therefore use the new data area.
1942 			 */
1943 			pbeacon = (qdf_nbuf_data(bcnbuf) + sizeof(*hdr));
1944 			/* length of the buffer to be copied */
1945 			tmplen = frame_len -
1946 				sizeof(*hdr) - ssid_ie_end_offset;
1947 			/*
1948 			 * tmp memory to copy the beacon info
1949 			 * after ssid ie.
1950 			 */
1951 			tmp = qdf_mem_malloc(tmplen * sizeof(u_int8_t));
1952 			if (!tmp)
1953 				return  QDF_STATUS_E_NOMEM;
1954 
1955 			/* Copy beacon data after ssid ie to tmp */
1956 			qdf_nbuf_copy_bits(bcnbuf, (sizeof(*hdr) +
1957 					   ssid_ie_end_offset), tmplen, tmp);
1958 			/* Add ssid length */
1959 			*(pbeacon + (ssid_ie_start_offset + 1))
1960 				= conf_ssid->length;
1961 			/* Insert the  SSID string */
1962 			qdf_mem_copy((pbeacon + ssid_ie_end_offset),
1963 				     conf_ssid->ssid, conf_ssid->length);
1964 			/* Copy rest of the beacon data */
1965 			qdf_mem_copy((pbeacon + ssid_ie_end_offset +
1966 				      conf_ssid->length), tmp, tmplen);
1967 			qdf_mem_free(tmp);
1968 
1969 			/* Hidden ssid with all 0's */
1970 		} else if (ssid.ssid_len == conf_ssid->length) {
1971 			/* Insert the  SSID string */
1972 			qdf_mem_copy((pbeacon + ssid_ie_start_offset +
1973 				      sizeof(struct ie_header)),
1974 				      conf_ssid->ssid, conf_ssid->length);
1975 		} else {
1976 			scm_debug("mismatch in hidden ssid length");
1977 			return QDF_STATUS_E_INVAL;
1978 		}
1979 	}
1980 	return QDF_STATUS_SUCCESS;
1981 }
1982 #endif /* WLAN_DFS_CHAN_HIDDEN_SSID */
1983 
1984 #ifdef WLAN_ADAPTIVE_11R
1985 /**
1986  * scm_fill_adaptive_11r_cap() - Check if the AP supports adaptive 11r
1987  * @scan_entry: Pointer to the scan entry
1988  *
1989  * Return: true if adaptive 11r is advertised else false
1990  */
1991 static void scm_fill_adaptive_11r_cap(struct scan_cache_entry *scan_entry)
1992 {
1993 	uint8_t *ie;
1994 	uint8_t data;
1995 	bool adaptive_11r;
1996 
1997 	ie = util_scan_entry_adaptive_11r(scan_entry);
1998 	if (!ie)
1999 		return;
2000 
2001 	data = *(ie + OUI_LENGTH);
2002 	adaptive_11r = (data & 0x1) ? true : false;
2003 
2004 	scan_entry->adaptive_11r_ap = adaptive_11r;
2005 }
2006 #else
2007 static void scm_fill_adaptive_11r_cap(struct scan_cache_entry *scan_entry)
2008 {
2009 	scan_entry->adaptive_11r_ap = false;
2010 }
2011 #endif
2012 
2013 static void util_scan_set_security(struct scan_cache_entry *scan_params)
2014 {
2015 	if (util_scan_entry_wpa(scan_params))
2016 		scan_params->security_type |= SCAN_SECURITY_TYPE_WPA;
2017 
2018 	if (util_scan_entry_rsn(scan_params))
2019 		scan_params->security_type |= SCAN_SECURITY_TYPE_RSN;
2020 	if (util_scan_entry_wapi(scan_params))
2021 		scan_params->security_type |= SCAN_SECURITY_TYPE_WAPI;
2022 
2023 	if (!scan_params->security_type &&
2024 	    scan_params->cap_info.wlan_caps.privacy)
2025 		scan_params->security_type |= SCAN_SECURITY_TYPE_WEP;
2026 }
2027 
2028 #ifdef WLAN_FEATURE_11BE_MLO
2029 /**
2030  * Multi link IE field offsets
2031  *  ------------------------------------------------------------------------
2032  * | EID(1) | Len (1) | EID_EXT (1) | ML_CONTROL (2) | CMN_INFO (var) | ... |
2033  *  ------------------------------------------------------------------------
2034  */
2035 #define ML_CONTROL_OFFSET 3
2036 #define ML_CMN_INFO_OFFSET ML_CONTROL_OFFSET + 2
2037 
2038 #define CMN_INFO_LINK_ID_PRESENT_BIT      BIT(4)
2039 #define LINK_INFO_MAC_ADDR_PRESENT_BIT    BIT(5)
2040 
2041 /* This function is implemented as per IEEE802.11be D1.0, there is no difference
2042  * in presence bitmap for beacon, probe response and probe request frames.
2043  * This code is to be revisited for future drafts if the presence bitmap values
2044  * changes for the beacon, probe response and probe request frames.
2045  */
2046 static uint8_t util_get_link_info_offset(uint8_t *ml_ie)
2047 {
2048 	qdf_size_t ml_ie_len = 0;
2049 	qdf_size_t parsed_ie_len = 0;
2050 	struct wlan_ie_multilink *mlie_fixed;
2051 	uint16_t mlcontrol;
2052 	uint16_t presencebm;
2053 
2054 	if (!ml_ie) {
2055 		scm_err("ml_ie is null");
2056 		return 0;
2057 	}
2058 
2059 	ml_ie_len = ml_ie[TAG_LEN_POS];
2060 	if (!ml_ie_len) {
2061 		scm_err("ml_ie_len is zero");
2062 		return 0;
2063 	}
2064 
2065 	if (ml_ie_len < sizeof(struct wlan_ie_multilink)) {
2066 		scm_err_rl("Length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)",
2067 			   ml_ie_len, sizeof(struct wlan_ie_multilink));
2068 		return 0;
2069 	}
2070 
2071 	mlie_fixed = (struct wlan_ie_multilink *)ml_ie;
2072 	mlcontrol = le16toh(mlie_fixed->mlcontrol);
2073 	presencebm = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
2074 				  WLAN_ML_CTRL_PBM_BITS);
2075 
2076 	parsed_ie_len += sizeof(*mlie_fixed);
2077 
2078 	parsed_ie_len += WLAN_ML_BV_CINFO_LENGTH_SIZE;
2079 	parsed_ie_len += QDF_MAC_ADDR_SIZE;
2080 
2081 	/* Check if Link ID info is present */
2082 	if (presencebm & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P)
2083 		parsed_ie_len += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE;
2084 
2085 	/* Check if BSS parameter change count is present */
2086 	if (presencebm & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P)
2087 		parsed_ie_len += WLAN_ML_BSSPARAMCHNGCNT_SIZE;
2088 
2089 	/* Check if Medium Sync Delay Info is present */
2090 	if (presencebm & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P)
2091 		parsed_ie_len += WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE;
2092 
2093 	/* Check if EML cap is present */
2094 	if (presencebm & WLAN_ML_BV_CTRL_PBM_EMLCAP_P)
2095 		parsed_ie_len += WLAN_ML_BV_CINFO_EMLCAP_SIZE;
2096 
2097 	/* Check if MLD cap and op is present */
2098 	if (presencebm & WLAN_ML_BV_CTRL_PBM_MLDCAPANDOP_P)
2099 		parsed_ie_len += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE;
2100 
2101 	/* Check if MLD ID is present */
2102 	if (presencebm & WLAN_ML_BV_CTRL_PBM_MLDID_P)
2103 		parsed_ie_len += WLAN_ML_BV_CINFO_MLDID_SIZE;
2104 
2105 	/* Offset calculation starts from the beginning of the ML IE (including
2106 	 * EID) hence, adding the size of IE header to ML IE length.
2107 	 */
2108 	if (parsed_ie_len < (ml_ie_len + sizeof(struct ie_header)))
2109 		return parsed_ie_len;
2110 
2111 	return 0;
2112 }
2113 
2114 static void util_get_partner_link_info(struct scan_cache_entry *scan_entry)
2115 {
2116 	uint8_t *ml_ie = scan_entry->ie_list.multi_link;
2117 	uint8_t offset = util_get_link_info_offset(ml_ie);
2118 	uint16_t sta_ctrl;
2119 	uint8_t *stactrl_offset = NULL, *ielist_offset;
2120 	uint8_t perstaprof_len = 0, perstaprof_stainfo_len = 0, ielist_len = 0;
2121 	struct partner_link_info *link_info = NULL;
2122 	uint8_t eid = 0;
2123 	uint8_t link_idx = 0;
2124 	uint8_t rnr_idx = 0;
2125 	struct rnr_bss_info *rnr = NULL;
2126 
2127 	/* Update partner info  from RNR IE */
2128 	while ((rnr_idx < MAX_RNR_BSS) && (rnr_idx < scan_entry->rnr.count)) {
2129 		if (link_idx >= (MLD_MAX_LINKS - 1))
2130 			break;
2131 		rnr = &scan_entry->rnr.bss_info[rnr_idx];
2132 		if (rnr->mld_info_valid && !rnr->mld_info.mld_id) {
2133 			link_info = &scan_entry->ml_info.link_info[link_idx];
2134 			qdf_mem_copy(&link_info->link_addr,
2135 				     &rnr->bssid, QDF_MAC_ADDR_SIZE);
2136 
2137 			link_info->link_id = rnr->mld_info.link_id;
2138 			link_info->freq =
2139 				wlan_reg_chan_opclass_to_freq(rnr->channel_number,
2140 							      rnr->operating_class,
2141 							      true);
2142 			if (!link_info->freq)
2143 				scm_debug("freq 0 rnr channel %u op_class %u",
2144 					  rnr->channel_number,
2145 					  rnr->operating_class);
2146 			link_info->op_class = rnr->operating_class;
2147 			link_idx++;
2148 		}
2149 		rnr_idx++;
2150 	}
2151 
2152 	scan_entry->ml_info.num_links = link_idx;
2153 	if (!offset)
2154 		return;
2155 
2156 	/* TODO: loop through all the STA info fields */
2157 
2158 	/* Sub element ID 0 represents Per-STA Profile */
2159 	if (ml_ie[offset] == 0) {
2160 		perstaprof_len = ml_ie[offset + 1];
2161 		stactrl_offset = &ml_ie[offset + 2];
2162 
2163 		/* Skip sub element ID and length fields */
2164 		offset += 2;
2165 
2166 		sta_ctrl = *(uint16_t *)(ml_ie + offset);
2167 
2168 		/* Skip STA control field */
2169 		offset += 2;
2170 
2171 		/*
2172 		 * offset points to the beginning of the STA Info field which
2173 		 * holds the length of the variable field.
2174 		 */
2175 		perstaprof_stainfo_len = ml_ie[offset];
2176 
2177 		/* Skip STA Info Length field */
2178 		offset += WLAN_ML_BV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE;
2179 
2180 		/*
2181 		 * To point to the ie_list offset move past the STA Info field.
2182 		 */
2183 		ielist_offset  = &ml_ie[offset + perstaprof_stainfo_len];
2184 
2185 		/*
2186 		 * Ensure that the STA Control Field + STA Info Field
2187 		 * is smaller than the per-STA profile when incrementing
2188 		 * the pointer to avoid underflow during subtraction.
2189 		 */
2190 		if ((perstaprof_stainfo_len +
2191 		     WLAN_ML_BV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE +
2192 		     WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE) <
2193 							perstaprof_len) {
2194 			ielist_len = perstaprof_len -
2195 			     (WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE +
2196 			      WLAN_ML_BV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE +
2197 			      perstaprof_stainfo_len);
2198 		} else {
2199 			scm_debug("No STA profile IE list found");
2200 			ielist_len = 0;
2201 		}
2202 
2203 		link_info = NULL;
2204 		for (link_idx = 0; link_idx < scan_entry->ml_info.num_links;
2205 		     link_idx++) {
2206 			if (scan_entry->ml_info.link_info[link_idx].link_id ==
2207 							(sta_ctrl & 0xF)) {
2208 				link_info = &scan_entry->ml_info.link_info[link_idx];
2209 			}
2210                 }
2211 
2212 		/* Get the pointers to CSA, ECSA, Max Channel Switch Time IE. */
2213 		if (link_info) {
2214 			link_info->csa_ie = wlan_get_ie_ptr_from_eid
2215 				(WLAN_ELEMID_CHANSWITCHANN, ielist_offset,
2216 				 ielist_len);
2217 
2218 			link_info->ecsa_ie = wlan_get_ie_ptr_from_eid
2219 				(WLAN_ELEMID_EXTCHANSWITCHANN, ielist_offset,
2220 				 ielist_len);
2221 
2222 			eid = WLAN_EXTN_ELEMID_MAX_CHAN_SWITCH_TIME;
2223 			link_info->max_cst_ie = wlan_get_ext_ie_ptr_from_ext_id
2224 					(&eid, 1, ielist_offset, ielist_len);
2225 		}
2226 	}
2227 }
2228 
2229 static void util_scan_update_ml_info(struct scan_cache_entry *scan_entry)
2230 {
2231 	uint8_t *ml_ie = scan_entry->ie_list.multi_link;
2232 	uint16_t multi_link_ctrl;
2233 	uint8_t offset;
2234 
2235 	if (!scan_entry->ie_list.multi_link) {
2236 		return;
2237 	}
2238 
2239 	multi_link_ctrl = *(uint16_t *)(ml_ie + ML_CONTROL_OFFSET);
2240 
2241 	/* TODO: update ml_info based on ML IE */
2242 
2243 	multi_link_ctrl = *(uint16_t *)(ml_ie + ML_CONTROL_OFFSET);
2244 	offset = ML_CMN_INFO_OFFSET;
2245 
2246 	/* Increment the offset to account for the Common Info Length */
2247 	offset += WLAN_ML_BV_CINFO_LENGTH_SIZE;
2248 
2249 	qdf_mem_copy(&scan_entry->ml_info.mld_mac_addr,
2250 		     ml_ie + offset, 6);
2251 	offset += 6;
2252 
2253 	/* TODO: Decode it from ML IE */
2254 	scan_entry->ml_info.num_links = 0;
2255 
2256 	/**
2257 	 * Copy Link ID & MAC address of the scan cache entry as first entry
2258 	 * in the partner info list
2259 	 */
2260 	if (multi_link_ctrl & CMN_INFO_LINK_ID_PRESENT_BIT)
2261 		scan_entry->ml_info.self_link_id = ml_ie[offset] & 0x0F;
2262 
2263 	util_get_partner_link_info(scan_entry);
2264 }
2265 #else
2266 static void util_scan_update_ml_info(struct scan_cache_entry *scan_entry)
2267 {
2268 }
2269 #endif
2270 
2271 static QDF_STATUS
2272 util_scan_gen_scan_entry(struct wlan_objmgr_pdev *pdev,
2273 			 uint8_t *frame, qdf_size_t frame_len,
2274 			 uint32_t frm_subtype,
2275 			 struct mgmt_rx_event_params *rx_param,
2276 			 struct scan_mbssid_info *mbssid_info,
2277 			 qdf_list_t *scan_list)
2278 {
2279 	struct wlan_frame_hdr *hdr;
2280 	struct wlan_bcn_frame *bcn;
2281 	QDF_STATUS status = QDF_STATUS_SUCCESS;
2282 	struct ie_ssid *ssid;
2283 	struct scan_cache_entry *scan_entry;
2284 	struct qbss_load_ie *qbss_load;
2285 	struct scan_cache_node *scan_node;
2286 	uint8_t i;
2287 	qdf_freq_t chan_freq = 0;
2288 	bool is_6g_dup_bcon = false;
2289 	uint8_t band_mask;
2290 	qdf_freq_t recv_freq = 0;
2291 
2292 	scan_entry = qdf_mem_malloc_atomic(sizeof(*scan_entry));
2293 	if (!scan_entry) {
2294 		scm_err("failed to allocate memory for scan_entry");
2295 		return QDF_STATUS_E_NOMEM;
2296 	}
2297 
2298 	scan_entry->raw_frame.ptr =
2299 			qdf_mem_malloc_atomic(frame_len);
2300 	if (!scan_entry->raw_frame.ptr) {
2301 		scm_err("failed to allocate memory for frame");
2302 		qdf_mem_free(scan_entry);
2303 		return QDF_STATUS_E_NOMEM;
2304 	}
2305 
2306 	bcn = (struct wlan_bcn_frame *)
2307 			   (frame + sizeof(*hdr));
2308 	hdr = (struct wlan_frame_hdr *)frame;
2309 
2310 	/* update timestamp in nanoseconds needed by kernel layers */
2311 	scan_entry->boottime_ns = qdf_get_bootbased_boottime_ns();
2312 
2313 	scan_entry->frm_subtype = frm_subtype;
2314 	qdf_mem_copy(scan_entry->bssid.bytes,
2315 		hdr->i_addr3, QDF_MAC_ADDR_SIZE);
2316 	/* Scr addr */
2317 	qdf_mem_copy(scan_entry->mac_addr.bytes,
2318 		hdr->i_addr2, QDF_MAC_ADDR_SIZE);
2319 	scan_entry->seq_num =
2320 		(le16toh(*(uint16_t *)hdr->i_seq) >> WLAN_SEQ_SEQ_SHIFT);
2321 
2322 	scan_entry->snr = rx_param->snr;
2323 	scan_entry->avg_snr = WLAN_SNR_IN(scan_entry->snr);
2324 	scan_entry->rssi_raw = rx_param->rssi;
2325 	scan_entry->avg_rssi = WLAN_RSSI_IN(scan_entry->rssi_raw);
2326 	scan_entry->tsf_delta = rx_param->tsf_delta;
2327 	scan_entry->pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
2328 
2329 	recv_freq = rx_param->chan_freq;
2330 	/* Copy per chain rssi to scan entry */
2331 	qdf_mem_copy(scan_entry->per_chain_rssi, rx_param->rssi_ctl,
2332 		     WLAN_MGMT_TXRX_HOST_MAX_ANTENNA);
2333 	band_mask = BIT(wlan_reg_freq_to_band(recv_freq));
2334 
2335 	if (!wlan_psoc_nif_fw_ext_cap_get(wlan_pdev_get_psoc(pdev),
2336 					  WLAN_SOC_CEXT_HW_DB2DBM)) {
2337 		for (i = 0; i < WLAN_MGMT_TXRX_HOST_MAX_ANTENNA; i++) {
2338 			if (scan_entry->per_chain_rssi[i] !=
2339 			    WLAN_INVALID_PER_CHAIN_SNR)
2340 				scan_entry->per_chain_rssi[i] +=
2341 						WLAN_NOISE_FLOOR_DBM_DEFAULT;
2342 			else
2343 				scan_entry->per_chain_rssi[i] =
2344 						WLAN_INVALID_PER_CHAIN_RSSI;
2345 		}
2346 	}
2347 
2348 	/* store jiffies */
2349 	scan_entry->rrm_parent_tsf = (uint32_t)qdf_system_ticks();
2350 
2351 	scan_entry->bcn_int = le16toh(bcn->beacon_interval);
2352 
2353 	/*
2354 	 * In case if the beacon doesn't have
2355 	 * valid beacon interval falback to def
2356 	 */
2357 	if (!scan_entry->bcn_int)
2358 		scan_entry->bcn_int = 100;
2359 	scan_entry->cap_info.value = le16toh(bcn->capability.value);
2360 	qdf_mem_copy(scan_entry->tsf_info.data,
2361 		bcn->timestamp, 8);
2362 	scan_entry->erp = ERP_NON_ERP_PRESENT;
2363 
2364 	scan_entry->scan_entry_time =
2365 		qdf_mc_timer_get_system_time();
2366 
2367 	scan_entry->raw_frame.len = frame_len;
2368 	qdf_mem_copy(scan_entry->raw_frame.ptr,
2369 		frame, frame_len);
2370 	status = util_scan_populate_bcn_ie_list(pdev, scan_entry, &chan_freq,
2371 						band_mask);
2372 	if (QDF_IS_STATUS_ERROR(status)) {
2373 		scm_debug(QDF_MAC_ADDR_FMT": failed to parse beacon IE",
2374 			  QDF_MAC_ADDR_REF(scan_entry->bssid.bytes));
2375 		qdf_mem_free(scan_entry->raw_frame.ptr);
2376 		qdf_mem_free(scan_entry);
2377 		return QDF_STATUS_E_FAILURE;
2378 	}
2379 
2380 	ssid = (struct ie_ssid *)
2381 		scan_entry->ie_list.ssid;
2382 
2383 	if (ssid && (ssid->ssid_len > WLAN_SSID_MAX_LEN)) {
2384 		qdf_mem_free(scan_entry->raw_frame.ptr);
2385 		qdf_mem_free(scan_entry);
2386 		return QDF_STATUS_E_FAILURE;
2387 	}
2388 
2389 	if (scan_entry->ie_list.p2p)
2390 		scan_entry->is_p2p = true;
2391 
2392 	if (!chan_freq && util_scan_entry_hecap(scan_entry)) {
2393 		status = util_scan_get_chan_from_he_6g_params(pdev, scan_entry,
2394 							      &chan_freq,
2395 							      &is_6g_dup_bcon,
2396 							      band_mask,
2397 							      recv_freq);
2398 		if (QDF_IS_STATUS_ERROR(status)) {
2399 			qdf_mem_free(scan_entry->raw_frame.ptr);
2400 			qdf_mem_free(scan_entry);
2401 			return QDF_STATUS_E_FAILURE;
2402 		}
2403 	}
2404 
2405 	if (chan_freq)
2406 		scan_entry->channel.chan_freq = chan_freq;
2407 
2408 	/* If no channel info is present in beacon use meta channel */
2409 	if (!scan_entry->channel.chan_freq) {
2410 		scan_entry->channel.chan_freq = recv_freq;
2411 	} else if (recv_freq !=
2412 	   scan_entry->channel.chan_freq) {
2413 		if (!wlan_reg_is_49ghz_freq(scan_entry->channel.chan_freq) &&
2414 		    !is_6g_dup_bcon)
2415 			scan_entry->channel_mismatch = true;
2416 	}
2417 
2418 	if (util_scan_is_hidden_ssid(ssid)) {
2419 		scan_entry->ie_list.ssid = NULL;
2420 		scan_entry->is_hidden_ssid = true;
2421 	} else {
2422 		qdf_mem_copy(scan_entry->ssid.ssid,
2423 				ssid->ssid, ssid->ssid_len);
2424 		scan_entry->ssid.length = ssid->ssid_len;
2425 		scan_entry->hidden_ssid_timestamp =
2426 			scan_entry->scan_entry_time;
2427 	}
2428 	qdf_mem_copy(&scan_entry->mbssid_info, mbssid_info,
2429 		     sizeof(scan_entry->mbssid_info));
2430 
2431 	scan_entry->phy_mode = util_scan_get_phymode(pdev, scan_entry);
2432 
2433 	scan_entry->nss = util_scan_scm_calc_nss_supported_by_ap(scan_entry);
2434 	scm_fill_adaptive_11r_cap(scan_entry);
2435 	util_scan_set_security(scan_entry);
2436 
2437 	util_scan_scm_update_bss_with_esp_data(scan_entry);
2438 	qbss_load = (struct qbss_load_ie *)
2439 			util_scan_entry_qbssload(scan_entry);
2440 	if (qbss_load)
2441 		scan_entry->qbss_chan_load = qbss_load->qbss_chan_load;
2442 
2443 	scan_node = qdf_mem_malloc_atomic(sizeof(*scan_node));
2444 	if (!scan_node) {
2445 		qdf_mem_free(scan_entry->raw_frame.ptr);
2446 		qdf_mem_free(scan_entry);
2447 		return QDF_STATUS_E_FAILURE;
2448 	}
2449 
2450 	util_scan_update_ml_info(scan_entry);
2451 
2452 	scan_node->entry = scan_entry;
2453 	qdf_list_insert_front(scan_list, &scan_node->node);
2454 
2455 	return status;
2456 }
2457 
2458 #ifdef WLAN_FEATURE_MBSSID
2459 /*
2460  * util_is_noninh_ie() - find the noninhertance information element
2461  * in the received frame's IE list, so that we can stop inheriting that IE
2462  * in the caller function.
2463  *
2464  * @elem_id: Element ID in the received frame's IE, which is being processed.
2465  * @non_inh_list: pointer to the non inherited list of element IDs or
2466  *                list of extension element IDs.
2467  * @len: Length of non inheritance IE list
2468  *
2469  * Return: False if the element ID is not found or else return true
2470  */
2471 static bool util_is_noninh_ie(uint8_t elem_id,
2472 			      uint8_t *non_inh_list,
2473 			      int8_t len)
2474 {
2475 	int count;
2476 
2477 	for (count = 0; count < len; count++) {
2478 		if (elem_id == non_inh_list[count])
2479 			return true;
2480 	}
2481 
2482 	return false;
2483 }
2484 
2485 /*
2486  * util_scan_find_noninheritance_ie() - find noninheritance information element
2487  * This block of code is to identify if there is any non-inheritance element
2488  * present as part of the nontransmitted BSSID profile.
2489  * @elem_id: element id
2490  * @ies: pointer consisting of IEs
2491  * @len: IE length
2492  *
2493  * Return: NULL if the element ID is not found or if IE pointer is NULL else
2494  * pointer to the first byte of the requested element
2495  */
2496 static uint8_t
2497 *util_scan_find_noninheritance_ie(uint8_t elem_id, uint8_t *ies,
2498 				  int32_t len)
2499 {
2500 	if (!ies)
2501 		return NULL;
2502 
2503 	while (len >= MIN_IE_LEN && len >= ies[TAG_LEN_POS] + MIN_IE_LEN) {
2504 		if ((ies[ID_POS] == elem_id) &&
2505 		    (ies[ELEM_ID_EXTN_POS] ==
2506 		     WLAN_EXTN_ELEMID_NONINHERITANCE)) {
2507 			return ies;
2508 		}
2509 		len -= ies[TAG_LEN_POS] + MIN_IE_LEN;
2510 		ies += ies[TAG_LEN_POS] + MIN_IE_LEN;
2511 	}
2512 
2513 	return NULL;
2514 }
2515 #endif
2516 
2517 /*
2518  * util_scan_find_ie() - find information element
2519  * @eid: element id
2520  * @ies: pointer consisting of IEs
2521  * @len: IE length
2522  *
2523  * Return: NULL if the element ID is not found or if IE pointer is NULL else
2524  * pointer to the first byte of the requested element
2525  */
2526 static uint8_t *util_scan_find_ie(uint8_t eid, uint8_t *ies,
2527 				  int32_t len)
2528 {
2529 	if (!ies)
2530 		return NULL;
2531 
2532 	while (len >= 2 && len >= ies[1] + 2) {
2533 		if (ies[0] == eid)
2534 			return ies;
2535 		len -= ies[1] + 2;
2536 		ies += ies[1] + 2;
2537 	}
2538 
2539 	return NULL;
2540 }
2541 
2542 #ifdef WLAN_FEATURE_MBSSID
2543 static void util_gen_new_bssid(uint8_t *bssid, uint8_t max_bssid,
2544 			       uint8_t mbssid_index,
2545 			       uint8_t *new_bssid_addr)
2546 {
2547 	uint8_t lsb_n;
2548 	int i;
2549 
2550 	for (i = 0; i < QDF_MAC_ADDR_SIZE; i++)
2551 		new_bssid_addr[i] = bssid[i];
2552 
2553 	lsb_n = new_bssid_addr[5] & ((1 << max_bssid) - 1);
2554 
2555 	new_bssid_addr[5] &= ~((1 << max_bssid) - 1);
2556 	new_bssid_addr[5] |= (lsb_n + mbssid_index) % (1 << max_bssid);
2557 }
2558 
2559 /*
2560  * util_parse_noninheritance_list() - This block of code will be executed only
2561  * if there is a valid non inheritance IE present in the nontx profile.
2562  * Host need not inherit those list of element IDs and list of element ID
2563  * extensions from the transmitted BSSID profile.
2564  * Since non-inheritance element is an element ID extension, it should
2565  * be part of extension element. So first we need to find if there are
2566  * any extension element present in the nontransmitted BSSID profile.
2567  * @extn_elem: If valid, it points to the element ID field of
2568  * extension element tag in the nontransmitted BSSID profile.
2569  * It may or may not have non inheritance tag present.
2570  *      _____________________________________________
2571  *     |         |       |       |List of|List of    |
2572  *     | Element |Length |Element|Element|Element ID |
2573  *     |  ID     |       |ID extn| IDs   |Extension  |
2574  *     |_________|_______|_______|_______|___________|
2575  * List of Element IDs:
2576  *      __________________
2577  *     |         |        |
2578  *     |  Length |Element |
2579  *     |         |ID List |
2580  *     |_________|________|
2581  * List of Element ID Extensions:
2582  *      __________________________
2583  *     |         |                |
2584  *     |  Length |Element ID      |
2585  *     |         |extension List  |
2586  *     |_________|________________|
2587  * @elem_list: Element ID list
2588  * @extn_elem_list: Element ID exiension list
2589  * @non_inheritance_ie: Non inheritance IE information
2590  */
2591 
2592 static void util_parse_noninheritance_list(uint8_t *extn_elem,
2593 					   uint8_t **elem_list,
2594 					   uint8_t **extn_elem_list,
2595 					   struct non_inheritance_ie *ninh)
2596 {
2597 	int8_t extn_rem_len = 0;
2598 
2599 	if (extn_elem[ELEM_ID_LIST_LEN_POS] < extn_elem[TAG_LEN_POS]) {
2600 		/*
2601 		 * extn_rem_len represents the number of bytes after
2602 		 * the length subfield of list of Element IDs.
2603 		 * So here, extn_rem_len should be equal to
2604 		 * Element ID list + Length subfield of Element ID
2605 		 * extension list + Element ID extension list.
2606 		 *
2607 		 * Here we have taken two pointers pointing to the
2608 		 * element ID list and element ID extension list
2609 		 * which we will use to detect the same elements
2610 		 * in the transmitted BSSID profile and choose not
2611 		 * to inherit those elements while constructing the
2612 		 * frame for nontransmitted BSSID profile.
2613 		 */
2614 		extn_rem_len = extn_elem[TAG_LEN_POS] - MIN_IE_LEN;
2615 		ninh->non_inherit = true;
2616 
2617 		if (extn_rem_len && extn_elem[ELEM_ID_LIST_LEN_POS]) {
2618 			if (extn_rem_len >= extn_elem[ELEM_ID_LIST_LEN_POS]) {
2619 				ninh->list_len =
2620 					extn_elem[ELEM_ID_LIST_LEN_POS];
2621 				*elem_list = extn_elem + ELEM_ID_LIST_POS;
2622 				extn_rem_len -= ninh->list_len;
2623 			} else {
2624 				/*
2625 				 * Corrupt frame. length subfield of
2626 				 * element ID list is greater than
2627 				 * what it should be. Go ahead with
2628 				 * frame generation but do not honour
2629 				 * the non inheritance part. Also, mark
2630 				 * the element ID in subcopy as 0, so
2631 				 * that this element info will not
2632 				 * be copied.
2633 				 */
2634 				ninh->non_inherit = false;
2635 				extn_elem[0] = 0;
2636 			}
2637 		}
2638 
2639 		extn_rem_len--;
2640 		if (extn_rem_len > 0) {
2641 			if (!ninh->list_len) {
2642 				ninh->extn_len =
2643 					extn_elem[ELEM_ID_LIST_LEN_POS + 1];
2644 			} else {
2645 				ninh->extn_len =
2646 					extn_elem[ELEM_ID_LIST_POS +
2647 					ninh->list_len];
2648 			}
2649 
2650 			if (extn_rem_len != ninh->extn_len) {
2651 				/*
2652 				 * Corrupt frame. length subfield of
2653 				 * element ID extn list is not
2654 				 * what it should be. Go ahead with
2655 				 * frame generation but do not honour
2656 				 * the non inheritance part. Also, mark
2657 				 * the element ID in subcopy as 0, so
2658 				 * that this element info will not
2659 				 * be copied.
2660 				 */
2661 				ninh->non_inherit = false;
2662 				extn_elem[0] = 0;
2663 			}
2664 
2665 			if (ninh->extn_len) {
2666 				*extn_elem_list =
2667 					(extn_elem + ninh->list_len +
2668 					 ELEM_ID_LIST_POS + 1);
2669 			}
2670 		}
2671 	}
2672 }
2673 
2674 #ifdef WLAN_FEATURE_11BE_MLO
2675 /**
2676  * util_handle_rnr_ie_for_mbssid() - parse and modify RNR IE for MBSSID feature
2677  * @rnr: The pointer to RNR IE
2678  * @bssid_index: BSSID index from MBSSID index IE
2679  * @pos: The buffer pointer to save the transformed RNR IE, caller is expected
2680  *       to supply a buffer that is at least as big as @rnr
2681  *
2682  * Per the description about Neighbor AP Information field about MLD
2683  * parameters subfield in section 9.4.2.170.2 of Draft P802.11be_D1.4.
2684  * If the reported AP is affiliated with the same MLD of the reporting AP,
2685  * the TBTT information is skipped; If the reported AP is affiliated with
2686  * the same MLD of the nontransmitted BSSID, the TBTT information is
2687  * copied and the MLD ID is changed to 0.
2688  *
2689  * Return: Length of the element written to @pos
2690  */
2691 static int util_handle_rnr_ie_for_mbssid(const uint8_t *rnr,
2692 					 uint8_t bssid_index, uint8_t *pos)
2693 {
2694 	size_t rnr_len;
2695 	const uint8_t *data, *rnr_end;
2696 	uint8_t *rnr_new;
2697 	struct neighbor_ap_info_field *neighbor_ap_info;
2698 	struct rnr_mld_info *mld_param;
2699 	uint8_t tbtt_type, tbtt_len, tbtt_count;
2700 	uint8_t mld_pos, mld_id;
2701 	int32_t i, copy_len;
2702 	/* The count of TBTT info field whose MLD ID equals to 0 in a neighbor
2703 	 * AP information field.
2704 	 */
2705 	uint32_t tbtt_info_field_count;
2706 	/* The total bytes of TBTT info fields whose MLD ID equals to 0 in
2707 	 * current RNR IE.
2708 	 */
2709 	uint32_t tbtt_info_field_len = 0;
2710 	uint8_t nbr_ap_info_len = sizeof(struct neighbor_ap_info_field);
2711 
2712 	rnr_len = rnr[TAG_LEN_POS];
2713 	rnr_end = rnr + rnr_len + MIN_IE_LEN;
2714 	rnr_new = pos;
2715 	qdf_mem_copy(pos, rnr, MIN_IE_LEN);
2716 	pos += MIN_IE_LEN;
2717 
2718 	data = rnr + PAYLOAD_START_POS;
2719 	while (data < rnr_end) {
2720 		neighbor_ap_info = (struct neighbor_ap_info_field *)data;
2721 		tbtt_count = neighbor_ap_info->tbtt_header.tbtt_info_count;
2722 		tbtt_len = neighbor_ap_info->tbtt_header.tbtt_info_length;
2723 		tbtt_type = neighbor_ap_info->tbtt_header.tbbt_info_fieldtype;
2724 		scm_debug("channel number %d, op class %d, bssid_index %d",
2725 			  neighbor_ap_info->channel_number,
2726 			  neighbor_ap_info->operting_class, bssid_index);
2727 		scm_debug("tbtt_count %d, tbtt_length %d, tbtt_type %d",
2728 			  tbtt_count, tbtt_len, tbtt_type);
2729 
2730 		copy_len = tbtt_len * (tbtt_count + 1) +
2731 			   nbr_ap_info_len;
2732 		if (data + copy_len > rnr_end)
2733 			return 0;
2734 
2735 		if (tbtt_len >=
2736 		    TBTT_NEIGHBOR_AP_BSSID_S_SSID_BSS_PARAM_20MHZ_PSD_MLD_PARAM)
2737 			mld_pos =
2738 			     TBTT_NEIGHBOR_AP_BSSID_S_SSID_BSS_PARAM_20MHZ_PSD;
2739 		else
2740 			mld_pos = 0;
2741 
2742 		/* If MLD params do not exist, copy this neighbor AP
2743 		 * information field.
2744 		 * Per Draft P802.11be_D1.4, tbtt_type value 1, 2 and 3
2745 		 * are reserved,
2746 		 */
2747 		if (mld_pos == 0 || tbtt_type != 0) {
2748 			scm_debug("no MLD params, tbtt_type %d", tbtt_type);
2749 			qdf_mem_copy(pos, data, copy_len);
2750 			pos += copy_len;
2751 			data += copy_len;
2752 			continue;
2753 		}
2754 
2755 		qdf_mem_copy(pos, data, nbr_ap_info_len);
2756 		neighbor_ap_info = (struct neighbor_ap_info_field *)pos;
2757 		pos += nbr_ap_info_len;
2758 		data += nbr_ap_info_len;
2759 
2760 		tbtt_info_field_count = 0;
2761 		for (i = 0; i < tbtt_count + 1; i++) {
2762 			mld_param = (struct rnr_mld_info *)&data[mld_pos];
2763 			mld_id = mld_param->mld_id;
2764 
2765 			/* Refer to Draft P802.11be_D1.4
2766 			 * 9.4.2.170.2 Neighbor AP Information field about
2767 			 * MLD parameters subfield
2768 			 */
2769 			if (mld_id == 0) {
2770 				/* Skip this TBTT information since this
2771 				 * reported AP is affiliated with the same MLD
2772 				 * of the reporting AP who sending the frame
2773 				 * carrying this element.
2774 				 */
2775 				tbtt_info_field_len += tbtt_len;
2776 				data += tbtt_len;
2777 				tbtt_info_field_count++;
2778 			} else if (mld_id == bssid_index) {
2779 				/* Copy this TBTT information and change MLD
2780 				 * to 0 as this reported AP is affiliated with
2781 				 * the same MLD of the nontransmitted BSSID.
2782 				 */
2783 				qdf_mem_copy(pos, data, tbtt_len);
2784 				mld_param =
2785 					(struct rnr_mld_info *)&pos[mld_pos];
2786 				scm_debug("change MLD ID from %d to 0",
2787 					  mld_param->mld_id);
2788 				mld_param->mld_id = 0;
2789 				data += tbtt_len;
2790 				pos += tbtt_len;
2791 			} else {
2792 				qdf_mem_copy(pos, data, tbtt_len);
2793 				data += tbtt_len;
2794 				pos += tbtt_len;
2795 			}
2796 		}
2797 
2798 		scm_debug("skip %d neighbor info", tbtt_info_field_count);
2799 		if (tbtt_info_field_count == (tbtt_count + 1)) {
2800 			/* If all the TBTT information are skipped, then also
2801 			 * revert the neighbor AP info which has been copied.
2802 			 */
2803 			pos -= nbr_ap_info_len;
2804 			tbtt_info_field_len += nbr_ap_info_len;
2805 		} else {
2806 			neighbor_ap_info->tbtt_header.tbtt_info_count -=
2807 							tbtt_info_field_count;
2808 		}
2809 	}
2810 
2811 	rnr_new[TAG_LEN_POS] = rnr_len - tbtt_info_field_len;
2812 	if (rnr_new[TAG_LEN_POS] > 0)
2813 		rnr_len = rnr_new[TAG_LEN_POS] + MIN_IE_LEN;
2814 	else
2815 		rnr_len = 0;
2816 
2817 	return rnr_len;
2818 }
2819 #else
2820 static int util_handle_rnr_ie_for_mbssid(const uint8_t *rnr,
2821 					 uint8_t bssid_index, uint8_t *pos)
2822 {
2823 	return 0;
2824 }
2825 #endif
2826 
2827 static uint32_t util_gen_new_ie(uint8_t *ie, uint32_t ielen,
2828 				uint8_t *subelement,
2829 				size_t subie_len, uint8_t *new_ie,
2830 				uint8_t bssid_index)
2831 {
2832 	uint8_t *pos, *tmp;
2833 	const uint8_t *tmp_old, *tmp_new;
2834 	uint8_t *sub_copy, *extn_elem = NULL;
2835 	struct non_inheritance_ie ninh = {0};
2836 	uint8_t *elem_list = NULL, *extn_elem_list = NULL;
2837 	size_t tmp_rem_len;
2838 
2839 	/* copy subelement as we need to change its content to
2840 	 * mark an ie after it is processed.
2841 	 */
2842 	sub_copy = qdf_mem_malloc(subie_len);
2843 	if (!sub_copy)
2844 		return 0;
2845 	qdf_mem_copy(sub_copy, subelement, subie_len);
2846 
2847 	pos = &new_ie[0];
2848 
2849 	/* new ssid */
2850 	tmp_new = util_scan_find_ie(WLAN_ELEMID_SSID, sub_copy, subie_len);
2851 	if (tmp_new) {
2852 		scm_debug(" SSID " QDF_SSID_FMT,
2853 			  QDF_SSID_REF(tmp_new[1],
2854 				       &tmp_new[PAYLOAD_START_POS]));
2855 		if ((pos + tmp_new[1] + MIN_IE_LEN) <=
2856 		    (new_ie + ielen)) {
2857 			qdf_mem_copy(pos, tmp_new,
2858 				     (tmp_new[1] + MIN_IE_LEN));
2859 			pos += (tmp_new[1] + MIN_IE_LEN);
2860 		}
2861 	}
2862 
2863 	extn_elem = util_scan_find_noninheritance_ie(WLAN_ELEMID_EXTN_ELEM,
2864 						     sub_copy, subie_len);
2865 
2866 	if (extn_elem && extn_elem[TAG_LEN_POS]) {
2867 		util_parse_noninheritance_list(extn_elem, &elem_list,
2868 					       &extn_elem_list, &ninh);
2869 	}
2870 
2871 	/* go through IEs in ie (skip SSID) and subelement,
2872 	 * merge them into new_ie
2873 	 */
2874 	tmp_old = util_scan_find_ie(WLAN_ELEMID_SSID, ie, ielen);
2875 	tmp_old = (tmp_old) ? tmp_old + tmp_old[1] + MIN_IE_LEN : ie;
2876 
2877 	while (((tmp_old + tmp_old[1] + MIN_IE_LEN) - ie) <= ielen) {
2878 		ninh.non_inh_ie_found = 0;
2879 		if (ninh.non_inherit) {
2880 			if (ninh.list_len) {
2881 				ninh.non_inh_ie_found =
2882 					util_is_noninh_ie(tmp_old[0],
2883 							  elem_list,
2884 							  ninh.list_len);
2885 			}
2886 
2887 			if (!ninh.non_inh_ie_found &&
2888 			    ninh.extn_len &&
2889 			    (tmp_old[0] == WLAN_ELEMID_EXTN_ELEM)) {
2890 				ninh.non_inh_ie_found =
2891 					util_is_noninh_ie(tmp_old[2],
2892 							  extn_elem_list,
2893 							  ninh.extn_len);
2894 			}
2895 		}
2896 
2897 		if (ninh.non_inh_ie_found || (tmp_old[0] == 0)) {
2898 			tmp_old += tmp_old[1] + MIN_IE_LEN;
2899 			continue;
2900 		}
2901 
2902 		tmp = (uint8_t *)util_scan_find_ie(tmp_old[0], sub_copy,
2903 						   subie_len);
2904 		if (!tmp) {
2905 			/* ie in old ie but not in subelement */
2906 			if (tmp_old[0] == WLAN_ELEMID_REDUCED_NEIGHBOR_REPORT) {
2907 				/* handle rnr ie for mbssid*/
2908 				pos +=
2909 				    util_handle_rnr_ie_for_mbssid(tmp_old,
2910 								  bssid_index,
2911 								  pos);
2912 			} else if (tmp_old[0] != WLAN_ELEMID_MULTIPLE_BSSID) {
2913 				if ((pos + tmp_old[1] + MIN_IE_LEN) <=
2914 				    (new_ie + ielen)) {
2915 					qdf_mem_copy(pos, tmp_old,
2916 						     (tmp_old[1] +
2917 						      MIN_IE_LEN));
2918 					pos += tmp_old[1] + MIN_IE_LEN;
2919 				}
2920 			}
2921 		} else {
2922 			/* ie in transmitting ie also in subelement,
2923 			 * copy from subelement and flag the ie in subelement
2924 			 * as copied (by setting eid field to 0xff).
2925 			 * To determine if the vendor ies are same:
2926 			 * 1. For Cisco OUI, compare only OUI + type
2927 			 * 2. For other OUI, compare OUI + type + subType
2928 			 */
2929 			tmp_rem_len = subie_len - (tmp - sub_copy);
2930 			if (tmp_old[0] == WLAN_ELEMID_VENDOR &&
2931 			    tmp_rem_len >= MIN_VENDOR_TAG_LEN) {
2932 				/* If Vendor IE also presents in STA profile,
2933 				 * then ignore the Vendor IE which is for
2934 				 * reporting STA. It only needs to copy Vendor
2935 				 * IE from STA profile for reported BSSID.
2936 				 * The copy happens when going through the
2937 				 * remaining IEs.
2938 				 */
2939 				;
2940 			} else if (tmp_old[0] == WLAN_ELEMID_EXTN_ELEM) {
2941 				if (tmp_old[PAYLOAD_START_POS] ==
2942 				    tmp[PAYLOAD_START_POS]) {
2943 					/* same ie, copy from subelement */
2944 					if ((pos + tmp[1] + MIN_IE_LEN) <=
2945 					    (new_ie + ielen)) {
2946 						qdf_mem_copy(pos, tmp,
2947 							     tmp[1] +
2948 							     MIN_IE_LEN);
2949 						pos += tmp[1] + MIN_IE_LEN;
2950 						tmp[0] = 0;
2951 					}
2952 				} else {
2953 					if ((pos + tmp_old[1] + MIN_IE_LEN) <=
2954 					    (new_ie + ielen)) {
2955 						qdf_mem_copy(pos, tmp_old,
2956 							     tmp_old[1] +
2957 							     MIN_IE_LEN);
2958 						pos += tmp_old[1] +
2959 							MIN_IE_LEN;
2960 					}
2961 				}
2962 
2963 			} else {
2964 				/* copy ie from subelement into new ie */
2965 				if ((pos + tmp[1] + MIN_IE_LEN) <=
2966 				    (new_ie + ielen)) {
2967 					qdf_mem_copy(pos, tmp,
2968 						     tmp[1] + MIN_IE_LEN);
2969 					pos += tmp[1] + MIN_IE_LEN;
2970 					tmp[0] = 0;
2971 				}
2972 			}
2973 		}
2974 
2975 		if (((tmp_old + tmp_old[1] + MIN_IE_LEN) - ie) >= ielen)
2976 			break;
2977 
2978 		tmp_old += tmp_old[1] + MIN_IE_LEN;
2979 	}
2980 
2981 	/* go through subelement again to check if there is any ie not
2982 	 * copied to new ie, skip ssid, capability, bssid-index ie
2983 	 */
2984 	tmp_new = sub_copy;
2985 	while (((tmp_new + tmp_new[1] + MIN_IE_LEN) - sub_copy) <=
2986 	       subie_len) {
2987 		if (!(tmp_new[0] == WLAN_ELEMID_NONTX_BSSID_CAP ||
2988 		      tmp_new[0] == WLAN_ELEMID_SSID ||
2989 		      tmp_new[0] == WLAN_ELEMID_MULTI_BSSID_IDX ||
2990 		      ((tmp_new[0] == WLAN_ELEMID_EXTN_ELEM) &&
2991 		       (tmp_new[2] == WLAN_EXTN_ELEMID_NONINHERITANCE)))) {
2992 			if ((pos + tmp_new[1] + MIN_IE_LEN) <=
2993 			    (new_ie + ielen)) {
2994 				qdf_mem_copy(pos, tmp_new,
2995 					     tmp_new[1] + MIN_IE_LEN);
2996 				pos += tmp_new[1] + MIN_IE_LEN;
2997 			}
2998 		}
2999 		if (((tmp_new + tmp_new[1] + MIN_IE_LEN) - sub_copy) >=
3000 		    subie_len)
3001 			break;
3002 		tmp_new += tmp_new[1] + MIN_IE_LEN;
3003 	}
3004 
3005 	qdf_mem_free(sub_copy);
3006 
3007 	if (pos > new_ie)
3008 		return pos - new_ie;
3009 	else
3010 		return 0;
3011 }
3012 
3013 static enum nontx_profile_reasoncode
3014 util_handle_nontx_prof(uint8_t *mbssid_elem, uint8_t *subelement,
3015 		       uint8_t *next_subelement,
3016 		       struct scan_mbssid_info *mbssid_info,
3017 		       char *bssid, char *new_bssid)
3018 {
3019 	uint8_t *mbssid_index_ie;
3020 	uint32_t prof_len;
3021 
3022 	prof_len = subelement[TAG_LEN_POS];
3023 	/*
3024 	 * If we are executing the split portion of the nontx
3025 	 * profile present in the subsequent MBSSID, then there
3026 	 * is no need of any sanity check for valid BSS profile
3027 	 */
3028 
3029 	if (mbssid_info->split_prof_continue) {
3030 		if ((subelement[ID_POS] != 0) ||
3031 		    (subelement[TAG_LEN_POS] < SPLIT_PROF_DATA_LEAST_LEN)) {
3032 			return INVALID_SPLIT_PROF;
3033 		}
3034 	} else {
3035 		if ((subelement[ID_POS] != 0) ||
3036 		    (subelement[TAG_LEN_POS] < VALID_ELEM_LEAST_LEN)) {
3037 			/* not a valid BSS profile */
3038 			return INVALID_NONTX_PROF;
3039 		}
3040 	}
3041 
3042 	if (mbssid_info->split_profile) {
3043 		if (next_subelement[PAYLOAD_START_POS] !=
3044 		    WLAN_ELEMID_NONTX_BSSID_CAP) {
3045 			mbssid_info->prof_residue = true;
3046 		}
3047 	}
3048 
3049 	if (!mbssid_info->split_prof_continue &&
3050 	    ((subelement[PAYLOAD_START_POS] != WLAN_ELEMID_NONTX_BSSID_CAP) ||
3051 	     (subelement[NONTX_BSSID_CAP_TAG_LEN_POS] != CAP_INFO_LEN))) {
3052 		/* The first element within the Nontransmitted
3053 		 * BSSID Profile is not the Nontransmitted
3054 		 * BSSID Capability element.
3055 		 */
3056 		return INVALID_NONTX_PROF;
3057 	}
3058 
3059 	/* found a Nontransmitted BSSID Profile */
3060 	mbssid_index_ie =
3061 		util_scan_find_ie(WLAN_ELEMID_MULTI_BSSID_IDX,
3062 				  (subelement + PAYLOAD_START_POS), prof_len);
3063 
3064 	if (!mbssid_index_ie) {
3065 		if (!mbssid_info->prof_residue)
3066 			return INVALID_NONTX_PROF;
3067 
3068 		mbssid_info->skip_bssid_copy = true;
3069 	} else if ((mbssid_index_ie[TAG_LEN_POS] < 1) ||
3070 		   (mbssid_index_ie[BSS_INDEX_POS] == 0)) {
3071 		/* No valid Multiple BSSID-Index element */
3072 		return INVALID_NONTX_PROF;
3073 	}
3074 
3075 	if (!mbssid_info->skip_bssid_copy) {
3076 		qdf_mem_copy(mbssid_info->trans_bssid,
3077 			     bssid, QDF_MAC_ADDR_SIZE);
3078 		mbssid_info->profile_num =
3079 			mbssid_index_ie[BSS_INDEX_POS];
3080 		util_gen_new_bssid(bssid,
3081 				   mbssid_elem[MBSSID_INDICATOR_POS],
3082 				   mbssid_index_ie[BSS_INDEX_POS],
3083 				   new_bssid);
3084 	}
3085 	/* In single MBSS IE, there could be subelement holding
3086 	 * remaining vendor IEs of non tx profile from last MBSS IE
3087 	 * [split profile] and new non tx profile, hence reset
3088 	 * skip_bssid_copy flag after each subelement processing
3089 	 */
3090 	mbssid_info->skip_bssid_copy = false;
3091 	return VALID_NONTX_PROF;
3092 }
3093 
3094 /*
3095  * What's split profile:
3096  *  If any nontransmitted BSSID profile is fragmented across
3097  * multiple MBSSID elements, then it is called split profile.
3098  * For a split profile to exist we need to have at least two
3099  * MBSSID elements as part of the RX beacon or probe response
3100  * Hence, first we need to identify the next MBSSID element
3101  * and check for the 5th bit from the starting of the next
3102  * MBSSID IE and if it does not have Nontransmitted BSSID
3103  * capability element, then it's a split profile case.
3104  */
3105 static bool util_scan_is_split_prof_found(uint8_t *next_elem,
3106 					  uint8_t *ie, uint32_t ielen)
3107 {
3108 	uint8_t *next_mbssid_elem;
3109 
3110 	if (next_elem[0] == WLAN_ELEMID_MULTIPLE_BSSID) {
3111 		if ((next_elem[TAG_LEN_POS] >= VALID_ELEM_LEAST_LEN) &&
3112 		    (next_elem[SUBELEM_DATA_POS_FROM_MBSSID] !=
3113 		     WLAN_ELEMID_NONTX_BSSID_CAP)) {
3114 			return true;
3115 		}
3116 	} else {
3117 		next_mbssid_elem =
3118 			util_scan_find_ie(WLAN_ELEMID_MULTIPLE_BSSID,
3119 					  next_elem,
3120 					  ielen - (next_elem - ie));
3121 		if (!next_mbssid_elem)
3122 			return false;
3123 
3124 		if ((next_mbssid_elem[TAG_LEN_POS] >= VALID_ELEM_LEAST_LEN) &&
3125 		    (next_mbssid_elem[SUBELEM_DATA_POS_FROM_MBSSID] !=
3126 		     WLAN_ELEMID_NONTX_BSSID_CAP)) {
3127 			return true;
3128 		}
3129 	}
3130 
3131 	return false;
3132 }
3133 
3134 static QDF_STATUS util_scan_parse_mbssid(struct wlan_objmgr_pdev *pdev,
3135 					 uint8_t *frame, qdf_size_t frame_len,
3136 					 uint32_t frm_subtype,
3137 					 struct mgmt_rx_event_params *rx_param,
3138 					 qdf_list_t *scan_list)
3139 {
3140 	struct wlan_bcn_frame *bcn;
3141 	struct wlan_frame_hdr *hdr;
3142 	struct scan_mbssid_info mbssid_info = {0};
3143 	QDF_STATUS status;
3144 	uint8_t *pos, *subelement, *next_elem;
3145 	uint8_t *mbssid_elem;
3146 	uint32_t subie_len, new_ie_len, ielen;
3147 	uint8_t *next_subelement = NULL;
3148 	uint8_t new_bssid[QDF_MAC_ADDR_SIZE], bssid[QDF_MAC_ADDR_SIZE];
3149 	uint8_t *new_ie, *split_prof_start = NULL, *split_prof_end = NULL;
3150 	uint8_t *ie, *new_frame = NULL;
3151 	int new_frame_len = 0, split_prof_len = 0;
3152 	enum nontx_profile_reasoncode retval;
3153 	uint8_t *nontx_profile = NULL;
3154 
3155 	hdr = (struct wlan_frame_hdr *)frame;
3156 	bcn = (struct wlan_bcn_frame *)(frame + sizeof(struct wlan_frame_hdr));
3157 	ie = (uint8_t *)&bcn->ie;
3158 	ielen = (uint16_t)(frame_len -
3159 			   sizeof(struct wlan_frame_hdr) -
3160 			   offsetof(struct wlan_bcn_frame, ie));
3161 	qdf_mem_copy(bssid, hdr->i_addr3, QDF_MAC_ADDR_SIZE);
3162 
3163 	if (!util_scan_find_ie(WLAN_ELEMID_MULTIPLE_BSSID, ie, ielen))
3164 		return QDF_STATUS_E_FAILURE;
3165 
3166 	pos = ie;
3167 
3168 	new_ie = qdf_mem_malloc(ielen);
3169 	if (!new_ie)
3170 		return QDF_STATUS_E_NOMEM;
3171 
3172 	while (pos < (ie + ielen + MIN_IE_LEN)) {
3173 		mbssid_elem =
3174 			util_scan_find_ie(WLAN_ELEMID_MULTIPLE_BSSID, pos,
3175 					  ielen - (pos - ie));
3176 		if (!mbssid_elem)
3177 			break;
3178 
3179 		mbssid_info.profile_count =
3180 			(1 << mbssid_elem[MBSSID_INDICATOR_POS]);
3181 
3182 		next_elem =
3183 			mbssid_elem + mbssid_elem[TAG_LEN_POS] + MIN_IE_LEN;
3184 
3185 		/* Skip Element ID, Len, MaxBSSID Indicator */
3186 		if (!mbssid_info.split_profile &&
3187 		    (mbssid_elem[TAG_LEN_POS] < VALID_ELEM_LEAST_LEN)) {
3188 			break;
3189 		}
3190 
3191 		/*
3192 		 * Find if the next IE is MBSSID, if not, then scan through
3193 		 * the IE list and find the next MBSSID tag, if present.
3194 		 * Once we find the MBSSID tag, check if this MBSSID tag has
3195 		 * the other fragmented part of the non Tx profile.
3196 		 */
3197 
3198 		mbssid_info.split_profile =
3199 			util_scan_is_split_prof_found(next_elem, ie, ielen);
3200 
3201 		for (subelement = mbssid_elem + SUBELEMENT_START_POS;
3202 		     subelement < (next_elem - 1);
3203 		     subelement += MIN_IE_LEN + subelement[TAG_LEN_POS]) {
3204 			subie_len = subelement[TAG_LEN_POS];
3205 
3206 			/*
3207 			 * if prof_residue is true, that means we are
3208 			 * in the continuation of the fragmented profile part,
3209 			 * present in the next MBSSD IE else this profile
3210 			 * is a non fragmented non tx BSSID profile.
3211 			 */
3212 
3213 			if (mbssid_info.prof_residue)
3214 				mbssid_info.split_prof_continue = true;
3215 			else
3216 				mbssid_info.split_prof_continue = false;
3217 
3218 			if (subie_len > MAX_SUBELEM_LEN) {
3219 				scm_err_rl("Corrupt frame with subie_len: %d\n"
3220 					   "split_prof_continue: %d\n"
3221 					   "prof_residue: %d\n",
3222 					   subie_len,
3223 					   mbssid_info.split_prof_continue,
3224 					   mbssid_info.prof_residue);
3225 				if (mbssid_info.split_prof_continue) {
3226 					qdf_mem_free(split_prof_start);
3227 					split_prof_start = NULL;
3228 				}
3229 
3230 				qdf_mem_free(new_ie);
3231 				return QDF_STATUS_E_INVAL;
3232 			}
3233 
3234 			if ((next_elem - subelement) <
3235 			    (MIN_IE_LEN + subie_len))
3236 				break;
3237 
3238 			next_subelement = subelement + subie_len + MIN_IE_LEN;
3239 			retval = util_handle_nontx_prof(mbssid_elem, subelement,
3240 							next_subelement,
3241 							&mbssid_info,
3242 							bssid, new_bssid);
3243 
3244 			if (retval == INVALID_SPLIT_PROF) {
3245 				scm_err_rl("Corrupt frame with ID_POS: %d\n"
3246 					   "TAG_LEN_POS: %d\n",
3247 					   subelement[ID_POS],
3248 					   subelement[TAG_LEN_POS]);
3249 				qdf_mem_free(split_prof_start);
3250 				split_prof_start = NULL;
3251 				qdf_mem_free(new_ie);
3252 				return QDF_STATUS_E_INVAL;
3253 			} else if (retval == INVALID_NONTX_PROF) {
3254 				continue;
3255 			}
3256 
3257 			/*
3258 			 * Merging parts of nontx profile-
3259 			 * Just for understanding, let's make an assumption
3260 			 * that nontx profile is fragmented across MBSSIE1
3261 			 * and MBSSIE2.
3262 			 * mbssid_info.prof_residue being set indicates
3263 			 * that the ongoing nontx profile is part of split
3264 			 * profile, whose other fragmented part is present
3265 			 * in MBSSIE2.
3266 			 * So once prof_residue is set, we need to
3267 			 * identify whether we are accessing the split
3268 			 * profile in MBSSIE1 or MBSSIE2.
3269 			 * If we are in MBSSIE1, then copy the part of split
3270 			 * profile from MBSSIE1 into a new buffer and then
3271 			 * move to the next part of the split profile which
3272 			 * is present in MBSSIE2 and append that part into
3273 			 * the new buffer.
3274 			 * Once the full profile is accumulated, go ahead with
3275 			 * the ie generation and length calculation of the
3276 			 * new frame.
3277 			 */
3278 
3279 			if (mbssid_info.prof_residue) {
3280 				if (!mbssid_info.split_prof_continue) {
3281 					split_prof_start =
3282 						qdf_mem_malloc(ielen);
3283 					if (!split_prof_start) {
3284 						scm_err_rl("Malloc failed");
3285 						qdf_mem_free(new_ie);
3286 						return QDF_STATUS_E_NOMEM;
3287 					}
3288 
3289 					qdf_mem_copy(split_prof_start,
3290 						     subelement,
3291 						     (subie_len +
3292 						      MIN_IE_LEN));
3293 					split_prof_end = (split_prof_start +
3294 							  subie_len +
3295 							  MIN_IE_LEN);
3296 					break;
3297 				}
3298 
3299 				/*
3300 				 * Currently we are accessing other part of the
3301 				 * split profile present in the subsequent
3302 				 * MBSSIE. There is a possibility that one
3303 				 * non tx profile is spread across more than
3304 				 * two MBSSID tag as well. This code will
3305 				 * handle such scenario.
3306 				 */
3307 
3308 				if (split_prof_end) {
3309 					qdf_mem_copy(split_prof_end,
3310 						     (subelement + MIN_IE_LEN),
3311 						     subie_len);
3312 					split_prof_end += subie_len;
3313 				}
3314 
3315 				/*
3316 				 * When to stop the process of accumulating
3317 				 * parts of split profile, is decided by
3318 				 * mbssid_info.prof_residue. prof_residue
3319 				 * could be made false if there is not any
3320 				 * continuation of the split profile.
3321 				 * which could be identified by two factors
3322 				 * 1. By checking if the next MBSSIE's first
3323 				 * non tx profile is not a fragmented one or
3324 				 * 2. there is a probability that first
3325 				 * subelement of MBSSIE2 is end if split
3326 				 * profile and the next subelement of MBSSIE2
3327 				 * is a non split one.
3328 				 */
3329 
3330 				if (!mbssid_info.split_profile ||
3331 				    (next_subelement[PAYLOAD_START_POS] ==
3332 				     WLAN_ELEMID_NONTX_BSSID_CAP)) {
3333 					mbssid_info.prof_residue = false;
3334 				}
3335 
3336 				/*
3337 				 * Until above mentioned conditions are met,
3338 				 * we need to iterate and keep accumulating
3339 				 * the split profile contents.
3340 				 */
3341 
3342 				if (mbssid_info.prof_residue)
3343 					break;
3344 
3345 				if (split_prof_end) {
3346 					split_prof_len =
3347 						(split_prof_end -
3348 						 split_prof_start - MIN_IE_LEN);
3349 				}
3350 			}
3351 
3352 			if (mbssid_info.split_prof_continue) {
3353 				nontx_profile = split_prof_start;
3354 				subie_len = split_prof_len;
3355 			} else {
3356 				nontx_profile = subelement;
3357 			}
3358 
3359 			new_ie_len =
3360 				util_gen_new_ie(ie, ielen,
3361 						(nontx_profile +
3362 						 PAYLOAD_START_POS),
3363 						subie_len, new_ie,
3364 						mbssid_info.profile_num);
3365 
3366 			if (!new_ie_len) {
3367 				if (mbssid_info.split_prof_continue) {
3368 					qdf_mem_free(split_prof_start);
3369 					split_prof_start = NULL;
3370 				}
3371 				continue;
3372 			}
3373 
3374 			new_frame_len = frame_len - ielen + new_ie_len;
3375 
3376 			if (new_frame_len < 0 || new_frame_len > frame_len) {
3377 				if (mbssid_info.split_prof_continue) {
3378 					qdf_mem_free(split_prof_start);
3379 					split_prof_start = NULL;
3380 				}
3381 				qdf_mem_free(new_ie);
3382 				scm_err("Invalid frame:Stop MBSSIE parsing");
3383 				scm_err("Frame_len: %zu,ielen:%u,new_ie_len:%u",
3384 					frame_len, ielen, new_ie_len);
3385 				return QDF_STATUS_E_INVAL;
3386 			}
3387 
3388 			new_frame = qdf_mem_malloc(new_frame_len);
3389 			if (!new_frame) {
3390 				if (mbssid_info.split_prof_continue) {
3391 					qdf_mem_free(split_prof_start);
3392 					split_prof_start = NULL;
3393 				}
3394 				qdf_mem_free(new_ie);
3395 				scm_err_rl("Malloc for new_frame failed");
3396 				scm_err_rl("split_prof_continue: %d",
3397 					   mbssid_info.split_prof_continue);
3398 				return QDF_STATUS_E_NOMEM;
3399 			}
3400 
3401 			/*
3402 			 * Copy the header(24byte), timestamp(8 byte),
3403 			 * beaconinterval(2byte) and capability(2byte)
3404 			 */
3405 			qdf_mem_copy(new_frame, frame, FIXED_LENGTH);
3406 			/* Copy the new ie generated from MBSSID profile*/
3407 			hdr = (struct wlan_frame_hdr *)new_frame;
3408 			qdf_mem_copy(hdr->i_addr2, new_bssid,
3409 				     QDF_MAC_ADDR_SIZE);
3410 			qdf_mem_copy(hdr->i_addr3, new_bssid,
3411 				     QDF_MAC_ADDR_SIZE);
3412 			bcn = (struct wlan_bcn_frame *)
3413 				(new_frame + sizeof(struct wlan_frame_hdr));
3414 			/* update the non-tx capability */
3415 			qdf_mem_copy(&bcn->capability,
3416 				     nontx_profile + CAP_INFO_POS,
3417 				     CAP_INFO_LEN);
3418 
3419 			/* Copy the new ie generated from MBSSID profile*/
3420 			qdf_mem_copy(new_frame +
3421 				     offsetof(struct wlan_bcn_frame, ie) +
3422 				     sizeof(struct wlan_frame_hdr),
3423 				     new_ie, new_ie_len);
3424 			status = util_scan_gen_scan_entry(pdev, new_frame,
3425 							  new_frame_len,
3426 							  frm_subtype,
3427 							  rx_param,
3428 							  &mbssid_info,
3429 							  scan_list);
3430 			if (QDF_IS_STATUS_ERROR(status)) {
3431 				if (mbssid_info.split_prof_continue) {
3432 					qdf_mem_free(split_prof_start);
3433 					split_prof_start = NULL;
3434 					qdf_mem_zero(&mbssid_info,
3435 						     sizeof(mbssid_info));
3436 				}
3437 				qdf_mem_free(new_frame);
3438 				scm_err_rl("failed to generate a scan entry");
3439 				scm_err_rl("split_prof_continue: %d",
3440 					   mbssid_info.split_prof_continue);
3441 				break;
3442 			}
3443 			/* scan entry makes its own copy so free the frame*/
3444 			if (mbssid_info.split_prof_continue) {
3445 				qdf_mem_free(split_prof_start);
3446 				split_prof_start = NULL;
3447 			}
3448 			qdf_mem_free(new_frame);
3449 		}
3450 
3451 		pos = next_elem;
3452 	}
3453 	qdf_mem_free(new_ie);
3454 
3455 	if (split_prof_start)
3456 		qdf_mem_free(split_prof_start);
3457 
3458 	return QDF_STATUS_SUCCESS;
3459 }
3460 #else
3461 static QDF_STATUS util_scan_parse_mbssid(struct wlan_objmgr_pdev *pdev,
3462 					 uint8_t *frame, qdf_size_t frame_len,
3463 					 uint32_t frm_subtype,
3464 					 struct mgmt_rx_event_params *rx_param,
3465 					 qdf_list_t *scan_list)
3466 {
3467 	return QDF_STATUS_SUCCESS;
3468 }
3469 #endif
3470 
3471 #if defined(WLAN_FEATURE_11BE) && defined(WLAN_FEATURE_11BE_MLO_MBSSID)
3472 /*
3473  * util_scan_gen_txvap_scan_entry() - Strip out the MBSSID tag from the received
3474  * frame and update the modified frame length before generating a scan entry.
3475  * It is redundant to have MBSSID information as part of the TX vap/ profile
3476  * specific scan entry.
3477  *
3478  * @pdev: pdev context
3479  * @frame: Unsoiled frame passed from util_scan_parse_beacon_frame()
3480  * @frame_len: Length of the unsoiled frame
3481  * @ie_list: Points to the start of IE list in parent/ unsoiled frame
3482  * @ielen: Length of the complete IE list from parent/ unsoiled frame
3483  * @frm_subtype: Frame subtype
3484  * @rx_param: host mgmt header params
3485  * @scan_list: Scan entry list of bss candidates after filtering
3486  * @mbssid_info: Data structure to carry MBSSID information
3487  *
3488  * Return: False if the scan entry generation is not successful
3489  */
3490 static QDF_STATUS
3491 util_scan_gen_txvap_scan_entry(struct wlan_objmgr_pdev *pdev,
3492 			       uint8_t *frame, qdf_size_t frame_len,
3493 			       uint8_t *ie_list, uint32_t ielen,
3494 			       uint32_t frm_subtype,
3495 			       struct mgmt_rx_event_params *rx_param,
3496 			       qdf_list_t *scan_list,
3497 			       struct scan_mbssid_info *mbssid_info)
3498 {
3499 	uint8_t *src_ie, *dest_ptr, *container;
3500 	uint16_t new_frame_len, new_ie_len = 0;
3501 	uint8_t *trimmed_frame, fixed_len = 0;
3502 	QDF_STATUS status = QDF_STATUS_SUCCESS;
3503 
3504 	/*
3505 	 * Allocate a buffer to copy only the TX VAP information after
3506 	 * stripping out the MBSSID IE from the parent beacon.
3507 	 * The allocation size should be the size of a frame as at
3508 	 * this point it is unknown what would be the new frame length
3509 	 * after stripping the MBSSID IE.
3510 	 */
3511 	container = qdf_mem_malloc(frame_len);
3512 	if (!container) {
3513 		scm_err_rl("Malloc for container failed");
3514 		return QDF_STATUS_E_NOMEM;
3515 	}
3516 
3517 	dest_ptr = &container[0];
3518 	fixed_len = sizeof(struct wlan_frame_hdr) +
3519 		offsetof(struct wlan_bcn_frame, ie);
3520 
3521 	/*Copy the data till IE list before procesisng the IE one by one*/
3522 	qdf_mem_copy(dest_ptr, frame, fixed_len);
3523 
3524 	dest_ptr += fixed_len;
3525 	src_ie = ie_list;
3526 
3527 	/*
3528 	 * Go through the IE list from the parent beacon and copy one by one.
3529 	 * Skip copying it to the container if it's an MBSSID tag.
3530 	 */
3531 	while (((src_ie + src_ie[TAG_LEN_POS] + MIN_IE_LEN) -
3532 		ie_list) <= ielen) {
3533 		if (src_ie[ID_POS] == WLAN_ELEMID_MULTIPLE_BSSID) {
3534 			src_ie += src_ie[TAG_LEN_POS] + MIN_IE_LEN;
3535 			continue;
3536 		}
3537 
3538 		qdf_mem_copy(dest_ptr, src_ie,
3539 			     (src_ie[TAG_LEN_POS] + MIN_IE_LEN));
3540 
3541 		dest_ptr += src_ie[TAG_LEN_POS] + MIN_IE_LEN;
3542 		if (((src_ie + src_ie[TAG_LEN_POS] +
3543 		      MIN_IE_LEN) - ie_list) >= ielen)
3544 			break;
3545 
3546 		src_ie += src_ie[TAG_LEN_POS] + MIN_IE_LEN;
3547 	}
3548 
3549 	if (dest_ptr > container)
3550 		new_ie_len = dest_ptr - (container + fixed_len);
3551 
3552 	new_frame_len = frame_len - ielen + new_ie_len;
3553 
3554 	/*
3555 	 * At the start of this handler, we have allocated a memory block
3556 	 * of size same as a full beacon frame size, as we are not sure
3557 	 * of what would be the size of the new frame. After stripping out
3558 	 * the MBSSID tag from the parent beacon, there are some unused
3559 	 * memory. Hence do another malloc of the new frame length
3560 	 * (length of the new frame which has only TX VAP information)
3561 	 * and copy the needed data from the container, then free the
3562 	 * memory corresponds to container.
3563 	 * Post copy, use the trimmed frame and the new frame length
3564 	 * to generate scan entry for the TX profile.
3565 	 */
3566 	trimmed_frame = qdf_mem_malloc(new_frame_len);
3567 	if (!trimmed_frame) {
3568 		scm_err_rl("Malloc for trimmed frame failed");
3569 		qdf_mem_free(container);
3570 		return QDF_STATUS_E_NOMEM;
3571 	}
3572 
3573 	qdf_mem_copy(trimmed_frame, container, new_frame_len);
3574 	qdf_mem_free(container);
3575 
3576 	status = util_scan_gen_scan_entry(pdev, trimmed_frame,
3577 					  new_frame_len,
3578 					  frm_subtype,
3579 					  rx_param,
3580 					  mbssid_info,
3581 					  scan_list);
3582 
3583 	if (QDF_IS_STATUS_ERROR(status))
3584 		scm_debug_rl("Failed to create a scan entry");
3585 
3586 	qdf_mem_free(trimmed_frame);
3587 	return status;
3588 }
3589 
3590 /*
3591  * util_scan_parse_eht_beacon() : This API will be executed
3592  * only for 11BE platforms as per current design.
3593  * IF MBSSID IE is present in the beacon then
3594  * scan component will create a new entry for
3595  * each BSSID found in the MBSSID
3596  * util_scan_parse_mbssid() takes care of creating
3597  * scan entries for every non tx profile present in
3598  * the MBSSID tag.
3599  * util_scan_gen_txvap_scan_entry() helps in generating
3600  * scan entry for the tx profile.
3601  */
3602 static QDF_STATUS
3603 util_scan_parse_eht_beacon(struct wlan_objmgr_pdev *pdev,
3604 			   uint8_t *frame, qdf_size_t frame_len,
3605 			   uint8_t *ie_list, uint32_t ielen,
3606 			   uint32_t frm_subtype,
3607 			   struct mgmt_rx_event_params *rx_param,
3608 			   qdf_list_t *scan_list,
3609 			   struct scan_mbssid_info *mbssid_info,
3610 			   uint8_t *mbssid_ie)
3611 {
3612 	QDF_STATUS status = QDF_STATUS_SUCCESS;
3613 
3614 	if (mbssid_ie) {
3615 		status = util_scan_parse_mbssid(pdev, frame, frame_len,
3616 						frm_subtype, rx_param,
3617 						scan_list);
3618 
3619 		if (QDF_IS_STATUS_ERROR(status)) {
3620 			scm_debug_rl("NonTx prof: Failed to create scan entry");
3621 			return status;
3622 		}
3623 
3624 		status = util_scan_gen_txvap_scan_entry(pdev, frame,
3625 							frame_len, ie_list,
3626 							ielen, frm_subtype,
3627 							rx_param, scan_list,
3628 							mbssid_info);
3629 
3630 		if (QDF_IS_STATUS_ERROR(status))
3631 			scm_debug_rl("TX prof: Failed to create scan entry");
3632 
3633 		return status;
3634 	}
3635 
3636 	/*For Non MBSSIE case*/
3637 	status = util_scan_gen_scan_entry(pdev, frame, frame_len,
3638 					  frm_subtype, rx_param,
3639 					  mbssid_info, scan_list);
3640 
3641 	if (QDF_IS_STATUS_ERROR(status))
3642 		scm_debug_rl("Non-MBSSIE frame: Failed to create scan entry");
3643 
3644 	return status;
3645 }
3646 
3647 static bool
3648 util_scan_is_platform_eht_capable(struct wlan_objmgr_pdev *pdev)
3649 {
3650 	struct wlan_objmgr_psoc *psoc = NULL;
3651 	struct wlan_lmac_if_tx_ops *tx_ops = NULL;
3652 	struct wlan_lmac_if_scan_tx_ops *scan_ops = NULL;
3653 	uint8_t pdev_id;
3654 
3655 	psoc = wlan_pdev_get_psoc(pdev);
3656 	if (!psoc) {
3657 		scm_debug_rl("psoc is null");
3658 		return false;
3659 	}
3660 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
3661 	if (!tx_ops) {
3662 		scm_debug_rl("tx_ops is null");
3663 		return false;
3664 	}
3665 	scan_ops = &tx_ops->scan;
3666 	if (!scan_ops) {
3667 		scm_debug_rl("scan_ops is null");
3668 		return false;
3669 	}
3670 	pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
3671 
3672 	if (scan_ops->is_platform_eht_capable)
3673 		return scan_ops->is_platform_eht_capable(psoc, pdev_id);
3674 
3675 	return false;
3676 }
3677 #else
3678 static QDF_STATUS
3679 util_scan_parse_eht_beacon(struct wlan_objmgr_pdev *pdev,
3680 			   uint8_t *frame, qdf_size_t frame_len,
3681 			   uint8_t *ie_list, uint32_t ielen,
3682 			   uint32_t frm_subtype,
3683 			   struct mgmt_rx_event_params *rx_param,
3684 			   qdf_list_t *scan_list,
3685 			   struct scan_mbssid_info *mbssid_info,
3686 			   uint8_t *mbssid_ie)
3687 {
3688 	return QDF_STATUS_SUCCESS;
3689 }
3690 
3691 static bool
3692 util_scan_is_platform_eht_capable(struct wlan_objmgr_pdev *pdev)
3693 {
3694 	return false;
3695 }
3696 #endif
3697 
3698 static QDF_STATUS
3699 util_scan_parse_beacon_frame(struct wlan_objmgr_pdev *pdev,
3700 			     uint8_t *frame,
3701 			     qdf_size_t frame_len,
3702 			     uint32_t frm_subtype,
3703 			     struct mgmt_rx_event_params *rx_param,
3704 			     qdf_list_t *scan_list)
3705 {
3706 	struct wlan_bcn_frame *bcn;
3707 	struct wlan_frame_hdr *hdr;
3708 	uint8_t *mbssid_ie = NULL, *extcap_ie;
3709 	uint32_t ie_len = 0;
3710 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
3711 	struct scan_mbssid_info mbssid_info = { 0 };
3712 	uint8_t *ie_list;
3713 	bool eht_support = false;
3714 
3715 	hdr = (struct wlan_frame_hdr *)frame;
3716 	bcn = (struct wlan_bcn_frame *)
3717 		(frame + sizeof(struct wlan_frame_hdr));
3718 	ie_list = (uint8_t *)&bcn->ie;
3719 	ie_len = (uint16_t)(frame_len -
3720 			    sizeof(struct wlan_frame_hdr) -
3721 			    offsetof(struct wlan_bcn_frame, ie));
3722 
3723 	extcap_ie = util_scan_find_ie(WLAN_ELEMID_XCAPS,
3724 				      (uint8_t *)&bcn->ie, ie_len);
3725 	/* Process MBSSID when Multiple BSSID (Bit 22) is set in Ext Caps */
3726 	if (extcap_ie &&
3727 	    extcap_ie[1] >= 3 && extcap_ie[1] <= WLAN_EXTCAP_IE_MAX_LEN &&
3728 	    (extcap_ie[4] & 0x40)) {
3729 		mbssid_ie = util_scan_find_ie(WLAN_ELEMID_MULTIPLE_BSSID,
3730 					      (uint8_t *)&bcn->ie, ie_len);
3731 		if (mbssid_ie) {
3732 			if (mbssid_ie[1] <= 0) {
3733 				scm_debug("MBSSID IE length is wrong %d",
3734 					  mbssid_ie[1]);
3735 				return status;
3736 			}
3737 			qdf_mem_copy(&mbssid_info.trans_bssid,
3738 				     hdr->i_addr3, QDF_MAC_ADDR_SIZE);
3739 			mbssid_info.profile_count = 1 << mbssid_ie[2];
3740 		}
3741 	}
3742 
3743 	eht_support = util_scan_is_platform_eht_capable(pdev);
3744 
3745 	if (eht_support) {
3746 		status = util_scan_parse_eht_beacon(pdev, frame, frame_len,
3747 						    ie_list, ie_len,
3748 						    frm_subtype, rx_param,
3749 						    scan_list, &mbssid_info,
3750 						    mbssid_ie);
3751 		return status;
3752 	}
3753 
3754 	status = util_scan_gen_scan_entry(pdev, frame, frame_len,
3755 					  frm_subtype, rx_param,
3756 					  &mbssid_info,
3757 					  scan_list);
3758 
3759 	if (mbssid_ie)
3760 		status = util_scan_parse_mbssid(pdev, frame, frame_len,
3761 						frm_subtype, rx_param,
3762 						scan_list);
3763 
3764 	if (QDF_IS_STATUS_ERROR(status))
3765 		scm_debug_rl("Failed to create scan entry");
3766 
3767 	return status;
3768 }
3769 
3770 qdf_list_t *
3771 util_scan_unpack_beacon_frame(struct wlan_objmgr_pdev *pdev, uint8_t *frame,
3772 			      qdf_size_t frame_len, uint32_t frm_subtype,
3773 			      struct mgmt_rx_event_params *rx_param)
3774 {
3775 	qdf_list_t *scan_list;
3776 	QDF_STATUS status;
3777 
3778 	scan_list = qdf_mem_malloc_atomic(sizeof(*scan_list));
3779 	if (!scan_list) {
3780 		scm_err("failed to allocate scan_list");
3781 		return NULL;
3782 	}
3783 	qdf_list_create(scan_list, MAX_SCAN_CACHE_SIZE);
3784 
3785 	status = util_scan_parse_beacon_frame(pdev, frame, frame_len,
3786 					      frm_subtype, rx_param,
3787 					      scan_list);
3788 	if (QDF_IS_STATUS_ERROR(status)) {
3789 		ucfg_scan_purge_results(scan_list);
3790 		return NULL;
3791 	}
3792 
3793 	return scan_list;
3794 }
3795 
3796 QDF_STATUS
3797 util_scan_entry_update_mlme_info(struct wlan_objmgr_pdev *pdev,
3798 	struct scan_cache_entry *scan_entry)
3799 {
3800 
3801 	if (!pdev || !scan_entry) {
3802 		scm_err("pdev 0x%pK, scan_entry: 0x%pK", pdev, scan_entry);
3803 		return QDF_STATUS_E_INVAL;
3804 	}
3805 
3806 	return scm_update_scan_mlme_info(pdev, scan_entry);
3807 }
3808 
3809 bool util_is_scan_completed(struct scan_event *event, bool *success)
3810 {
3811 	if ((event->type == SCAN_EVENT_TYPE_COMPLETED) ||
3812 	    (event->type == SCAN_EVENT_TYPE_DEQUEUED) ||
3813 	    (event->type == SCAN_EVENT_TYPE_START_FAILED)) {
3814 		if ((event->type == SCAN_EVENT_TYPE_COMPLETED) &&
3815 		    (event->reason == SCAN_REASON_COMPLETED))
3816 			*success = true;
3817 		else
3818 			*success = false;
3819 
3820 		return true;
3821 	}
3822 
3823 	*success = false;
3824 	return false;
3825 }
3826 
3827 #if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD)
3828 bool
3829 util_scan_entry_single_pmk(struct wlan_objmgr_psoc *psoc,
3830 			   struct scan_cache_entry *scan_entry)
3831 {
3832 	if (scan_entry->ie_list.single_pmk &&
3833 	    wlan_mlme_is_sae_single_pmk_enabled(psoc))
3834 		return true;
3835 
3836 	return false;
3837 }
3838 #endif
3839