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