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