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