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