1 /* 2 * Copyright (c) 2021, The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2024 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: contains MLO manager util api's 20 */ 21 #include <wlan_cmn.h> 22 #include <wlan_mlo_mgr_sta.h> 23 #include <wlan_cm_public_struct.h> 24 #include <wlan_mlo_mgr_main.h> 25 #include <wlan_cm_api.h> 26 #include "wlan_scan_api.h" 27 #include "qdf_types.h" 28 #include "utils_mlo.h" 29 #include "wlan_mlo_mgr_cmn.h" 30 #include "wlan_utility.h" 31 32 #ifdef WLAN_FEATURE_11BE_MLO 33 34 static uint8_t *util_find_eid(uint8_t eid, uint8_t *frame, qdf_size_t len) 35 { 36 if (!frame) 37 return NULL; 38 39 while (len >= MIN_IE_LEN && len >= frame[TAG_LEN_POS] + MIN_IE_LEN) { 40 if (frame[ID_POS] == eid) 41 return frame; 42 43 len -= frame[TAG_LEN_POS] + MIN_IE_LEN; 44 frame += frame[TAG_LEN_POS] + MIN_IE_LEN; 45 } 46 47 return NULL; 48 } 49 50 static 51 uint8_t *util_find_extn_eid(uint8_t eid, uint8_t extn_eid, 52 uint8_t *frame, qdf_size_t len) 53 { 54 if (!frame) 55 return NULL; 56 57 while (len > MIN_IE_LEN && len >= frame[TAG_LEN_POS] + MIN_IE_LEN) { 58 if ((frame[ID_POS] == eid) && 59 (frame[ELEM_ID_EXTN_POS] == extn_eid)) 60 return frame; 61 62 len -= frame[TAG_LEN_POS] + MIN_IE_LEN; 63 frame += frame[TAG_LEN_POS] + MIN_IE_LEN; 64 } 65 return NULL; 66 } 67 68 static QDF_STATUS 69 util_parse_multi_link_ctrl(uint8_t *mlieseqpayload, 70 qdf_size_t mlieseqpayloadlen, 71 uint8_t **link_info, 72 qdf_size_t *link_info_len) 73 { 74 qdf_size_t parsed_payload_len; 75 uint16_t mlcontrol; 76 uint16_t presence_bm; 77 uint16_t cinfo_len = 0; 78 uint16_t exp_cinfo_len = 0; 79 80 /* This helper returns the location(s) and length(s) of (sub)field(s) 81 * inferable after parsing the Multi Link element Control field. These 82 * location(s) and length(s) is/are in reference to the payload section 83 * of the Multi Link element (after defragmentation, if applicable). 84 * Here, the payload is the point after the element ID extension of the 85 * Multi Link element, and includes the payloads of all subsequent 86 * fragments (if any) but not the headers of those fragments. 87 * 88 * Currently, the helper returns the location and length of the Link 89 * Info field in the Multi Link element sequence. Other (sub)field(s) 90 * can be added later as required. 91 */ 92 93 if (!mlieseqpayload) { 94 mlo_err("ML seq payload pointer is NULL"); 95 return QDF_STATUS_E_NULL_VALUE; 96 } 97 98 if (!mlieseqpayloadlen) { 99 mlo_err("ML seq payload len is 0"); 100 return QDF_STATUS_E_INVAL; 101 } 102 103 if (mlieseqpayloadlen < WLAN_ML_CTRL_SIZE) { 104 mlo_err_rl("ML seq payload len %zu < ML Control size %u", 105 mlieseqpayloadlen, WLAN_ML_CTRL_SIZE); 106 return QDF_STATUS_E_PROTO; 107 } 108 109 parsed_payload_len = 0; 110 111 qdf_mem_copy(&mlcontrol, mlieseqpayload, WLAN_ML_CTRL_SIZE); 112 mlcontrol = qdf_le16_to_cpu(mlcontrol); 113 parsed_payload_len += WLAN_ML_CTRL_SIZE; 114 115 presence_bm = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 116 WLAN_ML_CTRL_PBM_BITS); 117 118 if (mlieseqpayloadlen < 119 (parsed_payload_len + WLAN_ML_BV_CINFO_LENGTH_SIZE)) { 120 mlo_err_rl("ML seq payload len %zu insufficient for common info length size %u after parsed payload len %zu.", 121 mlieseqpayloadlen, 122 WLAN_ML_BV_CINFO_LENGTH_SIZE, 123 parsed_payload_len); 124 return QDF_STATUS_E_PROTO; 125 } 126 127 cinfo_len = *(mlieseqpayload + parsed_payload_len); 128 129 if (cinfo_len > 130 (mlieseqpayloadlen - parsed_payload_len)) { 131 mlo_err_rl("ML seq common info len %u larger than ML seq payload len %zu after parsed payload len %zu.", 132 cinfo_len, 133 mlieseqpayloadlen, 134 parsed_payload_len); 135 return QDF_STATUS_E_PROTO; 136 } 137 138 parsed_payload_len += WLAN_ML_BV_CINFO_LENGTH_SIZE; 139 140 if (mlieseqpayloadlen < 141 (parsed_payload_len + QDF_MAC_ADDR_SIZE)) { 142 mlo_err_rl("ML seq payload len %zu insufficient for MAC address size %u after parsed payload len %zu.", 143 mlieseqpayloadlen, 144 QDF_MAC_ADDR_SIZE, 145 parsed_payload_len); 146 return QDF_STATUS_E_PROTO; 147 } 148 149 parsed_payload_len += QDF_MAC_ADDR_SIZE; 150 151 /* Check if Link ID info is present */ 152 if (presence_bm & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) { 153 if (mlieseqpayloadlen < 154 (parsed_payload_len + 155 WLAN_ML_BV_CINFO_LINKIDINFO_SIZE)) { 156 mlo_err_rl("ML seq payload len %zu insufficient for Link ID info size %u after parsed payload len %zu.", 157 mlieseqpayloadlen, 158 WLAN_ML_BV_CINFO_LINKIDINFO_SIZE, 159 parsed_payload_len); 160 return QDF_STATUS_E_PROTO; 161 } 162 163 parsed_payload_len += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; 164 } 165 166 /* Check if BSS parameter change count is present */ 167 if (presence_bm & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) { 168 if (mlieseqpayloadlen < 169 (parsed_payload_len + 170 WLAN_ML_BSSPARAMCHNGCNT_SIZE)) { 171 mlo_err_rl("ML seq payload len %zu insufficient for BSS parameter change count size %u after parsed payload len %zu.", 172 mlieseqpayloadlen, 173 WLAN_ML_BSSPARAMCHNGCNT_SIZE, 174 parsed_payload_len); 175 return QDF_STATUS_E_PROTO; 176 } 177 178 parsed_payload_len += WLAN_ML_BSSPARAMCHNGCNT_SIZE; 179 } 180 181 /* Check if Medium Sync Delay Info is present */ 182 if (presence_bm & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P) { 183 if (mlieseqpayloadlen < 184 (parsed_payload_len + 185 WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE)) { 186 mlo_err_rl("ML seq payload len %zu insufficient for Medium Sync Delay Info size %u after parsed payload len %zu.", 187 mlieseqpayloadlen, 188 WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE, 189 parsed_payload_len); 190 return QDF_STATUS_E_PROTO; 191 } 192 193 parsed_payload_len += WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE; 194 } 195 196 /* Check if EML cap is present */ 197 if (presence_bm & WLAN_ML_BV_CTRL_PBM_EMLCAP_P) { 198 if (mlieseqpayloadlen < 199 (parsed_payload_len + 200 WLAN_ML_BV_CINFO_EMLCAP_SIZE)) { 201 mlo_err_rl("ML seq payload len %zu insufficient for EML cap size %u after parsed payload len %zu.", 202 mlieseqpayloadlen, 203 WLAN_ML_BV_CINFO_EMLCAP_SIZE, 204 parsed_payload_len); 205 return QDF_STATUS_E_PROTO; 206 } 207 208 parsed_payload_len += WLAN_ML_BV_CINFO_EMLCAP_SIZE; 209 } 210 211 /* Check if MLD cap is present */ 212 if (presence_bm & WLAN_ML_BV_CTRL_PBM_MLDCAPANDOP_P) { 213 if (mlieseqpayloadlen < 214 (parsed_payload_len + 215 WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE)) { 216 mlo_err_rl("ML seq payload len %zu insufficient for MLD cap size %u after parsed payload len %zu.", 217 mlieseqpayloadlen, 218 WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE, 219 parsed_payload_len); 220 return QDF_STATUS_E_PROTO; 221 } 222 223 parsed_payload_len += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; 224 } 225 226 /* Check if MLD ID is present */ 227 if (presence_bm & WLAN_ML_BV_CTRL_PBM_MLDID_P) { 228 if (mlieseqpayloadlen < 229 (parsed_payload_len + 230 WLAN_ML_BV_CINFO_MLDID_SIZE)) { 231 mlo_err_rl("ML seq payload len %zu insufficient for MLD ID size %u after parsed payload len %zu.", 232 mlieseqpayloadlen, 233 WLAN_ML_BV_CINFO_MLDID_SIZE, 234 parsed_payload_len); 235 return QDF_STATUS_E_PROTO; 236 } 237 238 parsed_payload_len += WLAN_ML_BV_CINFO_MLDID_SIZE; 239 } 240 241 /* Check if Ext MLD CAP OP is present */ 242 if (presence_bm & WLAN_ML_BV_CTRL_PBM_EXT_MLDCAPANDOP_P) { 243 if (mlieseqpayloadlen < 244 (parsed_payload_len + 245 WLAN_ML_BV_CINFO_EXT_MLDCAPANDOP_SIZE)) { 246 mlo_err_rl("ML seq payload len %zu insufficient for Ext MLD CAP OP size %u after parsed payload len %zu.", 247 mlieseqpayloadlen, 248 WLAN_ML_BV_CINFO_EXT_MLDCAPANDOP_SIZE, 249 parsed_payload_len); 250 return QDF_STATUS_E_PROTO; 251 } 252 253 parsed_payload_len += WLAN_ML_BV_CINFO_EXT_MLDCAPANDOP_SIZE; 254 } 255 256 exp_cinfo_len = parsed_payload_len - WLAN_ML_CTRL_SIZE; 257 if (cinfo_len >= exp_cinfo_len) { 258 /* If common info length received is greater, 259 * skip through the additional bytes 260 */ 261 parsed_payload_len += (cinfo_len - exp_cinfo_len); 262 mlo_debug("ML seq common info len %u, parsed payload length %zu, expected common info len %u", 263 cinfo_len, parsed_payload_len, exp_cinfo_len); 264 } else { 265 /* If cinfo_len < exp_cinfo_len return error */ 266 mlo_err_rl("ML seq common info len %u doesn't match with expected common info len %u", 267 cinfo_len, exp_cinfo_len); 268 return QDF_STATUS_E_PROTO; 269 } 270 271 if (link_info_len) { 272 *link_info_len = mlieseqpayloadlen - parsed_payload_len; 273 mlo_debug("link_info_len:%zu, parsed_payload_len:%zu", 274 *link_info_len, parsed_payload_len); 275 } 276 277 if (mlieseqpayloadlen == parsed_payload_len) { 278 if (link_info) 279 *link_info = NULL; 280 return QDF_STATUS_SUCCESS; 281 } 282 283 if (link_info) 284 *link_info = mlieseqpayload + parsed_payload_len; 285 286 return QDF_STATUS_SUCCESS; 287 } 288 289 static QDF_STATUS 290 util_parse_prv_multi_link_ctrl(uint8_t *mlieseqpayload, 291 qdf_size_t mlieseqpayloadlen, 292 uint8_t **link_info, 293 qdf_size_t *link_info_len) 294 { 295 qdf_size_t parsed_payload_len; 296 uint16_t mlcontrol; 297 uint16_t presence_bm; 298 uint16_t cinfo_len = 0; 299 uint16_t exp_cinfo_len = 0; 300 301 /* This helper returns the location(s) and length(s) of (sub)field(s) 302 * inferable after parsing the Multi Link element Control field. These 303 * location(s) and length(s) is/are in reference to the payload section 304 * of the Multi Link element (after defragmentation, if applicable). 305 * Here, the payload is the point after the element ID extension of the 306 * Multi Link element, and includes the payloads of all subsequent 307 * fragments (if any) but not the headers of those fragments. 308 * 309 * Currently, the helper returns the location and length of the Link 310 * Info field in the Multi Link element sequence. Other (sub)field(s) 311 * can be added later as required. 312 */ 313 314 if (!mlieseqpayload) { 315 mlo_err("ML seq payload pointer is NULL"); 316 return QDF_STATUS_E_NULL_VALUE; 317 } 318 319 if (!mlieseqpayloadlen) { 320 mlo_err("ML seq payload len is 0"); 321 return QDF_STATUS_E_INVAL; 322 } 323 324 if (mlieseqpayloadlen < WLAN_ML_CTRL_SIZE) { 325 mlo_err_rl("ML seq payload len %zu < ML Control size %u", 326 mlieseqpayloadlen, WLAN_ML_CTRL_SIZE); 327 return QDF_STATUS_E_PROTO; 328 } 329 330 parsed_payload_len = 0; 331 332 qdf_mem_copy(&mlcontrol, mlieseqpayload, WLAN_ML_CTRL_SIZE); 333 mlcontrol = qdf_le16_to_cpu(mlcontrol); 334 parsed_payload_len += WLAN_ML_CTRL_SIZE; 335 336 presence_bm = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 337 WLAN_ML_CTRL_PBM_BITS); 338 339 if (mlieseqpayloadlen < 340 (parsed_payload_len + WLAN_ML_PRV_CINFO_LENGTH_SIZE)) { 341 mlo_err_rl("ML seq payload len %zu insufficient for common info length size %u after parsed payload len %zu.", 342 mlieseqpayloadlen, 343 WLAN_ML_PRV_CINFO_LENGTH_SIZE, 344 parsed_payload_len); 345 return QDF_STATUS_E_PROTO; 346 } 347 348 cinfo_len = *(mlieseqpayload + parsed_payload_len); 349 parsed_payload_len += WLAN_ML_PRV_CINFO_LENGTH_SIZE; 350 351 /* Check if MLD ID is present */ 352 if (presence_bm & WLAN_ML_PRV_CTRL_PBM_MLDID_P) { 353 if (mlieseqpayloadlen < 354 (parsed_payload_len + 355 WLAN_ML_PRV_CINFO_MLDID_SIZE)) { 356 mlo_err_rl("ML seq payload len %zu insufficient for MLD ID size %u after parsed payload len %zu.", 357 mlieseqpayloadlen, 358 WLAN_ML_PRV_CINFO_MLDID_SIZE, 359 parsed_payload_len); 360 return QDF_STATUS_E_PROTO; 361 } 362 363 parsed_payload_len += WLAN_ML_PRV_CINFO_MLDID_SIZE; 364 } 365 366 exp_cinfo_len = parsed_payload_len - WLAN_ML_CTRL_SIZE; 367 if (cinfo_len != exp_cinfo_len) { 368 mlo_err_rl("ML seq common info len %u doesn't match with expected common info len %u", 369 cinfo_len, exp_cinfo_len); 370 return QDF_STATUS_E_PROTO; 371 } 372 373 if (link_info_len) { 374 *link_info_len = mlieseqpayloadlen - parsed_payload_len; 375 mlo_debug("link_info_len:%zu, parsed_payload_len:%zu", 376 *link_info_len, parsed_payload_len); 377 } 378 379 if (mlieseqpayloadlen == parsed_payload_len) { 380 mlo_debug("No Link Info field present"); 381 if (link_info) 382 *link_info = NULL; 383 return QDF_STATUS_SUCCESS; 384 } 385 386 if (link_info) 387 *link_info = mlieseqpayload + parsed_payload_len; 388 389 return QDF_STATUS_SUCCESS; 390 } 391 392 static QDF_STATUS 393 util_parse_bvmlie_perstaprofile_stactrl(uint8_t *subelempayload, 394 qdf_size_t subelempayloadlen, 395 uint8_t *linkid, 396 uint16_t *beaconinterval, 397 bool *is_beaconinterval_valid, 398 uint64_t *tsfoffset, 399 bool *is_tsfoffset_valid, 400 bool *is_complete_profile, 401 bool *is_macaddr_valid, 402 struct qdf_mac_addr *macaddr, 403 bool is_staprof_reqd, 404 uint8_t **staprof, 405 qdf_size_t *staprof_len, 406 struct mlo_nstr_info *nstr_info, 407 bool *is_nstrlp_present) 408 { 409 qdf_size_t parsed_payload_len = 0; 410 uint16_t stacontrol; 411 uint8_t completeprofile; 412 uint8_t nstrlppresent; 413 enum wlan_ml_bv_linfo_perstaprof_stactrl_nstrbmsz nstrbmsz; 414 qdf_size_t nstrlpoffset = 0; 415 uint8_t link_id; 416 417 /* This helper returns the location(s) and where required, the length(s) 418 * of (sub)field(s) inferable after parsing the STA Control field in the 419 * per-STA profile subelement. These location(s) and length(s) is/are in 420 * reference to the payload section of the per-STA profile subelement 421 * (after defragmentation, if applicable). Here, the payload is the 422 * point after the subelement length in the subelement, and includes the 423 * payloads of all subsequent fragments (if any) but not the headers of 424 * those fragments. 425 * 426 * Currently, the helper returns the link ID, MAC address, and STA 427 * profile. More (sub)fields can be added when required. 428 */ 429 430 if (!subelempayload) { 431 mlo_err("Pointer to subelement payload is NULL"); 432 return QDF_STATUS_E_NULL_VALUE; 433 } 434 435 if (!subelempayloadlen) { 436 mlo_err("Length of subelement payload is zero"); 437 return QDF_STATUS_E_INVAL; 438 } 439 440 if (subelempayloadlen < WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE) { 441 mlo_err_rl("Subelement payload length %zu octets is smaller than STA control field of per-STA profile subelement %u octets", 442 subelempayloadlen, 443 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE); 444 return QDF_STATUS_E_PROTO; 445 } 446 447 parsed_payload_len = 0; 448 449 qdf_mem_copy(&stacontrol, 450 subelempayload, 451 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE); 452 stacontrol = le16toh(stacontrol); 453 parsed_payload_len += WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE; 454 455 link_id = QDF_GET_BITS(stacontrol, 456 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_LINKID_IDX, 457 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_LINKID_BITS); 458 if (linkid) 459 *linkid = link_id; 460 461 /* Check if this a complete profile */ 462 completeprofile = QDF_GET_BITS(stacontrol, 463 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_IDX, 464 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_BITS); 465 466 if (completeprofile && is_complete_profile) 467 *is_complete_profile = true; 468 469 /* Check STA Info Length */ 470 if (subelempayloadlen < 471 parsed_payload_len + WLAN_ML_BV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE) { 472 mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain STA Info Length of size %u octets after parsed payload length of %zu octets.", 473 subelempayloadlen, 474 WLAN_ML_BV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE, 475 parsed_payload_len); 476 return QDF_STATUS_E_PROTO; 477 } 478 479 parsed_payload_len += WLAN_ML_BV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE; 480 481 if (is_macaddr_valid) 482 *is_macaddr_valid = false; 483 484 /* Check STA MAC address present bit */ 485 if (QDF_GET_BITS(stacontrol, 486 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_MACADDRP_IDX, 487 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_MACADDRP_BITS)) { 488 if (subelempayloadlen < 489 (parsed_payload_len + QDF_MAC_ADDR_SIZE)) { 490 mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain MAC address of size %u octets after parsed payload length of %zu octets.", 491 subelempayloadlen, 492 QDF_MAC_ADDR_SIZE, 493 parsed_payload_len); 494 return QDF_STATUS_E_PROTO; 495 } 496 497 if (macaddr) { 498 qdf_mem_copy(macaddr->bytes, 499 subelempayload + parsed_payload_len, 500 QDF_MAC_ADDR_SIZE); 501 502 mlo_nofl_debug("Copied MAC address: " QDF_MAC_ADDR_FMT, 503 QDF_MAC_ADDR_REF(macaddr->bytes)); 504 505 if (is_macaddr_valid) 506 *is_macaddr_valid = true; 507 } 508 509 parsed_payload_len += QDF_MAC_ADDR_SIZE; 510 } 511 512 /* Check Beacon Interval present bit */ 513 if (QDF_GET_BITS(stacontrol, 514 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_BCNINTP_IDX, 515 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_BCNINTP_BITS)) { 516 if (subelempayloadlen < 517 (parsed_payload_len + 518 WLAN_BEACONINTERVAL_LEN)) { 519 mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain Beacon Interval of size %u octets after parsed payload length of %zu octets.", 520 subelempayloadlen, 521 WLAN_BEACONINTERVAL_LEN, 522 parsed_payload_len); 523 return QDF_STATUS_E_PROTO; 524 } 525 526 if (beaconinterval) { 527 qdf_mem_copy(beaconinterval, 528 subelempayload + parsed_payload_len, 529 WLAN_BEACONINTERVAL_LEN); 530 *beaconinterval = qdf_le16_to_cpu(*beaconinterval); 531 532 if (is_beaconinterval_valid) 533 *is_beaconinterval_valid = true; 534 } 535 parsed_payload_len += WLAN_BEACONINTERVAL_LEN; 536 } 537 538 /* Check TSF Offset present bit */ 539 if (QDF_GET_BITS(stacontrol, 540 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_TSFOFFSETP_IDX, 541 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_TSFOFFSETP_BITS)) { 542 if (!completeprofile) { 543 mlo_err_rl("TSF offset is expected only for complete profiles"); 544 return QDF_STATUS_E_PROTO; 545 } 546 547 if (subelempayloadlen < 548 (parsed_payload_len + 549 WLAN_ML_TSF_OFFSET_SIZE)) { 550 mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain TSF Offset of size %u octets after parsed payload length of %zu octets.", 551 subelempayloadlen, 552 WLAN_ML_TSF_OFFSET_SIZE, 553 parsed_payload_len); 554 return QDF_STATUS_E_PROTO; 555 } 556 557 if (tsfoffset) { 558 qdf_mem_copy(tsfoffset, 559 subelempayload + parsed_payload_len, 560 WLAN_TIMESTAMP_LEN); 561 *tsfoffset = qdf_le64_to_cpu(*tsfoffset); 562 563 if (is_tsfoffset_valid) 564 *is_tsfoffset_valid = true; 565 } 566 567 parsed_payload_len += WLAN_ML_TSF_OFFSET_SIZE; 568 } 569 570 /* Check DTIM Info present bit */ 571 if (QDF_GET_BITS(stacontrol, 572 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_DTIMINFOP_IDX, 573 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_DTIMINFOP_BITS)) { 574 if (subelempayloadlen < 575 (parsed_payload_len + 576 sizeof(struct wlan_ml_bv_linfo_perstaprof_stainfo_dtiminfo))) { 577 mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain DTIM Info of size %zu octets after parsed payload length of %zu octets.", 578 subelempayloadlen, 579 sizeof(struct wlan_ml_bv_linfo_perstaprof_stainfo_dtiminfo), 580 parsed_payload_len); 581 return QDF_STATUS_E_PROTO; 582 } 583 584 parsed_payload_len += 585 sizeof(struct wlan_ml_bv_linfo_perstaprof_stainfo_dtiminfo); 586 } 587 588 /* Check NTSR Link pair present bit */ 589 nstrlppresent = 590 QDF_GET_BITS(stacontrol, 591 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRLINKPRP_IDX, 592 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRLINKPRP_BITS); 593 594 if (completeprofile && nstrlppresent) { 595 nstrlpoffset = parsed_payload_len; 596 /* Check NTSR Bitmap Size bit */ 597 nstrbmsz = 598 QDF_GET_BITS(stacontrol, 599 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_IDX, 600 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_BITS); 601 602 if (nstrbmsz == WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_1_OCTET) { 603 if (subelempayloadlen < 604 (parsed_payload_len + 1)) { 605 mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain NTSR Bitmap of size 1 octet after parsed payload length of %zu octets.", 606 subelempayloadlen, 607 parsed_payload_len); 608 return QDF_STATUS_E_PROTO; 609 } 610 611 parsed_payload_len += 1; 612 } else if (nstrbmsz == WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_2_OCTETS) { 613 if (subelempayloadlen < 614 (parsed_payload_len + 2)) { 615 mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain NTSR Bitmap of size 2 octets after parsed payload length of %zu octets.", 616 subelempayloadlen, 617 parsed_payload_len); 618 return QDF_STATUS_E_PROTO; 619 } 620 621 parsed_payload_len += 2; 622 } else { 623 /* Though an invalid value cannot occur if only 1 bit is 624 * used, we check for it in a generic manner in case the 625 * number of bits is increased in the future. 626 */ 627 mlo_err_rl("Invalid NSTR Bitmap size %u", nstrbmsz); 628 return QDF_STATUS_E_PROTO; 629 } 630 if (nstr_info) { 631 nstr_info->nstr_lp_present = nstrlppresent; 632 nstr_info->nstr_bmp_size = nstrbmsz; 633 *is_nstrlp_present = true; 634 nstr_info->link_id = link_id; 635 636 if (nstrbmsz == WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_1_OCTET) { 637 nstr_info->nstr_lp_bitmap = 638 *(uint8_t *)(subelempayload + nstrlpoffset); 639 } else if (nstrbmsz == WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_2_OCTETS) { 640 nstr_info->nstr_lp_bitmap = 641 qdf_le16_to_cpu(*(uint16_t *)(subelempayload + nstrlpoffset)); 642 } 643 } 644 } 645 646 /* Check BSS Parameters Change Count Present bit */ 647 if (QDF_GET_BITS(stacontrol, 648 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_BSSPARAMCHNGCNTP_IDX, 649 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_BSSPARAMCHNGCNTP_BITS)) { 650 if (subelempayloadlen < 651 (parsed_payload_len + 652 WLAN_ML_BSSPARAMCHNGCNT_SIZE)) { 653 mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain BSS Parameters Change Count of size %u octets after parsed payload length of %zu octets.", 654 subelempayloadlen, 655 WLAN_ML_BSSPARAMCHNGCNT_SIZE, 656 parsed_payload_len); 657 return QDF_STATUS_E_PROTO; 658 } 659 660 parsed_payload_len += WLAN_ML_BSSPARAMCHNGCNT_SIZE; 661 } 662 663 /* Note: Some implementation versions of hostapd/wpa_supplicant may 664 * provide a per-STA profile without STA profile. Let the caller 665 * indicate whether a STA profile is required to be found. This may be 666 * revisited as upstreaming progresses. 667 */ 668 if (!is_staprof_reqd) 669 return QDF_STATUS_SUCCESS; 670 671 if (subelempayloadlen == parsed_payload_len) { 672 mlo_err_rl("Subelement payload length %zu == parsed payload length %zu. Unable to get STA profile.", 673 subelempayloadlen, 674 parsed_payload_len); 675 return QDF_STATUS_E_PROTO; 676 } 677 678 if (staprof_len) 679 *staprof_len = subelempayloadlen - parsed_payload_len; 680 681 if (staprof) 682 *staprof = subelempayload + parsed_payload_len; 683 684 return QDF_STATUS_SUCCESS; 685 } 686 687 static QDF_STATUS 688 util_parse_prvmlie_perstaprofile_stactrl(uint8_t *subelempayload, 689 qdf_size_t subelempayloadlen, 690 uint8_t *linkid, 691 bool is_staprof_reqd, 692 uint8_t **staprof, 693 qdf_size_t *staprof_len) 694 { 695 qdf_size_t parsed_payload_len = 0; 696 uint16_t stacontrol; 697 uint8_t completeprofile; 698 699 /* This helper returns the location(s) and where required, the length(s) 700 * of (sub)field(s) inferable after parsing the STA Control field in the 701 * per-STA profile subelement. These location(s) and length(s) is/are in 702 * reference to the payload section of the per-STA profile subelement 703 * (after defragmentation, if applicable). Here, the payload is the 704 * point after the subelement length in the subelement, and includes the 705 * payloads of all subsequent fragments (if any) but not the headers of 706 * those fragments. 707 * 708 * Currently, the helper returns the link ID, MAC address, and STA 709 * profile. More (sub)fields can be added when required. 710 */ 711 712 if (!subelempayload) { 713 mlo_err("Pointer to subelement payload is NULL"); 714 return QDF_STATUS_E_NULL_VALUE; 715 } 716 717 if (!subelempayloadlen) { 718 mlo_err("Length of subelement payload is zero"); 719 return QDF_STATUS_E_INVAL; 720 } 721 722 if (subelempayloadlen < WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_SIZE) { 723 mlo_err_rl("Subelement payload length %zu octets is smaller than STA control field of per-STA profile subelement %u octets", 724 subelempayloadlen, 725 WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_SIZE); 726 return QDF_STATUS_E_PROTO; 727 } 728 729 parsed_payload_len = 0; 730 731 qdf_mem_copy(&stacontrol, 732 subelempayload, 733 WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_SIZE); 734 stacontrol = qdf_le16_to_cpu(stacontrol); 735 parsed_payload_len += WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_SIZE; 736 737 if (linkid) { 738 *linkid = QDF_GET_BITS(stacontrol, 739 WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_LINKID_IDX, 740 WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_LINKID_BITS); 741 } 742 743 /* Check if this a complete profile */ 744 completeprofile = QDF_GET_BITS(stacontrol, 745 WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_IDX, 746 WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_BITS); 747 748 /* Note: Some implementation versions of hostapd/wpa_supplicant may 749 * provide a per-STA profile without STA profile. Let the caller 750 * indicate whether a STA profile is required to be found. This may be 751 * revisited as upstreaming progresses. 752 */ 753 if (!is_staprof_reqd) 754 return QDF_STATUS_SUCCESS; 755 756 if (subelempayloadlen == parsed_payload_len) { 757 mlo_err_rl("Subelement payload length %zu == parsed payload length %zu. Unable to get STA profile.", 758 subelempayloadlen, 759 parsed_payload_len); 760 return QDF_STATUS_E_PROTO; 761 } 762 763 if (staprof_len) 764 *staprof_len = subelempayloadlen - parsed_payload_len; 765 766 if (staprof) 767 *staprof = subelempayload + parsed_payload_len; 768 769 return QDF_STATUS_SUCCESS; 770 } 771 772 static 773 uint8_t *util_get_successorfrag(uint8_t *currie, uint8_t *frame, qdf_size_t len) 774 { 775 uint8_t *nextie; 776 777 if (!currie || !frame || !len) 778 return NULL; 779 780 if ((currie + MIN_IE_LEN) > (frame + len)) 781 return NULL; 782 783 /* Check whether there is sufficient space in the frame for the current 784 * IE, plus at least another MIN_IE_LEN bytes for the IE header of a 785 * fragment (if present) that would come just after the current IE. 786 */ 787 if ((currie + MIN_IE_LEN + currie[TAG_LEN_POS] + MIN_IE_LEN) > 788 (frame + len)) 789 return NULL; 790 791 nextie = currie + currie[TAG_LEN_POS] + MIN_IE_LEN; 792 793 /* Check whether there is sufficient space in the frame for the next IE 794 */ 795 if ((nextie + MIN_IE_LEN + nextie[TAG_LEN_POS]) > (frame + len)) 796 return NULL; 797 798 if (nextie[ID_POS] != WLAN_ELEMID_FRAGMENT) 799 return NULL; 800 801 return nextie; 802 } 803 804 static 805 QDF_STATUS util_parse_partner_info_from_linkinfo(uint8_t *linkinfo, 806 qdf_size_t linkinfo_len, 807 struct mlo_partner_info *partner_info) 808 { 809 uint8_t linkid; 810 struct qdf_mac_addr macaddr; 811 struct mlo_nstr_info nstr_info = {0}; 812 bool is_macaddr_valid; 813 uint8_t *linkinfo_currpos; 814 qdf_size_t linkinfo_remlen; 815 bool is_subelemfragseq; 816 uint8_t subelemid; 817 qdf_size_t subelemseqtotallen; 818 qdf_size_t subelemseqpayloadlen; 819 qdf_size_t defragpayload_len; 820 QDF_STATUS ret; 821 bool is_nstrlp_present = false; 822 823 /* This helper function parses partner info from the per-STA profiles 824 * present (if any) in the Link Info field in the payload of a Multi 825 * Link element (after defragmentation if required). The caller should 826 * pass a copy of the payload so that inline defragmentation of 827 * subelements can be carried out if required. The subelement 828 * defragmentation (if applicable) in this Control Path helper is 829 * required for maintainability, accuracy and eliminating current and 830 * future per-field-access multi-level fragment boundary checks and 831 * adjustments, given the complex format of Multi Link elements. It is 832 * also most likely to be required mainly at the client side. 833 */ 834 835 if (!linkinfo) { 836 mlo_err("linkinfo is NULL"); 837 return QDF_STATUS_E_NULL_VALUE; 838 } 839 840 if (!linkinfo_len) { 841 mlo_err("linkinfo_len is zero"); 842 return QDF_STATUS_E_NULL_VALUE; 843 } 844 845 if (!partner_info) { 846 mlo_err("ML partner info is NULL"); 847 return QDF_STATUS_E_NULL_VALUE; 848 } 849 850 partner_info->num_partner_links = 0; 851 linkinfo_currpos = linkinfo; 852 linkinfo_remlen = linkinfo_len; 853 854 while (linkinfo_remlen) { 855 if (linkinfo_remlen < sizeof(struct subelem_header)) { 856 mlo_err_rl("Remaining length in link info %zu octets is smaller than subelement header length %zu octets", 857 linkinfo_remlen, 858 sizeof(struct subelem_header)); 859 return QDF_STATUS_E_PROTO; 860 } 861 862 subelemid = linkinfo_currpos[ID_POS]; 863 is_subelemfragseq = false; 864 subelemseqtotallen = 0; 865 subelemseqpayloadlen = 0; 866 867 ret = wlan_get_subelem_fragseq_info(WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 868 linkinfo_currpos, 869 linkinfo_remlen, 870 &is_subelemfragseq, 871 &subelemseqtotallen, 872 &subelemseqpayloadlen); 873 if (QDF_IS_STATUS_ERROR(ret)) 874 return ret; 875 876 if (is_subelemfragseq) { 877 if (!subelemseqpayloadlen) { 878 mlo_err_rl("Subelement fragment sequence payload is reported as 0, investigate"); 879 return QDF_STATUS_E_FAILURE; 880 } 881 882 mlo_debug("Subelement fragment sequence found with payload len %zu", 883 subelemseqpayloadlen); 884 885 ret = wlan_defrag_subelem_fragseq(true, 886 WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 887 linkinfo_currpos, 888 linkinfo_remlen, 889 NULL, 890 0, 891 &defragpayload_len); 892 if (QDF_IS_STATUS_ERROR(ret)) 893 return ret; 894 895 if (defragpayload_len != subelemseqpayloadlen) { 896 mlo_err_rl("Length of defragmented payload %zu octets is not equal to length of subelement fragment sequence payload %zu octets", 897 defragpayload_len, 898 subelemseqpayloadlen); 899 return QDF_STATUS_E_FAILURE; 900 } 901 902 /* Adjust linkinfo_remlen to reflect removal of all 903 * subelement headers except the header of the lead 904 * subelement. 905 */ 906 linkinfo_remlen -= (subelemseqtotallen - 907 subelemseqpayloadlen - 908 sizeof(struct subelem_header)); 909 } else { 910 if (linkinfo_remlen < 911 (sizeof(struct subelem_header) + 912 linkinfo_currpos[TAG_LEN_POS])) { 913 mlo_err_rl("Remaining length in link info %zu octets is smaller than total size of current subelement %zu octets", 914 linkinfo_remlen, 915 sizeof(struct subelem_header) + 916 linkinfo_currpos[TAG_LEN_POS]); 917 return QDF_STATUS_E_PROTO; 918 } 919 920 subelemseqpayloadlen = linkinfo_currpos[TAG_LEN_POS]; 921 } 922 923 if (subelemid == WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE) { 924 is_macaddr_valid = false; 925 926 ret = util_parse_bvmlie_perstaprofile_stactrl(linkinfo_currpos + 927 sizeof(struct subelem_header), 928 subelemseqpayloadlen, 929 &linkid, 930 NULL, 931 NULL, 932 NULL, 933 NULL, 934 NULL, 935 &is_macaddr_valid, 936 &macaddr, 937 false, 938 NULL, 939 NULL, 940 &nstr_info, 941 &is_nstrlp_present); 942 if (QDF_IS_STATUS_ERROR(ret)) { 943 return ret; 944 } 945 946 if (is_nstrlp_present) { 947 if (partner_info->num_nstr_info_links >= 948 QDF_ARRAY_SIZE(partner_info->nstr_info)) { 949 mlo_err_rl("Insufficient size %zu of array for nstr link info", 950 QDF_ARRAY_SIZE(partner_info->nstr_info)); 951 return QDF_STATUS_E_NOMEM; 952 } 953 qdf_mem_copy(&partner_info->nstr_info[partner_info->num_nstr_info_links], 954 &nstr_info, sizeof(nstr_info)); 955 partner_info->num_nstr_info_links++; 956 is_nstrlp_present = false; 957 } 958 959 if (is_macaddr_valid) { 960 if (partner_info->num_partner_links >= 961 QDF_ARRAY_SIZE(partner_info->partner_link_info)) { 962 mlo_err_rl("Insufficient size %zu of array for partner link info", 963 QDF_ARRAY_SIZE(partner_info->partner_link_info)); 964 return QDF_STATUS_E_NOMEM; 965 } 966 967 partner_info->partner_link_info[partner_info->num_partner_links].link_id = 968 linkid; 969 qdf_mem_copy(&partner_info->partner_link_info[partner_info->num_partner_links].link_addr, 970 &macaddr, 971 sizeof(partner_info->partner_link_info[partner_info->num_partner_links].link_addr)); 972 973 partner_info->num_partner_links++; 974 } else { 975 mlo_warn_rl("MAC address not found in STA Info field of per-STA profile with link ID %u", 976 linkid); 977 } 978 } 979 980 linkinfo_remlen -= (sizeof(struct subelem_header) + 981 subelemseqpayloadlen); 982 linkinfo_currpos += (sizeof(struct subelem_header) + 983 subelemseqpayloadlen); 984 } 985 986 mlo_debug("Number of ML partner links found=%u", 987 partner_info->num_partner_links); 988 989 return QDF_STATUS_SUCCESS; 990 } 991 992 static QDF_STATUS 993 util_parse_probereq_info_from_linkinfo(uint8_t *linkinfo, 994 qdf_size_t linkinfo_len, 995 struct mlo_probereq_info *probereq_info) 996 { 997 uint8_t linkid; 998 uint8_t *linkinfo_currpos; 999 qdf_size_t linkinfo_remlen; 1000 bool is_subelemfragseq; 1001 uint8_t subelemid; 1002 qdf_size_t subelemseqtotallen; 1003 qdf_size_t subelemseqpayloadlen; 1004 qdf_size_t defragpayload_len; 1005 QDF_STATUS ret; 1006 1007 /* This helper function parses probe request info from the per-STA prof 1008 * present (if any) in the Link Info field in the payload of a Multi 1009 * Link element (after defragmentation if required). The caller should 1010 * pass a copy of the payload so that inline defragmentation of 1011 * subelements can be carried out if required. The subelement 1012 * defragmentation (if applicable) in this Control Path helper is 1013 * required for maintainability, accuracy and eliminating current and 1014 * future per-field-access multi-level fragment boundary checks and 1015 * adjustments, given the complex format of Multi Link elements. It is 1016 * also most likely to be required mainly at the client side. 1017 */ 1018 1019 if (!linkinfo) { 1020 mlo_err("linkinfo is NULL"); 1021 return QDF_STATUS_E_NULL_VALUE; 1022 } 1023 1024 if (!linkinfo_len) { 1025 mlo_err("linkinfo_len is zero"); 1026 return QDF_STATUS_E_NULL_VALUE; 1027 } 1028 1029 if (!probereq_info) { 1030 mlo_err("ML probe req info is NULL"); 1031 return QDF_STATUS_E_NULL_VALUE; 1032 } 1033 1034 probereq_info->num_links = 0; 1035 linkinfo_currpos = linkinfo; 1036 linkinfo_remlen = linkinfo_len; 1037 1038 while (linkinfo_remlen) { 1039 if (linkinfo_remlen < sizeof(struct subelem_header)) { 1040 mlo_err_rl("Remaining length in link info %zu octets is smaller than subelement header length %zu octets", 1041 linkinfo_remlen, 1042 sizeof(struct subelem_header)); 1043 return QDF_STATUS_E_PROTO; 1044 } 1045 1046 subelemid = linkinfo_currpos[ID_POS]; 1047 is_subelemfragseq = false; 1048 subelemseqtotallen = 0; 1049 subelemseqpayloadlen = 0; 1050 1051 ret = wlan_get_subelem_fragseq_info(WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 1052 linkinfo_currpos, 1053 linkinfo_remlen, 1054 &is_subelemfragseq, 1055 &subelemseqtotallen, 1056 &subelemseqpayloadlen); 1057 if (QDF_IS_STATUS_ERROR(ret)) 1058 return ret; 1059 1060 if (is_subelemfragseq) { 1061 if (!subelemseqpayloadlen) { 1062 mlo_err_rl("Subelement fragment sequence payload is reported as 0, investigate"); 1063 return QDF_STATUS_E_FAILURE; 1064 } 1065 1066 mlo_debug("Subelement fragment sequence found with payload len %zu", 1067 subelemseqpayloadlen); 1068 1069 ret = wlan_defrag_subelem_fragseq(true, 1070 WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 1071 linkinfo_currpos, 1072 linkinfo_remlen, 1073 NULL, 1074 0, 1075 &defragpayload_len); 1076 if (QDF_IS_STATUS_ERROR(ret)) 1077 return ret; 1078 1079 if (defragpayload_len != subelemseqpayloadlen) { 1080 mlo_err_rl("Length of defragmented payload %zu octets is not equal to length of subelement fragment sequence payload %zu octets", 1081 defragpayload_len, 1082 subelemseqpayloadlen); 1083 return QDF_STATUS_E_FAILURE; 1084 } 1085 1086 /* Adjust linkinfo_remlen to reflect removal of all 1087 * subelement headers except the header of the lead 1088 * subelement. 1089 */ 1090 linkinfo_remlen -= (subelemseqtotallen - 1091 subelemseqpayloadlen - 1092 sizeof(struct subelem_header)); 1093 } else { 1094 if (linkinfo_remlen < 1095 (sizeof(struct subelem_header) + 1096 linkinfo_currpos[TAG_LEN_POS])) { 1097 mlo_err_rl("Remaining length in link info %zu octets is smaller than total size of current subelement %zu octets", 1098 linkinfo_remlen, 1099 sizeof(struct subelem_header) + 1100 linkinfo_currpos[TAG_LEN_POS]); 1101 return QDF_STATUS_E_PROTO; 1102 } 1103 1104 subelemseqpayloadlen = linkinfo_currpos[TAG_LEN_POS]; 1105 } 1106 1107 if (subelemid == WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE) { 1108 ret = util_parse_prvmlie_perstaprofile_stactrl(linkinfo_currpos + 1109 sizeof(struct subelem_header), 1110 subelemseqpayloadlen, 1111 &linkid, 1112 false, 1113 NULL, 1114 NULL); 1115 if (QDF_IS_STATUS_ERROR(ret)) 1116 return ret; 1117 1118 if (probereq_info->num_links >= 1119 QDF_ARRAY_SIZE(probereq_info->link_id)) { 1120 mlo_err_rl("Insufficient size %zu of array for probe req link id", 1121 QDF_ARRAY_SIZE(probereq_info->link_id)); 1122 return QDF_STATUS_E_NOMEM; 1123 } 1124 1125 probereq_info->link_id[probereq_info->num_links] = linkid; 1126 1127 probereq_info->num_links++; 1128 mlo_debug("LINK ID requested is = %u", linkid); 1129 } 1130 1131 linkinfo_remlen -= (sizeof(struct subelem_header) + 1132 subelemseqpayloadlen); 1133 linkinfo_currpos += (sizeof(struct subelem_header) + 1134 subelemseqpayloadlen); 1135 } 1136 1137 mlo_debug("Number of ML probe request links found=%u", 1138 probereq_info->num_links); 1139 1140 return QDF_STATUS_SUCCESS; 1141 } 1142 1143 static 1144 QDF_STATUS util_get_noninheritlists(uint8_t *buff, qdf_size_t buff_len, 1145 uint8_t **ninherit_elemlist, 1146 qdf_size_t *ninherit_elemlist_len, 1147 uint8_t **ninherit_elemextlist, 1148 qdf_size_t *ninherit_elemextlist_len) 1149 { 1150 uint8_t *ninherit_ie; 1151 qdf_size_t unparsed_len; 1152 1153 /* Note: This functionality provided by this helper may be combined with 1154 * other, older non-inheritance parsing helper functionality and exposed 1155 * as a common API as part of future efforts once the older 1156 * functionality can be made generic. 1157 */ 1158 1159 if (!buff) { 1160 mlo_err("Pointer to buffer for IEs is NULL"); 1161 return QDF_STATUS_E_NULL_VALUE; 1162 } 1163 1164 if (!buff_len) { 1165 mlo_err("IE buffer length is zero"); 1166 return QDF_STATUS_E_INVAL; 1167 } 1168 1169 if (!ninherit_elemlist) { 1170 mlo_err("Pointer to Non-Inheritance element ID list array is NULL"); 1171 return QDF_STATUS_E_NULL_VALUE; 1172 } 1173 1174 if (!ninherit_elemlist_len) { 1175 mlo_err("Pointer to Non-Inheritance element ID list array length is NULL"); 1176 return QDF_STATUS_E_NULL_VALUE; 1177 } 1178 1179 if (!ninherit_elemextlist) { 1180 mlo_err("Pointer to Non-Inheritance element ID extension list array is NULL"); 1181 return QDF_STATUS_E_NULL_VALUE; 1182 } 1183 1184 if (!ninherit_elemextlist_len) { 1185 mlo_err("Pointer to Non-Inheritance element ID extension list array length is NULL"); 1186 return QDF_STATUS_E_NULL_VALUE; 1187 } 1188 1189 ninherit_ie = NULL; 1190 *ninherit_elemlist_len = 0; 1191 *ninherit_elemlist = NULL; 1192 *ninherit_elemextlist_len = 0; 1193 *ninherit_elemextlist = NULL; 1194 1195 ninherit_ie = 1196 (uint8_t *)util_find_extn_eid(WLAN_ELEMID_EXTN_ELEM, 1197 WLAN_EXTN_ELEMID_NONINHERITANCE, 1198 buff, 1199 buff_len); 1200 1201 if (ninherit_ie) { 1202 if ((ninherit_ie + TAG_LEN_POS) > (buff + buff_len - 1)) { 1203 mlo_err_rl("Position of length field of Non-Inheritance element would exceed IE buffer boundary"); 1204 return QDF_STATUS_E_PROTO; 1205 } 1206 1207 if ((ninherit_ie + ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN) > 1208 (buff + buff_len)) { 1209 mlo_err_rl("Non-Inheritance element with total length %u would exceed IE buffer boundary", 1210 ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN); 1211 return QDF_STATUS_E_PROTO; 1212 } 1213 1214 if ((ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN) < 1215 MIN_NONINHERITANCEELEM_LEN) { 1216 mlo_err_rl("Non-Inheritance element size %u is smaller than the minimum required %u", 1217 ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN, 1218 MIN_NONINHERITANCEELEM_LEN); 1219 return QDF_STATUS_E_PROTO; 1220 } 1221 1222 /* Track the number of unparsed octets, excluding the IE header. 1223 */ 1224 unparsed_len = ninherit_ie[TAG_LEN_POS]; 1225 1226 /* Mark the element ID extension as parsed */ 1227 unparsed_len--; 1228 1229 *ninherit_elemlist_len = ninherit_ie[ELEM_ID_LIST_LEN_POS]; 1230 unparsed_len--; 1231 1232 /* While checking if the Non-Inheritance element ID list length 1233 * exceeds the remaining unparsed IE space, we factor in one 1234 * octet for the element extension ID list length and subtract 1235 * this from the unparsed IE space. 1236 */ 1237 if (*ninherit_elemlist_len > (unparsed_len - 1)) { 1238 mlo_err_rl("Non-Inheritance element ID list length %zu exceeds remaining unparsed IE space, minus an octet for element extension ID list length %zu", 1239 *ninherit_elemlist_len, unparsed_len - 1); 1240 1241 return QDF_STATUS_E_PROTO; 1242 } 1243 1244 if (*ninherit_elemlist_len != 0) { 1245 *ninherit_elemlist = ninherit_ie + ELEM_ID_LIST_POS; 1246 unparsed_len -= *ninherit_elemlist_len; 1247 } 1248 1249 *ninherit_elemextlist_len = 1250 ninherit_ie[ELEM_ID_LIST_LEN_POS + *ninherit_elemlist_len + 1]; 1251 unparsed_len--; 1252 1253 if (*ninherit_elemextlist_len > unparsed_len) { 1254 mlo_err_rl("Non-Inheritance element ID extension list length %zu exceeds remaining unparsed IE space %zu", 1255 *ninherit_elemextlist_len, unparsed_len); 1256 1257 return QDF_STATUS_E_PROTO; 1258 } 1259 1260 if (*ninherit_elemextlist_len != 0) { 1261 *ninherit_elemextlist = ninherit_ie + 1262 ELEM_ID_LIST_LEN_POS + (*ninherit_elemlist_len) 1263 + 2; 1264 unparsed_len -= *ninherit_elemextlist_len; 1265 } 1266 1267 if (unparsed_len > 0) { 1268 mlo_err_rl("Unparsed length is %zu, expected 0", 1269 unparsed_len); 1270 return QDF_STATUS_E_PROTO; 1271 } 1272 } 1273 1274 /* If Non-Inheritance element is not found, we still return success, 1275 * with the list lengths kept at zero. 1276 */ 1277 mlo_debug("Non-Inheritance element ID list array length=%zu", 1278 *ninherit_elemlist_len); 1279 mlo_debug("Non-Inheritance element ID extension list array length=%zu", 1280 *ninherit_elemextlist_len); 1281 1282 return QDF_STATUS_SUCCESS; 1283 } 1284 1285 static 1286 QDF_STATUS util_eval_ie_in_noninheritlist(uint8_t *ie, qdf_size_t total_ie_len, 1287 uint8_t *ninherit_elemlist, 1288 qdf_size_t ninherit_elemlist_len, 1289 uint8_t *ninherit_elemextlist, 1290 qdf_size_t ninherit_elemextlist_len, 1291 bool *is_in_noninheritlist) 1292 { 1293 int i; 1294 1295 /* Evaluate whether the given IE is in the given Non-Inheritance element 1296 * ID list or Non-Inheritance element ID extension list, and update the 1297 * result into is_in_noninheritlist. If any list is empty, then the IE 1298 * is considered to not be present in that list. Both lists can be 1299 * empty. 1300 * 1301 * If QDF_STATUS_SUCCESS is returned, it means that the evaluation is 1302 * successful, and that is_in_noninheritlist contains a valid value 1303 * (which could be true or false). If a QDF_STATUS error value is 1304 * returned, the value in is_in_noninheritlist is invalid and the caller 1305 * should ignore it. 1306 */ 1307 1308 /* Note: The functionality provided by this helper may be combined with 1309 * other, older non-inheritance parsing helper functionality and exposed 1310 * as a common API as part of future efforts once the older 1311 * functionality can be made generic. 1312 */ 1313 1314 /* Except for is_in_noninheritlist and ie, other pointer arguments are 1315 * permitted to be NULL if they are inapplicable. If they are 1316 * applicable, they will be checked to ensure they are not NULL. 1317 */ 1318 1319 if (!is_in_noninheritlist) { 1320 mlo_err("NULL pointer to flag that indicates if element is in a Non-Inheritance list"); 1321 return QDF_STATUS_E_NULL_VALUE; 1322 } 1323 1324 /* If ninherit_elemlist_len and ninherit_elemextlist_len are both zero 1325 * as checked soon in this function, we won't be accessing the IE. 1326 * However, we still check right-away if the pointer to the IE is 1327 * non-NULL and whether the total IE length is sane enough to access the 1328 * element ID and if applicable, the element ID extension, since it 1329 * doesn't make sense to set the flag in is_in_noninheritlist for a NULL 1330 * IE pointer or an IE whose total length is not sane enough to 1331 * distinguish the identity of the IE. 1332 */ 1333 if (!ie) { 1334 mlo_err("NULL pointer to IE"); 1335 return QDF_STATUS_E_NULL_VALUE; 1336 } 1337 1338 if (total_ie_len < (ID_POS + 1)) { 1339 mlo_err("Total IE length %zu is smaller than minimum required to access element ID %u", 1340 total_ie_len, ID_POS + 1); 1341 return QDF_STATUS_E_INVAL; 1342 } 1343 1344 if ((ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) && 1345 (total_ie_len < (IDEXT_POS + 1))) { 1346 mlo_err("Total IE length %zu is smaller than minimum required to access element ID extension %u", 1347 total_ie_len, IDEXT_POS + 1); 1348 return QDF_STATUS_E_INVAL; 1349 } 1350 1351 *is_in_noninheritlist = false; 1352 1353 /* If both the Non-Inheritance element list and Non-Inheritance element 1354 * ID extension list are empty, then return success since we can 1355 * conclude immediately that the given element does not occur in any 1356 * Non-Inheritance list. The is_in_noninheritlist remains set to false 1357 * as required. 1358 */ 1359 if (!ninherit_elemlist_len && !ninherit_elemextlist_len) 1360 return QDF_STATUS_SUCCESS; 1361 1362 if (ie[ID_POS] != WLAN_ELEMID_EXTN_ELEM) { 1363 if (!ninherit_elemlist_len) 1364 return QDF_STATUS_SUCCESS; 1365 1366 if (!ninherit_elemlist) { 1367 mlo_err("NULL pointer to Non-Inheritance element ID list though length of element ID list is %zu", 1368 ninherit_elemlist_len); 1369 return QDF_STATUS_E_NULL_VALUE; 1370 } 1371 1372 for (i = 0; i < ninherit_elemlist_len; i++) { 1373 if (ie[ID_POS] == ninherit_elemlist[i]) { 1374 *is_in_noninheritlist = true; 1375 return QDF_STATUS_SUCCESS; 1376 } 1377 } 1378 } else { 1379 if (!ninherit_elemextlist_len) 1380 return QDF_STATUS_SUCCESS; 1381 1382 if (!ninherit_elemextlist) { 1383 mlo_err("NULL pointer to Non-Inheritance element ID extension list though length of element ID extension list is %zu", 1384 ninherit_elemextlist_len); 1385 return QDF_STATUS_E_NULL_VALUE; 1386 } 1387 1388 for (i = 0; i < ninherit_elemextlist_len; i++) { 1389 if (ie[IDEXT_POS] == ninherit_elemextlist[i]) { 1390 *is_in_noninheritlist = true; 1391 return QDF_STATUS_SUCCESS; 1392 } 1393 } 1394 } 1395 1396 return QDF_STATUS_SUCCESS; 1397 } 1398 1399 #if defined (SAP_MULTI_LINK_EMULATION) 1400 static inline 1401 QDF_STATUS util_validate_reportingsta_ie(const uint8_t *reportingsta_ie, 1402 const uint8_t *frame_iesection, 1403 const qdf_size_t frame_iesection_len) 1404 { 1405 return QDF_STATUS_SUCCESS; 1406 } 1407 #else 1408 static inline 1409 QDF_STATUS util_validate_reportingsta_ie(const uint8_t *reportingsta_ie, 1410 const uint8_t *frame_iesection, 1411 const qdf_size_t frame_iesection_len) 1412 { 1413 qdf_size_t reportingsta_ie_size; 1414 1415 if (!reportingsta_ie) { 1416 mlo_err("Pointer to reporting STA IE is NULL"); 1417 return QDF_STATUS_E_NULL_VALUE; 1418 } 1419 1420 if (!frame_iesection) { 1421 mlo_err("Pointer to start of IE section in reporting frame is NULL"); 1422 return QDF_STATUS_E_NULL_VALUE; 1423 } 1424 1425 if (!frame_iesection_len) { 1426 mlo_err("Length of IE section in reporting frame is zero"); 1427 return QDF_STATUS_E_INVAL; 1428 } 1429 1430 if ((reportingsta_ie + ID_POS) > (frame_iesection + 1431 frame_iesection_len - 1)) { 1432 mlo_err_rl("Position of element ID field of element for reporting STA would exceed frame IE section boundary"); 1433 return QDF_STATUS_E_PROTO; 1434 } 1435 1436 if ((reportingsta_ie + TAG_LEN_POS) > (frame_iesection + 1437 frame_iesection_len - 1)) { 1438 mlo_err_rl("Position of length field of element with element ID %u for reporting STA would exceed frame IE section boundary", 1439 reportingsta_ie[ID_POS]); 1440 return QDF_STATUS_E_PROTO; 1441 } 1442 1443 if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) && 1444 ((reportingsta_ie + IDEXT_POS) > (frame_iesection + 1445 frame_iesection_len - 1))) { 1446 mlo_err_rl("Position of element ID extension field of element would exceed frame IE section boundary"); 1447 return QDF_STATUS_E_PROTO; 1448 } 1449 1450 reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] + MIN_IE_LEN; 1451 1452 if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) && 1453 (reportingsta_ie_size < (IDEXT_POS + 1))) { 1454 mlo_err_rl("Total length %zu of element for reporting STA is smaller than minimum required to access element ID extension %u", 1455 reportingsta_ie_size, IDEXT_POS + 1); 1456 return QDF_STATUS_E_PROTO; 1457 } 1458 1459 if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_VENDOR) && 1460 (reportingsta_ie_size < (PAYLOAD_START_POS + OUI_LEN))) { 1461 mlo_err_rl("Total length %zu of element for reporting STA is smaller than minimum required to access vendor EID %u", 1462 reportingsta_ie_size, PAYLOAD_START_POS + OUI_LEN); 1463 return QDF_STATUS_E_PROTO; 1464 } 1465 1466 if ((reportingsta_ie + reportingsta_ie_size) > 1467 (frame_iesection + frame_iesection_len)) { 1468 if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 1469 mlo_err_rl("Total size %zu octets of element with element ID %u element ID extension %u for reporting STA would exceed frame IE section boundary", 1470 reportingsta_ie_size, 1471 reportingsta_ie[ID_POS], 1472 reportingsta_ie[IDEXT_POS]); 1473 } else { 1474 mlo_err_rl("Total size %zu octets of element with element ID %u for reporting STA would exceed frame IE section boundary", 1475 reportingsta_ie_size, 1476 reportingsta_ie[ID_POS]); 1477 } 1478 1479 return QDF_STATUS_E_PROTO; 1480 } 1481 1482 return QDF_STATUS_SUCCESS; 1483 } 1484 #endif 1485 1486 static inline 1487 QDF_STATUS util_validate_sta_prof_ie(const uint8_t *sta_prof_ie, 1488 const uint8_t *sta_prof_iesection, 1489 const qdf_size_t sta_prof_iesection_len) 1490 { 1491 qdf_size_t sta_prof_ie_size; 1492 1493 if (!sta_prof_ie) { 1494 mlo_err("Pointer to STA profile IE is NULL"); 1495 return QDF_STATUS_E_NULL_VALUE; 1496 } 1497 1498 if (!sta_prof_iesection) { 1499 mlo_err("Pointer to start of IE section in STA profile is NULL"); 1500 return QDF_STATUS_E_NULL_VALUE; 1501 } 1502 1503 if (!sta_prof_iesection_len) { 1504 mlo_err("Length of IE section in STA profile is zero"); 1505 return QDF_STATUS_E_INVAL; 1506 } 1507 1508 if ((sta_prof_ie + ID_POS) > (sta_prof_iesection + 1509 sta_prof_iesection_len - 1)) { 1510 mlo_err_rl("Position of element ID field of STA profile element would exceed STA profile IE section boundary"); 1511 return QDF_STATUS_E_PROTO; 1512 } 1513 1514 if ((sta_prof_ie + TAG_LEN_POS) > (sta_prof_iesection + 1515 sta_prof_iesection_len - 1)) { 1516 mlo_err_rl("Position of length field of element with element ID %u in STA profile would exceed STA profile IE section boundary", 1517 sta_prof_ie[ID_POS]); 1518 return QDF_STATUS_E_PROTO; 1519 } 1520 1521 if ((sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) && 1522 ((sta_prof_ie + IDEXT_POS) > (sta_prof_iesection + 1523 sta_prof_iesection_len - 1))) { 1524 mlo_err_rl("Position of element ID extension field of element would exceed STA profile IE section boundary"); 1525 return QDF_STATUS_E_PROTO; 1526 } 1527 1528 sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] + MIN_IE_LEN; 1529 1530 if ((sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) && 1531 (sta_prof_ie_size < (IDEXT_POS + 1))) { 1532 mlo_err_rl("Total length %zu of STA profile element is smaller than minimum required to access element ID extension %u", 1533 sta_prof_ie_size, IDEXT_POS + 1); 1534 return QDF_STATUS_E_PROTO; 1535 } 1536 1537 if ((sta_prof_ie + sta_prof_ie_size) > 1538 (sta_prof_iesection + sta_prof_iesection_len)) { 1539 if (sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 1540 mlo_err_rl("Total size %zu octets of element with element ID %u element ID extension %u in STA profile would exceed STA profile IE section boundary", 1541 sta_prof_ie_size, 1542 sta_prof_ie[ID_POS], 1543 sta_prof_ie[IDEXT_POS]); 1544 } else { 1545 mlo_err_rl("Total size %zu octets of element with element ID %u in STA profile would exceed STA profile IE section boundary", 1546 sta_prof_ie_size, 1547 sta_prof_ie[ID_POS]); 1548 } 1549 1550 return QDF_STATUS_E_PROTO; 1551 } 1552 1553 return QDF_STATUS_SUCCESS; 1554 } 1555 1556 #ifdef CONN_MGR_ADV_FEATURE 1557 /** 1558 * util_add_mlie_for_prb_rsp_gen - Add the basic variant Multi-Link element 1559 * when generating link specific probe response. 1560 * @reportingsta_ie: Pointer to the reportingsta ie 1561 * @reportingsta_ie_len: Length for reporting sta ie 1562 * @plink_frame_currpos: Pointer to Link frame current pos 1563 * @plink_frame_currlen: Current length of link frame. 1564 * @link_frame_maxsize: Maximum size of the frame to be generated 1565 * @linkid: Link Id value 1566 * 1567 * Add the basic variant Multi-Link element when 1568 * generating link specific probe response. 1569 * 1570 * Return: QDF_STATUS_SUCCESS in the case of success, QDF_STATUS value giving 1571 * the reason for error in the case of failure 1572 */ 1573 static QDF_STATUS 1574 util_add_mlie_for_prb_rsp_gen(const uint8_t *reportingsta_ie, 1575 qdf_size_t reportingsta_ie_len, 1576 uint8_t **plink_frame_currpos, 1577 qdf_size_t *plink_frame_currlen, 1578 qdf_size_t link_frame_maxsize, 1579 uint8_t linkid) 1580 { 1581 uint8_t mlie_len = 0; 1582 uint8_t common_info_len = 0; 1583 struct wlan_ie_multilink ml_ie_ff; 1584 uint16_t mlcontrol; 1585 uint16_t presencebm; 1586 uint8_t *mlie_frame = NULL; 1587 uint8_t link_id_offset = sizeof(struct wlan_ie_multilink) + 1588 QDF_MAC_ADDR_SIZE + 1589 WLAN_ML_BV_CINFO_LENGTH_SIZE; 1590 uint8_t *link_frame_currpos = *plink_frame_currpos; 1591 qdf_size_t link_frame_currlen = *plink_frame_currlen; 1592 QDF_STATUS status = QDF_STATUS_SUCCESS; 1593 1594 status = util_get_mlie_common_info_len((uint8_t *)reportingsta_ie, 1595 reportingsta_ie_len, 1596 &common_info_len); 1597 if (QDF_IS_STATUS_ERROR(status) || 1598 common_info_len > reportingsta_ie_len || 1599 (reportingsta_ie_len - common_info_len < 1600 sizeof(struct wlan_ie_multilink))) { 1601 mlo_err("Failed to parse common info, mlie len %d common info len %d", 1602 reportingsta_ie_len, common_info_len); 1603 return status; 1604 } 1605 1606 /* common info len + bvmlie fixed fields */ 1607 mlie_len = common_info_len + sizeof(struct wlan_ie_multilink); 1608 1609 mlo_debug_rl("mlie_len %d, common_info_len %d, link_id_offset %d", 1610 mlie_len, 1611 common_info_len, 1612 link_id_offset); 1613 1614 /* 1615 * Validate the buffer available before copying ML IE. 1616 * Incase if mlie_len is modified at later place, move this validation 1617 * there to make sure no buffer overflow happens. 1618 */ 1619 if ((link_frame_maxsize - link_frame_currlen) < mlie_len) { 1620 mlo_err("Insufficient space in link specific frame for ML IE. Required: %u octets, available: %zu octets", 1621 mlie_len, (link_frame_maxsize - link_frame_currlen)); 1622 return QDF_STATUS_E_NOMEM; 1623 } 1624 1625 mlie_frame = qdf_mem_malloc(mlie_len); 1626 if (!mlie_frame) 1627 return QDF_STATUS_E_NOMEM; 1628 1629 /* Copy ml ie fixed fields */ 1630 qdf_mem_copy(&ml_ie_ff, 1631 reportingsta_ie, 1632 sizeof(struct wlan_ie_multilink)); 1633 1634 ml_ie_ff.elem_len = mlie_len - sizeof(struct ie_header); 1635 1636 mlcontrol = qdf_le16_to_cpu(ml_ie_ff.mlcontrol); 1637 presencebm = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 1638 WLAN_ML_CTRL_PBM_BITS); 1639 qdf_set_bit(WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P, 1640 (unsigned long *)&presencebm); 1641 1642 QDF_SET_BITS(ml_ie_ff.mlcontrol, 1643 WLAN_ML_CTRL_PBM_IDX, 1644 WLAN_ML_CTRL_PBM_BITS, 1645 presencebm); 1646 1647 qdf_mem_copy(mlie_frame, 1648 &ml_ie_ff, 1649 sizeof(struct wlan_ie_multilink)); 1650 1651 qdf_mem_copy(mlie_frame + sizeof(struct wlan_ie_multilink), 1652 reportingsta_ie + sizeof(struct wlan_ie_multilink), 1653 mlie_len - sizeof(struct wlan_ie_multilink)); 1654 1655 if (linkid == 0xFF || mlie_len <= link_id_offset) { 1656 qdf_mem_free(mlie_frame); 1657 mlo_err("Failed to process link id, link_id %d", linkid); 1658 return QDF_STATUS_E_INVAL; 1659 } 1660 mlie_frame[link_id_offset] = (mlie_frame[link_id_offset] & ~0x0f) | 1661 (linkid & 0x0f); 1662 qdf_mem_copy(link_frame_currpos, 1663 mlie_frame, 1664 mlie_len); 1665 1666 mlo_debug("Add mlie for link id %d", linkid); 1667 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, 1668 mlie_frame, mlie_len); 1669 1670 link_frame_currpos += mlie_len; 1671 link_frame_currlen += mlie_len; 1672 *plink_frame_currpos = link_frame_currpos; 1673 *plink_frame_currlen = link_frame_currlen; 1674 qdf_mem_free(mlie_frame); 1675 1676 return QDF_STATUS_SUCCESS; 1677 } 1678 #else 1679 static QDF_STATUS 1680 util_add_mlie_for_prb_rsp_gen(const uint8_t *reportingsta_ie, 1681 qdf_size_t reportingsta_ie_len, 1682 uint8_t **plink_frame_currpos, 1683 qdf_size_t *plink_frame_currlen, 1684 qdf_size_t link_frame_maxsize, 1685 uint8_t linkid) 1686 { 1687 return QDF_STATUS_SUCCESS; 1688 } 1689 #endif 1690 1691 /** 1692 * util_find_bvmlie_persta_prof_for_linkid() - get per sta profile per link id 1693 * @req_link_id: link id 1694 * @linkinfo: the pointer of link info 1695 * @linkinfo_len: the length of link info 1696 * @persta_prof_frame: the pointer to store the address of sta profile 1697 * @persta_prof_len: the sta profile length 1698 * 1699 * This helper function parses partner info from the per-STA profiles 1700 * present (if any) in the Link Info field in the payload of a Multi 1701 * Link element (after defragmentation if required). The caller should 1702 * pass a copy of the payload so that inline defragmentation of 1703 * subelements can be carried out if required. The subelement 1704 * defragmentation (if applicable) in this Control Path helper is 1705 * required for maintainability, accuracy and eliminating current and 1706 * future per-field-access multi-level fragment boundary checks and 1707 * adjustments, given the complex format of Multi Link elements. It is 1708 * also most likely to be required mainly at the client side. 1709 * 1710 * Return: QDF_STATUS 1711 */ 1712 static QDF_STATUS 1713 util_find_bvmlie_persta_prof_for_linkid(uint8_t req_link_id, 1714 uint8_t *linkinfo, 1715 qdf_size_t linkinfo_len, 1716 uint8_t **persta_prof_frame, 1717 qdf_size_t *persta_prof_len) 1718 { 1719 uint8_t linkid; 1720 struct qdf_mac_addr macaddr; 1721 bool is_macaddr_valid; 1722 uint8_t *linkinfo_currpos; 1723 qdf_size_t linkinfo_remlen; 1724 bool is_subelemfragseq; 1725 uint8_t subelemid; 1726 qdf_size_t subelemseqtotallen; 1727 qdf_size_t subelemseqpayloadlen; 1728 qdf_size_t defragpayload_len; 1729 QDF_STATUS ret; 1730 1731 if (!linkinfo) { 1732 mlo_err("linkinfo is NULL"); 1733 return QDF_STATUS_E_NULL_VALUE; 1734 } 1735 1736 if (!linkinfo_len) { 1737 mlo_err("linkinfo_len is zero"); 1738 return QDF_STATUS_E_NULL_VALUE; 1739 } 1740 1741 if (!persta_prof_frame) { 1742 mlo_err("Pointer to per-STA prof frame is NULL"); 1743 return QDF_STATUS_E_NULL_VALUE; 1744 } 1745 1746 if (!persta_prof_len) { 1747 mlo_err("Length to per-STA prof frame is 0"); 1748 return QDF_STATUS_E_NULL_VALUE; 1749 } 1750 1751 linkinfo_currpos = linkinfo; 1752 linkinfo_remlen = linkinfo_len; 1753 1754 while (linkinfo_remlen) { 1755 if (linkinfo_remlen < sizeof(struct subelem_header)) { 1756 mlo_err_rl("Remaining length in link info %zu octets is smaller than subelement header length %zu octets", 1757 linkinfo_remlen, 1758 sizeof(struct subelem_header)); 1759 return QDF_STATUS_E_PROTO; 1760 } 1761 1762 subelemid = linkinfo_currpos[ID_POS]; 1763 is_subelemfragseq = false; 1764 subelemseqtotallen = 0; 1765 subelemseqpayloadlen = 0; 1766 1767 ret = wlan_get_subelem_fragseq_info(WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 1768 linkinfo_currpos, 1769 linkinfo_remlen, 1770 &is_subelemfragseq, 1771 &subelemseqtotallen, 1772 &subelemseqpayloadlen); 1773 if (QDF_IS_STATUS_ERROR(ret)) 1774 return ret; 1775 1776 if (is_subelemfragseq) { 1777 if (!subelemseqpayloadlen) { 1778 mlo_err_rl("Subelement fragment sequence payload is reported as 0, investigate"); 1779 return QDF_STATUS_E_FAILURE; 1780 } 1781 1782 mlo_debug("Subelement fragment sequence found with payload len %zu", 1783 subelemseqpayloadlen); 1784 1785 ret = wlan_defrag_subelem_fragseq(true, 1786 WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 1787 linkinfo_currpos, 1788 linkinfo_remlen, 1789 NULL, 1790 0, 1791 &defragpayload_len); 1792 if (QDF_IS_STATUS_ERROR(ret)) 1793 return ret; 1794 1795 if (defragpayload_len != subelemseqpayloadlen) { 1796 mlo_err_rl("Length of defragmented payload %zu octets is not equal to length of subelement fragment sequence payload %zu octets", 1797 defragpayload_len, 1798 subelemseqpayloadlen); 1799 return QDF_STATUS_E_FAILURE; 1800 } 1801 1802 /* Adjust linkinfo_remlen to reflect removal of all 1803 * subelement headers except the header of the lead 1804 * subelement. 1805 */ 1806 linkinfo_remlen -= (subelemseqtotallen - 1807 subelemseqpayloadlen - 1808 sizeof(struct subelem_header)); 1809 } else { 1810 if (linkinfo_remlen < 1811 (sizeof(struct subelem_header) + 1812 linkinfo_currpos[TAG_LEN_POS])) { 1813 mlo_err_rl("Remaining length in link info %zu octets is smaller than total size of current subelement %zu octets", 1814 linkinfo_remlen, 1815 sizeof(struct subelem_header) + 1816 linkinfo_currpos[TAG_LEN_POS]); 1817 return QDF_STATUS_E_PROTO; 1818 } 1819 1820 subelemseqpayloadlen = linkinfo_currpos[TAG_LEN_POS]; 1821 } 1822 1823 if (subelemid == WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE) { 1824 is_macaddr_valid = false; 1825 1826 ret = util_parse_bvmlie_perstaprofile_stactrl(linkinfo_currpos + 1827 sizeof(struct subelem_header), 1828 subelemseqpayloadlen, 1829 &linkid, 1830 NULL, 1831 NULL, 1832 NULL, 1833 NULL, 1834 NULL, 1835 &is_macaddr_valid, 1836 &macaddr, 1837 false, 1838 NULL, 1839 NULL, 1840 NULL, 1841 NULL); 1842 if (QDF_IS_STATUS_ERROR(ret)) 1843 return ret; 1844 1845 if (req_link_id == linkid) { 1846 mlo_debug("Found requested per-STA prof for linkid %u, len %zu", 1847 linkid, subelemseqpayloadlen); 1848 *persta_prof_frame = linkinfo_currpos; 1849 *persta_prof_len = subelemseqpayloadlen; 1850 return QDF_STATUS_SUCCESS; 1851 } 1852 } 1853 1854 linkinfo_remlen -= (sizeof(struct subelem_header) + 1855 subelemseqpayloadlen); 1856 linkinfo_currpos += (sizeof(struct subelem_header) + 1857 subelemseqpayloadlen); 1858 } 1859 1860 return QDF_STATUS_E_PROTO; 1861 } 1862 1863 static 1864 QDF_STATUS util_gen_link_reqrsp_cmn(uint8_t *frame, qdf_size_t frame_len, 1865 uint8_t subtype, 1866 uint8_t req_link_id, 1867 struct qdf_mac_addr link_addr, 1868 uint8_t *link_frame, 1869 qdf_size_t link_frame_maxsize, 1870 qdf_size_t *link_frame_len) 1871 { 1872 /* Please see documentation for util_gen_link_assoc_req() and 1873 * util_gen_link_assoc_resp() for information on the inputs to and 1874 * output from this helper, since those APIs are essentially wrappers 1875 * over this helper. 1876 */ 1877 1878 /* Pointer to Multi-Link element/Multi-Link element fragment sequence */ 1879 uint8_t *mlieseq; 1880 /* Total length of Multi-Link element sequence (including fragments if 1881 * any) 1882 */ 1883 qdf_size_t mlieseqlen; 1884 /* Variant (i.e. type) of the Multi-Link element */ 1885 enum wlan_ml_variant variant; 1886 1887 /* Length of the payload of the Multi-Link element (inclusive of 1888 * fragment payloads if any) without IE headers and element ID extension 1889 */ 1890 qdf_size_t mlieseqpayloadlen; 1891 /* Pointer to copy of the payload of the Multi-Link element (inclusive 1892 * of fragment payloads if any) without IE headers and element ID 1893 * extension 1894 */ 1895 uint8_t *mlieseqpayload_copy; 1896 1897 /* Pointer to start of Link Info within the copy of the payload of the 1898 * Multi-Link element 1899 */ 1900 uint8_t *link_info; 1901 /* Length of the Link Info */ 1902 qdf_size_t link_info_len; 1903 1904 /* Pointer to the IE section that occurs after the fixed fields in the 1905 * original frame for the reporting STA. 1906 */ 1907 uint8_t *frame_iesection; 1908 /* Offset to the start of the IE section in the original frame for the 1909 * reporting STA. 1910 */ 1911 qdf_size_t frame_iesection_offset; 1912 /* Total length of the IE section in the original frame for the 1913 * reporting STA. 1914 */ 1915 qdf_size_t frame_iesection_len; 1916 1917 /* Pointer to the IEEE802.11 frame header in the link specific frame 1918 * being generated for the reported STA. 1919 */ 1920 struct wlan_frame_hdr *link_frame_hdr; 1921 /* Current position in the link specific frame being generated for the 1922 * reported STA. 1923 */ 1924 uint8_t *link_frame_currpos; 1925 /* Current length of the link specific frame being generated for the 1926 * reported STA. 1927 */ 1928 qdf_size_t link_frame_currlen; 1929 1930 /* Pointer to IE for reporting STA */ 1931 const uint8_t *reportingsta_ie; 1932 /* Total size of IE for reporting STA, inclusive of the element header 1933 */ 1934 qdf_size_t reportingsta_ie_size; 1935 1936 /* Pointer to current position in STA profile */ 1937 uint8_t *sta_prof_currpos; 1938 /* Remaining length of STA profile */ 1939 qdf_size_t sta_prof_remlen; 1940 /* Pointer to start of IE section in STA profile that occurs after fixed 1941 * fields. 1942 */ 1943 uint8_t *sta_prof_iesection; 1944 /* Total length of IE section in STA profile */ 1945 qdf_size_t sta_prof_iesection_len; 1946 /* Pointer to current position being processed in IE section in STA 1947 * profile. 1948 */ 1949 uint8_t *sta_prof_iesection_currpos; 1950 /* Remaining length of IE section in STA profile */ 1951 qdf_size_t sta_prof_iesection_remlen; 1952 1953 /* Pointer to IE in STA profile, that occurs within IE section */ 1954 uint8_t *sta_prof_ie; 1955 /* Total size of IE in STA profile, inclusive of the element header */ 1956 qdf_size_t sta_prof_ie_size; 1957 1958 /* Pointer to element ID list in Non-Inheritance IE */ 1959 uint8_t *ninherit_elemlist; 1960 /* Length of element ID list in Non-Inheritance IE */ 1961 qdf_size_t ninherit_elemlist_len; 1962 /* Pointer to element ID extension list in Non-Inheritance IE */ 1963 uint8_t *ninherit_elemextlist; 1964 /* Length of element ID extension list in Non-Inheritance IE */ 1965 qdf_size_t ninherit_elemextlist_len; 1966 /* Whether a given IE is in a non-inheritance list */ 1967 bool is_in_noninheritlist; 1968 1969 /* Whether MAC address of reported STA is valid */ 1970 bool is_reportedmacaddr_valid; 1971 /* MAC address of reported STA */ 1972 struct qdf_mac_addr reportedmacaddr; 1973 1974 /* Pointer to per-STA profile */ 1975 uint8_t *persta_prof; 1976 /* Length of the containing buffer which starts with the per-STA profile 1977 */ 1978 qdf_size_t persta_prof_bufflen; 1979 1980 /* Other variables for temporary purposes */ 1981 1982 /* Variable into which API for determining fragment information will 1983 * indicate whether the element is the start of a fragment sequence or 1984 * not. 1985 */ 1986 bool is_elemfragseq; 1987 /* De-fragmented payload length returned by API for element 1988 * defragmentation. 1989 */ 1990 qdf_size_t defragpayload_len; 1991 /* Pointer to Beacon interval in STA info field */ 1992 uint16_t beaconinterval; 1993 /* Whether Beacon interval value valid */ 1994 bool is_beaconinterval_valid; 1995 /* TSF timer of the reporting AP */ 1996 uint64_t tsf; 1997 /* TSF offset of the reproted AP */ 1998 uint64_t tsfoffset; 1999 /* TSF offset value valid */ 2000 bool is_tsfoffset_valid; 2001 /* If Complete Profile or not*/ 2002 bool is_completeprofile; 2003 qdf_size_t tmplen; 2004 QDF_STATUS ret; 2005 uint8_t linkid = 0xFF; 2006 2007 if (!frame) { 2008 mlo_err("Pointer to original frame is NULL"); 2009 return QDF_STATUS_E_NULL_VALUE; 2010 } 2011 2012 if (!frame_len) { 2013 mlo_err("Length of original frame is zero"); 2014 return QDF_STATUS_E_INVAL; 2015 } 2016 2017 if ((subtype != WLAN_FC0_STYPE_ASSOC_REQ) && 2018 (subtype != WLAN_FC0_STYPE_REASSOC_REQ) && 2019 (subtype != WLAN_FC0_STYPE_ASSOC_RESP) && 2020 (subtype != WLAN_FC0_STYPE_REASSOC_RESP) && 2021 (subtype != WLAN_FC0_STYPE_PROBE_RESP)) { 2022 mlo_err("802.11 frame subtype %u is invalid", subtype); 2023 return QDF_STATUS_E_INVAL; 2024 } 2025 2026 if (!link_frame) { 2027 mlo_err("Pointer to secondary link specific frame is NULL"); 2028 return QDF_STATUS_E_NULL_VALUE; 2029 } 2030 2031 if (!link_frame_maxsize) { 2032 mlo_err("Maximum size of secondary link specific frame is zero"); 2033 return QDF_STATUS_E_INVAL; 2034 } 2035 2036 if (!link_frame_len) { 2037 mlo_err("Pointer to populated length of secondary link specific frame is NULL"); 2038 return QDF_STATUS_E_NULL_VALUE; 2039 } 2040 2041 frame_iesection_offset = 0; 2042 2043 if (subtype == WLAN_FC0_STYPE_ASSOC_REQ) { 2044 frame_iesection_offset = WLAN_ASSOC_REQ_IES_OFFSET; 2045 } else if (subtype == WLAN_FC0_STYPE_REASSOC_REQ) { 2046 frame_iesection_offset = WLAN_REASSOC_REQ_IES_OFFSET; 2047 } else if (subtype == WLAN_FC0_STYPE_PROBE_RESP) { 2048 frame_iesection_offset = WLAN_PROBE_RESP_IES_OFFSET; 2049 if (frame_len < WLAN_TIMESTAMP_LEN) { 2050 mlo_err("Frame length %zu is smaller than required timestamp length", 2051 frame_len); 2052 return QDF_STATUS_E_INVAL; 2053 } 2054 qdf_mem_copy(&tsf, frame, WLAN_TIMESTAMP_LEN); 2055 tsf = qdf_le64_to_cpu(tsf); 2056 } else { 2057 /* This is a (re)association response */ 2058 frame_iesection_offset = WLAN_ASSOC_RSP_IES_OFFSET; 2059 } 2060 2061 if (frame_len < frame_iesection_offset) { 2062 /* The caller is supposed to have confirmed that this is a valid 2063 * frame containing a Multi-Link element. Hence we treat this as 2064 * a case of invalid argument being passed to us. 2065 */ 2066 mlo_err("Frame length %zu is smaller than the IE section offset %zu for subtype %u", 2067 frame_len, frame_iesection_offset, subtype); 2068 return QDF_STATUS_E_INVAL; 2069 } 2070 2071 frame_iesection_len = frame_len - frame_iesection_offset; 2072 2073 if (frame_iesection_len == 0) { 2074 /* The caller is supposed to have confirmed that this is a valid 2075 * frame containing a Multi-Link element. Hence we treat this as 2076 * a case of invalid argument being passed to us. 2077 */ 2078 mlo_err("No space left in frame for IE section"); 2079 return QDF_STATUS_E_INVAL; 2080 } 2081 2082 frame_iesection = frame + frame_iesection_offset; 2083 2084 mlieseq = NULL; 2085 mlieseqlen = 0; 2086 2087 ret = util_find_mlie(frame_iesection, frame_iesection_len, &mlieseq, 2088 &mlieseqlen); 2089 if (QDF_IS_STATUS_ERROR(ret)) 2090 return ret; 2091 2092 if (!mlieseq) { 2093 /* The caller is supposed to have confirmed that a Multi-Link 2094 * element is present in the frame. Hence we treat this as a 2095 * case of invalid argument being passed to us. 2096 */ 2097 mlo_err("Invalid original frame since no Multi-Link element found"); 2098 return QDF_STATUS_E_INVAL; 2099 } 2100 2101 /* Sanity check the Multi-Link element sequence length */ 2102 if (!mlieseqlen) { 2103 mlo_err("Length of Multi-Link element sequence is zero. Investigate."); 2104 return QDF_STATUS_E_FAILURE; 2105 } 2106 2107 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) { 2108 mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)", 2109 mlieseqlen, sizeof(struct wlan_ie_multilink)); 2110 return QDF_STATUS_E_PROTO; 2111 } 2112 2113 ret = util_get_mlie_variant(mlieseq, mlieseqlen, (int *)&variant); 2114 if (QDF_IS_STATUS_ERROR(ret)) 2115 return ret; 2116 2117 if (variant != WLAN_ML_VARIANT_BASIC) { 2118 mlo_err_rl("Unexpected variant %u of Multi-Link element.", 2119 variant); 2120 return QDF_STATUS_E_PROTO; 2121 } 2122 2123 mlieseqpayloadlen = 0; 2124 tmplen = 0; 2125 is_elemfragseq = false; 2126 2127 ret = wlan_get_elem_fragseq_info(mlieseq, 2128 mlieseqlen, 2129 &is_elemfragseq, 2130 &tmplen, 2131 &mlieseqpayloadlen); 2132 if (QDF_IS_STATUS_ERROR(ret)) 2133 return ret; 2134 2135 if (is_elemfragseq) { 2136 if (tmplen != mlieseqlen) { 2137 mlo_err_rl("Mismatch in values of element fragment sequence total length. Val per frag info determination: %zu octets, val per Multi-Link element search: %zu octets", 2138 tmplen, mlieseqlen); 2139 return QDF_STATUS_E_FAILURE; 2140 } 2141 2142 if (!mlieseqpayloadlen) { 2143 mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate"); 2144 return QDF_STATUS_E_FAILURE; 2145 } 2146 2147 mlo_debug("ML IE fragment sequence found with payload len %zu", 2148 mlieseqpayloadlen); 2149 } else { 2150 if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) { 2151 mlo_err_rl("Expected presence of valid fragment sequence since Multi-Link element sequence length %zu octets is larger than frag threshold of %zu octets, however no valid fragment sequence found", 2152 mlieseqlen, 2153 sizeof(struct ie_header) + WLAN_MAX_IE_LEN); 2154 return QDF_STATUS_E_FAILURE; 2155 } 2156 2157 mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1); 2158 } 2159 2160 mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen); 2161 2162 if (!mlieseqpayload_copy) { 2163 mlo_err_rl("Could not allocate memory for Multi-Link element payload copy"); 2164 ret = QDF_STATUS_E_NOMEM; 2165 goto mem_free; 2166 } 2167 2168 if (is_elemfragseq) { 2169 ret = wlan_defrag_elem_fragseq(false, 2170 mlieseq, 2171 mlieseqlen, 2172 mlieseqpayload_copy, 2173 mlieseqpayloadlen, 2174 &defragpayload_len); 2175 if (QDF_IS_STATUS_ERROR(ret)) 2176 goto mem_free; 2177 2178 if (defragpayload_len != mlieseqpayloadlen) { 2179 mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets", 2180 defragpayload_len, mlieseqpayloadlen); 2181 ret = QDF_STATUS_E_FAILURE; 2182 goto mem_free; 2183 } 2184 } else { 2185 qdf_mem_copy(mlieseqpayload_copy, 2186 mlieseq + sizeof(struct ie_header) + 1, 2187 mlieseqpayloadlen); 2188 } 2189 2190 link_info = NULL; 2191 link_info_len = 0; 2192 2193 ret = util_parse_multi_link_ctrl(mlieseqpayload_copy, 2194 mlieseqpayloadlen, 2195 &link_info, 2196 &link_info_len); 2197 if (QDF_IS_STATUS_ERROR(ret)) 2198 goto mem_free; 2199 2200 /* As per the standard, the sender must include Link Info for 2201 * association request/response. Throw an error if we are unable to 2202 * obtain this. 2203 */ 2204 if (!link_info) { 2205 mlo_err_rl("Unable to successfully obtain Link Info"); 2206 ret = QDF_STATUS_E_PROTO; 2207 goto mem_free; 2208 } 2209 2210 /* Note: We may have a future change to skip subelements which are not 2211 * Per-STA Profile, handle more than two links in MLO, handle cases 2212 * where we unexpectedly find more Per-STA Profiles than expected, etc. 2213 */ 2214 2215 persta_prof = NULL; 2216 persta_prof_bufflen = 0; 2217 2218 ret = util_find_bvmlie_persta_prof_for_linkid(req_link_id, 2219 link_info, 2220 link_info_len, 2221 &persta_prof, 2222 &persta_prof_bufflen); 2223 2224 if (QDF_IS_STATUS_ERROR(ret)) { 2225 mlo_err_rl("Per STA profile not found for link id %d", 2226 req_link_id); 2227 goto mem_free; 2228 } 2229 2230 sta_prof_remlen = 0; 2231 sta_prof_currpos = NULL; 2232 is_reportedmacaddr_valid = false; 2233 is_beaconinterval_valid = false; 2234 is_completeprofile = false; 2235 is_tsfoffset_valid = false; 2236 2237 /* Parse per-STA profile */ 2238 ret = util_parse_bvmlie_perstaprofile_stactrl(persta_prof + 2239 sizeof(struct subelem_header), 2240 persta_prof_bufflen, 2241 &linkid, 2242 &beaconinterval, 2243 &is_beaconinterval_valid, 2244 &tsfoffset, 2245 &is_tsfoffset_valid, 2246 &is_completeprofile, 2247 &is_reportedmacaddr_valid, 2248 &reportedmacaddr, 2249 true, 2250 &sta_prof_currpos, 2251 &sta_prof_remlen, 2252 NULL, 2253 NULL); 2254 if (QDF_IS_STATUS_ERROR(ret)) 2255 goto mem_free; 2256 2257 if (subtype == WLAN_FC0_STYPE_PROBE_RESP && !is_completeprofile) { 2258 mlo_err("Complete profile information is not present in per-STA profile of probe response frame"); 2259 ret = QDF_STATUS_E_NOSUPPORT; 2260 goto mem_free; 2261 } 2262 2263 /* We double check for a NULL STA Profile, though the helper function 2264 * above would have taken care of this. We need to get a non-NULL STA 2265 * profile, because we need to get at least the expected fixed fields, 2266 * even if there is an (improbable) total inheritance. 2267 */ 2268 if (!sta_prof_currpos) { 2269 mlo_err_rl("STA profile is NULL"); 2270 ret = QDF_STATUS_E_PROTO; 2271 goto mem_free; 2272 } 2273 2274 /* As per the standard, the sender sets the MAC address in the per-STA 2275 * profile in association request/response. Without this, we cannot 2276 * generate the link specific frame. 2277 */ 2278 if (!is_reportedmacaddr_valid) { 2279 mlo_err_rl("Unable to get MAC address from per-STA profile"); 2280 ret = QDF_STATUS_E_PROTO; 2281 goto mem_free; 2282 } 2283 2284 link_frame_currpos = link_frame; 2285 *link_frame_len = 0; 2286 link_frame_currlen = 0; 2287 2288 if (link_frame_maxsize < WLAN_MAC_HDR_LEN_3A) { 2289 mlo_err("Insufficient space in link specific frame for 802.11 header. Required: %u octets, available: %zu octets", 2290 WLAN_MAC_HDR_LEN_3A, link_frame_maxsize); 2291 2292 ret = QDF_STATUS_E_NOMEM; 2293 goto mem_free; 2294 } 2295 2296 link_frame_currpos += WLAN_MAC_HDR_LEN_3A; 2297 link_frame_currlen += WLAN_MAC_HDR_LEN_3A; 2298 2299 if ((subtype == WLAN_FC0_STYPE_ASSOC_REQ) || 2300 (subtype == WLAN_FC0_STYPE_REASSOC_REQ)) { 2301 mlo_debug("Populating fixed fields for (re)assoc req in link specific frame"); 2302 2303 if (sta_prof_remlen < WLAN_CAPABILITYINFO_LEN) { 2304 mlo_err_rl("Remaining length of STA profile %zu octets is less than length of Capability Info %u", 2305 sta_prof_remlen, 2306 WLAN_CAPABILITYINFO_LEN); 2307 2308 ret = QDF_STATUS_E_PROTO; 2309 goto mem_free; 2310 } 2311 2312 /* Capability information is specific to the link. Copy this 2313 * from the STA profile. 2314 */ 2315 2316 if ((link_frame_maxsize - link_frame_currlen) < 2317 WLAN_CAPABILITYINFO_LEN) { 2318 mlo_err("Insufficient space in link specific frame for Capability Info field. Required: %u octets, available: %zu octets", 2319 WLAN_CAPABILITYINFO_LEN, 2320 (link_frame_maxsize - link_frame_currlen)); 2321 2322 ret = QDF_STATUS_E_NOMEM; 2323 goto mem_free; 2324 } 2325 2326 qdf_mem_copy(link_frame_currpos, sta_prof_currpos, 2327 WLAN_CAPABILITYINFO_LEN); 2328 link_frame_currpos += WLAN_CAPABILITYINFO_LEN; 2329 link_frame_currlen += WLAN_CAPABILITYINFO_LEN; 2330 2331 sta_prof_currpos += WLAN_CAPABILITYINFO_LEN; 2332 sta_prof_remlen -= WLAN_CAPABILITYINFO_LEN; 2333 2334 /* Listen Interval is common between all links. Copy this from 2335 * the reporting section of the frame. 2336 */ 2337 2338 if ((link_frame_maxsize - link_frame_currlen) < 2339 WLAN_LISTENINTERVAL_LEN) { 2340 mlo_err("Insufficient space in link specific frame for Listen Interval field. Required: %u octets, available: %zu octets", 2341 WLAN_LISTENINTERVAL_LEN, 2342 (link_frame_maxsize - link_frame_currlen)); 2343 2344 ret = QDF_STATUS_E_NOMEM; 2345 goto mem_free; 2346 } 2347 2348 qdf_mem_copy(link_frame_currpos, 2349 frame + WLAN_CAPABILITYINFO_LEN, 2350 WLAN_LISTENINTERVAL_LEN); 2351 link_frame_currpos += WLAN_LISTENINTERVAL_LEN; 2352 link_frame_currlen += WLAN_LISTENINTERVAL_LEN; 2353 2354 if (subtype == WLAN_FC0_STYPE_REASSOC_REQ) { 2355 /* Current AP address is common between all links. Copy 2356 * this from the reporting section of the frame. 2357 */ 2358 if ((link_frame_maxsize - link_frame_currlen) < 2359 QDF_MAC_ADDR_SIZE) { 2360 mlo_err("Insufficient space in link specific frame for current AP address. Required: %u octets, available: %zu octets", 2361 QDF_MAC_ADDR_SIZE, 2362 (link_frame_maxsize - 2363 link_frame_currlen)); 2364 2365 ret = QDF_STATUS_E_NOMEM; 2366 goto mem_free; 2367 } 2368 2369 qdf_mem_copy(link_frame_currpos, 2370 frame + WLAN_CAPABILITYINFO_LEN + 2371 WLAN_LISTENINTERVAL_LEN, 2372 QDF_MAC_ADDR_SIZE); 2373 link_frame_currpos += QDF_MAC_ADDR_SIZE; 2374 link_frame_currlen += QDF_MAC_ADDR_SIZE; 2375 mlo_debug("Reassoc req: Added Current AP address field (%u octets) to link specific frame", 2376 QDF_MAC_ADDR_SIZE); 2377 } 2378 } else if (subtype == WLAN_FC0_STYPE_ASSOC_RESP || 2379 subtype == WLAN_FC0_STYPE_REASSOC_RESP) { 2380 /* This is a (re)association response */ 2381 mlo_debug("Populating fixed fields for (re)assoc resp in link specific frame"); 2382 2383 if (sta_prof_remlen < 2384 (WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN)) { 2385 mlo_err_rl("Remaining length of STA profile %zu octets is less than length of Capability Info + length of Status Code %u", 2386 sta_prof_remlen, 2387 WLAN_CAPABILITYINFO_LEN + 2388 WLAN_STATUSCODE_LEN); 2389 2390 ret = QDF_STATUS_E_PROTO; 2391 goto mem_free; 2392 } 2393 2394 /* Capability information and Status Code are specific to the 2395 * link. Copy these from the STA profile. 2396 */ 2397 2398 if ((link_frame_maxsize - link_frame_currlen) < 2399 (WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN)) { 2400 mlo_err("Insufficient space in link specific frame for Capability Info and Status Code fields. Required: %u octets, available: %zu octets", 2401 WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN, 2402 (link_frame_maxsize - link_frame_currlen)); 2403 2404 ret = QDF_STATUS_E_NOMEM; 2405 goto mem_free; 2406 2407 } 2408 2409 qdf_mem_copy(link_frame_currpos, sta_prof_currpos, 2410 (WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN)); 2411 link_frame_currpos += (WLAN_CAPABILITYINFO_LEN + 2412 WLAN_STATUSCODE_LEN); 2413 link_frame_currlen += (WLAN_CAPABILITYINFO_LEN + 2414 WLAN_STATUSCODE_LEN); 2415 mlo_debug("Added Capability Info and Status Code fields (%u octets) to link specific frame", 2416 WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN); 2417 2418 sta_prof_currpos += (WLAN_CAPABILITYINFO_LEN + 2419 WLAN_STATUSCODE_LEN); 2420 sta_prof_remlen -= (WLAN_CAPABILITYINFO_LEN + 2421 WLAN_STATUSCODE_LEN); 2422 2423 /* AID is common between all links. Copy this from the original 2424 * frame. 2425 */ 2426 2427 if ((link_frame_maxsize - link_frame_currlen) < WLAN_AID_LEN) { 2428 mlo_err("Insufficient space in link specific frame for AID field. Required: %u octets, available: %zu octets", 2429 WLAN_AID_LEN, 2430 (link_frame_maxsize - link_frame_currlen)); 2431 2432 ret = QDF_STATUS_E_NOMEM; 2433 goto mem_free; 2434 } 2435 2436 qdf_mem_copy(link_frame_currpos, 2437 frame + WLAN_CAPABILITYINFO_LEN + 2438 WLAN_STATUSCODE_LEN, 2439 WLAN_AID_LEN); 2440 link_frame_currpos += WLAN_AID_LEN; 2441 link_frame_currlen += WLAN_AID_LEN; 2442 mlo_debug("Added AID field (%u octets) to link specific frame", 2443 WLAN_AID_LEN); 2444 } else if (subtype == WLAN_FC0_STYPE_PROBE_RESP) { 2445 /* This is a probe response */ 2446 mlo_debug("Populating fixed fields for probe response in link specific frame"); 2447 2448 if ((link_frame_maxsize - link_frame_currlen) < 2449 WLAN_TIMESTAMP_LEN) { 2450 mlo_err("Insufficient space in link specific frame for Timestamp Info field. Required: %u octets, available: %zu octets", 2451 WLAN_TIMESTAMP_LEN, 2452 (link_frame_maxsize - link_frame_currlen)); 2453 2454 ret = QDF_STATUS_E_NOMEM; 2455 goto mem_free; 2456 } 2457 2458 /* Per spec 11be_D2.1.1, the TSF Offset subfield of the STA Info 2459 * field indicates the offset (Toffset)between the TSF timer of 2460 * the reported AP (TA) and the TSF timer of the reporting 2461 * AP (TB) and is encoded as a 2s complement signed integer 2462 * with units of 2 µs. Toffset is calculated as 2463 * Toffset= Floor((TA – TB)/2). 2464 */ 2465 if (is_tsfoffset_valid) 2466 tsf += tsfoffset * 2; 2467 2468 qdf_mem_copy(link_frame_currpos, &tsf, WLAN_TIMESTAMP_LEN); 2469 link_frame_currpos += WLAN_TIMESTAMP_LEN; 2470 link_frame_currlen += WLAN_TIMESTAMP_LEN; 2471 2472 if (!is_beaconinterval_valid) { 2473 mlo_err_rl("Beacon interval information not present in STA info field of per-STA profile"); 2474 ret = QDF_STATUS_E_PROTO; 2475 goto mem_free; 2476 } 2477 2478 /* Beacon Interval information copy this from 2479 * the STA info field. 2480 */ 2481 if ((link_frame_maxsize - link_frame_currlen) < 2482 WLAN_BEACONINTERVAL_LEN) { 2483 mlo_err("Insufficient space in link specific frame for Beacon Interval Info field. Required: %u octets, available: %zu octets", 2484 WLAN_BEACONINTERVAL_LEN, 2485 (link_frame_maxsize - link_frame_currlen)); 2486 2487 ret = QDF_STATUS_E_NOMEM; 2488 goto mem_free; 2489 } 2490 2491 qdf_mem_copy(link_frame_currpos, &beaconinterval, 2492 WLAN_BEACONINTERVAL_LEN); 2493 link_frame_currpos += WLAN_BEACONINTERVAL_LEN; 2494 link_frame_currlen += WLAN_BEACONINTERVAL_LEN; 2495 2496 if (sta_prof_remlen < WLAN_CAPABILITYINFO_LEN) { 2497 mlo_err_rl("Remaining length of STA profile %zu octets is less than length of Capability Info %u", 2498 sta_prof_remlen, 2499 WLAN_CAPABILITYINFO_LEN); 2500 2501 ret = QDF_STATUS_E_PROTO; 2502 goto mem_free; 2503 } 2504 2505 /* Capability information is specific to the link. Copy this 2506 * from the STA profile. 2507 */ 2508 2509 if ((link_frame_maxsize - link_frame_currlen) < 2510 WLAN_CAPABILITYINFO_LEN) { 2511 mlo_err("Insufficient space in link specific frame for Capability Info field. Required: %u octets, available: %zu octets", 2512 WLAN_CAPABILITYINFO_LEN, 2513 (link_frame_maxsize - link_frame_currlen)); 2514 2515 ret = QDF_STATUS_E_NOMEM; 2516 goto mem_free; 2517 } 2518 2519 qdf_mem_copy(link_frame_currpos, sta_prof_currpos, 2520 WLAN_CAPABILITYINFO_LEN); 2521 link_frame_currpos += WLAN_CAPABILITYINFO_LEN; 2522 link_frame_currlen += WLAN_CAPABILITYINFO_LEN; 2523 2524 sta_prof_currpos += WLAN_CAPABILITYINFO_LEN; 2525 sta_prof_remlen -= WLAN_CAPABILITYINFO_LEN; 2526 } 2527 2528 sta_prof_iesection = sta_prof_currpos; 2529 sta_prof_iesection_len = sta_prof_remlen; 2530 2531 /* Populate non-inheritance lists if applicable */ 2532 ninherit_elemlist_len = 0; 2533 ninherit_elemlist = NULL; 2534 ninherit_elemextlist_len = 0; 2535 ninherit_elemextlist = NULL; 2536 2537 ret = util_get_noninheritlists(sta_prof_iesection, 2538 sta_prof_iesection_len, 2539 &ninherit_elemlist, 2540 &ninherit_elemlist_len, 2541 &ninherit_elemextlist, 2542 &ninherit_elemextlist_len); 2543 if (QDF_IS_STATUS_ERROR(ret)) 2544 goto mem_free; 2545 2546 /* Go through IEs of the reporting STA, and those in STA profile, merge 2547 * them into link_frame (except for elements in the Non-Inheritance 2548 * list). 2549 * 2550 * Note: Currently, only 2-link MLO is supported here. We may have a 2551 * future change to expand to more links. 2552 */ 2553 reportingsta_ie = util_find_eid(WLAN_ELEMID_SSID, frame_iesection, 2554 frame_iesection_len); 2555 2556 if ((subtype == WLAN_FC0_STYPE_ASSOC_REQ) || 2557 (subtype == WLAN_FC0_STYPE_REASSOC_REQ) || 2558 (subtype == WLAN_FC0_STYPE_PROBE_RESP)) { 2559 /* Sanity check that the SSID element is present for the 2560 * reporting STA. There is no stipulation in the standard for 2561 * the STA profile in this regard, so we do not check the STA 2562 * profile for the SSID element. 2563 */ 2564 if (!reportingsta_ie) { 2565 mlo_err_rl("SSID element not found in reporting STA of the frame."); 2566 ret = QDF_STATUS_E_PROTO; 2567 goto mem_free; 2568 } 2569 } else { 2570 /* This is a (re)association response. Sanity check that the 2571 * SSID element is present neither for the reporting STA nor in 2572 * the STA profile. 2573 */ 2574 if (reportingsta_ie) { 2575 mlo_err_rl("SSID element found for reporting STA for (re)association response. It should not be present."); 2576 ret = QDF_STATUS_E_PROTO; 2577 goto mem_free; 2578 } 2579 2580 sta_prof_ie = util_find_eid(WLAN_ELEMID_SSID, 2581 sta_prof_iesection, 2582 sta_prof_iesection_len); 2583 2584 if (sta_prof_ie) { 2585 mlo_err_rl("SSID element found in STA profile for (re)association response. It should not be present."); 2586 ret = QDF_STATUS_E_PROTO; 2587 goto mem_free; 2588 } 2589 } 2590 2591 reportingsta_ie = reportingsta_ie ? reportingsta_ie : frame_iesection; 2592 2593 ret = util_validate_reportingsta_ie(reportingsta_ie, frame_iesection, 2594 frame_iesection_len); 2595 if (QDF_IS_STATUS_ERROR(ret)) 2596 goto mem_free; 2597 2598 reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] + MIN_IE_LEN; 2599 2600 while (((reportingsta_ie + reportingsta_ie_size) - frame_iesection) 2601 <= frame_iesection_len) { 2602 /* Skip Multi-Link element */ 2603 if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) && 2604 (reportingsta_ie[IDEXT_POS] == 2605 WLAN_EXTN_ELEMID_MULTI_LINK)) { 2606 if (((reportingsta_ie + reportingsta_ie_size) - 2607 frame_iesection) == frame_iesection_len) 2608 break; 2609 2610 /* Add BV ML IE for link specific probe response */ 2611 if (subtype == WLAN_FC0_STYPE_PROBE_RESP) { 2612 ret = util_add_mlie_for_prb_rsp_gen( 2613 reportingsta_ie, 2614 reportingsta_ie[TAG_LEN_POS], 2615 &link_frame_currpos, 2616 &link_frame_currlen, 2617 link_frame_maxsize, 2618 linkid); 2619 if (QDF_IS_STATUS_ERROR(ret)) 2620 goto mem_free; 2621 } 2622 reportingsta_ie += reportingsta_ie_size; 2623 2624 ret = util_validate_reportingsta_ie(reportingsta_ie, 2625 frame_iesection, 2626 frame_iesection_len); 2627 if (QDF_IS_STATUS_ERROR(ret)) 2628 goto mem_free; 2629 2630 reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] + 2631 MIN_IE_LEN; 2632 2633 continue; 2634 } 2635 2636 sta_prof_ie = NULL; 2637 sta_prof_ie_size = 0; 2638 2639 if (sta_prof_iesection_len) { 2640 if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 2641 sta_prof_ie = (uint8_t *)util_find_extn_eid(reportingsta_ie[ID_POS], 2642 reportingsta_ie[IDEXT_POS], 2643 sta_prof_iesection, 2644 sta_prof_iesection_len); 2645 } else { 2646 sta_prof_ie = (uint8_t *)util_find_eid(reportingsta_ie[ID_POS], 2647 sta_prof_iesection, 2648 sta_prof_iesection_len); 2649 } 2650 } 2651 2652 if (!sta_prof_ie) { 2653 /* IE is present for reporting STA, but not in STA 2654 * profile. 2655 */ 2656 2657 is_in_noninheritlist = false; 2658 2659 ret = util_eval_ie_in_noninheritlist((uint8_t *)reportingsta_ie, 2660 reportingsta_ie_size, 2661 ninherit_elemlist, 2662 ninherit_elemlist_len, 2663 ninherit_elemextlist, 2664 ninherit_elemextlist_len, 2665 &is_in_noninheritlist); 2666 2667 if (QDF_IS_STATUS_ERROR(ret)) 2668 goto mem_free; 2669 2670 if (!is_in_noninheritlist) { 2671 if ((link_frame_currpos + 2672 reportingsta_ie_size) <= 2673 (link_frame + link_frame_maxsize)) { 2674 qdf_mem_copy(link_frame_currpos, 2675 reportingsta_ie, 2676 reportingsta_ie_size); 2677 2678 link_frame_currpos += 2679 reportingsta_ie_size; 2680 link_frame_currlen += 2681 reportingsta_ie_size; 2682 2683 if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 2684 mlo_etrace_debug("IE with element ID : %u extension element ID : %u (%zu octets) present for reporting STA but not in STA profile. Copied IE from reporting frame to link specific frame", 2685 reportingsta_ie[ID_POS], 2686 reportingsta_ie[IDEXT_POS], 2687 reportingsta_ie_size); 2688 } else { 2689 mlo_etrace_debug("IE with element ID : %u (%zu octets) present for reporting STA but not in STA profile. Copied IE from reporting frame to link specific frame", 2690 reportingsta_ie[ID_POS], 2691 reportingsta_ie_size); 2692 } 2693 } else { 2694 if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 2695 mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets", 2696 reportingsta_ie[ID_POS], 2697 reportingsta_ie[IDEXT_POS], 2698 reportingsta_ie_size, 2699 link_frame_maxsize - 2700 link_frame_currlen); 2701 } else { 2702 mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets", 2703 reportingsta_ie[ID_POS], 2704 reportingsta_ie_size, 2705 link_frame_maxsize - 2706 link_frame_currlen); 2707 } 2708 2709 ret = QDF_STATUS_E_NOMEM; 2710 goto mem_free; 2711 } 2712 } else { 2713 if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 2714 mlo_etrace_debug("IE with element ID : %u extension element ID : %u (%zu octets) present for reporting STA but not in STA profile. However it is in Non-Inheritance list, hence ignoring.", 2715 reportingsta_ie[ID_POS], 2716 reportingsta_ie[IDEXT_POS], 2717 reportingsta_ie_size); 2718 } else { 2719 mlo_etrace_debug("IE with element ID : %u (%zu octets) present for reporting STA but not in STA profile. However it is in Non-Inheritance list, hence ignoring.", 2720 reportingsta_ie[ID_POS], 2721 reportingsta_ie_size); 2722 } 2723 } 2724 } else { 2725 /* IE is present for reporting STA and also in STA 2726 * profile, copy from STA profile and flag the IE in STA 2727 * profile as copied (by setting EID field to 0). The 2728 * SSID element (with EID 0) is processed first to 2729 * enable this. For vendor IE, compare OUI + type + 2730 * subType to determine if they are the same IE. 2731 */ 2732 /* Note: This may be revisited in a future change, to 2733 * adhere to provisions in the standard for multiple 2734 * occurrences of a given element ID/extension element 2735 * ID. 2736 */ 2737 2738 ret = util_validate_sta_prof_ie(sta_prof_ie, 2739 sta_prof_iesection, 2740 sta_prof_iesection_len); 2741 if (QDF_IS_STATUS_ERROR(ret)) 2742 goto mem_free; 2743 2744 sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] + 2745 MIN_IE_LEN; 2746 2747 sta_prof_iesection_remlen = 2748 sta_prof_iesection_len - 2749 (sta_prof_ie - sta_prof_iesection); 2750 2751 if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_VENDOR) && 2752 (sta_prof_iesection_remlen >= MIN_VENDOR_TAG_LEN)) { 2753 /* If Vendor IE also presents in STA profile, 2754 * then ignore the Vendor IE which is for 2755 * reporting STA. It only needs to copy Vendor 2756 * IE from STA profile to link specific frame. 2757 * The copy happens when going through the 2758 * remaining IEs. 2759 */ 2760 ; 2761 } else { 2762 /* Copy IE from STA profile into link specific 2763 * frame. 2764 */ 2765 if ((link_frame_currpos + sta_prof_ie_size) <= 2766 (link_frame + link_frame_maxsize)) { 2767 qdf_mem_copy(link_frame_currpos, 2768 sta_prof_ie, 2769 sta_prof_ie_size); 2770 2771 link_frame_currpos += sta_prof_ie_size; 2772 link_frame_currlen += 2773 sta_prof_ie_size; 2774 2775 if (reportingsta_ie[ID_POS] == 2776 WLAN_ELEMID_EXTN_ELEM) { 2777 mlo_etrace_debug("IE with element ID : %u extension element ID : %u (%zu octets) for reporting STA also present in STA profile. Copied IE from STA profile to link specific frame", 2778 sta_prof_ie[ID_POS], 2779 sta_prof_ie[IDEXT_POS], 2780 sta_prof_ie_size); 2781 } else { 2782 mlo_etrace_debug("IE with element ID : %u (%zu octets) for reporting STA also present in STA profile. Copied IE from STA profile to link specific frame", 2783 sta_prof_ie[ID_POS], 2784 sta_prof_ie_size); 2785 } 2786 2787 sta_prof_ie[0] = 0; 2788 } else { 2789 if (sta_prof_ie[ID_POS] == 2790 WLAN_ELEMID_EXTN_ELEM) { 2791 mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets", 2792 sta_prof_ie[ID_POS], 2793 sta_prof_ie[IDEXT_POS], 2794 sta_prof_ie_size, 2795 link_frame_maxsize - 2796 link_frame_currlen); 2797 } else { 2798 mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets", 2799 sta_prof_ie[ID_POS], 2800 sta_prof_ie_size, 2801 link_frame_maxsize - 2802 link_frame_currlen); 2803 } 2804 2805 ret = QDF_STATUS_E_NOMEM; 2806 goto mem_free; 2807 } 2808 } 2809 } 2810 2811 if (((reportingsta_ie + reportingsta_ie_size) - 2812 frame_iesection) == frame_iesection_len) 2813 break; 2814 2815 reportingsta_ie += reportingsta_ie_size; 2816 2817 ret = util_validate_reportingsta_ie(reportingsta_ie, 2818 frame_iesection, 2819 frame_iesection_len); 2820 if (QDF_IS_STATUS_ERROR(ret)) 2821 goto mem_free; 2822 2823 reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] + 2824 MIN_IE_LEN; 2825 } 2826 2827 /* Go through the remaining unprocessed IEs in STA profile and copy them 2828 * to the link specific frame. The processed ones are marked with 0 in 2829 * the first octet. The first octet corresponds to the element ID. In 2830 * the case of (re)association request, the element with actual ID 2831 * WLAN_ELEMID_SSID(0) has already been copied to the link specific 2832 * frame. In the case of (re)association response, it has been verified 2833 * that the element with actual ID WLAN_ELEMID_SSID(0) is present 2834 * neither for the reporting STA nor in the STA profile. 2835 */ 2836 sta_prof_iesection_currpos = sta_prof_iesection; 2837 sta_prof_iesection_remlen = sta_prof_iesection_len; 2838 2839 while (sta_prof_iesection_remlen > 0) { 2840 sta_prof_ie = sta_prof_iesection_currpos; 2841 ret = util_validate_sta_prof_ie(sta_prof_ie, 2842 sta_prof_iesection_currpos, 2843 sta_prof_iesection_remlen); 2844 if (QDF_IS_STATUS_ERROR(ret)) 2845 goto mem_free; 2846 2847 sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] + MIN_IE_LEN; 2848 2849 if (!sta_prof_ie[0]) { 2850 /* Skip this, since it has already been processed */ 2851 sta_prof_iesection_currpos += sta_prof_ie_size; 2852 sta_prof_iesection_remlen -= sta_prof_ie_size; 2853 continue; 2854 } 2855 2856 /* Copy IE from STA profile into link specific frame. */ 2857 if ((link_frame_currpos + sta_prof_ie_size) <= 2858 (link_frame + link_frame_maxsize)) { 2859 qdf_mem_copy(link_frame_currpos, 2860 sta_prof_ie, 2861 sta_prof_ie_size); 2862 2863 link_frame_currpos += sta_prof_ie_size; 2864 link_frame_currlen += 2865 sta_prof_ie_size; 2866 2867 if (reportingsta_ie[ID_POS] == 2868 WLAN_ELEMID_EXTN_ELEM) { 2869 mlo_etrace_debug("IE with element ID : %u extension element ID : %u (%zu octets) is present only in STA profile. Copied IE from STA profile to link specific frame", 2870 sta_prof_ie[ID_POS], 2871 sta_prof_ie[IDEXT_POS], 2872 sta_prof_ie_size); 2873 } else { 2874 mlo_etrace_debug("IE with element ID : %u (%zu octets) is present only in STA profile. Copied IE from STA profile to link specific frame", 2875 sta_prof_ie[ID_POS], 2876 sta_prof_ie_size); 2877 } 2878 2879 sta_prof_ie[0] = 0; 2880 } else { 2881 if (sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 2882 mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets", 2883 sta_prof_ie[ID_POS], 2884 sta_prof_ie[IDEXT_POS], 2885 sta_prof_ie_size, 2886 link_frame_maxsize - 2887 link_frame_currlen); 2888 } else { 2889 mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets", 2890 sta_prof_ie[ID_POS], 2891 sta_prof_ie_size, 2892 link_frame_maxsize - 2893 link_frame_currlen); 2894 } 2895 2896 ret = QDF_STATUS_E_NOMEM; 2897 goto mem_free; 2898 } 2899 2900 sta_prof_iesection_currpos += sta_prof_ie_size; 2901 sta_prof_iesection_remlen -= sta_prof_ie_size; 2902 } 2903 2904 /* Copy the link MAC addr */ 2905 link_frame_hdr = (struct wlan_frame_hdr *)link_frame; 2906 2907 if ((subtype == WLAN_FC0_STYPE_ASSOC_REQ) || 2908 (subtype == WLAN_FC0_STYPE_REASSOC_REQ)) { 2909 qdf_mem_copy(link_frame_hdr->i_addr3, &link_addr, 2910 QDF_MAC_ADDR_SIZE); 2911 qdf_mem_copy(link_frame_hdr->i_addr2, reportedmacaddr.bytes, 2912 QDF_MAC_ADDR_SIZE); 2913 qdf_mem_copy(link_frame_hdr->i_addr1, &link_addr, 2914 QDF_MAC_ADDR_SIZE); 2915 2916 link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_ASSOC_REQ_FC0; 2917 link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_ASSOC_REQ_FC1; 2918 } else if (subtype == WLAN_FC0_STYPE_PROBE_RESP) { 2919 qdf_mem_copy(link_frame_hdr->i_addr3, reportedmacaddr.bytes, 2920 QDF_MAC_ADDR_SIZE); 2921 qdf_mem_copy(link_frame_hdr->i_addr2, reportedmacaddr.bytes, 2922 QDF_MAC_ADDR_SIZE); 2923 qdf_mem_copy(link_frame_hdr->i_addr1, &link_addr, 2924 QDF_MAC_ADDR_SIZE); 2925 2926 link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_PROBE_RESP_FC0; 2927 link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_PROBE_RESP_FC1; 2928 } else { 2929 /* This is a (re)association response */ 2930 2931 qdf_mem_copy(link_frame_hdr->i_addr3, reportedmacaddr.bytes, 2932 QDF_MAC_ADDR_SIZE); 2933 qdf_mem_copy(link_frame_hdr->i_addr2, reportedmacaddr.bytes, 2934 QDF_MAC_ADDR_SIZE); 2935 qdf_mem_copy(link_frame_hdr->i_addr1, &link_addr, 2936 QDF_MAC_ADDR_SIZE); 2937 2938 link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_ASSOC_RESP_FC0; 2939 link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_ASSOC_RESP_FC1; 2940 } 2941 2942 mlo_debug("subtype:%u addr3:" QDF_MAC_ADDR_FMT " addr2:" 2943 QDF_MAC_ADDR_FMT " addr1:" QDF_MAC_ADDR_FMT, 2944 subtype, 2945 QDF_MAC_ADDR_REF(link_frame_hdr->i_addr3), 2946 QDF_MAC_ADDR_REF(link_frame_hdr->i_addr2), 2947 QDF_MAC_ADDR_REF(link_frame_hdr->i_addr1)); 2948 2949 /* Seq num not used so not populated */ 2950 2951 *link_frame_len = link_frame_currlen; 2952 ret = QDF_STATUS_SUCCESS; 2953 2954 mem_free: 2955 qdf_mem_free(mlieseqpayload_copy); 2956 return ret; 2957 } 2958 2959 QDF_STATUS 2960 util_gen_link_assoc_req(uint8_t *frame, qdf_size_t frame_len, bool isreassoc, 2961 uint8_t link_id, 2962 struct qdf_mac_addr link_addr, 2963 uint8_t *link_frame, 2964 qdf_size_t link_frame_maxsize, 2965 qdf_size_t *link_frame_len) 2966 { 2967 return util_gen_link_reqrsp_cmn(frame, frame_len, 2968 (isreassoc ? WLAN_FC0_STYPE_REASSOC_REQ : 2969 WLAN_FC0_STYPE_ASSOC_REQ), 2970 link_id, link_addr, link_frame, 2971 link_frame_maxsize, link_frame_len); 2972 } 2973 2974 QDF_STATUS 2975 util_gen_link_assoc_rsp(uint8_t *frame, qdf_size_t frame_len, bool isreassoc, 2976 uint8_t link_id, 2977 struct qdf_mac_addr link_addr, 2978 uint8_t *link_frame, 2979 qdf_size_t link_frame_maxsize, 2980 qdf_size_t *link_frame_len) 2981 { 2982 return util_gen_link_reqrsp_cmn(frame, frame_len, 2983 (isreassoc ? WLAN_FC0_STYPE_REASSOC_RESP : 2984 WLAN_FC0_STYPE_ASSOC_RESP), 2985 link_id, link_addr, link_frame, 2986 link_frame_maxsize, link_frame_len); 2987 } 2988 2989 QDF_STATUS 2990 util_gen_link_probe_rsp(uint8_t *frame, qdf_size_t frame_len, 2991 uint8_t link_id, 2992 struct qdf_mac_addr link_addr, 2993 uint8_t *link_frame, 2994 qdf_size_t link_frame_maxsize, 2995 qdf_size_t *link_frame_len) 2996 { 2997 return util_gen_link_reqrsp_cmn(frame, frame_len, 2998 WLAN_FC0_STYPE_PROBE_RESP, link_id, 2999 link_addr, link_frame, link_frame_maxsize, 3000 link_frame_len); 3001 } 3002 3003 QDF_STATUS 3004 util_find_mlie(uint8_t *buf, qdf_size_t buflen, uint8_t **mlieseq, 3005 qdf_size_t *mlieseqlen) 3006 { 3007 uint8_t *bufboundary; 3008 uint8_t *ieseq; 3009 qdf_size_t ieseqlen; 3010 uint8_t *currie; 3011 uint8_t *successorfrag; 3012 3013 if (!buf || !buflen || !mlieseq || !mlieseqlen) 3014 return QDF_STATUS_E_NULL_VALUE; 3015 3016 *mlieseq = NULL; 3017 *mlieseqlen = 0; 3018 3019 /* Find Multi-Link element. In case a fragment sequence is present, 3020 * this element will be the leading fragment. 3021 */ 3022 ieseq = util_find_extn_eid(WLAN_ELEMID_EXTN_ELEM, 3023 WLAN_EXTN_ELEMID_MULTI_LINK, buf, 3024 buflen); 3025 3026 /* Even if the element is not found, we have successfully examined the 3027 * buffer. The caller will be provided a NULL value for the starting of 3028 * the Multi-Link element. Hence, we return success. 3029 */ 3030 if (!ieseq) 3031 return QDF_STATUS_SUCCESS; 3032 3033 bufboundary = buf + buflen; 3034 3035 if ((ieseq + MIN_IE_LEN) > bufboundary) 3036 return QDF_STATUS_E_INVAL; 3037 3038 ieseqlen = MIN_IE_LEN + ieseq[TAG_LEN_POS]; 3039 3040 if (ieseqlen < sizeof(struct wlan_ie_multilink)) 3041 return QDF_STATUS_E_PROTO; 3042 3043 if ((ieseq + ieseqlen) > bufboundary) 3044 return QDF_STATUS_E_INVAL; 3045 3046 /* In the next sequence of checks, if there is no space in the buffer 3047 * for another element after the Multi-Link element/element fragment 3048 * sequence, it could indicate an issue since non-MLO EHT elements 3049 * would be expected to follow the Multi-Link element/element fragment 3050 * sequence. However, this is outside of the purview of this function, 3051 * hence we ignore it. 3052 */ 3053 3054 currie = ieseq; 3055 successorfrag = util_get_successorfrag(currie, buf, buflen); 3056 3057 /* Fragmentation definitions as of IEEE802.11be D1.0 and 3058 * IEEE802.11REVme D0.2 are applied. Only the case where Multi-Link 3059 * element is present in a buffer from the core frame is considered. 3060 * Future changes to fragmentation, cases where the Multi-Link element 3061 * is present in a subelement, etc. to be reflected here if applicable 3062 * as and when the rules evolve. 3063 */ 3064 while (successorfrag) { 3065 /* We should not be seeing a successor fragment if the length 3066 * of the current IE is lesser than the max. 3067 */ 3068 if (currie[TAG_LEN_POS] != WLAN_MAX_IE_LEN) 3069 return QDF_STATUS_E_PROTO; 3070 3071 if (successorfrag[TAG_LEN_POS] == 0) 3072 return QDF_STATUS_E_PROTO; 3073 3074 ieseqlen += (MIN_IE_LEN + successorfrag[TAG_LEN_POS]); 3075 3076 currie = successorfrag; 3077 successorfrag = util_get_successorfrag(currie, buf, buflen); 3078 } 3079 3080 *mlieseq = ieseq; 3081 *mlieseqlen = ieseqlen; 3082 return QDF_STATUS_SUCCESS; 3083 } 3084 3085 static inline QDF_STATUS 3086 util_validate_bv_mlie_min_seq_len(qdf_size_t mlieseqlen) 3087 { 3088 qdf_size_t parsed_len = sizeof(struct wlan_ie_multilink); 3089 3090 if (mlieseqlen < parsed_len + WLAN_ML_BV_CINFO_LENGTH_SIZE) { 3091 mlo_err_rl("ML seq payload of len %zu doesn't accommodate the mandatory BV ML IE Common info len field", 3092 mlieseqlen); 3093 return QDF_STATUS_E_PROTO; 3094 } 3095 parsed_len += WLAN_ML_BV_CINFO_LENGTH_SIZE; 3096 3097 if (mlieseqlen < parsed_len + QDF_MAC_ADDR_SIZE) { 3098 mlo_err_rl("ML seq payload of len %zu doesn't accommodate the mandatory MLD addr", 3099 mlieseqlen); 3100 return QDF_STATUS_E_PROTO; 3101 } 3102 3103 return QDF_STATUS_SUCCESS; 3104 } 3105 3106 QDF_STATUS 3107 util_find_mlie_by_variant(uint8_t *buf, qdf_size_t buflen, uint8_t **mlieseq, 3108 qdf_size_t *mlieseqlen, int variant) 3109 { 3110 uint8_t *ieseq; 3111 qdf_size_t ieseqlen; 3112 QDF_STATUS status; 3113 int ml_variant; 3114 qdf_size_t buf_parsed_len; 3115 3116 if (!buf || !buflen || !mlieseq || !mlieseqlen) 3117 return QDF_STATUS_E_NULL_VALUE; 3118 3119 if (variant >= WLAN_ML_VARIANT_INVALIDSTART) 3120 return QDF_STATUS_E_PROTO; 3121 3122 ieseq = NULL; 3123 ieseqlen = 0; 3124 *mlieseq = NULL; 3125 *mlieseqlen = 0; 3126 buf_parsed_len = 0; 3127 3128 while (buflen > buf_parsed_len) { 3129 status = util_find_mlie(buf + buf_parsed_len, 3130 buflen - buf_parsed_len, 3131 &ieseq, &ieseqlen); 3132 3133 if (QDF_IS_STATUS_ERROR(status)) 3134 return status; 3135 3136 /* Even if the element is not found, we have successfully 3137 * examined the buffer. The caller will be provided a NULL value 3138 * for the starting of the Multi-Link element. Hence, we return 3139 * success. 3140 */ 3141 if (!ieseq) 3142 return QDF_STATUS_SUCCESS; 3143 3144 status = util_get_mlie_variant(ieseq, ieseqlen, 3145 &ml_variant); 3146 if (QDF_IS_STATUS_ERROR(status)) { 3147 mlo_err("Unable to get Multi-link element variant"); 3148 return status; 3149 } 3150 3151 if (ml_variant == variant) { 3152 *mlieseq = ieseq; 3153 *mlieseqlen = ieseqlen; 3154 return QDF_STATUS_SUCCESS; 3155 } 3156 3157 buf_parsed_len = ieseq + ieseqlen - buf; 3158 } 3159 3160 return QDF_STATUS_E_INVAL; 3161 } 3162 3163 QDF_STATUS 3164 util_get_mlie_common_info_len(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3165 uint8_t *commoninfo_len) 3166 { 3167 struct wlan_ie_multilink *mlie_fixed; 3168 enum wlan_ml_variant variant; 3169 uint16_t mlcontrol; 3170 3171 if (!mlieseq || !mlieseqlen || !commoninfo_len) 3172 return QDF_STATUS_E_NULL_VALUE; 3173 3174 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3175 return QDF_STATUS_E_INVAL; 3176 3177 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3178 3179 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 3180 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) 3181 return QDF_STATUS_E_INVAL; 3182 3183 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3184 3185 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3186 WLAN_ML_CTRL_TYPE_BITS); 3187 3188 if (variant != WLAN_ML_VARIANT_BASIC) 3189 return QDF_STATUS_E_INVAL; 3190 3191 /* Common Info starts at mlieseq + sizeof(struct wlan_ie_multilink). 3192 * Check if there is sufficient space in the buffer for the Common Info 3193 * Length and MLD MAC address. 3194 */ 3195 if ((sizeof(struct wlan_ie_multilink) + WLAN_ML_BV_CINFO_LENGTH_SIZE + 3196 QDF_MAC_ADDR_SIZE) > mlieseqlen) 3197 return QDF_STATUS_E_PROTO; 3198 3199 *commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink)); 3200 3201 return QDF_STATUS_SUCCESS; 3202 } 3203 3204 QDF_STATUS 3205 util_get_bvmlie_bssparamchangecnt(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3206 bool *bssparamchangecntfound, 3207 uint8_t *bssparamchangecnt) 3208 { 3209 struct wlan_ie_multilink *mlie_fixed; 3210 enum wlan_ml_variant variant; 3211 uint16_t mlcontrol; 3212 uint16_t presencebitmap; 3213 uint8_t *commoninfo; 3214 uint8_t commoninfolen; 3215 qdf_size_t mldcap_offset; 3216 3217 if (!mlieseq || !mlieseqlen || !bssparamchangecntfound || 3218 !bssparamchangecnt) 3219 return QDF_STATUS_E_NULL_VALUE; 3220 3221 *bssparamchangecntfound = false; 3222 *bssparamchangecnt = 0; 3223 3224 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3225 return QDF_STATUS_E_INVAL; 3226 3227 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3228 3229 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 3230 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) 3231 return QDF_STATUS_E_INVAL; 3232 3233 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3234 3235 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3236 WLAN_ML_CTRL_TYPE_BITS); 3237 3238 if (variant != WLAN_ML_VARIANT_BASIC) 3239 return QDF_STATUS_E_NOSUPPORT; 3240 3241 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3242 WLAN_ML_CTRL_PBM_BITS); 3243 3244 if (QDF_IS_STATUS_ERROR(util_validate_bv_mlie_min_seq_len(mlieseqlen))) 3245 return QDF_STATUS_E_INVAL; 3246 3247 commoninfo = mlieseq + sizeof(struct wlan_ie_multilink); 3248 commoninfolen = *(mlieseq + sizeof(struct wlan_ie_multilink)); 3249 3250 mldcap_offset = WLAN_ML_BV_CINFO_LENGTH_SIZE; 3251 3252 mldcap_offset += QDF_MAC_ADDR_SIZE; 3253 3254 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) { 3255 mldcap_offset += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; 3256 3257 if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) > 3258 mlieseqlen) 3259 return QDF_STATUS_E_PROTO; 3260 } 3261 3262 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) { 3263 if (commoninfolen < (mldcap_offset + 3264 WLAN_ML_BSSPARAMCHNGCNT_SIZE)) 3265 return QDF_STATUS_E_PROTO; 3266 3267 if ((sizeof(struct wlan_ie_multilink) + mldcap_offset + 3268 WLAN_ML_BSSPARAMCHNGCNT_SIZE) > 3269 mlieseqlen) 3270 return QDF_STATUS_E_PROTO; 3271 *bssparamchangecntfound = true; 3272 *bssparamchangecnt = *(commoninfo + mldcap_offset); 3273 } 3274 3275 return QDF_STATUS_SUCCESS; 3276 } 3277 3278 QDF_STATUS 3279 util_get_mlie_variant(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3280 int *variant) 3281 { 3282 struct wlan_ie_multilink *mlie_fixed; 3283 enum wlan_ml_variant var; 3284 uint16_t mlcontrol; 3285 3286 if (!mlieseq || !mlieseqlen || !variant) 3287 return QDF_STATUS_E_NULL_VALUE; 3288 3289 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3290 return QDF_STATUS_E_INVAL; 3291 3292 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3293 3294 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3295 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) 3296 return QDF_STATUS_E_INVAL; 3297 3298 mlcontrol = le16toh(mlie_fixed->mlcontrol); 3299 var = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3300 WLAN_ML_CTRL_TYPE_BITS); 3301 3302 if (var >= WLAN_ML_VARIANT_INVALIDSTART) 3303 return QDF_STATUS_E_PROTO; 3304 3305 *variant = var; 3306 return QDF_STATUS_SUCCESS; 3307 } 3308 3309 QDF_STATUS 3310 util_get_bvmlie_eml_cap(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3311 bool *eml_cap_found, 3312 uint16_t *eml_cap) 3313 { 3314 struct wlan_ie_multilink *mlie_fixed; 3315 enum wlan_ml_variant variant; 3316 uint16_t mlcontrol; 3317 uint8_t eml_cap_offset; 3318 uint8_t commoninfo_len; 3319 uint16_t presencebitmap; 3320 3321 if (!mlieseq || !mlieseqlen || !eml_cap_found || !eml_cap) 3322 return QDF_STATUS_E_NULL_VALUE; 3323 3324 *eml_cap = 0; 3325 *eml_cap_found = false; 3326 3327 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3328 return QDF_STATUS_E_INVAL; 3329 3330 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3331 3332 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3333 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) 3334 return QDF_STATUS_E_INVAL; 3335 3336 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3337 3338 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3339 WLAN_ML_CTRL_TYPE_BITS); 3340 3341 if (variant != WLAN_ML_VARIANT_BASIC) 3342 return QDF_STATUS_E_INVAL; 3343 3344 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3345 WLAN_ML_CTRL_PBM_BITS); 3346 3347 /* eml_cap_offset stores the offset of EML Capabilities within 3348 * Common Info 3349 */ 3350 eml_cap_offset = WLAN_ML_BV_CINFO_LENGTH_SIZE + QDF_MAC_ADDR_SIZE; 3351 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) 3352 eml_cap_offset += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; 3353 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) 3354 eml_cap_offset += WLAN_ML_BSSPARAMCHNGCNT_SIZE; 3355 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P) 3356 eml_cap_offset += WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE; 3357 3358 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_EMLCAP_P) { 3359 /* Common Info starts at 3360 * mlieseq + sizeof(struct wlan_ie_multilink). 3361 * Check if there is sufficient space in the buffer for 3362 * the Common Info Length. 3363 */ 3364 if (mlieseqlen < (sizeof(struct wlan_ie_multilink) + 3365 WLAN_ML_BV_CINFO_LENGTH_SIZE)) 3366 return QDF_STATUS_E_PROTO; 3367 3368 /* Check if the value indicated in the Common Info Length 3369 * subfield is sufficient to access the EML capabilities. 3370 */ 3371 commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink)); 3372 if (commoninfo_len < (eml_cap_offset + 3373 WLAN_ML_BV_CINFO_EMLCAP_SIZE)) 3374 return QDF_STATUS_E_PROTO; 3375 3376 /* Common Info starts at mlieseq + sizeof(struct 3377 * wlan_ie_multilink). Check if there is sufficient space in 3378 * Common Info for the EML capability. 3379 */ 3380 if (mlieseqlen < (sizeof(struct wlan_ie_multilink) + 3381 eml_cap_offset + 3382 WLAN_ML_BV_CINFO_EMLCAP_SIZE)) 3383 return QDF_STATUS_E_PROTO; 3384 3385 *eml_cap_found = true; 3386 *eml_cap = qdf_le16_to_cpu(*(uint16_t *)(mlieseq + 3387 sizeof(struct wlan_ie_multilink) + 3388 eml_cap_offset)); 3389 } 3390 return QDF_STATUS_SUCCESS; 3391 } 3392 3393 QDF_STATUS 3394 util_get_bvmlie_msd_cap(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3395 bool *msd_cap_found, 3396 uint16_t *msd_cap) 3397 { 3398 struct wlan_ie_multilink *mlie_fixed; 3399 enum wlan_ml_variant variant; 3400 uint16_t mlcontrol; 3401 uint8_t msd_cap_offset; 3402 uint8_t commoninfo_len; 3403 uint16_t presencebitmap; 3404 3405 if (!mlieseq || !mlieseqlen || !msd_cap_found || !msd_cap) 3406 return QDF_STATUS_E_NULL_VALUE; 3407 3408 *msd_cap = 0; 3409 *msd_cap_found = false; 3410 3411 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3412 return QDF_STATUS_E_INVAL; 3413 3414 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3415 3416 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3417 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) 3418 return QDF_STATUS_E_INVAL; 3419 3420 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3421 3422 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3423 WLAN_ML_CTRL_TYPE_BITS); 3424 3425 if (variant != WLAN_ML_VARIANT_BASIC) 3426 return QDF_STATUS_E_INVAL; 3427 3428 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3429 WLAN_ML_CTRL_PBM_BITS); 3430 3431 /* msd_cap_offset stores the offset of MSD capabilities within 3432 * Common Info 3433 */ 3434 msd_cap_offset = WLAN_ML_BV_CINFO_LENGTH_SIZE + QDF_MAC_ADDR_SIZE; 3435 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) 3436 msd_cap_offset += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; 3437 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) 3438 msd_cap_offset += WLAN_ML_BSSPARAMCHNGCNT_SIZE; 3439 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P) { 3440 /* Common Info starts at 3441 * mlieseq + sizeof(struct wlan_ie_multilink). 3442 * Check if there is sufficient space in the buffer for 3443 * the Common Info Length. 3444 */ 3445 if (mlieseqlen < (sizeof(struct wlan_ie_multilink) + 3446 WLAN_ML_BV_CINFO_LENGTH_SIZE)) 3447 return QDF_STATUS_E_PROTO; 3448 3449 /* Check if the value indicated in the Common Info Length 3450 * subfield is sufficient to access the MSD capabilities. 3451 */ 3452 commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink)); 3453 if (commoninfo_len < (msd_cap_offset + 3454 WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE)) 3455 return QDF_STATUS_E_PROTO; 3456 3457 /* Common Info starts at mlieseq + sizeof(struct 3458 * wlan_ie_multilink). Check if there is sufficient space in 3459 * Common Info for the MSD capability. 3460 */ 3461 if (mlieseqlen < (sizeof(struct wlan_ie_multilink) + 3462 msd_cap_offset + 3463 WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE)) 3464 return QDF_STATUS_E_PROTO; 3465 3466 *msd_cap_found = true; 3467 *msd_cap = qdf_le16_to_cpu(*(uint16_t *)(mlieseq + 3468 sizeof(struct wlan_ie_multilink) + 3469 msd_cap_offset)); 3470 } else { 3471 mlo_debug("MSD caps not found in assoc rsp"); 3472 } 3473 3474 return QDF_STATUS_SUCCESS; 3475 } 3476 3477 QDF_STATUS 3478 util_get_bvmlie_mldmacaddr(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3479 struct qdf_mac_addr *mldmacaddr) 3480 { 3481 struct wlan_ie_multilink *mlie_fixed; 3482 enum wlan_ml_variant variant; 3483 uint16_t mlcontrol; 3484 uint8_t commoninfo_len; 3485 3486 if (!mlieseq || !mlieseqlen || !mldmacaddr) 3487 return QDF_STATUS_E_NULL_VALUE; 3488 3489 qdf_mem_zero(mldmacaddr, sizeof(*mldmacaddr)); 3490 3491 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3492 return QDF_STATUS_E_INVAL; 3493 3494 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3495 3496 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3497 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) 3498 return QDF_STATUS_E_INVAL; 3499 3500 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3501 3502 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3503 WLAN_ML_CTRL_TYPE_BITS); 3504 3505 if (variant != WLAN_ML_VARIANT_BASIC) 3506 return QDF_STATUS_E_INVAL; 3507 3508 /* Common Info starts at mlieseq + sizeof(struct wlan_ie_multilink). 3509 * Check if there is sufficient space in the buffer for the Common Info 3510 * Length and MLD MAC address. 3511 */ 3512 if ((sizeof(struct wlan_ie_multilink) + WLAN_ML_BV_CINFO_LENGTH_SIZE + 3513 QDF_MAC_ADDR_SIZE) > mlieseqlen) 3514 return QDF_STATUS_E_PROTO; 3515 3516 /* Check if the value indicated in the Common Info Length subfield is 3517 * sufficient to access the MLD MAC address. 3518 */ 3519 commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink)); 3520 if (commoninfo_len < (WLAN_ML_BV_CINFO_LENGTH_SIZE + QDF_MAC_ADDR_SIZE)) 3521 return QDF_STATUS_E_PROTO; 3522 3523 qdf_mem_copy(mldmacaddr->bytes, 3524 mlieseq + sizeof(struct wlan_ie_multilink) + 3525 WLAN_ML_BV_CINFO_LENGTH_SIZE, 3526 QDF_MAC_ADDR_SIZE); 3527 3528 return QDF_STATUS_SUCCESS; 3529 } 3530 3531 QDF_STATUS 3532 util_get_bvmlie_primary_linkid(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3533 bool *linkidfound, uint8_t *linkid) 3534 { 3535 struct wlan_ie_multilink *mlie_fixed; 3536 enum wlan_ml_variant variant; 3537 uint16_t mlcontrol; 3538 uint16_t presencebitmap; 3539 uint8_t *commoninfo; 3540 qdf_size_t commoninfolen; 3541 uint8_t *linkidinfo; 3542 3543 if (!mlieseq || !mlieseqlen || !linkidfound || !linkid) 3544 return QDF_STATUS_E_NULL_VALUE; 3545 3546 *linkidfound = false; 3547 *linkid = 0; 3548 3549 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3550 return QDF_STATUS_E_INVAL; 3551 3552 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3553 3554 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3555 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) 3556 return QDF_STATUS_E_INVAL; 3557 3558 mlcontrol = le16toh(mlie_fixed->mlcontrol); 3559 3560 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3561 WLAN_ML_CTRL_TYPE_BITS); 3562 3563 if (variant != WLAN_ML_VARIANT_BASIC) 3564 return QDF_STATUS_E_INVAL; 3565 3566 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3567 WLAN_ML_CTRL_PBM_BITS); 3568 3569 commoninfo = mlieseq + sizeof(struct wlan_ie_multilink); 3570 commoninfolen = 0; 3571 commoninfolen += WLAN_ML_BV_CINFO_LENGTH_SIZE; 3572 if ((sizeof(struct wlan_ie_multilink) + commoninfolen) > 3573 mlieseqlen) 3574 return QDF_STATUS_E_PROTO; 3575 3576 commoninfolen += QDF_MAC_ADDR_SIZE; 3577 if ((sizeof(struct wlan_ie_multilink) + commoninfolen) > 3578 mlieseqlen) 3579 return QDF_STATUS_E_PROTO; 3580 3581 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) { 3582 linkidinfo = commoninfo + commoninfolen; 3583 commoninfolen += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; 3584 3585 if ((sizeof(struct wlan_ie_multilink) + commoninfolen) > 3586 mlieseqlen) 3587 return QDF_STATUS_E_PROTO; 3588 3589 *linkidfound = true; 3590 *linkid = QDF_GET_BITS(linkidinfo[0], 3591 WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_IDX, 3592 WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_BITS); 3593 } 3594 3595 return QDF_STATUS_SUCCESS; 3596 } 3597 3598 QDF_STATUS 3599 util_get_bvmlie_mldcap(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3600 bool *mldcapfound, uint16_t *mldcap) 3601 { 3602 struct wlan_ie_multilink *mlie_fixed; 3603 enum wlan_ml_variant variant; 3604 uint16_t mlcontrol; 3605 uint16_t presencebitmap; 3606 uint8_t *commoninfo; 3607 uint8_t commoninfo_len; 3608 qdf_size_t mldcap_offset; 3609 3610 if (!mlieseq || !mlieseqlen || !mldcapfound || !mldcap) 3611 return QDF_STATUS_E_NULL_VALUE; 3612 3613 *mldcapfound = false; 3614 *mldcap = 0; 3615 3616 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3617 return QDF_STATUS_E_INVAL; 3618 3619 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3620 3621 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 3622 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) 3623 return QDF_STATUS_E_INVAL; 3624 3625 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3626 3627 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3628 WLAN_ML_CTRL_TYPE_BITS); 3629 3630 if (variant != WLAN_ML_VARIANT_BASIC) 3631 return QDF_STATUS_E_NOSUPPORT; 3632 3633 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3634 WLAN_ML_CTRL_PBM_BITS); 3635 3636 if (QDF_IS_STATUS_ERROR(util_validate_bv_mlie_min_seq_len(mlieseqlen))) 3637 return QDF_STATUS_E_INVAL; 3638 3639 commoninfo = mlieseq + sizeof(struct wlan_ie_multilink); 3640 commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink)); 3641 /* mldcap_offset stores the offset of MLD Capabilities within 3642 * Common Info 3643 */ 3644 mldcap_offset = WLAN_ML_BV_CINFO_LENGTH_SIZE; 3645 mldcap_offset += QDF_MAC_ADDR_SIZE; 3646 3647 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) { 3648 mldcap_offset += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; 3649 3650 if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) > 3651 mlieseqlen) 3652 return QDF_STATUS_E_PROTO; 3653 } 3654 3655 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) { 3656 mldcap_offset += WLAN_ML_BSSPARAMCHNGCNT_SIZE; 3657 3658 if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) > 3659 mlieseqlen) 3660 return QDF_STATUS_E_PROTO; 3661 } 3662 3663 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P) { 3664 mldcap_offset += WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE; 3665 3666 if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) > 3667 mlieseqlen) 3668 return QDF_STATUS_E_PROTO; 3669 } 3670 3671 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_EMLCAP_P) { 3672 mldcap_offset += WLAN_ML_BV_CINFO_EMLCAP_SIZE; 3673 3674 if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) > 3675 mlieseqlen) 3676 return QDF_STATUS_E_PROTO; 3677 } 3678 3679 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MLDCAPANDOP_P) { 3680 /* Check if the value indicated in the Common Info Length 3681 * subfield is sufficient to access the MLD capabilities. 3682 */ 3683 if (commoninfo_len < (mldcap_offset + 3684 WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE)) 3685 return QDF_STATUS_E_PROTO; 3686 3687 if ((sizeof(struct wlan_ie_multilink) + mldcap_offset + 3688 WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE) > 3689 mlieseqlen) 3690 return QDF_STATUS_E_PROTO; 3691 3692 *mldcap = qdf_le16_to_cpu(*((uint16_t *)(commoninfo + mldcap_offset))); 3693 *mldcapfound = true; 3694 } 3695 3696 return QDF_STATUS_SUCCESS; 3697 } 3698 3699 QDF_STATUS 3700 util_get_bvmlie_ext_mld_cap_op_info(uint8_t *mlie_seq, 3701 qdf_size_t mlie_seqlen, 3702 bool *ext_mld_cap_found, 3703 uint16_t *ext_mld_cap) 3704 { 3705 struct wlan_ie_multilink *mlie_fixed; 3706 uint16_t mlcontrol; 3707 enum wlan_ml_variant variant; 3708 uint16_t presence_bitmap; 3709 uint8_t *commoninfo; 3710 uint8_t commoninfo_len; 3711 qdf_size_t extmldcap_offset; 3712 3713 if (!mlie_seq || !mlie_seqlen || !ext_mld_cap_found || !ext_mld_cap) 3714 return QDF_STATUS_E_NULL_VALUE; 3715 3716 *ext_mld_cap_found = false; 3717 *ext_mld_cap = 0; 3718 3719 if (mlie_seqlen < sizeof(struct wlan_ie_multilink)) 3720 return QDF_STATUS_E_INVAL; 3721 3722 mlie_fixed = (struct wlan_ie_multilink *)mlie_seq; 3723 3724 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 3725 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) 3726 return QDF_STATUS_E_INVAL; 3727 3728 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3729 3730 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3731 WLAN_ML_CTRL_TYPE_BITS); 3732 3733 if (variant != WLAN_ML_VARIANT_BASIC) 3734 return QDF_STATUS_E_NOSUPPORT; 3735 3736 presence_bitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3737 WLAN_ML_CTRL_PBM_BITS); 3738 3739 commoninfo = mlie_seq + sizeof(struct wlan_ie_multilink); 3740 commoninfo_len = *(mlie_seq + sizeof(struct wlan_ie_multilink)); 3741 /* extmldcap_offset stores the offset of Ext MLD Capabilities and 3742 * operations within the Common Info 3743 */ 3744 3745 extmldcap_offset = WLAN_ML_BV_CINFO_LENGTH_SIZE; 3746 extmldcap_offset += QDF_MAC_ADDR_SIZE; 3747 3748 if (presence_bitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) { 3749 extmldcap_offset += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; 3750 3751 if ((sizeof(struct wlan_ie_multilink) + extmldcap_offset) > 3752 mlie_seqlen) 3753 return QDF_STATUS_E_PROTO; 3754 } 3755 3756 if (presence_bitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) { 3757 extmldcap_offset += WLAN_ML_BSSPARAMCHNGCNT_SIZE; 3758 3759 if ((sizeof(struct wlan_ie_multilink) + extmldcap_offset) > 3760 mlie_seqlen) 3761 return QDF_STATUS_E_PROTO; 3762 } 3763 3764 if (presence_bitmap & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P) { 3765 extmldcap_offset += WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE; 3766 3767 if ((sizeof(struct wlan_ie_multilink) + extmldcap_offset) > 3768 mlie_seqlen) 3769 return QDF_STATUS_E_PROTO; 3770 } 3771 3772 if (presence_bitmap & WLAN_ML_BV_CTRL_PBM_EMLCAP_P) { 3773 extmldcap_offset += WLAN_ML_BV_CINFO_EMLCAP_SIZE; 3774 3775 if ((sizeof(struct wlan_ie_multilink) + extmldcap_offset) > 3776 mlie_seqlen) 3777 return QDF_STATUS_E_PROTO; 3778 } 3779 3780 if (presence_bitmap & WLAN_ML_BV_CTRL_PBM_MLDCAPANDOP_P) { 3781 extmldcap_offset += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; 3782 3783 if ((sizeof(struct wlan_ie_multilink) + extmldcap_offset) > 3784 mlie_seqlen) 3785 return QDF_STATUS_E_PROTO; 3786 } 3787 3788 if (presence_bitmap & WLAN_ML_BV_CTRL_PBM_MLDID_P) { 3789 extmldcap_offset += WLAN_ML_BV_CINFO_MLDID_SIZE; 3790 3791 if ((sizeof(struct wlan_ie_multilink) + extmldcap_offset) > 3792 mlie_seqlen) 3793 return QDF_STATUS_E_PROTO; 3794 } 3795 3796 if (presence_bitmap & WLAN_ML_BV_CTRL_PBM_EXT_MLDCAPANDOP_P) { 3797 /* Check if the value indicated in the Common Info Length 3798 * subfield is sufficient to access the Ext MLD capabilities. 3799 */ 3800 if (commoninfo_len < (extmldcap_offset + 3801 WLAN_ML_BV_CINFO_EXT_MLDCAPANDOP_SIZE)) 3802 return QDF_STATUS_E_PROTO; 3803 3804 if ((sizeof(struct wlan_ie_multilink) + extmldcap_offset + 3805 WLAN_ML_BV_CINFO_EXT_MLDCAPANDOP_SIZE) > 3806 mlie_seqlen) 3807 return QDF_STATUS_E_PROTO; 3808 3809 *ext_mld_cap = qdf_le16_to_cpu(*((uint16_t *)(commoninfo + 3810 extmldcap_offset))); 3811 3812 *ext_mld_cap_found = true; 3813 } 3814 3815 return QDF_STATUS_SUCCESS; 3816 } 3817 3818 QDF_STATUS 3819 util_get_bvmlie_persta_partner_info(uint8_t *mlieseq, 3820 qdf_size_t mlieseqlen, 3821 struct mlo_partner_info *partner_info) 3822 { 3823 struct wlan_ie_multilink *mlie_fixed; 3824 uint16_t mlcontrol; 3825 enum wlan_ml_variant variant; 3826 uint8_t *linkinfo; 3827 qdf_size_t linkinfo_len; 3828 struct mlo_partner_info pinfo = {0}; 3829 qdf_size_t mlieseqpayloadlen; 3830 uint8_t *mlieseqpayload_copy; 3831 bool is_elemfragseq; 3832 qdf_size_t defragpayload_len; 3833 3834 qdf_size_t tmplen; 3835 QDF_STATUS ret; 3836 3837 if (!mlieseq) { 3838 mlo_err("Pointer to Multi-Link element sequence is NULL"); 3839 return QDF_STATUS_E_NULL_VALUE; 3840 } 3841 3842 if (!mlieseqlen) { 3843 mlo_err("Length of Multi-Link element sequence is zero"); 3844 return QDF_STATUS_E_INVAL; 3845 } 3846 3847 if (!partner_info) { 3848 mlo_err("partner_info is NULL"); 3849 return QDF_STATUS_E_NULL_VALUE; 3850 } 3851 3852 partner_info->num_partner_links = 0; 3853 3854 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) { 3855 mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)", 3856 mlieseqlen, sizeof(struct wlan_ie_multilink)); 3857 return QDF_STATUS_E_INVAL; 3858 } 3859 3860 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3861 3862 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3863 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) { 3864 mlo_err("The element is not a Multi-Link element"); 3865 return QDF_STATUS_E_INVAL; 3866 } 3867 3868 mlcontrol = le16toh(mlie_fixed->mlcontrol); 3869 3870 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3871 WLAN_ML_CTRL_TYPE_BITS); 3872 3873 if (variant != WLAN_ML_VARIANT_BASIC) { 3874 mlo_err("The variant value %u does not correspond to Basic Variant value %u", 3875 variant, WLAN_ML_VARIANT_BASIC); 3876 return QDF_STATUS_E_INVAL; 3877 } 3878 3879 mlieseqpayloadlen = 0; 3880 tmplen = 0; 3881 is_elemfragseq = false; 3882 3883 ret = wlan_get_elem_fragseq_info(mlieseq, 3884 mlieseqlen, 3885 &is_elemfragseq, 3886 &tmplen, 3887 &mlieseqpayloadlen); 3888 if (QDF_IS_STATUS_ERROR(ret)) 3889 return ret; 3890 3891 if (is_elemfragseq) { 3892 if (tmplen != mlieseqlen) { 3893 mlo_err_rl("Mismatch in values of element fragment sequence total length. Val per frag info determination: %zu octets, val passed as arg: %zu octets", 3894 tmplen, mlieseqlen); 3895 return QDF_STATUS_E_INVAL; 3896 } 3897 3898 if (!mlieseqpayloadlen) { 3899 mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate"); 3900 return QDF_STATUS_E_FAILURE; 3901 } 3902 3903 mlo_debug("Multi-Link element fragment sequence found with payload len %zu", 3904 mlieseqpayloadlen); 3905 } else { 3906 if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) { 3907 mlo_err_rl("Expected presence of valid fragment sequence since Multi-Link element sequence length %zu octets is larger than frag threshold of %zu octets, however no valid fragment sequence found", 3908 mlieseqlen, 3909 sizeof(struct ie_header) + WLAN_MAX_IE_LEN); 3910 return QDF_STATUS_E_FAILURE; 3911 } 3912 3913 mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1); 3914 } 3915 3916 mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen); 3917 3918 if (!mlieseqpayload_copy) { 3919 mlo_err_rl("Could not allocate memory for Multi-Link element payload copy"); 3920 return QDF_STATUS_E_NOMEM; 3921 } 3922 3923 if (is_elemfragseq) { 3924 ret = wlan_defrag_elem_fragseq(false, 3925 mlieseq, 3926 mlieseqlen, 3927 mlieseqpayload_copy, 3928 mlieseqpayloadlen, 3929 &defragpayload_len); 3930 if (QDF_IS_STATUS_ERROR(ret)) { 3931 qdf_mem_free(mlieseqpayload_copy); 3932 return ret; 3933 } 3934 3935 if (defragpayload_len != mlieseqpayloadlen) { 3936 mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets", 3937 defragpayload_len, mlieseqpayloadlen); 3938 qdf_mem_free(mlieseqpayload_copy); 3939 return QDF_STATUS_E_FAILURE; 3940 } 3941 } else { 3942 qdf_mem_copy(mlieseqpayload_copy, 3943 mlieseq + sizeof(struct ie_header) + 1, 3944 mlieseqpayloadlen); 3945 } 3946 3947 linkinfo = NULL; 3948 linkinfo_len = 0; 3949 3950 ret = util_parse_multi_link_ctrl(mlieseqpayload_copy, 3951 mlieseqpayloadlen, 3952 &linkinfo, 3953 &linkinfo_len); 3954 if (QDF_IS_STATUS_ERROR(ret)) { 3955 qdf_mem_free(mlieseqpayload_copy); 3956 return ret; 3957 } 3958 3959 /* 3960 * If Probe Request variant Multi-Link element in the Multi-Link probe 3961 * request does not include any per-STA profile, then all APs affiliated 3962 * with the same AP MLD as the AP identified in the Addr 1 or Addr 3 3963 * field or AP MLD ID of the Multi-Link probe request are requested 3964 * APs return success here 3965 */ 3966 if (!linkinfo) { 3967 qdf_mem_free(mlieseqpayload_copy); 3968 return QDF_STATUS_SUCCESS; 3969 } 3970 3971 ret = util_parse_partner_info_from_linkinfo(linkinfo, 3972 linkinfo_len, 3973 &pinfo); 3974 3975 if (QDF_IS_STATUS_ERROR(ret)) { 3976 qdf_mem_free(mlieseqpayload_copy); 3977 return ret; 3978 } 3979 3980 qdf_mem_copy(partner_info, &pinfo, sizeof(*partner_info)); 3981 3982 qdf_mem_free(mlieseqpayload_copy); 3983 3984 return QDF_STATUS_SUCCESS; 3985 } 3986 3987 QDF_STATUS 3988 util_get_prvmlie_persta_link_id(uint8_t *mlieseq, 3989 qdf_size_t mlieseqlen, 3990 struct mlo_probereq_info *probereq_info) 3991 { 3992 struct wlan_ie_multilink *mlie_fixed; 3993 uint16_t mlcontrol; 3994 enum wlan_ml_variant variant; 3995 uint8_t *linkinfo; 3996 qdf_size_t linkinfo_len; 3997 qdf_size_t mlieseqpayloadlen; 3998 uint8_t *mlieseqpayload_copy; 3999 bool is_elemfragseq; 4000 qdf_size_t defragpayload_len; 4001 4002 qdf_size_t tmplen; 4003 QDF_STATUS ret; 4004 4005 if (!mlieseq) { 4006 mlo_err("Pointer to Multi-Link element sequence is NULL"); 4007 return QDF_STATUS_E_NULL_VALUE; 4008 } 4009 4010 if (!mlieseqlen) { 4011 mlo_err("Length of Multi-Link element sequence is zero"); 4012 return QDF_STATUS_E_INVAL; 4013 } 4014 4015 if (!probereq_info) { 4016 mlo_err("probe request_info is NULL"); 4017 return QDF_STATUS_E_NULL_VALUE; 4018 } 4019 4020 probereq_info->num_links = 0; 4021 4022 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) { 4023 mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)", 4024 mlieseqlen, sizeof(struct wlan_ie_multilink)); 4025 return QDF_STATUS_E_INVAL; 4026 } 4027 4028 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 4029 4030 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 4031 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) { 4032 mlo_err("The element is not a Multi-Link element"); 4033 return QDF_STATUS_E_INVAL; 4034 } 4035 4036 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 4037 4038 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 4039 WLAN_ML_CTRL_TYPE_BITS); 4040 4041 if (variant != WLAN_ML_VARIANT_PROBEREQ) { 4042 mlo_err("The variant value %u does not correspond to Probe Request Variant value %u", 4043 variant, WLAN_ML_VARIANT_PROBEREQ); 4044 return QDF_STATUS_E_INVAL; 4045 } 4046 4047 mlieseqpayloadlen = 0; 4048 tmplen = 0; 4049 is_elemfragseq = false; 4050 4051 ret = wlan_get_elem_fragseq_info(mlieseq, 4052 mlieseqlen, 4053 &is_elemfragseq, 4054 &tmplen, 4055 &mlieseqpayloadlen); 4056 if (QDF_IS_STATUS_ERROR(ret)) 4057 return ret; 4058 4059 if (is_elemfragseq) { 4060 if (tmplen != mlieseqlen) { 4061 mlo_err_rl("Mismatch in values of element fragment sequence total length. Val per frag info determination: %zu octets, val passed as arg: %zu octets", 4062 tmplen, mlieseqlen); 4063 return QDF_STATUS_E_INVAL; 4064 } 4065 4066 if (!mlieseqpayloadlen) { 4067 mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate"); 4068 return QDF_STATUS_E_FAILURE; 4069 } 4070 4071 mlo_debug("Multi-Link element fragment sequence found with payload len %zu", 4072 mlieseqpayloadlen); 4073 } else { 4074 if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) { 4075 mlo_err_rl("Expected presence of valid fragment sequence since Multi-Link element sequence length %zu octets is larger than frag threshold of %zu octets, however no valid fragment sequence found", 4076 mlieseqlen, 4077 sizeof(struct ie_header) + WLAN_MAX_IE_LEN); 4078 return QDF_STATUS_E_FAILURE; 4079 } 4080 4081 mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1); 4082 } 4083 4084 mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen); 4085 4086 if (!mlieseqpayload_copy) { 4087 mlo_err_rl("Could not allocate memory for Multi-Link element payload copy"); 4088 return QDF_STATUS_E_NOMEM; 4089 } 4090 4091 if (is_elemfragseq) { 4092 ret = wlan_defrag_elem_fragseq(false, 4093 mlieseq, 4094 mlieseqlen, 4095 mlieseqpayload_copy, 4096 mlieseqpayloadlen, 4097 &defragpayload_len); 4098 if (QDF_IS_STATUS_ERROR(ret)) { 4099 qdf_mem_free(mlieseqpayload_copy); 4100 return ret; 4101 } 4102 4103 if (defragpayload_len != mlieseqpayloadlen) { 4104 mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets", 4105 defragpayload_len, mlieseqpayloadlen); 4106 qdf_mem_free(mlieseqpayload_copy); 4107 return QDF_STATUS_E_FAILURE; 4108 } 4109 } else { 4110 qdf_mem_copy(mlieseqpayload_copy, 4111 mlieseq + sizeof(struct ie_header) + 1, 4112 mlieseqpayloadlen); 4113 } 4114 4115 linkinfo = NULL; 4116 linkinfo_len = 0; 4117 ret = util_parse_prv_multi_link_ctrl(mlieseqpayload_copy, 4118 mlieseqpayloadlen, 4119 &linkinfo, 4120 &linkinfo_len); 4121 if (QDF_IS_STATUS_ERROR(ret)) { 4122 qdf_mem_free(mlieseqpayload_copy); 4123 return ret; 4124 } 4125 4126 /* In case Link Info is absent, the number of links will remain 4127 * zero. 4128 */ 4129 if (!linkinfo) { 4130 mlo_debug("No link info present"); 4131 qdf_mem_free(mlieseqpayload_copy); 4132 return QDF_STATUS_SUCCESS; 4133 } 4134 4135 ret = util_parse_probereq_info_from_linkinfo(linkinfo, 4136 linkinfo_len, 4137 probereq_info); 4138 4139 if (QDF_IS_STATUS_ERROR(ret)) { 4140 qdf_mem_free(mlieseqpayload_copy); 4141 return ret; 4142 } 4143 4144 qdf_mem_free(mlieseqpayload_copy); 4145 4146 return QDF_STATUS_SUCCESS; 4147 } 4148 4149 QDF_STATUS 4150 util_get_prvmlie_mldid(uint8_t *mlieseq, qdf_size_t mlieseqlen, 4151 bool *mldidfound, uint8_t *mldid) 4152 { 4153 struct wlan_ie_multilink *mlie_fixed; 4154 enum wlan_ml_variant variant; 4155 uint16_t mlcontrol; 4156 uint16_t presencebitmap; 4157 uint8_t *commoninfo; 4158 qdf_size_t commoninfolen; 4159 4160 if (!mlieseq || !mlieseqlen || !mldidfound || !mldid) 4161 return QDF_STATUS_E_NULL_VALUE; 4162 4163 *mldidfound = false; 4164 *mldid = 0; 4165 4166 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 4167 return QDF_STATUS_E_INVAL; 4168 4169 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 4170 4171 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 4172 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) 4173 return QDF_STATUS_E_INVAL; 4174 4175 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 4176 4177 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 4178 WLAN_ML_CTRL_TYPE_BITS); 4179 4180 if (variant != WLAN_ML_VARIANT_PROBEREQ) 4181 return QDF_STATUS_E_NOSUPPORT; 4182 4183 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 4184 WLAN_ML_CTRL_PBM_BITS); 4185 4186 commoninfo = mlieseq + sizeof(struct wlan_ie_multilink); 4187 commoninfolen = WLAN_ML_PRV_CINFO_LENGTH_SIZE; 4188 4189 if (presencebitmap & WLAN_ML_PRV_CTRL_PBM_MLDID_P) { 4190 if ((sizeof(struct wlan_ie_multilink) + commoninfolen + 4191 WLAN_ML_PRV_CINFO_MLDID_SIZE) > 4192 mlieseqlen) 4193 return QDF_STATUS_E_PROTO; 4194 4195 *mldid = *((uint8_t *)(commoninfo + commoninfolen)); 4196 commoninfolen += WLAN_ML_PRV_CINFO_MLDID_SIZE; 4197 4198 *mldidfound = true; 4199 } 4200 4201 return QDF_STATUS_SUCCESS; 4202 } 4203 4204 QDF_STATUS util_get_rvmlie_mldmacaddr(uint8_t *mlieseq, qdf_size_t mlieseqlen, 4205 struct qdf_mac_addr *mldmacaddr, 4206 bool *is_mldmacaddr_found) 4207 { 4208 struct wlan_ie_multilink *mlie_fixed; 4209 enum wlan_ml_variant variant; 4210 uint16_t mlcontrol; 4211 uint16_t presencebitmap; 4212 qdf_size_t rv_cinfo_len; 4213 4214 if (!mlieseq || !mlieseqlen || !mldmacaddr || !is_mldmacaddr_found) 4215 return QDF_STATUS_E_NULL_VALUE; 4216 4217 *is_mldmacaddr_found = false; 4218 qdf_mem_zero(mldmacaddr, sizeof(*mldmacaddr)); 4219 4220 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 4221 return QDF_STATUS_E_INVAL; 4222 4223 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 4224 4225 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 4226 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) 4227 return QDF_STATUS_E_INVAL; 4228 4229 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 4230 4231 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 4232 WLAN_ML_CTRL_TYPE_BITS); 4233 4234 if (variant != WLAN_ML_VARIANT_RECONFIG) 4235 return QDF_STATUS_E_INVAL; 4236 4237 /* ML Reconfig Common Info Length field present */ 4238 if ((sizeof(struct wlan_ie_multilink) + WLAN_ML_RV_CINFO_LENGTH_SIZE) > 4239 mlieseqlen) 4240 return QDF_STATUS_E_PROTO; 4241 4242 rv_cinfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink)); 4243 4244 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 4245 WLAN_ML_CTRL_PBM_BITS); 4246 4247 /* Check if MLD mac address is present */ 4248 if (presencebitmap & WLAN_ML_RV_CTRL_PBM_MLDMACADDR_P) { 4249 /* Check if the value indicated in the Common Info Length 4250 * subfield is sufficient to access the MLD MAC address. 4251 */ 4252 if (rv_cinfo_len < (WLAN_ML_RV_CINFO_LENGTH_SIZE + 4253 QDF_MAC_ADDR_SIZE)) 4254 return QDF_STATUS_E_PROTO; 4255 4256 if ((sizeof(struct wlan_ie_multilink) + 4257 WLAN_ML_RV_CINFO_LENGTH_SIZE + QDF_MAC_ADDR_SIZE) > 4258 mlieseqlen) 4259 return QDF_STATUS_E_PROTO; 4260 4261 qdf_mem_copy(mldmacaddr->bytes, 4262 mlieseq + sizeof(struct wlan_ie_multilink) + 4263 WLAN_ML_RV_CINFO_LENGTH_SIZE, 4264 QDF_MAC_ADDR_SIZE); 4265 *is_mldmacaddr_found = true; 4266 } 4267 4268 return QDF_STATUS_SUCCESS; 4269 } 4270 4271 static QDF_STATUS 4272 util_parse_rv_multi_link_ctrl(uint8_t *mlieseqpayload, 4273 qdf_size_t mlieseqpayloadlen, 4274 uint8_t **link_info, 4275 qdf_size_t *link_info_len) 4276 { 4277 qdf_size_t parsed_payload_len, rv_cinfo_len; 4278 uint16_t mlcontrol; 4279 uint16_t presence_bm; 4280 4281 /* This helper returns the location(s) and length(s) of (sub)field(s) 4282 * inferable after parsing the Multi Link element Control field. These 4283 * location(s) and length(s) is/are in reference to the payload section 4284 * of the Multi Link element (after defragmentation, if applicable). 4285 * Here, the payload is the point after the element ID extension of the 4286 * Multi Link element, and includes the payloads of all subsequent 4287 * fragments (if any) but not the headers of those fragments. 4288 * 4289 * Currently, the helper returns the location and length of the Link 4290 * Info field in the Multi Link element sequence. Other (sub)field(s) 4291 * can be added later as required. 4292 */ 4293 if (!mlieseqpayload) { 4294 mlo_err("ML seq payload pointer is NULL"); 4295 return QDF_STATUS_E_NULL_VALUE; 4296 } 4297 4298 if (!mlieseqpayloadlen) { 4299 mlo_err("ML seq payload len is 0"); 4300 return QDF_STATUS_E_INVAL; 4301 } 4302 4303 if (mlieseqpayloadlen < WLAN_ML_CTRL_SIZE) { 4304 mlo_err_rl("ML seq payload len %zu < ML Control size %u", 4305 mlieseqpayloadlen, WLAN_ML_CTRL_SIZE); 4306 return QDF_STATUS_E_PROTO; 4307 } 4308 4309 parsed_payload_len = 0; 4310 4311 qdf_mem_copy(&mlcontrol, mlieseqpayload, WLAN_ML_CTRL_SIZE); 4312 mlcontrol = qdf_le16_to_cpu(mlcontrol); 4313 parsed_payload_len += WLAN_ML_CTRL_SIZE; 4314 4315 if (mlieseqpayloadlen < 4316 (parsed_payload_len + WLAN_ML_RV_CINFO_LENGTH_SIZE)) { 4317 mlo_err_rl("ML rv seq payload len %zu insufficient for common info length size %u after parsed payload len %zu.", 4318 mlieseqpayloadlen, 4319 WLAN_ML_RV_CINFO_LENGTH_SIZE, 4320 parsed_payload_len); 4321 return QDF_STATUS_E_PROTO; 4322 } 4323 4324 rv_cinfo_len = *(mlieseqpayload + parsed_payload_len); 4325 parsed_payload_len += WLAN_ML_RV_CINFO_LENGTH_SIZE; 4326 4327 presence_bm = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 4328 WLAN_ML_CTRL_PBM_BITS); 4329 4330 /* Check if MLD MAC address is present */ 4331 if (presence_bm & WLAN_ML_RV_CTRL_PBM_MLDMACADDR_P) { 4332 /* Check if the value indicated in the Common Info Length 4333 * subfield is sufficient to access the MLD MAC address. 4334 * Note: In D3.0, MLD MAC address will not be present 4335 * in ML Reconfig IE. But for code completeness, we 4336 * should have below code to sanity check. 4337 */ 4338 if (rv_cinfo_len < (WLAN_ML_RV_CINFO_LENGTH_SIZE + 4339 QDF_MAC_ADDR_SIZE)) { 4340 mlo_err_rl("ML rv Common Info Length %zu insufficient to access MLD MAC addr size %u.", 4341 rv_cinfo_len, 4342 QDF_MAC_ADDR_SIZE); 4343 return QDF_STATUS_E_PROTO; 4344 } 4345 4346 if (mlieseqpayloadlen < 4347 (parsed_payload_len + 4348 QDF_MAC_ADDR_SIZE)) { 4349 mlo_err_rl("ML seq payload len %zu insufficient for MLD MAC size %u after parsed payload len %zu.", 4350 mlieseqpayloadlen, 4351 QDF_MAC_ADDR_SIZE, 4352 parsed_payload_len); 4353 return QDF_STATUS_E_PROTO; 4354 } 4355 4356 parsed_payload_len += QDF_MAC_ADDR_SIZE; 4357 } 4358 4359 /* At present, we only handle MAC address field in common info field. 4360 * To be compatible with future spec updating, if new items are added 4361 * to common info, below log will highlight the spec change. 4362 */ 4363 if (rv_cinfo_len != (parsed_payload_len - WLAN_ML_CTRL_SIZE)) 4364 mlo_debug_rl("ML rv seq common info len %zu doesn't match with expected common info len %zu", 4365 rv_cinfo_len, 4366 parsed_payload_len - WLAN_ML_CTRL_SIZE); 4367 4368 if (mlieseqpayloadlen < (WLAN_ML_CTRL_SIZE + rv_cinfo_len)) { 4369 mlo_err_rl("ML seq payload len %zu insufficient for rv link info after parsed mutli-link control %u and indicated Common Info length %zu", 4370 mlieseqpayloadlen, 4371 WLAN_ML_CTRL_SIZE, 4372 rv_cinfo_len); 4373 return QDF_STATUS_E_PROTO; 4374 } 4375 /* Update parsed_payload_len to reflect the actual bytes in common info 4376 * field to be compatible with future spec updating. 4377 */ 4378 parsed_payload_len = WLAN_ML_CTRL_SIZE + rv_cinfo_len; 4379 4380 if (link_info_len) { 4381 *link_info_len = mlieseqpayloadlen - parsed_payload_len; 4382 mlo_debug("link_info_len:%zu, parsed_payload_len:%zu, rv_cinfo_len %zu ", 4383 *link_info_len, parsed_payload_len, rv_cinfo_len); 4384 } 4385 4386 if (mlieseqpayloadlen == parsed_payload_len) { 4387 mlo_debug("No Link Info field present"); 4388 if (link_info) 4389 *link_info = NULL; 4390 4391 return QDF_STATUS_SUCCESS; 4392 } 4393 4394 if (link_info) 4395 *link_info = mlieseqpayload + parsed_payload_len; 4396 4397 return QDF_STATUS_SUCCESS; 4398 } 4399 4400 static QDF_STATUS 4401 util_parse_rvmlie_perstaprofile_stactrl(uint8_t *subelempayload, 4402 qdf_size_t subelempayloadlen, 4403 uint8_t *linkid, 4404 bool *is_macaddr_valid, 4405 struct qdf_mac_addr *macaddr, 4406 bool *is_ap_removal_timer_valid, 4407 uint16_t *ap_removal_timer) 4408 { 4409 qdf_size_t parsed_payload_len = 0, sta_info_len; 4410 qdf_size_t parsed_sta_info_len; 4411 uint16_t stacontrol; 4412 uint8_t completeprofile; 4413 4414 /* This helper returns the location(s) and where required, the length(s) 4415 * of (sub)field(s) inferable after parsing the STA Control field in the 4416 * per-STA profile subelement. These location(s) and length(s) is/are in 4417 * reference to the payload section of the per-STA profile subelement 4418 * (after defragmentation, if applicable). Here, the payload is the 4419 * point after the subelement length in the subelement, and includes the 4420 * payloads of all subsequent fragments (if any) but not the headers of 4421 * those fragments. 4422 * 4423 * Currently, the helper returns the link ID, MAC address, AP removal 4424 * timer and STA profile. More (sub)fields can be added when required. 4425 */ 4426 if (!subelempayload) { 4427 mlo_err("Pointer to subelement payload is NULL"); 4428 return QDF_STATUS_E_NULL_VALUE; 4429 } 4430 4431 if (!subelempayloadlen) { 4432 mlo_err("Length of subelement payload is zero"); 4433 return QDF_STATUS_E_INVAL; 4434 } 4435 4436 if (subelempayloadlen < WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_SIZE) { 4437 mlo_err_rl("Subelement payload length %zu octets is smaller than STA control field of per-STA profile subelement %u octets", 4438 subelempayloadlen, 4439 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_SIZE); 4440 return QDF_STATUS_E_PROTO; 4441 } 4442 4443 parsed_payload_len = 0; 4444 qdf_mem_copy(&stacontrol, 4445 subelempayload, 4446 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_SIZE); 4447 4448 stacontrol = qdf_le16_to_cpu(stacontrol); 4449 parsed_payload_len += WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_SIZE; 4450 4451 if (linkid) 4452 *linkid = QDF_GET_BITS(stacontrol, 4453 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_LINKID_IDX, 4454 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_LINKID_BITS); 4455 4456 /* Check if this a complete profile */ 4457 completeprofile = QDF_GET_BITS(stacontrol, 4458 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_IDX, 4459 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_BITS); 4460 4461 if (is_macaddr_valid) 4462 *is_macaddr_valid = false; 4463 if (subelempayloadlen < parsed_payload_len + 4464 WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE) { 4465 mlo_err_rl("Length of subelement payload %zu octets not sufficient for sta info length of size %u octets after parsed payload length of %zu octets.", 4466 subelempayloadlen, WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE, 4467 parsed_payload_len); 4468 return QDF_STATUS_E_PROTO; 4469 } 4470 4471 sta_info_len = *(subelempayload + parsed_payload_len); 4472 parsed_payload_len += WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE; 4473 parsed_sta_info_len = WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE; 4474 4475 /* Check STA MAC address present bit */ 4476 if (QDF_GET_BITS(stacontrol, 4477 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_STAMACADDRP_IDX, 4478 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_STAMACADDRP_BITS)) { 4479 if (sta_info_len < (parsed_sta_info_len + QDF_MAC_ADDR_SIZE)) { 4480 mlo_err_rl("Length of sta info len %zu octets not sufficient to contain MAC address of size %u octets after parsed sta info length of %zu octets.", 4481 sta_info_len, QDF_MAC_ADDR_SIZE, 4482 parsed_sta_info_len); 4483 return QDF_STATUS_E_PROTO; 4484 } 4485 4486 if (subelempayloadlen < 4487 (parsed_payload_len + QDF_MAC_ADDR_SIZE)) { 4488 mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain MAC address of size %u octets after parsed payload length of %zu octets.", 4489 subelempayloadlen, QDF_MAC_ADDR_SIZE, 4490 parsed_payload_len); 4491 return QDF_STATUS_E_PROTO; 4492 } 4493 4494 if (macaddr) { 4495 qdf_mem_copy(macaddr->bytes, 4496 subelempayload + parsed_payload_len, 4497 QDF_MAC_ADDR_SIZE); 4498 mlo_nofl_debug("Copied MAC address: " QDF_MAC_ADDR_FMT, 4499 QDF_MAC_ADDR_REF(macaddr->bytes)); 4500 4501 if (is_macaddr_valid) 4502 *is_macaddr_valid = true; 4503 } 4504 4505 parsed_payload_len += QDF_MAC_ADDR_SIZE; 4506 parsed_sta_info_len += QDF_MAC_ADDR_SIZE; 4507 } 4508 4509 /* Check AP Removal timer present bit */ 4510 if (QDF_GET_BITS(stacontrol, 4511 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_APREMOVALTIMERP_IDX, 4512 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_APREMOVALTIMERP_BITS)) { 4513 if (sta_info_len < 4514 (parsed_sta_info_len + 4515 WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_APREMOVALTIMER_SIZE)) { 4516 mlo_err_rl("Length of sta info len %zu octets not sufficient to contain AP removal timer of size %u octets after parsed sta info length of %zu octets.", 4517 sta_info_len, WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_APREMOVALTIMER_SIZE, 4518 parsed_sta_info_len); 4519 return QDF_STATUS_E_PROTO; 4520 } 4521 4522 if (subelempayloadlen < 4523 (parsed_payload_len + 4524 WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_APREMOVALTIMER_SIZE)) { 4525 mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain AP removal timer of size %u octets after parsed payload length of %zu octets.", 4526 subelempayloadlen, 4527 WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_APREMOVALTIMER_SIZE, 4528 parsed_payload_len); 4529 return QDF_STATUS_E_PROTO; 4530 } 4531 4532 if (ap_removal_timer) { 4533 qdf_mem_copy(ap_removal_timer, 4534 subelempayload + parsed_payload_len, 4535 WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_APREMOVALTIMER_SIZE); 4536 4537 if (is_ap_removal_timer_valid) 4538 *is_ap_removal_timer_valid = true; 4539 } 4540 4541 parsed_payload_len += 4542 WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_APREMOVALTIMER_SIZE; 4543 parsed_sta_info_len += WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_APREMOVALTIMER_SIZE; 4544 } 4545 /* At present, we only handle link MAC address field and ap removal 4546 * timer tbtt field parsing. To be compatible with future spec 4547 * updating, if new items are added to sta info, below log will 4548 * highlight the spec change. 4549 */ 4550 if (sta_info_len != (parsed_payload_len - 4551 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_SIZE)) 4552 mlo_debug_rl("Length of sta info len %zu octets not match parsed payload length of %zu octets.", 4553 sta_info_len, 4554 parsed_payload_len - 4555 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_SIZE); 4556 4557 return QDF_STATUS_SUCCESS; 4558 } 4559 4560 static QDF_STATUS 4561 util_parse_rv_info_from_linkinfo(uint8_t *linkinfo, 4562 qdf_size_t linkinfo_len, 4563 struct ml_rv_info *reconfig_info) 4564 { 4565 uint8_t linkid; 4566 uint8_t *linkinfo_currpos; 4567 qdf_size_t linkinfo_remlen; 4568 bool is_subelemfragseq; 4569 uint8_t subelemid; 4570 qdf_size_t subelemseqtotallen; 4571 qdf_size_t subelemseqpayloadlen; 4572 qdf_size_t defragpayload_len; 4573 QDF_STATUS ret; 4574 struct qdf_mac_addr mac_addr; 4575 bool is_macaddr_valid; 4576 bool is_ap_removal_timer_valid; 4577 uint16_t ap_removal_timer; 4578 4579 /* This helper function parses probe request info from the per-STA prof 4580 * present (if any) in the Link Info field in the payload of a Multi 4581 * Link element (after defragmentation if required). The caller should 4582 * pass a copy of the payload so that inline defragmentation of 4583 * subelements can be carried out if required. The subelement 4584 * defragmentation (if applicable) in this Control Path helper is 4585 * required for maintainability, accuracy and eliminating current and 4586 * future per-field-access multi-level fragment boundary checks and 4587 * adjustments, given the complex format of Multi Link elements. It is 4588 * also most likely to be required mainly at the client side. 4589 * Fragmentation is currently unlikely to be required for subelements 4590 * in Reconfiguration variant Multi-Link elements, but it should be 4591 * handled in order to be future ready. 4592 */ 4593 if (!linkinfo) { 4594 mlo_err("linkinfo is NULL"); 4595 return QDF_STATUS_E_NULL_VALUE; 4596 } 4597 4598 if (!linkinfo_len) { 4599 mlo_err("linkinfo_len is zero"); 4600 return QDF_STATUS_E_NULL_VALUE; 4601 } 4602 4603 if (!reconfig_info) { 4604 mlo_err("ML reconfig info is NULL"); 4605 return QDF_STATUS_E_NULL_VALUE; 4606 } 4607 4608 reconfig_info->num_links = 0; 4609 linkinfo_currpos = linkinfo; 4610 linkinfo_remlen = linkinfo_len; 4611 4612 while (linkinfo_remlen) { 4613 if (linkinfo_remlen < sizeof(struct subelem_header)) { 4614 mlo_err_rl("Remaining length in link info %zu octets is smaller than subelement header length %zu octets", 4615 linkinfo_remlen, 4616 sizeof(struct subelem_header)); 4617 return QDF_STATUS_E_PROTO; 4618 } 4619 4620 subelemid = linkinfo_currpos[ID_POS]; 4621 is_subelemfragseq = false; 4622 subelemseqtotallen = 0; 4623 subelemseqpayloadlen = 0; 4624 4625 ret = wlan_get_subelem_fragseq_info(WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 4626 linkinfo_currpos, 4627 linkinfo_remlen, 4628 &is_subelemfragseq, 4629 &subelemseqtotallen, 4630 &subelemseqpayloadlen); 4631 if (QDF_IS_STATUS_ERROR(ret)) 4632 return ret; 4633 4634 if (qdf_unlikely(is_subelemfragseq)) { 4635 if (!subelemseqpayloadlen) { 4636 mlo_err_rl("Subelement fragment sequence payload is reported as 0, investigate"); 4637 return QDF_STATUS_E_FAILURE; 4638 } 4639 4640 mlo_debug("Subelement fragment sequence found with payload len %zu", 4641 subelemseqpayloadlen); 4642 4643 ret = wlan_defrag_subelem_fragseq(true, 4644 WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 4645 linkinfo_currpos, 4646 linkinfo_remlen, 4647 NULL, 4648 0, 4649 &defragpayload_len); 4650 4651 if (QDF_IS_STATUS_ERROR(ret)) 4652 return ret; 4653 4654 if (defragpayload_len != subelemseqpayloadlen) { 4655 mlo_err_rl("Length of defragmented payload %zu octets is not equal to length of subelement fragment sequence payload %zu octets", 4656 defragpayload_len, 4657 subelemseqpayloadlen); 4658 return QDF_STATUS_E_FAILURE; 4659 } 4660 4661 /* Adjust linkinfo_remlen to reflect removal of all 4662 * subelement headers except the header of the lead 4663 * subelement. 4664 */ 4665 linkinfo_remlen -= (subelemseqtotallen - 4666 subelemseqpayloadlen - 4667 sizeof(struct subelem_header)); 4668 } else { 4669 if (linkinfo_remlen < 4670 (sizeof(struct subelem_header) + 4671 linkinfo_currpos[TAG_LEN_POS])) { 4672 mlo_err_rl("Remaining length in link info %zu octets is smaller than total size of current subelement %zu octets", 4673 linkinfo_remlen, 4674 sizeof(struct subelem_header) + 4675 linkinfo_currpos[TAG_LEN_POS]); 4676 return QDF_STATUS_E_PROTO; 4677 } 4678 4679 subelemseqpayloadlen = linkinfo_currpos[TAG_LEN_POS]; 4680 } 4681 4682 if (subelemid == WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE) { 4683 struct ml_rv_partner_link_info *link_info; 4684 is_macaddr_valid = false; 4685 is_ap_removal_timer_valid = false; 4686 ret = util_parse_rvmlie_perstaprofile_stactrl(linkinfo_currpos + 4687 sizeof(struct subelem_header), 4688 subelemseqpayloadlen, 4689 &linkid, 4690 &is_macaddr_valid, 4691 &mac_addr, 4692 &is_ap_removal_timer_valid, 4693 &ap_removal_timer); 4694 if (QDF_IS_STATUS_ERROR(ret)) 4695 return ret; 4696 if (reconfig_info->num_links >= 4697 WLAN_UMAC_MLO_MAX_VDEVS) { 4698 mlo_err("num_link %d invalid", 4699 reconfig_info->num_links); 4700 return QDF_STATUS_E_INVAL; 4701 } 4702 link_info = 4703 &reconfig_info->link_info[reconfig_info->num_links]; 4704 link_info->link_id = linkid; 4705 link_info->is_ap_removal_timer_p = is_ap_removal_timer_valid; 4706 if (is_macaddr_valid) 4707 qdf_copy_macaddr(&link_info->link_mac_addr, 4708 &mac_addr); 4709 4710 if (is_ap_removal_timer_valid) 4711 link_info->ap_removal_timer = ap_removal_timer; 4712 else 4713 mlo_warn_rl("AP removal timer not found in STA Info field of per-STA profile with link ID %u", 4714 linkid); 4715 4716 mlo_debug("Per-STA Profile Link ID: %u AP removal timer present: %d AP removal timer: %u", 4717 link_info->link_id, 4718 link_info->is_ap_removal_timer_p, 4719 link_info->ap_removal_timer); 4720 4721 reconfig_info->num_links++; 4722 } 4723 4724 linkinfo_remlen -= (sizeof(struct subelem_header) + 4725 subelemseqpayloadlen); 4726 linkinfo_currpos += (sizeof(struct subelem_header) + 4727 subelemseqpayloadlen); 4728 } 4729 4730 mlo_debug("Number of ML probe request links found=%u", 4731 reconfig_info->num_links); 4732 4733 return QDF_STATUS_SUCCESS; 4734 } 4735 4736 QDF_STATUS util_get_rvmlie_persta_link_info(uint8_t *mlieseq, 4737 qdf_size_t mlieseqlen, 4738 struct ml_rv_info *reconfig_info) 4739 { 4740 struct wlan_ie_multilink *mlie_fixed; 4741 uint16_t mlcontrol; 4742 enum wlan_ml_variant variant; 4743 uint8_t *linkinfo; 4744 qdf_size_t linkinfo_len; 4745 struct ml_rv_info rinfo = {0}; 4746 qdf_size_t mlieseqpayloadlen; 4747 uint8_t *mlieseqpayload_copy; 4748 bool is_elemfragseq; 4749 qdf_size_t defragpayload_len; 4750 qdf_size_t tmplen; 4751 QDF_STATUS ret; 4752 4753 if (!mlieseq) { 4754 mlo_err("Pointer to Multi-Link element sequence is NULL"); 4755 return QDF_STATUS_E_NULL_VALUE; 4756 } 4757 4758 if (!mlieseqlen) { 4759 mlo_err("Length of Multi-Link element sequence is zero"); 4760 return QDF_STATUS_E_INVAL; 4761 } 4762 4763 if (!reconfig_info) { 4764 mlo_err("reconfig_info is NULL"); 4765 return QDF_STATUS_E_NULL_VALUE; 4766 } 4767 4768 reconfig_info->num_links = 0; 4769 4770 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) { 4771 mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)", 4772 mlieseqlen, sizeof(struct wlan_ie_multilink)); 4773 return QDF_STATUS_E_INVAL; 4774 } 4775 4776 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 4777 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 4778 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) { 4779 mlo_err("The element is not a Multi-Link element"); 4780 return QDF_STATUS_E_INVAL; 4781 } 4782 4783 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 4784 4785 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 4786 WLAN_ML_CTRL_TYPE_BITS); 4787 4788 if (variant != WLAN_ML_VARIANT_RECONFIG) { 4789 mlo_err("The variant value %u does not correspond to Reconfig Variant value %u", 4790 variant, WLAN_ML_VARIANT_RECONFIG); 4791 return QDF_STATUS_E_INVAL; 4792 } 4793 4794 mlieseqpayloadlen = 0; 4795 tmplen = 0; 4796 is_elemfragseq = false; 4797 4798 ret = wlan_get_elem_fragseq_info(mlieseq, 4799 mlieseqlen, 4800 &is_elemfragseq, 4801 &tmplen, 4802 &mlieseqpayloadlen); 4803 4804 if (QDF_IS_STATUS_ERROR(ret)) 4805 return ret; 4806 4807 if (qdf_unlikely(is_elemfragseq)) { 4808 if (tmplen != mlieseqlen) { 4809 mlo_err_rl("Mismatch in values of element fragment sequence total length. Val per frag info determination: %zu octets, val passed as arg: %zu octets", 4810 tmplen, mlieseqlen); 4811 return QDF_STATUS_E_INVAL; 4812 } 4813 4814 if (!mlieseqpayloadlen) { 4815 mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate"); 4816 return QDF_STATUS_E_FAILURE; 4817 } 4818 4819 mlo_debug("Multi-Link element fragment sequence found with payload len %zu", 4820 mlieseqpayloadlen); 4821 } else { 4822 if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) { 4823 mlo_err_rl("Expected presence of valid fragment sequence since Multi-Link element sequence length %zu octets is larger than frag threshold of %zu octets, however no valid fragment sequence found", 4824 mlieseqlen, 4825 sizeof(struct ie_header) + WLAN_MAX_IE_LEN); 4826 return QDF_STATUS_E_FAILURE; 4827 } 4828 4829 mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1); 4830 } 4831 4832 mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen); 4833 4834 if (!mlieseqpayload_copy) { 4835 mlo_err_rl("Could not allocate memory for Multi-Link element payload copy"); 4836 return QDF_STATUS_E_NOMEM; 4837 } 4838 4839 if (qdf_unlikely(is_elemfragseq)) { 4840 ret = wlan_defrag_elem_fragseq(false, 4841 mlieseq, 4842 mlieseqlen, 4843 mlieseqpayload_copy, 4844 mlieseqpayloadlen, 4845 &defragpayload_len); 4846 if (QDF_IS_STATUS_ERROR(ret)) { 4847 qdf_mem_free(mlieseqpayload_copy); 4848 return ret; 4849 } 4850 4851 if (defragpayload_len != mlieseqpayloadlen) { 4852 mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets", 4853 defragpayload_len, mlieseqpayloadlen); 4854 qdf_mem_free(mlieseqpayload_copy); 4855 return QDF_STATUS_E_FAILURE; 4856 } 4857 } else { 4858 qdf_mem_copy(mlieseqpayload_copy, 4859 mlieseq + sizeof(struct ie_header) + 1, 4860 mlieseqpayloadlen); 4861 } 4862 4863 linkinfo = NULL; 4864 linkinfo_len = 0; 4865 4866 ret = util_parse_rv_multi_link_ctrl(mlieseqpayload_copy, 4867 mlieseqpayloadlen, 4868 &linkinfo, 4869 &linkinfo_len); 4870 if (QDF_IS_STATUS_ERROR(ret)) { 4871 qdf_mem_free(mlieseqpayload_copy); 4872 return ret; 4873 } 4874 4875 /* In case Link Info is absent, the number of links will remain 4876 * zero. 4877 */ 4878 if (!linkinfo) { 4879 qdf_mem_free(mlieseqpayload_copy); 4880 return QDF_STATUS_SUCCESS; 4881 } 4882 4883 ret = util_parse_rv_info_from_linkinfo(linkinfo, linkinfo_len, &rinfo); 4884 if (QDF_IS_STATUS_ERROR(ret)) { 4885 qdf_mem_free(mlieseqpayload_copy); 4886 return ret; 4887 } 4888 4889 qdf_mem_copy(reconfig_info, &rinfo, sizeof(*reconfig_info)); 4890 qdf_mem_free(mlieseqpayload_copy); 4891 4892 return QDF_STATUS_SUCCESS; 4893 } 4894 4895 static QDF_STATUS 4896 util_parse_pa_multi_link_ctrl(uint8_t *mlieseqpayload, 4897 qdf_size_t mlieseqpayloadlen, 4898 uint8_t **link_info, 4899 qdf_size_t *link_info_len) 4900 { 4901 qdf_size_t parsed_payload_len; 4902 4903 /* This helper returns the location(s) and length(s) of (sub)field(s) 4904 * inferable after parsing the Multi Link element Control field. These 4905 * location(s) and length(s) is/are in reference to the payload section 4906 * of the Multi Link element (after defragmentation, if applicable). 4907 * Here, the payload is the point after the element ID extension of the 4908 * Multi Link element, and includes the payloads of all subsequent 4909 * fragments (if any) but not the headers of those fragments. 4910 * 4911 * Currently, the helper returns the location and length of the Link 4912 * Info field in the Multi Link element sequence. Other (sub)field(s) 4913 * can be added later as required. 4914 */ 4915 if (!mlieseqpayload) { 4916 mlo_err("ML seq payload pointer is NULL"); 4917 return QDF_STATUS_E_NULL_VALUE; 4918 } 4919 4920 if (!mlieseqpayloadlen) { 4921 mlo_err("ML seq payload len is 0"); 4922 return QDF_STATUS_E_INVAL; 4923 } 4924 4925 if (mlieseqpayloadlen < WLAN_ML_CTRL_SIZE) { 4926 mlo_err_rl("ML seq payload len %zu < ML Control size %u", 4927 mlieseqpayloadlen, WLAN_ML_CTRL_SIZE); 4928 return QDF_STATUS_E_PROTO; 4929 } 4930 4931 parsed_payload_len = 0; 4932 4933 parsed_payload_len += WLAN_ML_CTRL_SIZE; 4934 4935 if (mlieseqpayloadlen < 4936 (parsed_payload_len + 4937 WLAN_ML_PAV_CINFO_LENGTH_MAX)) { 4938 mlo_err_rl("ML seq payload len %zu insufficient for MLD cmn size %u after parsed payload len %zu.", 4939 mlieseqpayloadlen, 4940 WLAN_ML_PAV_CINFO_LENGTH_MAX, 4941 parsed_payload_len); 4942 return QDF_STATUS_E_PROTO; 4943 } 4944 4945 parsed_payload_len += QDF_MAC_ADDR_SIZE + WLAN_ML_PAV_CINFO_LENGTH_SIZE; 4946 4947 if (link_info_len) { 4948 *link_info_len = mlieseqpayloadlen - parsed_payload_len; 4949 mlo_debug("link_info_len:%zu, parsed_payload_len:%zu", 4950 *link_info_len, parsed_payload_len); 4951 } 4952 4953 if (mlieseqpayloadlen == parsed_payload_len) { 4954 mlo_debug("No Link Info field present"); 4955 if (link_info) 4956 *link_info = NULL; 4957 4958 return QDF_STATUS_SUCCESS; 4959 } 4960 4961 if (link_info) 4962 *link_info = mlieseqpayload + parsed_payload_len; 4963 4964 return QDF_STATUS_SUCCESS; 4965 } 4966 4967 static QDF_STATUS 4968 util_parse_pamlie_perstaprofile_stactrl(uint8_t *subelempayload, 4969 qdf_size_t subelempayloadlen, 4970 struct ml_pa_partner_link_info *pa_link_info) 4971 { 4972 qdf_size_t parsed_payload_len = 0; 4973 uint16_t stacontrol; 4974 struct ie_header *ie; 4975 struct extn_ie_header *extn_ie; 4976 4977 /* This helper returns the location(s) and where required, the length(s) 4978 * of (sub)field(s) inferable after parsing the STA Control field in the 4979 * per-STA profile subelement. These location(s) and length(s) is/are in 4980 * reference to the payload section of the per-STA profile subelement 4981 * (after defragmentation, if applicable). Here, the payload is the 4982 * point after the subelement length in the subelement, and includes the 4983 * payloads of all subsequent fragments (if any) but not the headers of 4984 * those fragments. 4985 * 4986 * Currently, the helper returns the priority access link information 4987 * for all parner links. 4988 */ 4989 if (!subelempayload) { 4990 mlo_err("Pointer to subelement payload is NULL"); 4991 return QDF_STATUS_E_NULL_VALUE; 4992 } 4993 4994 if (!subelempayloadlen) { 4995 mlo_err("Length of subelement payload is zero"); 4996 return QDF_STATUS_E_INVAL; 4997 } 4998 4999 if (subelempayloadlen < WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_SIZE) { 5000 mlo_err_rl("Subelement payload length %zu octets is smaller than STA control field of per-STA profile subelement %u octets", 5001 subelempayloadlen, 5002 WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_SIZE); 5003 return QDF_STATUS_E_PROTO; 5004 } 5005 5006 parsed_payload_len = 0; 5007 qdf_mem_copy(&stacontrol, 5008 subelempayload, 5009 WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_SIZE); 5010 5011 stacontrol = qdf_le16_to_cpu(stacontrol); 5012 parsed_payload_len += WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_SIZE; 5013 5014 subelempayload += WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_SIZE; 5015 5016 pa_link_info->link_id = 5017 QDF_GET_BITS(stacontrol, 5018 WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_LINKID_IDX, 5019 WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_LINKID_BITS); 5020 5021 pa_link_info->edca_ie_present = false; 5022 pa_link_info->ven_wme_ie_present = false; 5023 pa_link_info->muedca_ie_present = false; 5024 5025 do { 5026 if (subelempayloadlen < 5027 (parsed_payload_len + 5028 sizeof(struct ie_header))) { 5029 mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain min ie length %zu after parsed payload length of %zu octets", 5030 subelempayloadlen, 5031 sizeof(struct ie_header), 5032 parsed_payload_len); 5033 return QDF_STATUS_E_PROTO; 5034 } 5035 5036 ie = (struct ie_header *)subelempayload; 5037 5038 if (subelempayloadlen < 5039 (parsed_payload_len + 5040 (sizeof(struct ie_header) + ie->ie_len))) { 5041 mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain ie length %zu after parsed payload length of %zu octets", 5042 subelempayloadlen, 5043 sizeof(struct ie_header) + ie->ie_len, 5044 parsed_payload_len); 5045 return QDF_STATUS_E_PROTO; 5046 } 5047 5048 switch (ie->ie_id) { 5049 case WLAN_ELEMID_EDCAPARMS: 5050 if (pa_link_info->ven_wme_ie_present) { 5051 /* WME parameters already present 5052 * use that one instead of EDCA */ 5053 break; 5054 } 5055 if (ie->ie_len == (sizeof(struct edca_ie) - 5056 sizeof(struct ie_header))) { 5057 pa_link_info->edca_ie_present = true; 5058 qdf_mem_copy(&pa_link_info->edca, 5059 subelempayload, 5060 sizeof(struct edca_ie)); 5061 } else { 5062 epcs_debug("Invalid edca length %d in PAV IE", 5063 ie->ie_len); 5064 } 5065 break; 5066 case WLAN_ELEMID_VENDOR: 5067 if (is_wme_param((uint8_t *)ie) && 5068 (ie->ie_len == WLAN_VENDOR_WME_IE_LEN)) { 5069 pa_link_info->ven_wme_ie_present = true; 5070 qdf_mem_copy(&pa_link_info->ven_wme_ie_bytes, 5071 subelempayload, 5072 sizeof(WLAN_VENDOR_WME_IE_LEN + 5073 sizeof(struct ie_header))); 5074 pa_link_info->edca_ie_present = false; 5075 } else { 5076 epcs_debug("Unrelated Venfor IE reecived ie_id %d ie_len %d", 5077 ie->ie_id, 5078 ie->ie_len); 5079 } 5080 break; 5081 case WLAN_ELEMID_EXTN_ELEM: 5082 extn_ie = (struct extn_ie_header *)ie; 5083 switch (extn_ie->ie_extn_id) { 5084 case WLAN_EXTN_ELEMID_MUEDCA: 5085 if (extn_ie->ie_len == WLAN_MAX_MUEDCA_IE_LEN) { 5086 pa_link_info->muedca_ie_present = true; 5087 qdf_mem_copy(&pa_link_info->muedca, 5088 subelempayload, 5089 sizeof(struct muedca_ie)); 5090 } else { 5091 epcs_debug("Invalid muedca length %d in PAV IE", 5092 ie->ie_len); 5093 } 5094 break; 5095 default: 5096 epcs_debug("Unrelated Extn IE reecived ie_id %d ie_len %d extid %d IN PAV IE", 5097 ie->ie_id, 5098 ie->ie_len, 5099 extn_ie->ie_extn_id); 5100 break; 5101 } 5102 break; 5103 default: 5104 epcs_debug("Unrelated IE reecived ie_id %d ie_len %d in PAV IE", 5105 ie->ie_id, 5106 ie->ie_len); 5107 break; 5108 } 5109 subelempayload += ie->ie_len + sizeof(struct ie_header); 5110 parsed_payload_len += ie->ie_len + sizeof(struct ie_header); 5111 } while (parsed_payload_len < subelempayloadlen); 5112 5113 if (parsed_payload_len != subelempayloadlen) 5114 epcs_debug("Error in processing per sta profile of PA ML IE %zu %zu", 5115 parsed_payload_len, 5116 subelempayloadlen); 5117 5118 epcs_debug("Link id %d presence of edca %d muedca %d wme %d", 5119 pa_link_info->link_id, 5120 pa_link_info->edca_ie_present, 5121 pa_link_info->muedca_ie_present, 5122 pa_link_info->ven_wme_ie_present); 5123 5124 return QDF_STATUS_SUCCESS; 5125 } 5126 5127 static QDF_STATUS 5128 util_parse_pa_info_from_linkinfo(uint8_t *linkinfo, 5129 qdf_size_t linkinfo_len, 5130 struct ml_pa_info *pa_info) 5131 { 5132 uint8_t *linkinfo_currpos; 5133 qdf_size_t linkinfo_remlen; 5134 bool is_subelemfragseq; 5135 uint8_t subelemid; 5136 qdf_size_t subelemseqtotallen; 5137 qdf_size_t subelemseqpayloadlen; 5138 qdf_size_t defragpayload_len; 5139 QDF_STATUS ret; 5140 5141 /* This helper function parses priority access info from the per-STA 5142 * prof present (if any) in the Link Info field in the payload of a 5143 * Multi Link element (after defragmentation if required). The caller 5144 * should pass a copy of the payload so that inline defragmentation of 5145 * subelements can be carried out if required. The subelement 5146 * defragmentation (if applicable) in this Control Path helper is 5147 * required for maintainability, accuracy and eliminating current and 5148 * future per-field-access multi-level fragment boundary checks and 5149 * adjustments, given the complex format of Multi Link elements. It is 5150 * also most likely to be required mainly at the client side. 5151 * Fragmentation is currently unlikely to be required for subelements 5152 * in Reconfiguration variant Multi-Link elements, but it should be 5153 * handled in order to be future ready. 5154 */ 5155 if (!linkinfo) { 5156 mlo_err("linkinfo is NULL"); 5157 return QDF_STATUS_E_NULL_VALUE; 5158 } 5159 5160 if (!linkinfo_len) { 5161 mlo_err("linkinfo_len is zero"); 5162 return QDF_STATUS_E_NULL_VALUE; 5163 } 5164 5165 if (!pa_info) { 5166 mlo_err("ML pa info is NULL"); 5167 return QDF_STATUS_E_NULL_VALUE; 5168 } 5169 5170 pa_info->num_links = 0; 5171 linkinfo_currpos = linkinfo; 5172 linkinfo_remlen = linkinfo_len; 5173 5174 while (linkinfo_remlen) { 5175 if (linkinfo_remlen < sizeof(struct subelem_header)) { 5176 mlo_err_rl("Remaining length in link info %zu octets is smaller than subelement header length %zu octets", 5177 linkinfo_remlen, 5178 sizeof(struct subelem_header)); 5179 return QDF_STATUS_E_PROTO; 5180 } 5181 5182 subelemid = linkinfo_currpos[ID_POS]; 5183 is_subelemfragseq = false; 5184 subelemseqtotallen = 0; 5185 subelemseqpayloadlen = 0; 5186 5187 ret = wlan_get_subelem_fragseq_info(WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 5188 linkinfo_currpos, 5189 linkinfo_remlen, 5190 &is_subelemfragseq, 5191 &subelemseqtotallen, 5192 &subelemseqpayloadlen); 5193 if (QDF_IS_STATUS_ERROR(ret)) 5194 return ret; 5195 5196 if (qdf_unlikely(is_subelemfragseq)) { 5197 if (!subelemseqpayloadlen) { 5198 mlo_err_rl("Subelement fragment sequence payload is reported as 0, investigate"); 5199 return QDF_STATUS_E_FAILURE; 5200 } 5201 5202 mlo_debug("Subelement fragment sequence found with payload len %zu", 5203 subelemseqpayloadlen); 5204 5205 ret = wlan_defrag_subelem_fragseq(true, 5206 WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 5207 linkinfo_currpos, 5208 linkinfo_remlen, 5209 NULL, 5210 0, 5211 &defragpayload_len); 5212 5213 if (QDF_IS_STATUS_ERROR(ret)) 5214 return ret; 5215 5216 if (defragpayload_len != subelemseqpayloadlen) { 5217 mlo_err_rl("Length of defragmented payload %zu octets is not equal to length of subelement fragment sequence payload %zu octets", 5218 defragpayload_len, 5219 subelemseqpayloadlen); 5220 return QDF_STATUS_E_FAILURE; 5221 } 5222 5223 /* Adjust linkinfo_remlen to reflect removal of all 5224 * subelement headers except the header of the lead 5225 * subelement. 5226 */ 5227 linkinfo_remlen -= (subelemseqtotallen - 5228 subelemseqpayloadlen - 5229 sizeof(struct subelem_header)); 5230 } else { 5231 if (linkinfo_remlen < 5232 (sizeof(struct subelem_header) + 5233 linkinfo_currpos[TAG_LEN_POS])) { 5234 mlo_err_rl("Remaining length in link info %zu octets is smaller than total size of current subelement %zu octets", 5235 linkinfo_remlen, 5236 sizeof(struct subelem_header) + 5237 linkinfo_currpos[TAG_LEN_POS]); 5238 return QDF_STATUS_E_PROTO; 5239 } 5240 5241 subelemseqpayloadlen = linkinfo_currpos[TAG_LEN_POS]; 5242 } 5243 5244 if (subelemid == WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE) { 5245 struct ml_pa_partner_link_info *link_info = 5246 &pa_info->link_info[pa_info->num_links]; 5247 ret = util_parse_pamlie_perstaprofile_stactrl(linkinfo_currpos + 5248 sizeof(struct subelem_header), 5249 subelemseqpayloadlen, 5250 link_info); 5251 if (QDF_IS_STATUS_ERROR(ret)) 5252 return ret; 5253 } 5254 5255 pa_info->num_links++; 5256 5257 linkinfo_remlen -= (sizeof(struct subelem_header) + 5258 subelemseqpayloadlen); 5259 linkinfo_currpos += (sizeof(struct subelem_header) + 5260 subelemseqpayloadlen); 5261 } 5262 5263 mlo_debug("Number of ML probe request links found=%u", 5264 pa_info->num_links); 5265 5266 return QDF_STATUS_SUCCESS; 5267 } 5268 5269 QDF_STATUS 5270 util_get_pav_mlie_link_info(uint8_t *mlieseq, 5271 qdf_size_t mlieseqlen, 5272 struct ml_pa_info *pa_info) 5273 { 5274 struct wlan_ie_multilink *mlie_fixed; 5275 uint16_t mlcontrol; 5276 enum wlan_ml_variant variant; 5277 uint8_t *linkinfo; 5278 qdf_size_t linkinfo_len; 5279 struct ml_pa_info painfo = {0}; 5280 qdf_size_t mlieseqpayloadlen; 5281 uint8_t *mlieseqpayload_copy; 5282 bool is_elemfragseq; 5283 qdf_size_t defragpayload_len; 5284 qdf_size_t tmplen; 5285 QDF_STATUS ret; 5286 5287 if (!mlieseq) { 5288 mlo_err("Pointer to Multi-Link element sequence is NULL"); 5289 return QDF_STATUS_E_NULL_VALUE; 5290 } 5291 5292 if (!mlieseqlen) { 5293 mlo_err("Length of Multi-Link element sequence is zero"); 5294 return QDF_STATUS_E_INVAL; 5295 } 5296 5297 if (!pa_info) { 5298 mlo_err("pa_info is NULL"); 5299 return QDF_STATUS_E_NULL_VALUE; 5300 } 5301 5302 pa_info->num_links = 0; 5303 5304 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) { 5305 mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)", 5306 mlieseqlen, sizeof(struct wlan_ie_multilink)); 5307 return QDF_STATUS_E_INVAL; 5308 } 5309 5310 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 5311 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 5312 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) { 5313 mlo_err("The element is not a Multi-Link element"); 5314 return QDF_STATUS_E_INVAL; 5315 } 5316 5317 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 5318 5319 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 5320 WLAN_ML_CTRL_TYPE_BITS); 5321 5322 if (variant != WLAN_ML_VARIANT_PRIORITYACCESS) { 5323 mlo_err("The variant value %u does not correspond to priority access Variant value %u", 5324 variant, WLAN_ML_VARIANT_PRIORITYACCESS); 5325 return QDF_STATUS_E_INVAL; 5326 } 5327 5328 mlieseqpayloadlen = 0; 5329 tmplen = 0; 5330 is_elemfragseq = false; 5331 5332 ret = wlan_get_elem_fragseq_info(mlieseq, 5333 mlieseqlen, 5334 &is_elemfragseq, 5335 &tmplen, 5336 &mlieseqpayloadlen); 5337 5338 if (QDF_IS_STATUS_ERROR(ret)) 5339 return ret; 5340 5341 if (qdf_unlikely(is_elemfragseq)) { 5342 if (tmplen != mlieseqlen) { 5343 mlo_err_rl("Mismatch in values of element fragment sequence total length. Val per frag info determination: %zu octets, val passed as arg: %zu octets", 5344 tmplen, mlieseqlen); 5345 return QDF_STATUS_E_INVAL; 5346 } 5347 5348 if (!mlieseqpayloadlen) { 5349 mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate"); 5350 return QDF_STATUS_E_FAILURE; 5351 } 5352 5353 mlo_debug("Multi-Link element fragment sequence found with payload len %zu", 5354 mlieseqpayloadlen); 5355 } else { 5356 if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) { 5357 mlo_err_rl("Expected presence of valid fragment sequence since Multi-Link element sequence length %zu octets is larger than frag threshold of %zu octets, however no valid fragment sequence found", 5358 mlieseqlen, 5359 sizeof(struct ie_header) + WLAN_MAX_IE_LEN); 5360 return QDF_STATUS_E_FAILURE; 5361 } 5362 5363 mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1); 5364 } 5365 5366 mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen); 5367 5368 if (!mlieseqpayload_copy) { 5369 mlo_err_rl("Could not allocate memory for Multi-Link element payload copy"); 5370 return QDF_STATUS_E_NOMEM; 5371 } 5372 5373 if (qdf_unlikely(is_elemfragseq)) { 5374 ret = wlan_defrag_elem_fragseq(false, 5375 mlieseq, 5376 mlieseqlen, 5377 mlieseqpayload_copy, 5378 mlieseqpayloadlen, 5379 &defragpayload_len); 5380 if (QDF_IS_STATUS_ERROR(ret)) { 5381 qdf_mem_free(mlieseqpayload_copy); 5382 return ret; 5383 } 5384 5385 if (defragpayload_len != mlieseqpayloadlen) { 5386 mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets", 5387 defragpayload_len, mlieseqpayloadlen); 5388 qdf_mem_free(mlieseqpayload_copy); 5389 return QDF_STATUS_E_FAILURE; 5390 } 5391 } else { 5392 qdf_mem_copy(mlieseqpayload_copy, 5393 mlieseq + sizeof(struct ie_header) + 1, 5394 mlieseqpayloadlen); 5395 } 5396 5397 linkinfo = NULL; 5398 linkinfo_len = 0; 5399 5400 ret = util_parse_pa_multi_link_ctrl(mlieseqpayload_copy, 5401 mlieseqpayloadlen, 5402 &linkinfo, 5403 &linkinfo_len); 5404 if (QDF_IS_STATUS_ERROR(ret)) { 5405 qdf_mem_free(mlieseqpayload_copy); 5406 return ret; 5407 } 5408 5409 /* In case Link Info is absent, the number of links will remain 5410 * zero. 5411 */ 5412 if (!linkinfo) { 5413 qdf_mem_free(mlieseqpayload_copy); 5414 return QDF_STATUS_SUCCESS; 5415 } 5416 5417 mlo_debug("Dumping hex of link info after parsing Multi-Link element control"); 5418 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_MLO, QDF_TRACE_LEVEL_ERROR, 5419 linkinfo, linkinfo_len); 5420 5421 ret = util_parse_pa_info_from_linkinfo(linkinfo, linkinfo_len, &painfo); 5422 if (QDF_IS_STATUS_ERROR(ret)) { 5423 qdf_mem_free(mlieseqpayload_copy); 5424 return ret; 5425 } 5426 5427 qdf_mem_copy(pa_info, &painfo, sizeof(painfo)); 5428 qdf_mem_free(mlieseqpayload_copy); 5429 5430 return QDF_STATUS_SUCCESS; 5431 } 5432 5433 #endif 5434 5435 #ifdef WLAN_FEATURE_11BE 5436 5437 QDF_STATUS util_add_bw_ind(struct wlan_ie_bw_ind *bw_ind, uint8_t ccfs0, 5438 uint8_t ccfs1, enum phy_ch_width ch_width, 5439 uint16_t puncture_bitmap, int *bw_ind_len) 5440 { 5441 uint8_t bw_ind_width; 5442 5443 if (!bw_ind) { 5444 mlo_err("Pointer to bandwidth indiaction element is NULL"); 5445 return QDF_STATUS_E_NULL_VALUE; 5446 } 5447 5448 if (!bw_ind_len) { 5449 mlo_err("Length of bandwidth indaication element is Zero"); 5450 return QDF_STATUS_E_INVAL; 5451 } 5452 5453 switch (ch_width) { 5454 case CH_WIDTH_20MHZ: 5455 bw_ind_width = IEEE80211_11BEOP_CHWIDTH_20; 5456 break; 5457 case CH_WIDTH_40MHZ: 5458 bw_ind_width = IEEE80211_11BEOP_CHWIDTH_40; 5459 break; 5460 case CH_WIDTH_80MHZ: 5461 bw_ind_width = IEEE80211_11BEOP_CHWIDTH_80; 5462 break; 5463 case CH_WIDTH_160MHZ: 5464 bw_ind_width = IEEE80211_11BEOP_CHWIDTH_160; 5465 break; 5466 case CH_WIDTH_320MHZ: 5467 bw_ind_width = IEEE80211_11BEOP_CHWIDTH_320; 5468 break; 5469 default: 5470 bw_ind_width = IEEE80211_11BEOP_CHWIDTH_20; 5471 } 5472 5473 bw_ind->elem_id = WLAN_ELEMID_EXTN_ELEM; 5474 *bw_ind_len = WLAN_BW_IND_IE_MAX_LEN; 5475 bw_ind->elem_len = WLAN_BW_IND_IE_MAX_LEN - WLAN_IE_HDR_LEN; 5476 bw_ind->elem_id_extn = WLAN_EXTN_ELEMID_BW_IND; 5477 bw_ind->ccfs0 = ccfs0; 5478 bw_ind->ccfs1 = ccfs1; 5479 QDF_SET_BITS(bw_ind->control, BW_IND_CHAN_WIDTH_IDX, 5480 BW_IND_CHAN_WIDTH_BITS, bw_ind_width); 5481 5482 if (puncture_bitmap) { 5483 bw_ind->disabled_sub_chan_bitmap[0] = 5484 QDF_GET_BITS(puncture_bitmap, 0, 8); 5485 bw_ind->disabled_sub_chan_bitmap[1] = 5486 QDF_GET_BITS(puncture_bitmap, 8, 8); 5487 QDF_SET_BITS(bw_ind->bw_ind_param, 5488 BW_IND_PARAM_DISABLED_SC_BITMAP_PRESENT_IDX, 5489 BW_IND_PARAM_DISABLED_SC_BITMAP_PRESENT_BITS, 1); 5490 } else { 5491 QDF_SET_BITS(bw_ind->bw_ind_param, 5492 BW_IND_PARAM_DISABLED_SC_BITMAP_PRESENT_IDX, 5493 BW_IND_PARAM_DISABLED_SC_BITMAP_PRESENT_BITS, 0); 5494 bw_ind->elem_len -= 5495 QDF_ARRAY_SIZE(bw_ind->disabled_sub_chan_bitmap); 5496 *bw_ind_len -= 5497 QDF_ARRAY_SIZE(bw_ind->disabled_sub_chan_bitmap); 5498 } 5499 5500 return QDF_STATUS_SUCCESS; 5501 } 5502 5503 QDF_STATUS util_parse_bw_ind(struct wlan_ie_bw_ind *bw_ind, uint8_t *ccfs0, 5504 uint8_t *ccfs1, enum phy_ch_width *ch_width, 5505 uint16_t *puncture_bitmap) 5506 { 5507 uint8_t bw_ind_width; 5508 5509 if (!bw_ind) { 5510 mlo_err("Pointer to bandwidth indiaction element is NULL"); 5511 return QDF_STATUS_E_NULL_VALUE; 5512 } 5513 5514 *ccfs0 = bw_ind->ccfs0; 5515 *ccfs1 = bw_ind->ccfs1; 5516 bw_ind_width = QDF_GET_BITS(bw_ind->control, BW_IND_CHAN_WIDTH_IDX, 5517 BW_IND_CHAN_WIDTH_BITS); 5518 5519 switch (bw_ind_width) { 5520 case IEEE80211_11BEOP_CHWIDTH_20: 5521 *ch_width = CH_WIDTH_20MHZ; 5522 break; 5523 case IEEE80211_11BEOP_CHWIDTH_40: 5524 *ch_width = CH_WIDTH_40MHZ; 5525 break; 5526 case IEEE80211_11BEOP_CHWIDTH_80: 5527 *ch_width = CH_WIDTH_80MHZ; 5528 break; 5529 case IEEE80211_11BEOP_CHWIDTH_160: 5530 *ch_width = CH_WIDTH_160MHZ; 5531 break; 5532 case IEEE80211_11BEOP_CHWIDTH_320: 5533 *ch_width = CH_WIDTH_320MHZ; 5534 break; 5535 default: 5536 *ch_width = CH_WIDTH_20MHZ; 5537 } 5538 5539 if (QDF_GET_BITS(bw_ind->bw_ind_param, 5540 BW_IND_PARAM_DISABLED_SC_BITMAP_PRESENT_IDX, 5541 BW_IND_PARAM_DISABLED_SC_BITMAP_PRESENT_BITS)) { 5542 QDF_SET_BITS(*puncture_bitmap, 0, 8, 5543 bw_ind->disabled_sub_chan_bitmap[0]); 5544 QDF_SET_BITS(*puncture_bitmap, 8, 8, 5545 bw_ind->disabled_sub_chan_bitmap[1]); 5546 } else { 5547 *puncture_bitmap = 0; 5548 } 5549 5550 return QDF_STATUS_SUCCESS; 5551 } 5552 #endif 5553