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