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