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