1 /*
2  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /**
19  * DOC: This file contains definition for mandatory legacy API
20  */
21 
22 #include "qdf_str.h"
23 #include "wlan_utility.h"
24 #include <wlan_cmn.h>
25 #include "wlan_osif_priv.h"
26 #include <net/cfg80211.h>
27 #include <qdf_module.h>
28 #include <wlan_vdev_mlme_api.h>
29 #include "cfg_ucfg_api.h"
30 #include <wlan_serialization_api.h>
31 #include "wlan_cm_api.h"
32 #include "host_diag_core_event.h"
33 
34 /* CRC polynomial 0xedb88320 */
35 static unsigned long const wlan_shortssid_table[] = {
36 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
37 	0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
38 	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
39 	0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
40 	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
41 	0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
42 	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
43 	0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
44 	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
45 	0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
46 	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
47 	0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
48 	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
49 	0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
50 	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
51 	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
52 	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
53 	0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
54 	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
55 	0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
56 	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
57 	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
58 	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
59 	0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
60 	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
61 	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
62 	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
63 	0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
64 	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
65 	0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
66 	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
67 	0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
68 	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
69 	0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
70 	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
71 	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
72 	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
73 	0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
74 	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
75 	0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
76 	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
77 	0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
78 	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
79 };
80 
wlan_construct_shortssid(uint8_t * ssid,uint8_t ssid_len)81 uint32_t wlan_construct_shortssid(uint8_t *ssid, uint8_t ssid_len)
82 {
83 	uint32_t shortssid = 0xffffffff;
84 	uint8_t i;
85 
86 	if (!ssid || ssid_len > WLAN_SSID_MAX_LEN)
87 		return shortssid;
88 
89 	for (i = 0; i < ssid_len; i++)
90 		shortssid = wlan_shortssid_table[(shortssid ^ ssid[i]) & 0xff] ^
91 						(shortssid >> 8);
92 	return (shortssid ^ 0xffffffff);
93 }
94 
wlan_chan_to_freq(uint8_t chan)95 uint32_t wlan_chan_to_freq(uint8_t chan)
96 {
97 	if (chan == 0 )
98 		return 0;
99 
100 	if (chan < WLAN_24_GHZ_CHANNEL_14)
101 		return WLAN_24_GHZ_BASE_FREQ + chan * WLAN_CHAN_SPACING_5MHZ;
102 	else if (chan == WLAN_24_GHZ_CHANNEL_14)
103 		return WLAN_CHAN_14_FREQ;
104 	else if (chan < WLAN_24_GHZ_CHANNEL_27)
105 		/* ch 15 - ch 26 */
106 		return WLAN_CHAN_15_FREQ +
107 		  (chan - WLAN_24_GHZ_CHANNEL_15) * WLAN_CHAN_SPACING_20MHZ;
108 	else if (chan == WLAN_5_GHZ_CHANNEL_170)
109 		return WLAN_CHAN_170_FREQ;
110 	else
111 		return WLAN_5_GHZ_BASE_FREQ + chan * WLAN_CHAN_SPACING_5MHZ;
112 }
113 
wlan_freq_to_chan(uint32_t freq)114 uint8_t wlan_freq_to_chan(uint32_t freq)
115 {
116 	uint8_t chan;
117 
118 	if (freq == 0)
119 		return 0;
120 
121 	if (freq > WLAN_24_GHZ_BASE_FREQ && freq < WLAN_CHAN_14_FREQ)
122 		chan = ((freq - WLAN_24_GHZ_BASE_FREQ) /
123 			WLAN_CHAN_SPACING_5MHZ);
124 	else if (freq == WLAN_CHAN_14_FREQ)
125 		chan = WLAN_24_GHZ_CHANNEL_14;
126 	else if ((freq > WLAN_24_GHZ_BASE_FREQ) &&
127 		(freq < WLAN_5_GHZ_BASE_FREQ))
128 		chan = (((freq - WLAN_CHAN_15_FREQ) /
129 			WLAN_CHAN_SPACING_20MHZ) +
130 			WLAN_24_GHZ_CHANNEL_15);
131 	else
132 		chan = (freq - WLAN_5_GHZ_BASE_FREQ) /
133 			WLAN_CHAN_SPACING_5MHZ;
134 
135 	return chan;
136 }
137 
138 void
wlan_get_320_center_freq(qdf_freq_t freq,qdf_freq_t * center_freq1,qdf_freq_t * center_freq2)139 wlan_get_320_center_freq(qdf_freq_t freq,
140 			 qdf_freq_t *center_freq1,
141 			 qdf_freq_t *center_freq2)
142 {
143 	*center_freq1 = 0;
144 	*center_freq2 = 0;
145 
146 	if ((freq >= 5500) && (freq <= 5800)) {
147 		*center_freq1 = 5650;
148 	} else if ((freq >= 5955) && (freq <= 6095)) {
149 		*center_freq1 = 6105;
150 	} else if ((freq >= 6115) && (freq <= 6255)) {
151 		*center_freq1 = 6105;
152 		*center_freq2 = 6265;
153 	} else if ((freq >= 6275) && (freq <= 6415)) {
154 		*center_freq1 = 6265;
155 		*center_freq2 = 6425;
156 	} else if ((freq >= 6435) && (freq <= 6575)) {
157 		*center_freq1 = 6425;
158 		*center_freq2 = 6585;
159 	} else if ((freq >= 6595) && (freq <= 6735)) {
160 		*center_freq1 = 6585;
161 		*center_freq2 = 6745;
162 	} else if ((freq >= 6755) && (freq <= 6895)) {
163 		*center_freq1 = 6745;
164 		*center_freq2 = 6905;
165 	} else if ((freq >= 6915) && (freq <= 7055)) {
166 		*center_freq1 = 6905;
167 	}
168 }
169 
wlan_is_ie_valid(const uint8_t * ie,size_t ie_len)170 bool wlan_is_ie_valid(const uint8_t *ie, size_t ie_len)
171 {
172 	uint8_t elen;
173 
174 	while (ie_len) {
175 		if (ie_len < 2)
176 			return false;
177 
178 		elen = ie[1];
179 		ie_len -= 2;
180 		ie += 2;
181 		if (elen > ie_len)
182 			return false;
183 
184 		ie_len -= elen;
185 		ie += elen;
186 	}
187 
188 	return true;
189 }
190 
wlan_get_ie_ptr_from_eid_n_oui(uint8_t eid,const uint8_t * oui,uint8_t oui_size,const uint8_t * ie,uint16_t ie_len)191 static const uint8_t *wlan_get_ie_ptr_from_eid_n_oui(uint8_t eid,
192 						     const uint8_t *oui,
193 						     uint8_t oui_size,
194 						     const uint8_t *ie,
195 						     uint16_t ie_len)
196 {
197 	int32_t left = ie_len;
198 	const uint8_t *ptr = ie;
199 	uint8_t elem_id, elem_len;
200 
201 	while (left >= 2) {
202 		elem_id  = ptr[0];
203 		elem_len = ptr[1];
204 		left -= 2;
205 
206 		if (elem_len > left)
207 			return NULL;
208 
209 		if (eid == elem_id) {
210 			/* if oui is not provide eid match is enough */
211 			if (!oui)
212 				return ptr;
213 
214 			/*
215 			 * if oui is provided and oui_size is more than left
216 			 * bytes, then we cannot have match
217 			 */
218 			if (oui_size > left)
219 				return NULL;
220 
221 			if (qdf_mem_cmp(&ptr[2], oui, oui_size) == 0)
222 				return ptr;
223 		}
224 
225 		left -= elem_len;
226 		ptr += (elem_len + 2);
227 	}
228 
229 	return NULL;
230 }
231 
wlan_iecap_set(uint8_t * iecap,uint8_t bit_pos,uint8_t tot_bits,uint32_t value)232 void wlan_iecap_set(uint8_t *iecap,
233 		    uint8_t bit_pos,
234 		    uint8_t tot_bits,
235 		    uint32_t value)
236 {
237 	uint8_t fit_bits;
238 	uint8_t byte_cnt;
239 	uint8_t prev_fit_bits = 0;
240 	uint32_t shift_value;
241 
242 	/* calculate byte position of the field in IE capability */
243 	byte_cnt = bit_pos / 8;
244 	/* calculate the bit position in the start byte that needs to be set */
245 	bit_pos = bit_pos % 8;
246 	fit_bits = 8 - bit_pos;
247 	fit_bits = (tot_bits > fit_bits) ? 8 - bit_pos : tot_bits;
248 
249 	while ((bit_pos + tot_bits) > 8) {
250 		/* clear the target bit */
251 		QDF_SET_BITS(iecap[byte_cnt], bit_pos, fit_bits, value);
252 		tot_bits = tot_bits - fit_bits;
253 		bit_pos = bit_pos + fit_bits;
254 		if (bit_pos == 8) {
255 			bit_pos = 0;
256 			byte_cnt++;
257 		}
258 		prev_fit_bits = prev_fit_bits + fit_bits;
259 		fit_bits = 8 - bit_pos;
260 		fit_bits = (tot_bits > fit_bits) ? 8 - bit_pos : tot_bits;
261 	}
262 
263 	if ((bit_pos + tot_bits) <= 8) {
264 		/* clear the target bit */
265 		shift_value = value >> prev_fit_bits;
266 		QDF_SET_BITS(iecap[byte_cnt], bit_pos, fit_bits, shift_value);
267 	}
268 }
269 
wlan_iecap_get(uint8_t * iecap,uint8_t bit_pos,uint32_t tot_bits)270 uint32_t wlan_iecap_get(uint8_t *iecap,
271 			uint8_t bit_pos,
272 			uint32_t tot_bits)
273 {
274 	uint8_t fit_bits;
275 	uint8_t byte_cnt;
276 	uint8_t temp_val;
277 	uint8_t cur_bit_pos = 0;
278 	uint32_t val = 0;
279 
280 	/* calculate byte position of the field in IE capability */
281 	byte_cnt = bit_pos / 8;
282 	temp_val = *(iecap + byte_cnt);
283 	/* calculate the bit position in the start byte */
284 	bit_pos = bit_pos % 8;
285 	fit_bits = 8 - bit_pos;
286 	fit_bits = (tot_bits > fit_bits) ? 8 - bit_pos : tot_bits;
287 
288 	while ((tot_bits + bit_pos) > 8) {
289 		val |= QDF_GET_BITS(temp_val, bit_pos, fit_bits) << cur_bit_pos;
290 		tot_bits = tot_bits - fit_bits;
291 		bit_pos = bit_pos + fit_bits;
292 		if (bit_pos == 8) {
293 			bit_pos = 0;
294 			byte_cnt++;
295 			temp_val = *(iecap + byte_cnt);
296 		}
297 		cur_bit_pos = cur_bit_pos + fit_bits;
298 
299 		fit_bits = 8 - bit_pos;
300 		fit_bits = (tot_bits > fit_bits) ? 8 - bit_pos : tot_bits;
301 	}
302 
303 	if ((bit_pos + tot_bits) <= 8)
304 		val |= QDF_GET_BITS(temp_val, bit_pos, fit_bits) << cur_bit_pos;
305 
306 	return val;
307 }
308 
wlan_get_ie_ptr_from_eid(uint8_t eid,const uint8_t * ie,int ie_len)309 const uint8_t *wlan_get_ie_ptr_from_eid(uint8_t eid,
310 					const uint8_t *ie,
311 					int ie_len)
312 {
313 	return wlan_get_ie_ptr_from_eid_n_oui(eid, NULL, 0, ie, ie_len);
314 }
315 
wlan_get_vendor_ie_ptr_from_oui(const uint8_t * oui,uint8_t oui_size,const uint8_t * ie,uint16_t ie_len)316 const uint8_t *wlan_get_vendor_ie_ptr_from_oui(const uint8_t *oui,
317 					       uint8_t oui_size,
318 					       const uint8_t *ie,
319 					       uint16_t ie_len)
320 {
321 	return wlan_get_ie_ptr_from_eid_n_oui(WLAN_MAC_EID_VENDOR,
322 					      oui, oui_size, ie, ie_len);
323 }
324 
wlan_get_ext_ie_ptr_from_ext_id(const uint8_t * oui,uint8_t oui_size,const uint8_t * ie,uint16_t ie_len)325 const uint8_t *wlan_get_ext_ie_ptr_from_ext_id(const uint8_t *oui,
326 					       uint8_t oui_size,
327 					       const uint8_t *ie,
328 					       uint16_t ie_len)
329 {
330 	return wlan_get_ie_ptr_from_eid_n_oui(WLAN_MAC_EID_EXT,
331 					      oui, oui_size, ie, ie_len);
332 }
333 
334 static inline
wlan_get_elemunit_info(bool is_subelem,uint8_t subelemfragid,uint8_t * elemunit_fragid,qdf_size_t * elemunit_hdrlen,qdf_size_t * elemunit_maxpayloadlen,int * elemunit_id_pos,int * elemunit_len_pos,int * elemunit_idext_pos)335 QDF_STATUS wlan_get_elemunit_info(bool is_subelem,
336 				  uint8_t subelemfragid,
337 				  uint8_t *elemunit_fragid,
338 				  qdf_size_t *elemunit_hdrlen,
339 				  qdf_size_t *elemunit_maxpayloadlen,
340 				  int *elemunit_id_pos,
341 				  int *elemunit_len_pos,
342 				  int *elemunit_idext_pos)
343 {
344 	/* Helper function to populate information about the given element unit.
345 	 * Here, an 'element unit' refers to either an 802.11 element or a
346 	 * 802.11 subelement.
347 	 *
348 	 * Populating this information in a central helper here allows for
349 	 * better control over handling of future variances, and also for common
350 	 * code for handling different types of element units.
351 	 */
352 
353 	if (is_subelem) {
354 		/* Populate the subelement header length */
355 		if (elemunit_hdrlen)
356 			*elemunit_hdrlen = sizeof(struct subelem_header);
357 
358 		/* Populate the subelement's max payload length */
359 		if (elemunit_maxpayloadlen)
360 			*elemunit_maxpayloadlen = WLAN_MAX_SUBELEM_LEN;
361 
362 		/* Populate the index position for the subelement ID */
363 		if (elemunit_id_pos)
364 			*elemunit_id_pos = qdf_offsetof(struct subelem_header,
365 							subelem_id);
366 
367 		/* Populate the index position for the subelement length */
368 		if (elemunit_len_pos)
369 			*elemunit_len_pos = qdf_offsetof(struct subelem_header,
370 							 subelem_len);
371 
372 		/* Mark that there is (currently) no valid value for subelement
373 		 * ID extension.
374 		 */
375 		if (elemunit_idext_pos)
376 			*elemunit_idext_pos = -1;
377 
378 		/* Populate the subelement fragment ID (which can vary by
379 		 * protocol area). This could also have been directly populated
380 		 * by the caller, but we populate it here for uniformity and
381 		 * future control of variability.
382 		 */
383 		if (elemunit_fragid)
384 			*elemunit_fragid = subelemfragid;
385 	} else {
386 		/* Populate the element header length */
387 		if (elemunit_hdrlen)
388 			*elemunit_hdrlen = sizeof(struct ie_header);
389 
390 		/* Populate the element's max payload length */
391 		if (elemunit_maxpayloadlen)
392 			*elemunit_maxpayloadlen = WLAN_MAX_IE_LEN;
393 
394 		/* Populate the index position for the element ID */
395 		if (elemunit_id_pos)
396 			*elemunit_id_pos = qdf_offsetof(struct ie_header,
397 							ie_id);
398 
399 		/* Populate the index position for the element length */
400 		if (elemunit_len_pos)
401 			*elemunit_len_pos = qdf_offsetof(struct ie_header,
402 							 ie_len);
403 
404 		/* Populate the index position for the element ID extension
405 		 */
406 		if (elemunit_idext_pos)
407 			*elemunit_idext_pos =
408 				qdf_offsetof(struct extn_ie_header, ie_extn_id);
409 
410 		/* Populate the element fragment ID. */
411 		if (elemunit_fragid)
412 			*elemunit_fragid = WLAN_ELEMID_FRAGMENT;
413 	}
414 
415 	return QDF_STATUS_SUCCESS;
416 }
417 
418 static QDF_STATUS
wlan_get_elemsubelem_fragseq_creationparams(bool is_subelem,uint8_t id,qdf_size_t payloadlen,bool * is_frag_required,qdf_size_t * expected_fragseqlen,qdf_size_t * prepayload_leadbytes,uint32_t * num_maxsizefrags,qdf_size_t * smallerfrag_size,qdf_size_t * extrahdrbytes)419 wlan_get_elemsubelem_fragseq_creationparams(bool is_subelem,
420 					    uint8_t id,
421 					    qdf_size_t payloadlen,
422 					    bool *is_frag_required,
423 					    qdf_size_t *expected_fragseqlen,
424 					    qdf_size_t *prepayload_leadbytes,
425 					    uint32_t *num_maxsizefrags,
426 					    qdf_size_t *smallerfrag_size,
427 					    qdf_size_t *extrahdrbytes)
428 {
429 	/* elemunit, i.e. 'element unit' here refers to either an 802.11 element
430 	 * or a 802.11 subelement.
431 	 */
432 	qdf_size_t elemunit_hdrlen;
433 	qdf_size_t elemunit_maxpayloadlen;
434 
435 	qdf_size_t tmp_expected_fragseqlen;
436 	qdf_size_t tmp_prepayload_leadbytes;
437 	uint32_t tmp_num_maxsizefrags;
438 	qdf_size_t tmp_smallerfrag_size;
439 	qdf_size_t tmp_extrahdrbytes;
440 
441 	QDF_STATUS ret;
442 
443 	/* Helper function to determine element or subelement fragment sequence
444 	 * creation parameters. Currently, this helper determines the following
445 	 * parameters (it is mandatory for the caller to provide the pointer
446 	 * for the first parameter, those for the remaining are optional):
447 	 *
448 	 * - Whether fragmentation is required
449 	 * If fragmentation is required then the following are determined, else
450 	 * they should be ignored by the caller:
451 	 * - Expected fragment sequence length (inclusive of payload and all
452 	 *   headers)
453 	 * - The lead bytes that occur before the payload (i.e. the lead
454 	 *   element/subelement's header, and if applicable, the element's
455 	 *   element ID extension)
456 	 * - The number of max sized fragments (inclusive of the lead element)
457 	 * - The size of the smaller sized fragment at the end (non-zero if such
458 	 *   a fragment would be present, zero if it would be absent)
459 	 * - The number of extra header bytes that would be introduced (not
460 	 *   inclusive of the header of the lead fragment).
461 	 */
462 
463 	if (!is_frag_required) {
464 		qdf_nofl_err("Pointer to indication of whether fragmentation is required or not is NULL");
465 		return QDF_STATUS_E_NULL_VALUE;
466 	}
467 
468 	ret = wlan_get_elemunit_info(is_subelem,
469 				     0,
470 				     NULL,
471 				     &elemunit_hdrlen,
472 				     &elemunit_maxpayloadlen,
473 				     NULL,
474 				     NULL,
475 				     NULL);
476 	if (QDF_IS_STATUS_ERROR(ret)) {
477 		qdf_rl_nofl_err("Get elem unit info: Error %d",
478 				ret);
479 		return QDF_STATUS_E_FAILURE;
480 	}
481 
482 	if (!is_subelem && (id == WLAN_ELEMID_EXTN_ELEM)) {
483 		if (payloadlen <= (elemunit_maxpayloadlen - 1)) {
484 			*is_frag_required = false;
485 			return QDF_STATUS_SUCCESS;
486 		}
487 	} else {
488 		if (payloadlen <= elemunit_maxpayloadlen) {
489 			*is_frag_required = false;
490 			return QDF_STATUS_SUCCESS;
491 		}
492 	}
493 
494 	*is_frag_required = true;
495 
496 	if (!expected_fragseqlen &&
497 	    !prepayload_leadbytes && !num_maxsizefrags &&
498 	    !smallerfrag_size && !extrahdrbytes)
499 		return QDF_STATUS_SUCCESS;
500 
501 	tmp_expected_fragseqlen = 0;
502 	tmp_prepayload_leadbytes = 0;
503 	tmp_num_maxsizefrags = 0;
504 	tmp_smallerfrag_size = 0;
505 	tmp_extrahdrbytes = 0;
506 
507 	/* As per the standard, the information to be fragmented is divided into
508 	 * M + N portions, where the following define each variable:
509 	 *
510 	 * I)For an element without an Element ID Extension field, or for a
511 	 * subelement:
512 	 * L is the size of the information in octets (this does not include the
513 	 * element/subelement header)
514 	 * M is L/255 floored
515 	 * N is equal to 1 if L mod 255 > 0 and equal to 0 otherwise.
516 	 * The size of each of the M fragments is 255 octets
517 	 * If N is 1, then the size of this single fragment is L mod 255 octets
518 	 *
519 	 * II) For an element with an Element ID Extension field:
520 	 * L is the size of the information in octets (this does not include the
521 	 * element header and the element ID extension field)
522 	 * M is (L + 1)/255 floored
523 	 * N is equal to 1 if (L - 254) mod 255 > 0 and equal to 0 otherwise.
524 	 * The size of each of the M fragments is 255 octets
525 	 * If N is 1, then the size of this single fragment is (L - 254) mod 255
526 	 * octets.
527 	 *
528 	 * For both I and II above, the mapping of code variables is as follows:
529 	 * payloadlen = L
530 	 * tmp_num_maxsizefrags = M
531 	 * tmp_smallerfrag_size = Size of N if N is 1, else 0
532 	 * Additionally, elemunit_maxpayloadlen is used to denote the value
533 	 * 255 for future extensibility if and when required.
534 	 */
535 
536 	if (!is_subelem && (id == WLAN_ELEMID_EXTN_ELEM)) {
537 		tmp_num_maxsizefrags = (payloadlen + 1) /
538 						elemunit_maxpayloadlen;
539 		tmp_smallerfrag_size =
540 				(payloadlen - (elemunit_maxpayloadlen - 1)) %
541 						elemunit_maxpayloadlen;
542 	} else {
543 		tmp_num_maxsizefrags = payloadlen / elemunit_maxpayloadlen;
544 		tmp_smallerfrag_size = payloadlen %
545 						elemunit_maxpayloadlen;
546 	}
547 
548 	/* Determine the number of extra bytes introduced due to the headers of
549 	 * non-leading fragments.
550 	 */
551 	tmp_extrahdrbytes = (tmp_num_maxsizefrags - 1) * elemunit_hdrlen;
552 	if (tmp_smallerfrag_size)
553 		tmp_extrahdrbytes += elemunit_hdrlen;
554 
555 	if (!is_subelem && (id == WLAN_ELEMID_EXTN_ELEM))
556 		tmp_prepayload_leadbytes = elemunit_hdrlen + 1;
557 	else
558 		tmp_prepayload_leadbytes = elemunit_hdrlen;
559 
560 	tmp_expected_fragseqlen = tmp_prepayload_leadbytes +
561 					payloadlen + tmp_extrahdrbytes;
562 
563 	if (expected_fragseqlen)
564 		*expected_fragseqlen = tmp_expected_fragseqlen;
565 
566 	if (prepayload_leadbytes)
567 		*prepayload_leadbytes = tmp_prepayload_leadbytes;
568 
569 	if (num_maxsizefrags)
570 		*num_maxsizefrags = tmp_num_maxsizefrags;
571 
572 	if (smallerfrag_size)
573 		*smallerfrag_size = tmp_smallerfrag_size;
574 
575 	if (extrahdrbytes)
576 		*extrahdrbytes = tmp_extrahdrbytes;
577 
578 	return QDF_STATUS_SUCCESS;
579 }
580 
581 static QDF_STATUS
wlan_create_elemsubelem_fragseq(bool inline_frag,bool is_subelem,uint8_t id,uint8_t idext,uint8_t subelemfragid,uint8_t * payloadbuff,qdf_size_t payloadbuff_maxsize,qdf_size_t payloadlen,uint8_t * fragbuff,qdf_size_t fragbuff_maxsize,qdf_size_t * fragseqlen)582 wlan_create_elemsubelem_fragseq(bool inline_frag,
583 				bool is_subelem,
584 				uint8_t id,
585 				uint8_t idext,
586 				uint8_t subelemfragid,
587 				uint8_t *payloadbuff,
588 				qdf_size_t payloadbuff_maxsize,
589 				qdf_size_t payloadlen,
590 				uint8_t *fragbuff,
591 				qdf_size_t fragbuff_maxsize,
592 				qdf_size_t *fragseqlen)
593 {
594 	/* elemunit, i.e. 'element unit' here refers to either an 802.11 element
595 	 * or a 802.11 subelement.
596 	 */
597 	uint8_t elemunit_fragid;
598 	qdf_size_t elemunit_hdrlen;
599 	qdf_size_t elemunit_maxpayloadlen;
600 	int elemunit_id_pos;
601 	int elemunit_len_pos;
602 	int elemunit_idext_pos;
603 	uint8_t *curr_elemunit_ptr;
604 
605 	/* Whether fragmentation is required */
606 	bool is_frag_required;
607 
608 	 /*Fragment sequence length (inclusive of payload and all headers) */
609 	qdf_size_t expected_fragseqlen;
610 
611 	/* Number of fragments with the maximum size */
612 	uint32_t num_maxsizefrags;
613 	/* Size of the last fragment which is smaller than the maximum (if
614 	 * present). If such a fragment is not present, this size will be zero.
615 	 */
616 	qdf_size_t smallerfrag_size;
617 
618 	 /* The number of extra header bytes that would be introduced (not
619 	  * inclusive of the header of the lead fragment).
620 	  */
621 	qdf_size_t extrahdrbytes;
622 	/* The number of extra header bytes remaining to be introduced */
623 	qdf_size_t extrahdrbytes_remaining;
624 
625 	 /* The lead bytes that occur before the payload */
626 	qdf_size_t prepayload_leadbytes;
627 
628 	 /* used for inline copy, the extra bytes needed in the payload buffer
629 	  * due to difference in destination and source.
630 	  * Note that the caller should ensure there is enough bytes beyond
631 	  * valid data until payloadbuff_maxsize*/
632 	qdf_size_t payloadbuff_shiftsize;
633 
634 	/* Miscellaneous variables */
635 	uint8_t *src;
636 	uint8_t *dst;
637 	uint16_t i;
638 	qdf_size_t bytes_to_transfer;
639 
640 	QDF_STATUS ret;
641 
642 	/* Helper function to create an element or subelement fragment sequence.
643 	 * Refer to the documentation of the public APIs which call this helper,
644 	 * for more information. These APIs are mainly wrappers over this
645 	 * helper.
646 	 */
647 
648 	ret = wlan_get_elemunit_info(is_subelem,
649 				     subelemfragid,
650 				     &elemunit_fragid,
651 				     &elemunit_hdrlen,
652 				     &elemunit_maxpayloadlen,
653 				     &elemunit_id_pos,
654 				     &elemunit_len_pos,
655 				     &elemunit_idext_pos);
656 	if (QDF_IS_STATUS_ERROR(ret)) {
657 		qdf_rl_nofl_err("Get elem unit info: Error %d",
658 				ret);
659 		return QDF_STATUS_E_FAILURE;
660 	}
661 
662 	ret = wlan_get_elemsubelem_fragseq_creationparams(is_subelem,
663 							  id,
664 							  payloadlen,
665 							  &is_frag_required,
666 							  &expected_fragseqlen,
667 							  &prepayload_leadbytes,
668 							  &num_maxsizefrags,
669 							  &smallerfrag_size,
670 							  &extrahdrbytes);
671 	if (QDF_IS_STATUS_ERROR(ret))
672 		return ret;
673 
674 	if (!is_frag_required) {
675 		/* We treat this as an error since the caller is expected to
676 		 * have first determined requirements related to fragmentation,
677 		 * including whether fragmentation is required or not.
678 		 */
679 		if (!is_subelem && (id == WLAN_ELEMID_EXTN_ELEM))
680 			qdf_nofl_err("Fragmentation inapplicable for elem with elem ID ext and post elem ID ext payload len %zu",
681 				     payloadlen);
682 		else
683 			qdf_nofl_err("Fragmentation inapplicable for subelem/elem without elem ID ext and with payload len %zu",
684 				     payloadlen);
685 
686 		return QDF_STATUS_E_INVAL;
687 	}
688 
689 	if (!payloadbuff) {
690 		qdf_nofl_err("Payload buff is NULL");
691 		return QDF_STATUS_E_NULL_VALUE;
692 	}
693 
694 	if (payloadbuff_maxsize == 0) {
695 		qdf_nofl_err("Payload buff max size is 0");
696 		return QDF_STATUS_E_INVAL;
697 	}
698 
699 	if (payloadbuff_maxsize < payloadlen) {
700 		qdf_nofl_err("Payload buff max size %zu < payload len %zu",
701 			     payloadbuff_maxsize,
702 			     payloadlen);
703 		return QDF_STATUS_E_INVAL;
704 	}
705 
706 	if (inline_frag) {
707 		if (payloadbuff_maxsize < expected_fragseqlen) {
708 			qdf_nofl_err("Inline frag buff max size %zu < frag sequence expected len %zu",
709 				     payloadbuff_maxsize,
710 				     expected_fragseqlen);
711 			return QDF_STATUS_E_INVAL;
712 		}
713 	} else {
714 		if (!fragbuff) {
715 			qdf_nofl_err("Frag sequence buff is NULL");
716 			return QDF_STATUS_E_NULL_VALUE;
717 		}
718 
719 		if (fragbuff_maxsize == 0) {
720 			qdf_nofl_err("Frag sequence buff max size is 0");
721 			return QDF_STATUS_E_INVAL;
722 		}
723 
724 		if (fragbuff_maxsize < expected_fragseqlen) {
725 			qdf_nofl_err("Frag sequence buff max size %zu < frag sequence expected len %zu",
726 				     fragbuff_maxsize,
727 				     expected_fragseqlen);
728 			return QDF_STATUS_E_INVAL;
729 		}
730 	}
731 
732 	if (!fragseqlen) {
733 		qdf_nofl_err("Pointer to location of frag sequence len is NULL");
734 		return QDF_STATUS_E_NULL_VALUE;
735 	}
736 
737 	/* Preferably, ensure that error checks (if any) for future changes are
738 	 * executed before this point. We wouldn't want to touch the destination
739 	 * buffer unless we are sure we can successfully execute (especially for
740 	 * the inline mode).
741 	 */
742 
743 	/* We rely on wlan_get_elemsubelem_fragseq_creationparams() to give us
744 	 * sane values for extrahdrbytes and other parameters.
745 	 */
746 
747 	extrahdrbytes_remaining = extrahdrbytes;
748 
749 	/* We need to accommodate elemunit_hdrlen bytes for each non-leading
750 	 * fragment by moving the non-leading fragment to a higher location.
751 	 * Shift bytes and form fragment elements/subelements starting with the
752 	 * last fragment and going backwards from there.
753 	 */
754 
755 	/* First move/copy the smaller sized fragment if present */
756 	if (smallerfrag_size) {
757 		/* The source for the copy/move is just after the end of all the
758 		 * max sized fragments (including the lead fragment). The
759 		 * element unit header is present for the lead fragment alone.
760 		 */
761 		src = payloadbuff + elemunit_hdrlen +
762 				(num_maxsizefrags * elemunit_maxpayloadlen);
763 
764 		/* The destination for the copy/move is computed to reflect a
765 		 * shift by extrahdrbytes_remaining to accommodate the headers
766 		 * for the smaller fragment and all the non-lead max sized
767 		 * fragments.
768 		 */
769 		if (inline_frag)
770 			dst = src + extrahdrbytes_remaining;
771 		else
772 			dst = fragbuff + elemunit_hdrlen +
773 				(num_maxsizefrags * elemunit_maxpayloadlen) +
774 				extrahdrbytes_remaining;
775 
776 		bytes_to_transfer = smallerfrag_size;
777 
778 		/* Account for increased size due to shift in data */
779 		if (inline_frag && (dst > src))
780 			payloadbuff_shiftsize = (dst - src);
781 		else
782 			payloadbuff_shiftsize = 0;
783 
784 		/* In the case of inline fragmentation, if the payload buffer
785 		 * has additional contents beyond the payload, include those
786 		 * contents in the move/copy.
787 		 */
788 		if (inline_frag &&
789 		    (payloadbuff_maxsize > (prepayload_leadbytes + payloadlen)))
790 			bytes_to_transfer += (payloadbuff_maxsize -
791 					      prepayload_leadbytes -
792 					      payloadlen -
793 					      payloadbuff_shiftsize);
794 
795 		if (inline_frag)
796 			qdf_mem_move(dst, src, bytes_to_transfer);
797 		else
798 			qdf_mem_copy(dst, src, bytes_to_transfer);
799 
800 		/* Copy/move of payload done. Set fragment ID and length in
801 		 * element unit header.
802 		 */
803 		curr_elemunit_ptr = dst - elemunit_hdrlen;
804 		curr_elemunit_ptr[elemunit_id_pos] = elemunit_fragid;
805 		curr_elemunit_ptr[elemunit_len_pos] = smallerfrag_size;
806 
807 		extrahdrbytes_remaining -= elemunit_hdrlen;
808 	}
809 
810 	/* Next, move/copy the non-lead max-sized fragments, if present.
811 	 * Fragments at higher memory locations are processed first.
812 	 */
813 	for (i = num_maxsizefrags; i > 1; i--) {
814 		/* Process the 'i'th max-sized fragment. The lead max-sized
815 		 * fragment has i=1 and is not processed in this 'for' loop.
816 		 * Also note that 'previous .* fragments' in comments for this
817 		 * 'for' loop refers to fragments in lower memory locations as
818 		 * compared to the current, i.e. 'i'th max-sized fragment.
819 		 */
820 
821 		/* The source for the copy/move is just after the end of all the
822 		 * previous max-sized fragments (including the lead fragment).
823 		 * The element unit header is present for the lead fragment
824 		 * alone.
825 		 */
826 		src = payloadbuff + elemunit_hdrlen +
827 			((i - 1) * elemunit_maxpayloadlen);
828 
829 		/* The destination for the copy/move is computed to reflect a
830 		 * shift by extrahdrbytes_remaining to accommodate the headers
831 		 * for the current non-lead max-sized fragment and all the
832 		 * previous max-sized non-lead fragments.
833 		 */
834 		if (inline_frag)
835 			dst = src + extrahdrbytes_remaining;
836 		else
837 			dst = fragbuff + elemunit_hdrlen +
838 				((i - 1) * elemunit_maxpayloadlen) +
839 				extrahdrbytes_remaining;
840 
841 		bytes_to_transfer = elemunit_maxpayloadlen;
842 
843 		/* Account for increased size due to shift in data */
844 		if (inline_frag && (dst > src))
845 			payloadbuff_shiftsize = (dst - src);
846 		else
847 			payloadbuff_shiftsize = 0;
848 
849 		/* In the case of inline fragmentation, if this is the last
850 		 * non-lead max-sized fragment (i.e. at the highest memory
851 		 * location), if the payload buffer has additional contents
852 		 * beyond the payload, and these additional contents have not
853 		 * already been taken care of by the presence (and processing)
854 		 * of a smaller fragment, include the additional contents in the
855 		 * move/copy.
856 		 */
857 		if (inline_frag &&
858 		    (i == num_maxsizefrags) &&
859 		    (payloadbuff_maxsize > (prepayload_leadbytes +
860 					    payloadlen)) &&
861 			!smallerfrag_size)
862 			bytes_to_transfer += (payloadbuff_maxsize -
863 					      prepayload_leadbytes -
864 					      payloadlen -
865 					      payloadbuff_shiftsize);
866 
867 		if (inline_frag)
868 			qdf_mem_move(dst, src, bytes_to_transfer);
869 		else
870 			qdf_mem_copy(dst, src, bytes_to_transfer);
871 
872 		/* Copy/move of payload done. Set fragment ID and length in
873 		 * element unit header.
874 		 */
875 		curr_elemunit_ptr = dst - elemunit_hdrlen;
876 		curr_elemunit_ptr[elemunit_id_pos] = elemunit_fragid;
877 		curr_elemunit_ptr[elemunit_len_pos] = elemunit_maxpayloadlen;
878 
879 		extrahdrbytes_remaining -= elemunit_hdrlen;
880 	}
881 
882 	/* Update the element unit pointer for the lead max-sized fragment.
883 	 *
884 	 * Copy the payload of the lead max-sized fragment if inline
885 	 * fragmentation is not being used.
886 	 */
887 	if (inline_frag) {
888 		curr_elemunit_ptr = payloadbuff;
889 	} else {
890 		qdf_mem_copy(fragbuff + elemunit_hdrlen,
891 			     payloadbuff + elemunit_hdrlen,
892 			     elemunit_maxpayloadlen);
893 		curr_elemunit_ptr = fragbuff;
894 	}
895 
896 	/* Set IDs and length in the header for the leading fragment */
897 	curr_elemunit_ptr[elemunit_id_pos] = id;
898 	curr_elemunit_ptr[elemunit_len_pos] = elemunit_maxpayloadlen;
899 	if (!is_subelem && (id == WLAN_ELEMID_EXTN_ELEM))
900 		curr_elemunit_ptr[elemunit_idext_pos] = idext;
901 
902 	*fragseqlen = expected_fragseqlen;
903 
904 	return QDF_STATUS_SUCCESS;
905 }
906 
907 static inline QDF_STATUS
wlan_get_elemsubelem_successorfrag(bool is_subelem,uint8_t subelemfragid,uint8_t * curr_elemunit_ptr,uint8_t * buff,qdf_size_t buff_maxsize,uint8_t ** successorfrag,qdf_size_t * successorfrag_totallen,qdf_size_t * successorfrag_payloadlen)908 wlan_get_elemsubelem_successorfrag(bool is_subelem,
909 				   uint8_t subelemfragid,
910 				   uint8_t *curr_elemunit_ptr,
911 				   uint8_t *buff,
912 				   qdf_size_t buff_maxsize,
913 				   uint8_t **successorfrag,
914 				   qdf_size_t *successorfrag_totallen,
915 				   qdf_size_t *successorfrag_payloadlen)
916 {
917 	/* elemunit, i.e. 'element unit' here refers to either an 802.11 element
918 	 * or a 802.11 subelement.
919 	 */
920 	uint8_t elemunit_fragid;
921 	qdf_size_t elemunit_hdrlen;
922 	qdf_size_t elemunit_maxpayloadlen;
923 	int elemunit_id_pos;
924 	int elemunit_len_pos;
925 
926 	qdf_size_t curr_elemunit_totallen;
927 
928 	uint8_t *next_elemunit_ptr;
929 	qdf_size_t next_elemunit_totallen;
930 
931 	QDF_STATUS ret;
932 
933 	/* This helper checks if the very next element unit after the current
934 	 * one is a valid fragment element unit and that there is sufficient
935 	 * space in the buffer for this next element, and if so, it returns a
936 	 * pointer to this fragment element unit as well as the total length of
937 	 * this fragment element unit and the length of the payload of this
938 	 * fragment element unit.
939 	 */
940 
941 	ret = wlan_get_elemunit_info(is_subelem,
942 				     subelemfragid,
943 				     &elemunit_fragid,
944 				     &elemunit_hdrlen,
945 				     &elemunit_maxpayloadlen,
946 				     &elemunit_id_pos,
947 				     &elemunit_len_pos,
948 				     NULL);
949 	if (QDF_IS_STATUS_ERROR(ret)) {
950 		qdf_rl_nofl_err("Get elem unit info: Error %d",
951 				ret);
952 		return QDF_STATUS_E_FAILURE;
953 	}
954 
955 	if (!curr_elemunit_ptr) {
956 		qdf_nofl_err("Ptr to curr elem unit is NULL");
957 		return QDF_STATUS_E_NULL_VALUE;
958 	}
959 
960 	if (!buff) {
961 		qdf_nofl_err("Elem unit buff is NULL");
962 		return QDF_STATUS_E_NULL_VALUE;
963 	}
964 
965 	if (buff_maxsize == 0) {
966 		qdf_nofl_err("Max size of elem unit buff is 0");
967 		return QDF_STATUS_E_INVAL;
968 	}
969 
970 	if (!successorfrag) {
971 		qdf_nofl_err("Double ptr to successor frag is NULL");
972 		return QDF_STATUS_E_NULL_VALUE;
973 	}
974 
975 	if (!successorfrag_totallen) {
976 		qdf_nofl_err("Ptr to successor frag total len is NULL");
977 		return QDF_STATUS_E_NULL_VALUE;
978 	}
979 
980 	if (!successorfrag_payloadlen) {
981 		qdf_nofl_err("Ptr to successor frag payload len is NULL");
982 		return QDF_STATUS_E_NULL_VALUE;
983 	}
984 
985 	if ((buff + buff_maxsize) < (curr_elemunit_ptr + elemunit_hdrlen)) {
986 		qdf_rl_nofl_err("(Space %zu after curr elem unit offset %zu in elem unit buff) < (header size of elem unit %zu)",
987 				buff_maxsize - (curr_elemunit_ptr - buff),
988 				curr_elemunit_ptr - buff,
989 				elemunit_hdrlen);
990 		return QDF_STATUS_E_PROTO;
991 	}
992 
993 	curr_elemunit_totallen =
994 		elemunit_hdrlen + curr_elemunit_ptr[elemunit_len_pos];
995 
996 	if ((buff + buff_maxsize) <
997 		(curr_elemunit_ptr + curr_elemunit_totallen)) {
998 		qdf_rl_nofl_err("(Space %zu after curr elem unit offset %zu in elem unit buff) < (indicated total len of elem unit %zu)",
999 				buff_maxsize - (curr_elemunit_ptr - buff),
1000 				curr_elemunit_ptr - buff,
1001 				curr_elemunit_totallen);
1002 		return QDF_STATUS_E_PROTO;
1003 	}
1004 
1005 	if ((buff + buff_maxsize) ==
1006 		(curr_elemunit_ptr + curr_elemunit_totallen)) {
1007 		/* We have reached the end of the buffer. There is no successor
1008 		 * fragment.
1009 		 */
1010 		*successorfrag = NULL;
1011 		return QDF_STATUS_SUCCESS;
1012 	}
1013 
1014 	next_elemunit_ptr = curr_elemunit_ptr + curr_elemunit_totallen;
1015 
1016 	if ((buff + buff_maxsize) < (next_elemunit_ptr + elemunit_hdrlen)) {
1017 		qdf_rl_nofl_err("(Space %zu after next elem unit offset %zu in elem unit buff) < (header size of elem unit %zu)",
1018 				buff_maxsize - (next_elemunit_ptr - buff),
1019 				next_elemunit_ptr - buff,
1020 				elemunit_hdrlen);
1021 		return QDF_STATUS_E_PROTO;
1022 	}
1023 
1024 	next_elemunit_totallen =
1025 		elemunit_hdrlen + next_elemunit_ptr[elemunit_len_pos];
1026 
1027 	if ((buff + buff_maxsize) <
1028 		(next_elemunit_ptr + next_elemunit_totallen)) {
1029 		qdf_rl_nofl_err("(Space %zu after next elem unit offset %zu in elem unit buff) < (indicated total len of elem unit %zu)",
1030 				buff_maxsize - (next_elemunit_ptr - buff),
1031 				next_elemunit_ptr - buff,
1032 				next_elemunit_totallen);
1033 		return QDF_STATUS_E_PROTO;
1034 	}
1035 
1036 	if (next_elemunit_ptr[elemunit_id_pos] != elemunit_fragid) {
1037 		*successorfrag = NULL;
1038 		return QDF_STATUS_SUCCESS;
1039 	}
1040 
1041 	/* We should not be seeing a successor fragment if the length of the
1042 	 * current element unit is lesser than the max.
1043 	 */
1044 	if (curr_elemunit_ptr[elemunit_len_pos] != elemunit_maxpayloadlen) {
1045 		qdf_rl_nofl_err("Potential successor frag found though (len %u of payload of curr elem unit) != (max payload len %zu)",
1046 				curr_elemunit_ptr[elemunit_len_pos],
1047 				elemunit_maxpayloadlen);
1048 		return QDF_STATUS_E_PROTO;
1049 	}
1050 
1051 	if (next_elemunit_ptr[elemunit_len_pos] == 0) {
1052 		qdf_rl_nofl_err("Potential successor frag len is 0");
1053 		return QDF_STATUS_E_PROTO;
1054 	}
1055 
1056 	*successorfrag = next_elemunit_ptr;
1057 	*successorfrag_totallen = next_elemunit_totallen;
1058 	*successorfrag_payloadlen = next_elemunit_ptr[elemunit_len_pos];
1059 
1060 	return QDF_STATUS_SUCCESS;
1061 }
1062 
1063 static QDF_STATUS
wlan_get_elemsubelem_fragseq_info(bool is_subelem,uint8_t subelemfragid,uint8_t * buff,qdf_size_t buff_maxsize,bool * is_fragseq,qdf_size_t * fragseq_totallen,qdf_size_t * fragseq_payloadlen)1064 wlan_get_elemsubelem_fragseq_info(bool is_subelem,
1065 				  uint8_t subelemfragid,
1066 				  uint8_t *buff,
1067 				  qdf_size_t buff_maxsize,
1068 				  bool *is_fragseq,
1069 				  qdf_size_t *fragseq_totallen,
1070 				  qdf_size_t *fragseq_payloadlen)
1071 {
1072 	/* elemunit, i.e. 'element unit' here refers to either an 802.11 element
1073 	 * or a 802.11 subelement.
1074 	 */
1075 	qdf_size_t elemunit_hdrlen;
1076 	int elemunit_id_pos;
1077 	int elemunit_len_pos;
1078 
1079 	uint8_t *curr_elemunit_ptr;
1080 	qdf_size_t curr_elemunit_totallen;
1081 
1082 	qdf_size_t fragseq_currtotallen;
1083 	qdf_size_t fragseq_currpayloadlen;
1084 
1085 	uint8_t *successorfrag;
1086 	qdf_size_t successorfrag_totallen;
1087 	qdf_size_t successorfrag_payloadlen;
1088 
1089 	QDF_STATUS ret;
1090 
1091 	/* Helper function to get element or subelement fragment sequence
1092 	 * information. Refer to the documentation of the public APIs which
1093 	 * call this helper, for more information. These APIs are mainly
1094 	 * wrappers over this helper.
1095 	 *
1096 	 * If this helper reports that an element fragment sequence is present,
1097 	 * it also serves to check for the sanity of various lengths and
1098 	 * protocol requirements related to the fragment sequence (either by
1099 	 * itself or though other helpers).
1100 	 */
1101 
1102 	ret = wlan_get_elemunit_info(is_subelem,
1103 				     0,
1104 				     NULL,
1105 				     &elemunit_hdrlen,
1106 				     NULL,
1107 				     &elemunit_id_pos,
1108 				     &elemunit_len_pos,
1109 				     NULL);
1110 	if (QDF_IS_STATUS_ERROR(ret)) {
1111 		qdf_rl_nofl_err("Get elem unit info: Error %d",
1112 				ret);
1113 		return QDF_STATUS_E_FAILURE;
1114 	}
1115 
1116 	if (!buff) {
1117 		qdf_nofl_err("Elem unit buff is NULL");
1118 		return QDF_STATUS_E_NULL_VALUE;
1119 	}
1120 
1121 	if (buff_maxsize == 0) {
1122 		qdf_nofl_err("Max size of elem unit buff is 0");
1123 		return QDF_STATUS_E_INVAL;
1124 	}
1125 
1126 	if (!is_fragseq) {
1127 		qdf_nofl_err("Ptr to status of frag seq presence is NULL");
1128 		return QDF_STATUS_E_NULL_VALUE;
1129 	}
1130 
1131 	if (!fragseq_totallen) {
1132 		qdf_nofl_err("Ptr to total len of frag seq is NULL");
1133 		return QDF_STATUS_E_NULL_VALUE;
1134 	}
1135 
1136 	if (!fragseq_payloadlen) {
1137 		qdf_nofl_err("Ptr to payload len of frag seq is NULL");
1138 		return QDF_STATUS_E_NULL_VALUE;
1139 	}
1140 
1141 	curr_elemunit_ptr = buff;
1142 	fragseq_currtotallen = 0;
1143 	fragseq_currpayloadlen = 0;
1144 
1145 	if ((buff + buff_maxsize) < (curr_elemunit_ptr + elemunit_hdrlen)) {
1146 		qdf_rl_nofl_err("(Space %zu after curr elem unit offset %zu in elem unit buff) < (header size of elem unit %zu)",
1147 				buff_maxsize - (curr_elemunit_ptr - buff),
1148 				curr_elemunit_ptr - buff,
1149 				elemunit_hdrlen);
1150 		return QDF_STATUS_E_PROTO;
1151 	}
1152 
1153 	curr_elemunit_totallen =
1154 		elemunit_hdrlen + curr_elemunit_ptr[elemunit_len_pos];
1155 
1156 	if ((buff + buff_maxsize) <
1157 		(curr_elemunit_ptr + curr_elemunit_totallen)) {
1158 		qdf_rl_nofl_err("(Space %zu after curr elem unit offset %zu in elem unit buff) < (indicated total len of elem unit %zu)",
1159 				buff_maxsize - (curr_elemunit_ptr - buff),
1160 				curr_elemunit_ptr - buff,
1161 				curr_elemunit_totallen);
1162 		return QDF_STATUS_E_PROTO;
1163 	}
1164 
1165 	successorfrag = NULL;
1166 
1167 	ret = wlan_get_elemsubelem_successorfrag(is_subelem,
1168 						 subelemfragid,
1169 						 curr_elemunit_ptr,
1170 						 buff,
1171 						 buff_maxsize,
1172 						 &successorfrag,
1173 						 &successorfrag_totallen,
1174 						 &successorfrag_payloadlen);
1175 	if (QDF_IS_STATUS_ERROR(ret))
1176 		return ret;
1177 
1178 	if (!successorfrag) {
1179 		*is_fragseq = false;
1180 		*fragseq_totallen = 0;
1181 		*fragseq_payloadlen = 0;
1182 		return QDF_STATUS_SUCCESS;
1183 	}
1184 
1185 	fragseq_currtotallen += curr_elemunit_totallen;
1186 
1187 	if (!is_subelem &&
1188 	    (curr_elemunit_ptr[elemunit_id_pos] == WLAN_ELEMID_EXTN_ELEM)) {
1189 		fragseq_currpayloadlen +=
1190 			(curr_elemunit_ptr[elemunit_len_pos] - 1);
1191 	} else {
1192 		fragseq_currpayloadlen +=
1193 			curr_elemunit_ptr[elemunit_len_pos];
1194 	}
1195 
1196 	while (successorfrag) {
1197 		/* wlan_get_elemsubelem_successorfrag() has already validated
1198 		 * the length values for the successor fragment.
1199 		 */
1200 		fragseq_currtotallen += successorfrag_totallen;
1201 		fragseq_currpayloadlen += successorfrag_payloadlen;
1202 
1203 		curr_elemunit_ptr = successorfrag;
1204 		successorfrag = NULL;
1205 
1206 		ret = wlan_get_elemsubelem_successorfrag(is_subelem,
1207 							 subelemfragid,
1208 							 curr_elemunit_ptr,
1209 							 buff,
1210 							 buff_maxsize,
1211 							 &successorfrag,
1212 							 &successorfrag_totallen,
1213 							 &successorfrag_payloadlen);
1214 		if (QDF_IS_STATUS_ERROR(ret))
1215 			return ret;
1216 	}
1217 
1218 	*is_fragseq = true;
1219 	*fragseq_totallen = fragseq_currtotallen;
1220 	*fragseq_payloadlen = fragseq_currpayloadlen;
1221 
1222 	return QDF_STATUS_SUCCESS;
1223 }
1224 
wlan_defrag_elemsubelem_fragseq(bool inline_defrag,bool is_subelem,uint8_t subelemfragid,uint8_t * fragbuff,qdf_size_t fragbuff_maxsize,uint8_t * defragbuff,qdf_size_t defragbuff_maxsize,qdf_size_t * defragpayload_len)1225 static QDF_STATUS wlan_defrag_elemsubelem_fragseq(bool inline_defrag,
1226 						  bool is_subelem,
1227 						  uint8_t subelemfragid,
1228 						  uint8_t *fragbuff,
1229 						  qdf_size_t fragbuff_maxsize,
1230 						  uint8_t *defragbuff,
1231 						  qdf_size_t defragbuff_maxsize,
1232 						  qdf_size_t *defragpayload_len)
1233 {
1234 	/* elemunit, i.e. 'element unit' here refers to either an 802.11 element
1235 	 * or a 802.11 subelement.
1236 	 */
1237 	uint8_t elemunit_fragid;
1238 	qdf_size_t elemunit_hdrlen;
1239 	int elemunit_id_pos;
1240 	int elemunit_len_pos;
1241 	int elemunit_idext_pos;
1242 
1243 	bool is_fragseq;
1244 	qdf_size_t fragseq_totallen;
1245 	qdf_size_t fragseq_payloadlen;
1246 
1247 	uint8_t *curr_elemunit_ptr;
1248 	qdf_size_t curr_elemunit_payloadlen;
1249 	qdf_size_t curr_elemunit_totallen;
1250 
1251 	uint8_t *src;
1252 	uint8_t *dst;
1253 
1254 	/* Current length of the defragmented payload */
1255 	qdf_size_t defragpayload_currlen;
1256 
1257 	/* Remaining length available in the source buffer containing the
1258 	 * fragment sequence, after element units processed so far.
1259 	 */
1260 	qdf_size_t fragbuff_remlen;
1261 
1262 	QDF_STATUS ret;
1263 
1264 	/* Helper function to de-fragment element or subelement fragment
1265 	 * sequence. Refer to the documentation of the public APIs which call
1266 	 * this helper, for more information. Those APIs are mainly wrappers
1267 	 * over this helper.
1268 	 */
1269 
1270 	ret = wlan_get_elemunit_info(is_subelem,
1271 				     subelemfragid,
1272 				     &elemunit_fragid,
1273 				     &elemunit_hdrlen,
1274 				     NULL,
1275 				     &elemunit_id_pos,
1276 				     &elemunit_len_pos,
1277 				     &elemunit_idext_pos);
1278 	if (QDF_IS_STATUS_ERROR(ret)) {
1279 		qdf_rl_nofl_err("Get elem unit info: Error %d",
1280 				ret);
1281 		return QDF_STATUS_E_FAILURE;
1282 	}
1283 
1284 	if (!fragbuff) {
1285 		qdf_nofl_err("Src buff for frag seq is NULL");
1286 		return QDF_STATUS_E_NULL_VALUE;
1287 	}
1288 
1289 	if (fragbuff_maxsize == 0) {
1290 		qdf_nofl_err("Size of src buff for frag seq is 0");
1291 		return QDF_STATUS_E_INVAL;
1292 	}
1293 
1294 	if (!inline_defrag) {
1295 		if (!defragbuff) {
1296 			qdf_nofl_err("Dest buff for defragged payload is NULL");
1297 			return QDF_STATUS_E_NULL_VALUE;
1298 		}
1299 
1300 		if (defragbuff_maxsize == 0) {
1301 			qdf_nofl_err("Size of dest buff for defragged payload is 0");
1302 			return QDF_STATUS_E_INVAL;
1303 		}
1304 	}
1305 
1306 	if (!defragpayload_len) {
1307 		qdf_nofl_err("Ptr to len of defragged payload is NULL");
1308 		return QDF_STATUS_E_NULL_VALUE;
1309 	}
1310 
1311 	ret = wlan_get_elemsubelem_fragseq_info(is_subelem,
1312 						subelemfragid,
1313 						fragbuff,
1314 						fragbuff_maxsize,
1315 						&is_fragseq,
1316 						&fragseq_totallen,
1317 						&fragseq_payloadlen);
1318 	if (QDF_IS_STATUS_ERROR(ret))
1319 		return ret;
1320 
1321 	if (!is_fragseq) {
1322 		/* We treat this as an error since the caller is supposed to
1323 		 * check this.
1324 		 */
1325 		qdf_rl_nofl_err("Frag seq not found at start of src buff for frag seq");
1326 		return QDF_STATUS_E_INVAL;
1327 	}
1328 
1329 	/* fragseq_totallen is known to be smaller than or equal to
1330 	 * fragbuff_maxsize since wlan_get_elemsubelem_fragseq_info() is bound
1331 	 * by fragbuff_maxsize in the search for a fragment sequence and it's
1332 	 * total length.
1333 	 */
1334 
1335 	if (!inline_defrag && (defragbuff_maxsize < fragseq_payloadlen)) {
1336 		qdf_rl_nofl_err("(Size of dest buff for defragged payload %zu) < (size of frag seq payload %zu)",
1337 				defragbuff_maxsize, fragseq_payloadlen);
1338 		return QDF_STATUS_E_INVAL;
1339 	}
1340 
1341 	defragpayload_currlen = 0;
1342 	fragbuff_remlen = fragbuff_maxsize;
1343 
1344 	/* We have already validated through wlan_get_elemsubelem_fragseq_info()
1345 	 * that the elements we are about to access below are within the bounds
1346 	 * of fragbuff.
1347 	 */
1348 
1349 	curr_elemunit_ptr = fragbuff;
1350 
1351 	if (!is_subelem &&
1352 	    (curr_elemunit_ptr[elemunit_id_pos] == WLAN_ELEMID_EXTN_ELEM)) {
1353 		curr_elemunit_payloadlen =
1354 			curr_elemunit_ptr[elemunit_len_pos] - 1;
1355 		src = curr_elemunit_ptr + elemunit_hdrlen + 1;
1356 	} else {
1357 		curr_elemunit_payloadlen = curr_elemunit_ptr[elemunit_len_pos];
1358 		src = curr_elemunit_ptr + elemunit_hdrlen;
1359 	}
1360 
1361 	curr_elemunit_totallen =
1362 		elemunit_hdrlen + curr_elemunit_ptr[elemunit_len_pos];
1363 
1364 	if (inline_defrag) {
1365 		/* There is no need to move any bytes in the lead element. Set
1366 		 * dst=src so that the next update for dst can happen in a
1367 		 * manner uniform with the non-inlined defrag case.
1368 		 */
1369 		dst = src;
1370 	} else {
1371 		dst = defragbuff;
1372 		qdf_mem_copy(dst, src, curr_elemunit_payloadlen);
1373 	}
1374 
1375 	defragpayload_currlen += curr_elemunit_payloadlen;
1376 
1377 	fragbuff_remlen -= curr_elemunit_totallen;
1378 
1379 	dst += curr_elemunit_payloadlen;
1380 
1381 	curr_elemunit_ptr += curr_elemunit_totallen;
1382 
1383 	/* We have already validated through wlan_get_elemsubelem_fragseq_info()
1384 	 * that at least one non-lead fragment element is present as required in
1385 	 * the standard.
1386 	 */
1387 	while (curr_elemunit_ptr[elemunit_id_pos] == elemunit_fragid) {
1388 		curr_elemunit_payloadlen = curr_elemunit_ptr[elemunit_len_pos];
1389 		curr_elemunit_totallen =
1390 			elemunit_hdrlen + curr_elemunit_ptr[elemunit_len_pos];
1391 		src = curr_elemunit_ptr + elemunit_hdrlen;
1392 
1393 		if (inline_defrag)
1394 			qdf_mem_move(dst, src, curr_elemunit_payloadlen);
1395 		else
1396 			qdf_mem_copy(dst, src, curr_elemunit_payloadlen);
1397 
1398 		defragpayload_currlen += curr_elemunit_payloadlen;
1399 
1400 		fragbuff_remlen -= curr_elemunit_totallen;
1401 
1402 		if (fragbuff_remlen == 0)
1403 			break;
1404 
1405 		dst += curr_elemunit_payloadlen;
1406 
1407 		curr_elemunit_ptr += curr_elemunit_totallen;
1408 	}
1409 
1410 	if (inline_defrag && (fragbuff_remlen != 0)) {
1411 		/* Move the residual content after the fragments, in the source
1412 		 * buffer.
1413 		 */
1414 		src = curr_elemunit_ptr;
1415 		qdf_mem_move(dst, src, fragbuff_remlen);
1416 	}
1417 
1418 	*defragpayload_len = defragpayload_currlen;
1419 
1420 	return QDF_STATUS_SUCCESS;
1421 }
1422 
1423 QDF_STATUS
wlan_get_elem_fragseq_requirements(uint8_t elemid,qdf_size_t payloadlen,bool * is_frag_required,qdf_size_t * required_fragbuff_size)1424 wlan_get_elem_fragseq_requirements(uint8_t elemid,
1425 				   qdf_size_t payloadlen,
1426 				   bool *is_frag_required,
1427 				   qdf_size_t *required_fragbuff_size)
1428 {
1429 	return wlan_get_elemsubelem_fragseq_creationparams(false,
1430 							   elemid,
1431 							   payloadlen,
1432 							   is_frag_required,
1433 							   required_fragbuff_size,
1434 							   NULL,
1435 							   NULL,
1436 							   NULL,
1437 							   NULL);
1438 }
1439 
wlan_create_elem_fragseq(bool inline_frag,uint8_t elemid,uint8_t elemidext,uint8_t * payloadbuff,qdf_size_t payloadbuff_maxsize,qdf_size_t payloadlen,uint8_t * fragbuff,qdf_size_t fragbuff_maxsize,qdf_size_t * fragseqlen)1440 QDF_STATUS wlan_create_elem_fragseq(bool inline_frag,
1441 				    uint8_t elemid,
1442 				    uint8_t elemidext,
1443 				    uint8_t *payloadbuff,
1444 				    qdf_size_t payloadbuff_maxsize,
1445 				    qdf_size_t payloadlen,
1446 				    uint8_t *fragbuff,
1447 				    qdf_size_t fragbuff_maxsize,
1448 				    qdf_size_t *fragseqlen)
1449 {
1450 	return  wlan_create_elemsubelem_fragseq(inline_frag,
1451 						false,
1452 						elemid,
1453 						elemidext,
1454 						0,
1455 						payloadbuff,
1456 						payloadbuff_maxsize,
1457 						payloadlen,
1458 						fragbuff,
1459 						fragbuff_maxsize,
1460 						fragseqlen);
1461 }
1462 
1463 QDF_STATUS
wlan_get_subelem_fragseq_requirements(uint8_t subelemid,qdf_size_t payloadlen,bool * is_frag_required,qdf_size_t * required_fragbuff_size)1464 wlan_get_subelem_fragseq_requirements(uint8_t subelemid,
1465 				      qdf_size_t payloadlen,
1466 				      bool *is_frag_required,
1467 				      qdf_size_t *required_fragbuff_size)
1468 {
1469 	return wlan_get_elemsubelem_fragseq_creationparams(true,
1470 							   subelemid,
1471 							   payloadlen,
1472 							   is_frag_required,
1473 							   required_fragbuff_size,
1474 							   NULL,
1475 							   NULL,
1476 							   NULL,
1477 							   NULL);
1478 }
1479 
wlan_create_subelem_fragseq(bool inline_frag,uint8_t subelemid,uint8_t subelemfragid,uint8_t * payloadbuff,qdf_size_t payloadbuff_maxsize,qdf_size_t payloadlen,uint8_t * fragbuff,qdf_size_t fragbuff_maxsize,qdf_size_t * fragseqlen)1480 QDF_STATUS wlan_create_subelem_fragseq(bool inline_frag,
1481 				       uint8_t subelemid,
1482 				       uint8_t subelemfragid,
1483 				       uint8_t *payloadbuff,
1484 				       qdf_size_t payloadbuff_maxsize,
1485 				       qdf_size_t payloadlen,
1486 				       uint8_t *fragbuff,
1487 				       qdf_size_t fragbuff_maxsize,
1488 				       qdf_size_t *fragseqlen)
1489 {
1490 	return  wlan_create_elemsubelem_fragseq(inline_frag,
1491 						true,
1492 						subelemid,
1493 						0,
1494 						subelemfragid,
1495 						payloadbuff,
1496 						payloadbuff_maxsize,
1497 						payloadlen,
1498 						fragbuff,
1499 						fragbuff_maxsize,
1500 						fragseqlen);
1501 }
1502 
wlan_get_elem_fragseq_info(uint8_t * elembuff,qdf_size_t elembuff_maxsize,bool * is_fragseq,qdf_size_t * fragseq_totallen,qdf_size_t * fragseq_payloadlen)1503 QDF_STATUS wlan_get_elem_fragseq_info(uint8_t *elembuff,
1504 				      qdf_size_t elembuff_maxsize,
1505 				      bool *is_fragseq,
1506 				      qdf_size_t *fragseq_totallen,
1507 				      qdf_size_t *fragseq_payloadlen)
1508 {
1509 	return wlan_get_elemsubelem_fragseq_info(false,
1510 						 0,
1511 						 elembuff,
1512 						 elembuff_maxsize,
1513 						 is_fragseq,
1514 						 fragseq_totallen,
1515 						 fragseq_payloadlen);
1516 }
1517 
wlan_defrag_elem_fragseq(bool inline_defrag,uint8_t * fragbuff,qdf_size_t fragbuff_maxsize,uint8_t * defragbuff,qdf_size_t defragbuff_maxsize,qdf_size_t * defragpayload_len)1518 QDF_STATUS wlan_defrag_elem_fragseq(bool inline_defrag,
1519 				    uint8_t *fragbuff,
1520 				    qdf_size_t fragbuff_maxsize,
1521 				    uint8_t *defragbuff,
1522 				    qdf_size_t defragbuff_maxsize,
1523 				    qdf_size_t *defragpayload_len)
1524 {
1525 	return wlan_defrag_elemsubelem_fragseq(inline_defrag,
1526 					       false,
1527 					       0,
1528 					       fragbuff,
1529 					       fragbuff_maxsize,
1530 					       defragbuff,
1531 					       defragbuff_maxsize,
1532 					       defragpayload_len);
1533 }
1534 
wlan_get_subelem_fragseq_info(uint8_t subelemfragid,uint8_t * subelembuff,qdf_size_t subelembuff_maxsize,bool * is_fragseq,qdf_size_t * fragseq_totallen,qdf_size_t * fragseq_payloadlen)1535 QDF_STATUS wlan_get_subelem_fragseq_info(uint8_t subelemfragid,
1536 					 uint8_t *subelembuff,
1537 					 qdf_size_t subelembuff_maxsize,
1538 					 bool *is_fragseq,
1539 					 qdf_size_t *fragseq_totallen,
1540 					 qdf_size_t *fragseq_payloadlen)
1541 {
1542 	return wlan_get_elemsubelem_fragseq_info(true,
1543 						 subelemfragid,
1544 						 subelembuff,
1545 						 subelembuff_maxsize,
1546 						 is_fragseq,
1547 						 fragseq_totallen,
1548 						 fragseq_payloadlen);
1549 }
1550 
wlan_defrag_subelem_fragseq(bool inline_defrag,uint8_t subelemfragid,uint8_t * fragbuff,qdf_size_t fragbuff_maxsize,uint8_t * defragbuff,qdf_size_t defragbuff_maxsize,qdf_size_t * defragpayload_len)1551 QDF_STATUS wlan_defrag_subelem_fragseq(bool inline_defrag,
1552 				       uint8_t subelemfragid,
1553 				       uint8_t *fragbuff,
1554 				       qdf_size_t fragbuff_maxsize,
1555 				       uint8_t *defragbuff,
1556 				       qdf_size_t defragbuff_maxsize,
1557 				       qdf_size_t *defragpayload_len)
1558 {
1559 	return wlan_defrag_elemsubelem_fragseq(inline_defrag,
1560 					       true,
1561 					       subelemfragid,
1562 					       fragbuff,
1563 					       fragbuff_maxsize,
1564 					       defragbuff,
1565 					       defragbuff_maxsize,
1566 					       defragpayload_len);
1567 }
1568 
wlan_is_emulation_platform(uint32_t phy_version)1569 bool wlan_is_emulation_platform(uint32_t phy_version)
1570 {
1571 	if ((phy_version == 0xABC0) || (phy_version == 0xABC1) ||
1572 		(phy_version == 0xABC2) || (phy_version == 0xABC3) ||
1573 		(phy_version == 0xFFFF) || (phy_version == 0xABCD))
1574 		return true;
1575 
1576 	return false;
1577 }
1578 
wlan_get_pdev_id_from_vdev_id(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,wlan_objmgr_ref_dbgid dbg_id)1579 uint32_t wlan_get_pdev_id_from_vdev_id(struct wlan_objmgr_psoc *psoc,
1580 				      uint8_t vdev_id,
1581 				      wlan_objmgr_ref_dbgid dbg_id)
1582 {
1583 	struct wlan_objmgr_vdev *vdev;
1584 	struct wlan_objmgr_pdev *pdev = NULL;
1585 	uint32_t pdev_id = WLAN_INVALID_PDEV_ID;
1586 
1587 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
1588 						    vdev_id, dbg_id);
1589 
1590 	if (vdev) {
1591 		pdev = wlan_vdev_get_pdev(vdev);
1592 		if (pdev)
1593 			pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
1594 		wlan_objmgr_vdev_release_ref(vdev, dbg_id);
1595 	}
1596 
1597 	return pdev_id;
1598 }
1599 qdf_export_symbol(wlan_get_pdev_id_from_vdev_id);
1600 
wlan_vdev_active(struct wlan_objmgr_pdev * pdev,void * object,void * arg)1601 static void wlan_vdev_active(struct wlan_objmgr_pdev *pdev, void *object,
1602 			     void *arg)
1603 {
1604 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
1605 	uint8_t *flag = (uint8_t *)arg;
1606 
1607 	wlan_vdev_obj_lock(vdev);
1608 	if (wlan_vdev_mlme_is_active(vdev) == QDF_STATUS_SUCCESS)
1609 		*flag = 1;
1610 
1611 	wlan_vdev_obj_unlock(vdev);
1612 }
1613 
wlan_vdev_is_up(struct wlan_objmgr_vdev * vdev)1614 QDF_STATUS wlan_vdev_is_up(struct wlan_objmgr_vdev *vdev)
1615 {
1616 	return wlan_vdev_allow_connect_n_tx(vdev);
1617 }
1618 qdf_export_symbol(wlan_vdev_is_up);
1619 
wlan_util_is_vdev_active(struct wlan_objmgr_pdev * pdev,wlan_objmgr_ref_dbgid dbg_id)1620 QDF_STATUS wlan_util_is_vdev_active(struct wlan_objmgr_pdev *pdev,
1621 				    wlan_objmgr_ref_dbgid dbg_id)
1622 {
1623 	uint8_t flag = 0;
1624 
1625 	if (!pdev)
1626 		return QDF_STATUS_E_INVAL;
1627 
1628 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, wlan_vdev_active,
1629 					  &flag, 0, dbg_id);
1630 
1631 	if (flag == 1)
1632 		return QDF_STATUS_SUCCESS;
1633 
1634 	return QDF_STATUS_E_INVAL;
1635 }
1636 
1637 qdf_export_symbol(wlan_util_is_vdev_active);
1638 
wlan_util_change_map_index(unsigned long * map,uint8_t id,uint8_t set)1639 void wlan_util_change_map_index(unsigned long *map, uint8_t id, uint8_t set)
1640 {
1641 	if (set)
1642 		qdf_set_bit(id, map);
1643 	else
1644 		qdf_clear_bit(id, map);
1645 }
1646 
wlan_util_map_index_is_set(unsigned long * map,uint8_t id)1647 bool wlan_util_map_index_is_set(unsigned long *map, uint8_t id)
1648 {
1649 	return qdf_test_bit(id, map);
1650 }
1651 
wlan_util_map_is_any_index_set(unsigned long * map,unsigned long nbytes)1652 bool wlan_util_map_is_any_index_set(unsigned long *map, unsigned long nbytes)
1653 {
1654 	return !qdf_bitmap_empty(map, QDF_CHAR_BIT * nbytes);
1655 }
1656 
wlan_vdev_chan_change_pending(struct wlan_objmgr_pdev * pdev,void * object,void * arg)1657 static void wlan_vdev_chan_change_pending(struct wlan_objmgr_pdev *pdev,
1658 					  void *object, void *arg)
1659 {
1660 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
1661 	unsigned long *vdev_id_map = (unsigned long *)arg;
1662 	uint8_t id = 0;
1663 	struct wlan_objmgr_psoc *psoc;
1664 
1665 	psoc = wlan_pdev_get_psoc(pdev);
1666 	if (!psoc)
1667 		return;
1668 
1669 	wlan_vdev_obj_lock(vdev);
1670 	if (wlan_vdev_chan_config_valid(vdev) == QDF_STATUS_SUCCESS) {
1671 		id = wlan_vdev_get_id(vdev);
1672 		/* Invalid vdev id */
1673 		if (id >= wlan_psoc_get_max_vdev_count(psoc)) {
1674 			wlan_vdev_obj_unlock(vdev);
1675 			return;
1676 		}
1677 
1678 		wlan_util_change_map_index(vdev_id_map, id, 1);
1679 	}
1680 
1681 	wlan_vdev_obj_unlock(vdev);
1682 }
1683 
wlan_pdev_chan_change_pending_vdevs(struct wlan_objmgr_pdev * pdev,unsigned long * vdev_id_map,wlan_objmgr_ref_dbgid dbg_id)1684 QDF_STATUS wlan_pdev_chan_change_pending_vdevs(struct wlan_objmgr_pdev *pdev,
1685 					       unsigned long *vdev_id_map,
1686 					       wlan_objmgr_ref_dbgid dbg_id)
1687 {
1688 	if (!pdev)
1689 		return QDF_STATUS_E_INVAL;
1690 
1691 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
1692 					  wlan_vdev_chan_change_pending,
1693 					  vdev_id_map, 0, dbg_id);
1694 
1695 	return QDF_STATUS_SUCCESS;
1696 }
1697 
wlan_vdev_down_pending(struct wlan_objmgr_pdev * pdev,void * object,void * arg)1698 static void wlan_vdev_down_pending(struct wlan_objmgr_pdev *pdev,
1699 				   void *object, void *arg)
1700 {
1701 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
1702 	unsigned long *vdev_id_map = (unsigned long *)arg;
1703 	uint8_t id = 0;
1704 	struct wlan_objmgr_psoc *psoc;
1705 	enum wlan_serialization_cmd_type cmd_type;
1706 
1707 	psoc = wlan_pdev_get_psoc(pdev);
1708 	if (!psoc)
1709 		return;
1710 
1711 	if (wlan_vdev_mlme_is_mlo_bridge_vdev(vdev))
1712 		return;
1713 
1714 	cmd_type = wlan_serialization_get_vdev_active_cmd_type(vdev);
1715 	wlan_vdev_obj_lock(vdev);
1716 	if ((wlan_vdev_mlme_is_init_state(vdev) != QDF_STATUS_SUCCESS) ||
1717 	    (cmd_type == WLAN_SER_CMD_VDEV_START_BSS)) {
1718 		id = wlan_vdev_get_id(vdev);
1719 		/* Invalid vdev id */
1720 		if (id >= wlan_psoc_get_max_vdev_count(psoc)) {
1721 			wlan_vdev_obj_unlock(vdev);
1722 			return;
1723 		}
1724 		wlan_util_change_map_index(vdev_id_map, id, 1);
1725 	}
1726 
1727 	wlan_vdev_obj_unlock(vdev);
1728 }
1729 
wlan_vdev_ap_down_pending(struct wlan_objmgr_pdev * pdev,void * object,void * arg)1730 static void wlan_vdev_ap_down_pending(struct wlan_objmgr_pdev *pdev,
1731 				      void *object, void *arg)
1732 {
1733 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
1734 	unsigned long *vdev_id_map = (unsigned long *)arg;
1735 	uint8_t id = 0;
1736 	struct wlan_objmgr_psoc *psoc;
1737 	enum wlan_serialization_cmd_type cmd_type;
1738 
1739 	psoc = wlan_pdev_get_psoc(pdev);
1740 	if (!psoc)
1741 		return;
1742 
1743 	if (wlan_vdev_mlme_get_opmode(vdev) != QDF_SAP_MODE)
1744 		return;
1745 
1746 	if (wlan_vdev_mlme_is_mlo_bridge_vdev(vdev))
1747 		return;
1748 
1749 	cmd_type = wlan_serialization_get_vdev_active_cmd_type(vdev);
1750 	wlan_vdev_obj_lock(vdev);
1751 	if ((wlan_vdev_mlme_is_init_state(vdev) != QDF_STATUS_SUCCESS) ||
1752 	    (cmd_type == WLAN_SER_CMD_VDEV_START_BSS)) {
1753 		id = wlan_vdev_get_id(vdev);
1754 		/* Invalid vdev id */
1755 		if (id >= wlan_psoc_get_max_vdev_count(psoc)) {
1756 			wlan_vdev_obj_unlock(vdev);
1757 			return;
1758 		}
1759 		wlan_util_change_map_index(vdev_id_map, id, 1);
1760 	}
1761 
1762 	wlan_vdev_obj_unlock(vdev);
1763 }
1764 
wlan_pdev_chan_change_pending_vdevs_down(struct wlan_objmgr_pdev * pdev,unsigned long * vdev_id_map,wlan_objmgr_ref_dbgid dbg_id)1765 QDF_STATUS wlan_pdev_chan_change_pending_vdevs_down(
1766 					struct wlan_objmgr_pdev *pdev,
1767 					unsigned long *vdev_id_map,
1768 					wlan_objmgr_ref_dbgid dbg_id)
1769 {
1770 	if (!pdev)
1771 		return QDF_STATUS_E_INVAL;
1772 
1773 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
1774 					  wlan_vdev_down_pending,
1775 					  vdev_id_map, 0, dbg_id);
1776 
1777 	return QDF_STATUS_SUCCESS;
1778 }
1779 
wlan_pdev_chan_change_pending_ap_vdevs_down(struct wlan_objmgr_pdev * pdev,unsigned long * vdev_id_map,wlan_objmgr_ref_dbgid dbg_id)1780 QDF_STATUS wlan_pdev_chan_change_pending_ap_vdevs_down(
1781 						struct wlan_objmgr_pdev *pdev,
1782 						unsigned long *vdev_id_map,
1783 						wlan_objmgr_ref_dbgid dbg_id)
1784 {
1785 	if (!pdev)
1786 		return QDF_STATUS_E_INVAL;
1787 
1788 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
1789 					  wlan_vdev_ap_down_pending,
1790 					  vdev_id_map, 0, dbg_id);
1791 
1792 	return QDF_STATUS_SUCCESS;
1793 }
1794 
1795 #ifdef WLAN_FEATURE_11BE
1796 static inline bool
wlan_chan_puncture_eq(struct wlan_channel * chan1,struct wlan_channel * chan2)1797 wlan_chan_puncture_eq(struct wlan_channel *chan1, struct wlan_channel *chan2)
1798 {
1799 	if (chan1->puncture_bitmap == chan2->puncture_bitmap)
1800 		return true;
1801 
1802 	return false;
1803 }
1804 #else
1805 static inline bool
wlan_chan_puncture_eq(struct wlan_channel * chan1,struct wlan_channel * chan2)1806 wlan_chan_puncture_eq(struct wlan_channel *chan1, struct wlan_channel *chan2)
1807 {
1808 	return true;
1809 }
1810 #endif /* WLAN_FEATURE_11BE */
1811 
wlan_chan_eq(struct wlan_channel * chan1,struct wlan_channel * chan2)1812 QDF_STATUS wlan_chan_eq(struct wlan_channel *chan1, struct wlan_channel *chan2)
1813 {
1814 	if ((chan1->ch_ieee == chan2->ch_ieee) &&
1815 	    (chan1->ch_freq_seg2 == chan2->ch_freq_seg2) &&
1816 	    wlan_chan_puncture_eq(chan1, chan2))
1817 		return QDF_STATUS_SUCCESS;
1818 
1819 	return QDF_STATUS_E_FAILURE;
1820 }
1821 
wlan_chan_copy(struct wlan_channel * tgt,struct wlan_channel * src)1822 void wlan_chan_copy(struct wlan_channel *tgt, struct wlan_channel *src)
1823 {
1824 	qdf_mem_copy(tgt, src, sizeof(struct wlan_channel));
1825 }
1826 
wlan_vdev_get_active_channel(struct wlan_objmgr_vdev * vdev)1827 struct wlan_channel *wlan_vdev_get_active_channel(struct wlan_objmgr_vdev *vdev)
1828 {
1829 	struct wlan_channel *comp_vdev_chan = NULL;
1830 
1831 	if (wlan_vdev_chan_config_valid(vdev) == QDF_STATUS_SUCCESS) {
1832 		/* compare with BSS channel, when vdev is active, since desired
1833 		 * channel gets update, if channel is triggered in another path
1834 		 */
1835 		if (wlan_vdev_mlme_is_active(vdev) == QDF_STATUS_SUCCESS)
1836 			comp_vdev_chan = wlan_vdev_mlme_get_bss_chan(vdev);
1837 		else
1838 			comp_vdev_chan = wlan_vdev_mlme_get_des_chan(vdev);
1839 	}
1840 
1841 	return comp_vdev_chan;
1842 }
1843 
1844 /**
1845  * struct wlan_check_bssid_context - bssid check context
1846  * @bssid: bssid to be checked
1847  * @connected: connected by vdev or not
1848  * @vdev_id: vdev id of connected vdev
1849  */
1850 struct wlan_check_bssid_context {
1851 	struct qdf_mac_addr bssid;
1852 	bool connected;
1853 	uint8_t vdev_id;
1854 };
1855 
1856 /**
1857  * wlan_get_connected_vdev_handler() - check vdev connected on bssid
1858  * @psoc: psoc object
1859  * @obj: vdev object
1860  * @args: handler context
1861  *
1862  * This function will check whether vdev is connected on bssid or not and
1863  * update the result to handler context accordingly.
1864  *
1865  * Return: void
1866  */
wlan_get_connected_vdev_handler(struct wlan_objmgr_psoc * psoc,void * obj,void * args)1867 static void wlan_get_connected_vdev_handler(struct wlan_objmgr_psoc *psoc,
1868 					    void *obj, void *args)
1869 {
1870 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)obj;
1871 	struct wlan_check_bssid_context *context =
1872 				(struct wlan_check_bssid_context *)args;
1873 	struct qdf_mac_addr bss_peer_mac;
1874 	enum QDF_OPMODE op_mode;
1875 
1876 	if (context->connected)
1877 		return;
1878 
1879 	op_mode = wlan_vdev_mlme_get_opmode(vdev);
1880 	if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE)
1881 		return;
1882 
1883 	if (wlan_cm_is_vdev_disconnected(vdev))
1884 		return;
1885 
1886 	if (wlan_vdev_get_bss_peer_mac(vdev, &bss_peer_mac) !=
1887 	    QDF_STATUS_SUCCESS)
1888 		return;
1889 	if (qdf_is_macaddr_equal(&bss_peer_mac, &context->bssid)) {
1890 		context->connected = true;
1891 		context->vdev_id = wlan_vdev_get_id(vdev);
1892 	}
1893 }
1894 
wlan_get_connected_vdev_from_psoc_by_bssid(struct wlan_objmgr_psoc * psoc,uint8_t * bssid,uint8_t * vdev_id)1895 bool wlan_get_connected_vdev_from_psoc_by_bssid(struct wlan_objmgr_psoc *psoc,
1896 						uint8_t *bssid,
1897 						uint8_t *vdev_id)
1898 {
1899 	struct wlan_check_bssid_context context;
1900 
1901 	qdf_mem_zero(&context, sizeof(struct wlan_check_bssid_context));
1902 	qdf_mem_copy(context.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE);
1903 	wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP,
1904 				     wlan_get_connected_vdev_handler,
1905 				     &context, true, WLAN_OSIF_SCAN_ID);
1906 	if (context.connected)
1907 		*vdev_id = context.vdev_id;
1908 
1909 	return context.connected;
1910 }
1911 
1912 qdf_export_symbol(wlan_get_connected_vdev_from_psoc_by_bssid);
1913 
wlan_get_connected_vdev_by_bssid(struct wlan_objmgr_pdev * pdev,uint8_t * bssid,uint8_t * vdev_id)1914 bool wlan_get_connected_vdev_by_bssid(struct wlan_objmgr_pdev *pdev,
1915 				      uint8_t *bssid, uint8_t *vdev_id)
1916 {
1917 	return wlan_get_connected_vdev_from_psoc_by_bssid(
1918 			wlan_pdev_get_psoc(pdev), bssid, vdev_id);
1919 }
1920 
1921 qdf_export_symbol(wlan_get_connected_vdev_by_bssid);
1922 
1923 #ifdef WLAN_FEATURE_11BE_MLO
1924 /**
1925  * struct wlan_check_mld_addr_context - mld mac addr check context
1926  * @mld_addr: mld_addrto be checked
1927  * @connected: connected by vdev or not
1928  * @vdev_id: vdev id of connected vdev
1929  */
1930 struct wlan_check_mld_addr_context {
1931 	struct qdf_mac_addr mld_addr;
1932 	bool connected;
1933 	uint8_t vdev_id;
1934 };
1935 
1936 /**
1937  * wlan_get_connected_mlo_dev_ctx_handler() - check vdev connected on mld mac
1938  * @psoc: psoc object
1939  * @obj: vdev object
1940  * @args: handler context
1941  *
1942  * This function will check whether vdev is connected on mld mac or not and
1943  * update the result to handler context accordingly.
1944  *
1945  * Return: void
1946  */
wlan_get_connected_mlo_dev_ctx_handler(struct wlan_objmgr_psoc * psoc,void * obj,void * args)1947 static void wlan_get_connected_mlo_dev_ctx_handler(
1948 			struct wlan_objmgr_psoc *psoc,
1949 			void *obj, void *args)
1950 {
1951 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)obj;
1952 	struct wlan_check_mld_addr_context *context =
1953 				(struct wlan_check_mld_addr_context *)args;
1954 	struct qdf_mac_addr bss_peer_mld_mac;
1955 	enum QDF_OPMODE op_mode;
1956 
1957 	if (context->connected)
1958 		return;
1959 	op_mode = wlan_vdev_mlme_get_opmode(vdev);
1960 	if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE)
1961 		return;
1962 	if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS)
1963 		return;
1964 	if (QDF_IS_STATUS_ERROR(wlan_vdev_get_bss_peer_mld_mac(
1965 					vdev, &bss_peer_mld_mac)))
1966 		return;
1967 	if (qdf_is_macaddr_equal(&bss_peer_mld_mac, &context->mld_addr)) {
1968 		context->connected = true;
1969 		context->vdev_id = wlan_vdev_get_id(vdev);
1970 	}
1971 }
1972 
wlan_get_connected_vdev_by_mld_addr(struct wlan_objmgr_psoc * psoc,uint8_t * mld_mac,uint8_t * vdev_id)1973 bool wlan_get_connected_vdev_by_mld_addr(struct wlan_objmgr_psoc *psoc,
1974 					 uint8_t *mld_mac, uint8_t *vdev_id)
1975 {
1976 	struct wlan_check_mld_addr_context context;
1977 
1978 	qdf_mem_zero(&context, sizeof(struct wlan_check_mld_addr_context));
1979 	qdf_copy_macaddr(&context.mld_addr, (struct qdf_mac_addr *)mld_mac);
1980 	wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP,
1981 				     wlan_get_connected_mlo_dev_ctx_handler,
1982 				     &context, true, WLAN_MLME_OBJMGR_ID);
1983 
1984 	if (context.connected)
1985 		*vdev_id = context.vdev_id;
1986 
1987 	return context.connected;
1988 }
1989 #endif
1990 
1991 #if defined(WLAN_FEATURE_11BE)
1992 enum wlan_phymode
wlan_eht_chan_phy_mode(uint32_t freq,uint16_t bw_val,enum phy_ch_width chan_width)1993 wlan_eht_chan_phy_mode(uint32_t freq,
1994 		       uint16_t bw_val,
1995 		       enum phy_ch_width chan_width)
1996 {
1997 	if (wlan_reg_is_24ghz_ch_freq(freq)) {
1998 		if (bw_val == 20)
1999 			return WLAN_PHYMODE_11BEG_EHT20;
2000 		else if (bw_val == 40)
2001 			return WLAN_PHYMODE_11BEG_EHT40;
2002 	} else {
2003 		if (bw_val == 20)
2004 			return WLAN_PHYMODE_11BEA_EHT20;
2005 		else if (bw_val == 40)
2006 			return WLAN_PHYMODE_11BEA_EHT40;
2007 		else if (bw_val == 80)
2008 			return WLAN_PHYMODE_11BEA_EHT80;
2009 		else if (chan_width == CH_WIDTH_160MHZ)
2010 			return WLAN_PHYMODE_11BEA_EHT160;
2011 		else if (chan_width == CH_WIDTH_320MHZ)
2012 			return WLAN_PHYMODE_11BEA_EHT320;
2013 	}
2014 	return WLAN_PHYMODE_AUTO;
2015 }
2016 #else
2017 enum wlan_phymode
wlan_eht_chan_phy_mode(uint32_t freq,uint16_t bw_val,enum phy_ch_width chan_width)2018 wlan_eht_chan_phy_mode(uint32_t freq,
2019 		       uint16_t bw_val,
2020 		       enum phy_ch_width chan_width)
2021 {
2022 	return WLAN_PHYMODE_AUTO;
2023 }
2024 
2025 #endif
2026 
wlan_pdev_chan_match(struct wlan_objmgr_pdev * pdev,void * object,void * arg)2027 static void wlan_pdev_chan_match(struct wlan_objmgr_pdev *pdev, void *object,
2028 				 void *arg)
2029 {
2030 	struct wlan_objmgr_vdev *comp_vdev = (struct wlan_objmgr_vdev *)object;
2031 	struct wlan_vdev_ch_check_filter *ch_filter = arg;
2032 	struct wlan_channel vdev_chan, *chan;
2033 	struct wlan_channel *iter_vdev_chan;
2034 
2035 	if (ch_filter->flag)
2036 		return;
2037 
2038 	if (comp_vdev == ch_filter->vdev)
2039 		return;
2040 
2041 	wlan_vdev_obj_lock(comp_vdev);
2042 	chan = wlan_vdev_get_active_channel(comp_vdev);
2043 	if (!chan) {
2044 		wlan_vdev_obj_unlock(comp_vdev);
2045 		return;
2046 	}
2047 	wlan_chan_copy(&vdev_chan, chan);
2048 	wlan_vdev_obj_unlock(comp_vdev);
2049 
2050 	wlan_vdev_obj_lock(ch_filter->vdev);
2051 	iter_vdev_chan = wlan_vdev_mlme_get_des_chan(ch_filter->vdev);
2052 	if (wlan_chan_eq(&vdev_chan, iter_vdev_chan)
2053 		!= QDF_STATUS_SUCCESS) {
2054 		ch_filter->flag = 1;
2055 		qdf_debug("==> iter vdev id: %d: ieee %d, mode %d",
2056 			  wlan_vdev_get_id(comp_vdev),
2057 			  vdev_chan.ch_ieee,
2058 			  vdev_chan.ch_phymode);
2059 		qdf_debug("fl %016llx, fl-ext %08x, s1 %d, s2 %d ",
2060 			  vdev_chan.ch_flags, vdev_chan.ch_flagext,
2061 			  vdev_chan.ch_freq_seg1,
2062 			  vdev_chan.ch_freq_seg2);
2063 		qdf_debug("==> base vdev id: %d: ieee %d mode %d",
2064 			  wlan_vdev_get_id(ch_filter->vdev),
2065 			  iter_vdev_chan->ch_ieee,
2066 			  iter_vdev_chan->ch_phymode);
2067 		qdf_debug("fl %016llx, fl-ext %08x s1 %d, s2 %d",
2068 			  iter_vdev_chan->ch_flags,
2069 			  iter_vdev_chan->ch_flagext,
2070 			  iter_vdev_chan->ch_freq_seg1,
2071 			  iter_vdev_chan->ch_freq_seg2);
2072 	}
2073 	wlan_vdev_obj_unlock(ch_filter->vdev);
2074 }
2075 
wlan_util_pdev_vdevs_deschan_match(struct wlan_objmgr_pdev * pdev,struct wlan_objmgr_vdev * vdev,wlan_objmgr_ref_dbgid dbg_id)2076 QDF_STATUS wlan_util_pdev_vdevs_deschan_match(struct wlan_objmgr_pdev *pdev,
2077 					      struct wlan_objmgr_vdev *vdev,
2078 					      wlan_objmgr_ref_dbgid dbg_id)
2079 {
2080 	struct wlan_vdev_ch_check_filter ch_filter;
2081 
2082 	if (!pdev)
2083 		return QDF_STATUS_E_INVAL;
2084 
2085 	if (wlan_pdev_nif_feat_cap_get(pdev, WLAN_PDEV_F_CHAN_CONCURRENCY))
2086 		return QDF_STATUS_SUCCESS;
2087 
2088 	if (wlan_objmgr_vdev_try_get_ref(vdev, dbg_id) == QDF_STATUS_SUCCESS) {
2089 		ch_filter.flag = 0;
2090 		ch_filter.vdev = vdev;
2091 
2092 		wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
2093 						  wlan_pdev_chan_match,
2094 						  &ch_filter, 0, dbg_id);
2095 
2096 		wlan_objmgr_vdev_release_ref(vdev, dbg_id);
2097 
2098 		if (ch_filter.flag == 0)
2099 			return QDF_STATUS_SUCCESS;
2100 	}
2101 
2102 	return QDF_STATUS_E_FAILURE;
2103 }
2104 
wlan_vdev_restart_progress(struct wlan_objmgr_pdev * pdev,void * object,void * arg)2105 static void wlan_vdev_restart_progress(struct wlan_objmgr_pdev *pdev,
2106 				       void *object, void *arg)
2107 {
2108 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
2109 	uint8_t *flag = (uint8_t *)arg;
2110 
2111 	wlan_vdev_obj_lock(vdev);
2112 	if (wlan_vdev_is_restart_progress(vdev) == QDF_STATUS_SUCCESS)
2113 		*flag = 1;
2114 
2115 	wlan_vdev_obj_unlock(vdev);
2116 }
2117 
wlan_util_is_pdev_restart_progress(struct wlan_objmgr_pdev * pdev,wlan_objmgr_ref_dbgid dbg_id)2118 QDF_STATUS wlan_util_is_pdev_restart_progress(struct wlan_objmgr_pdev *pdev,
2119 					      wlan_objmgr_ref_dbgid dbg_id)
2120 {
2121 	uint8_t flag = 0;
2122 
2123 	if (!pdev)
2124 		return QDF_STATUS_E_INVAL;
2125 
2126 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
2127 					  wlan_vdev_restart_progress,
2128 					  &flag, 0, dbg_id);
2129 
2130 	if (flag == 1)
2131 		return QDF_STATUS_SUCCESS;
2132 
2133 	return QDF_STATUS_E_INVAL;
2134 }
2135 
wlan_vdev_scan_allowed(struct wlan_objmgr_pdev * pdev,void * object,void * arg)2136 static void wlan_vdev_scan_allowed(struct wlan_objmgr_pdev *pdev, void *object,
2137 				   void *arg)
2138 {
2139 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
2140 	uint8_t *flag = (uint8_t *)arg;
2141 
2142 	wlan_vdev_obj_lock(vdev);
2143 	if (wlan_vdev_mlme_is_scan_allowed(vdev) != QDF_STATUS_SUCCESS)
2144 		*flag = 1;
2145 
2146 	wlan_vdev_obj_unlock(vdev);
2147 }
2148 
wlan_util_is_pdev_scan_allowed(struct wlan_objmgr_pdev * pdev,wlan_objmgr_ref_dbgid dbg_id)2149 QDF_STATUS wlan_util_is_pdev_scan_allowed(struct wlan_objmgr_pdev *pdev,
2150 					  wlan_objmgr_ref_dbgid dbg_id)
2151 {
2152 	uint8_t flag = 0;
2153 
2154 	if (!pdev)
2155 		return QDF_STATUS_E_INVAL;
2156 
2157 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
2158 					  wlan_vdev_scan_allowed,
2159 					  &flag, 0, dbg_id);
2160 
2161 	if (flag == 1)
2162 		return QDF_STATUS_E_FAILURE;
2163 
2164 	return QDF_STATUS_SUCCESS;
2165 }
2166 
2167 void
wlan_util_stats_get_rssi(bool db2dbm_enabled,int32_t bcn_snr,int32_t dat_snr,int8_t * rssi)2168 wlan_util_stats_get_rssi(bool db2dbm_enabled, int32_t bcn_snr, int32_t dat_snr,
2169 			 int8_t *rssi)
2170 {
2171 	uint32_t snr;
2172 
2173 	if (db2dbm_enabled) {
2174 		if (TGT_IS_VALID_RSSI(bcn_snr))
2175 			*rssi = bcn_snr;
2176 		else if (TGT_IS_VALID_RSSI(dat_snr))
2177 			*rssi = dat_snr;
2178 		else
2179 			*rssi = TGT_NOISE_FLOOR_DBM;
2180 	} else {
2181 		if (TGT_IS_VALID_SNR(bcn_snr))
2182 			snr = bcn_snr;
2183 		else if (TGT_IS_VALID_SNR(dat_snr))
2184 			snr = dat_snr;
2185 		else
2186 			snr = TGT_INVALID_SNR;
2187 
2188 		/* Get the absolute rssi value from the current rssi value */
2189 		*rssi = snr + TGT_NOISE_FLOOR_DBM;
2190 	}
2191 }
2192 
2193 /**
2194  * wlan_util_get_mode_specific_peer_count - This api gives vdev mode specific
2195  * peer count`
2196  * @pdev: PDEV object
2197  * @object: vdev object
2198  * @arg: argument passed by caller
2199  *
2200  * Return: void
2201  */
2202 static void
wlan_util_get_mode_specific_peer_count(struct wlan_objmgr_pdev * pdev,void * object,void * arg)2203 wlan_util_get_mode_specific_peer_count(struct wlan_objmgr_pdev *pdev,
2204 				       void *object, void *arg)
2205 {
2206 	struct wlan_objmgr_vdev *vdev = object;
2207 	uint16_t temp_count = 0;
2208 	struct wlan_op_mode_peer_count *count = arg;
2209 
2210 	wlan_vdev_obj_lock(vdev);
2211 	if (wlan_vdev_mlme_get_opmode(vdev) == count->opmode) {
2212 		temp_count = wlan_vdev_get_peer_count(vdev);
2213 		/* Decrement the self peer count */
2214 		if (temp_count > 1)
2215 			count->peer_count += (temp_count - 1);
2216 	}
2217 	wlan_vdev_obj_unlock(vdev);
2218 }
2219 
wlan_util_get_peer_count_for_mode(struct wlan_objmgr_pdev * pdev,enum QDF_OPMODE mode)2220 uint16_t wlan_util_get_peer_count_for_mode(struct wlan_objmgr_pdev *pdev,
2221 					   enum QDF_OPMODE mode)
2222 {
2223 	struct wlan_op_mode_peer_count count;
2224 
2225 	count.opmode = mode;
2226 	count.peer_count = 0;
2227 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
2228 				wlan_util_get_mode_specific_peer_count, &count,
2229 				0, WLAN_OBJMGR_ID);
2230 
2231 	return count.peer_count;
2232 }
2233 
2234 #ifdef CONFIG_QCA_MINIDUMP
wlan_minidump_log_enabled(struct wlan_objmgr_psoc * psoc,enum wlan_minidump_host_data type)2235 static bool wlan_minidump_log_enabled(struct wlan_objmgr_psoc *psoc,
2236 				      enum wlan_minidump_host_data type)
2237 {
2238 	bool setval = false;
2239 
2240 	switch (type) {
2241 	case WLAN_MD_CP_EXT_PDEV:
2242 		if (cfg_get(psoc, CFG_OL_MD_CP_EXT_PDEV))
2243 			setval = true;
2244 		break;
2245 	case WLAN_MD_CP_EXT_PSOC:
2246 		if (cfg_get(psoc, CFG_OL_MD_CP_EXT_PSOC))
2247 			setval = true;
2248 		break;
2249 	case WLAN_MD_CP_EXT_VDEV:
2250 		if (cfg_get(psoc, CFG_OL_MD_CP_EXT_VDEV))
2251 			setval = true;
2252 		break;
2253 	case WLAN_MD_CP_EXT_PEER:
2254 		if (cfg_get(psoc, CFG_OL_MD_CP_EXT_PEER))
2255 			setval = true;
2256 		break;
2257 	case WLAN_MD_DP_SOC:
2258 		if (cfg_get(psoc, CFG_OL_MD_DP_SOC))
2259 			setval = true;
2260 		break;
2261 	case WLAN_MD_DP_PDEV:
2262 		if (cfg_get(psoc, CFG_OL_MD_DP_PDEV))
2263 			setval = true;
2264 		break;
2265 	case WLAN_MD_DP_PEER:
2266 		if (cfg_get(psoc, CFG_OL_MD_DP_PEER))
2267 			setval = true;
2268 		break;
2269 	case WLAN_MD_DP_SRNG_REO_DEST:
2270 	case WLAN_MD_DP_SRNG_REO_EXCEPTION:
2271 	case WLAN_MD_DP_SRNG_RX_REL:
2272 	case WLAN_MD_DP_SRNG_REO_REINJECT:
2273 	case WLAN_MD_DP_SRNG_REO_CMD:
2274 	case WLAN_MD_DP_SRNG_REO_STATUS:
2275 		if (cfg_get(psoc, CFG_OL_MD_DP_SRNG_REO))
2276 			setval = true;
2277 		break;
2278 	case WLAN_MD_DP_SRNG_TCL_DATA:
2279 	case WLAN_MD_DP_SRNG_TCL_CMD:
2280 	case WLAN_MD_DP_SRNG_TCL_STATUS:
2281 	case WLAN_MD_DP_SRNG_TX_COMP:
2282 		if (cfg_get(psoc, CFG_OL_MD_DP_SRNG_TCL))
2283 			setval = true;
2284 		break;
2285 	case WLAN_MD_DP_SRNG_WBM_DESC_REL:
2286 	case WLAN_MD_DP_SRNG_WBM_IDLE_LINK:
2287 		if (cfg_get(psoc, CFG_OL_MD_DP_SRNG_WBM))
2288 			setval = true;
2289 		break;
2290 	case WLAN_MD_DP_LINK_DESC_BANK:
2291 		if (cfg_get(psoc, CFG_OL_MD_DP_LINK_DESC_BANK))
2292 			setval = true;
2293 		break;
2294 	case WLAN_MD_DP_SRNG_RXDMA_MON_BUF:
2295 	case WLAN_MD_DP_SRNG_RXDMA_MON_DST:
2296 	case WLAN_MD_DP_SRNG_RXDMA_MON_DESC:
2297 	case WLAN_MD_DP_SRNG_RXDMA_ERR_DST:
2298 	case WLAN_MD_DP_SRNG_RXDMA_MON_STATUS:
2299 		if (cfg_get(psoc, CFG_OL_MD_DP_SRNG_RXDMA))
2300 			setval = true;
2301 		break;
2302 	case WLAN_MD_DP_HAL_SOC:
2303 		if (cfg_get(psoc, CFG_OL_MD_DP_HAL_SOC))
2304 			setval = true;
2305 		break;
2306 	case WLAN_MD_OBJMGR_PSOC:
2307 	case WLAN_MD_OBJMGR_PSOC_TGT_INFO:
2308 		if (cfg_get(psoc, CFG_OL_MD_OBJMGR_PSOC))
2309 			setval = true;
2310 		break;
2311 	case WLAN_MD_OBJMGR_PDEV:
2312 	case WLAN_MD_OBJMGR_PDEV_MLME:
2313 		if (cfg_get(psoc, CFG_OL_MD_OBJMGR_PDEV))
2314 			setval = true;
2315 		break;
2316 	case WLAN_MD_OBJMGR_VDEV_MLME:
2317 	case WLAN_MD_OBJMGR_VDEV_SM:
2318 	case WLAN_MD_OBJMGR_VDEV:
2319 		if (cfg_get(psoc, CFG_OL_MD_OBJMGR_VDEV))
2320 			setval = true;
2321 		break;
2322 	default:
2323 		qdf_debug("Minidump: Type not implemented");
2324 	}
2325 
2326 	return setval;
2327 }
2328 #else /* CONFIG_QCA_MINIDUMP */
wlan_minidump_log_enabled(struct wlan_objmgr_psoc * psoc,enum wlan_minidump_host_data type)2329 static bool wlan_minidump_log_enabled(struct wlan_objmgr_psoc *psoc,
2330 				      enum wlan_minidump_host_data type)
2331 {
2332 	return false;
2333 }
2334 #endif
2335 
wlan_minidump_log(void * start_addr,const size_t size,void * psoc_obj,enum wlan_minidump_host_data type,const char * name)2336 void wlan_minidump_log(void *start_addr, const size_t size,
2337 		       void *psoc_obj,
2338 		       enum wlan_minidump_host_data type,
2339 		       const char *name)
2340 {
2341 	struct wlan_objmgr_psoc *psoc;
2342 
2343 	if (!psoc_obj) {
2344 		qdf_debug("Minidump: Psoc is NULL");
2345 		return;
2346 	}
2347 
2348 	psoc = (struct wlan_objmgr_psoc *)psoc_obj;
2349 
2350 	if (psoc && wlan_minidump_log_enabled(psoc, type))
2351 		qdf_minidump_log(start_addr, size, name);
2352 }
2353 qdf_export_symbol(wlan_minidump_log);
2354 
wlan_minidump_remove(void * start_addr,const size_t size,void * psoc_obj,enum wlan_minidump_host_data type,const char * name)2355 void wlan_minidump_remove(void *start_addr, const size_t size,
2356 			  void *psoc_obj,
2357 			  enum wlan_minidump_host_data type,
2358 			  const char *name)
2359 {
2360 	struct wlan_objmgr_psoc *psoc;
2361 
2362 	if (!psoc_obj) {
2363 		qdf_debug("Minidump: Psoc is NULL");
2364 		return;
2365 	}
2366 
2367 	psoc = (struct wlan_objmgr_psoc *)psoc_obj;
2368 
2369 	if (psoc && wlan_minidump_log_enabled(psoc, type))
2370 		qdf_minidump_remove(start_addr, size, name);
2371 }
2372 qdf_export_symbol(wlan_minidump_remove);
2373 
vdev_cac_in_progress(struct wlan_objmgr_pdev * pdev,void * object,void * arg)2374 static void vdev_cac_in_progress(struct wlan_objmgr_pdev *pdev,
2375 				 void *object, void *arg)
2376 {
2377 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
2378 	bool *cac_is_in_progress = (bool *)arg;
2379 
2380 	if (*cac_is_in_progress)
2381 		return;
2382 
2383 	if (wlan_vdev_is_dfs_cac_wait(vdev) == QDF_STATUS_SUCCESS)
2384 		*cac_is_in_progress = true;
2385 }
2386 
wlan_util_is_vdev_in_cac_wait(struct wlan_objmgr_pdev * pdev,wlan_objmgr_ref_dbgid dbg_id)2387 bool wlan_util_is_vdev_in_cac_wait(struct wlan_objmgr_pdev *pdev,
2388 				   wlan_objmgr_ref_dbgid dbg_id)
2389 {
2390 	bool cac_is_in_progress = false;
2391 
2392 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
2393 					  vdev_cac_in_progress,
2394 					  &cac_is_in_progress, 0,
2395 					  dbg_id);
2396 
2397 	return cac_is_in_progress;
2398 }
2399 
2400 qdf_export_symbol(wlan_util_is_vdev_in_cac_wait);
2401