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