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