1 /* 2 * Copyright (c) 2021, The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /* 19 * DOC: 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 exp_cinfo_len = parsed_payload_len - WLAN_ML_CTRL_SIZE; 232 if (cinfo_len != exp_cinfo_len) { 233 mlo_err_rl("ML seq common info len %u doesn't match with expected common info len %u", 234 cinfo_len, exp_cinfo_len); 235 return QDF_STATUS_E_PROTO; 236 } 237 238 if (link_info_len) { 239 *link_info_len = mlieseqpayloadlen - parsed_payload_len; 240 mlo_debug("link_info_len:%zu, parsed_payload_len:%zu", 241 *link_info_len, parsed_payload_len); 242 } 243 244 if (mlieseqpayloadlen == parsed_payload_len) { 245 mlo_debug("No Link Info field present"); 246 if (link_info) 247 *link_info = NULL; 248 return QDF_STATUS_SUCCESS; 249 } 250 251 if (link_info) 252 *link_info = mlieseqpayload + parsed_payload_len; 253 254 return QDF_STATUS_SUCCESS; 255 } 256 257 static QDF_STATUS 258 util_parse_prv_multi_link_ctrl(uint8_t *mlieseqpayload, 259 qdf_size_t mlieseqpayloadlen, 260 uint8_t **link_info, 261 qdf_size_t *link_info_len) 262 { 263 qdf_size_t parsed_payload_len; 264 uint16_t mlcontrol; 265 uint16_t presence_bm; 266 uint16_t cinfo_len = 0; 267 uint16_t exp_cinfo_len = 0; 268 269 /* This helper returns the location(s) and length(s) of (sub)field(s) 270 * inferable after parsing the Multi Link element Control field. These 271 * location(s) and length(s) is/are in reference to the payload section 272 * of the Multi Link element (after defragmentation, if applicable). 273 * Here, the payload is the point after the element ID extension of the 274 * Multi Link element, and includes the payloads of all subsequent 275 * fragments (if any) but not the headers of those fragments. 276 * 277 * Currently, the helper returns the location and length of the Link 278 * Info field in the Multi Link element sequence. Other (sub)field(s) 279 * can be added later as required. 280 */ 281 282 if (!mlieseqpayload) { 283 mlo_err("ML seq payload pointer is NULL"); 284 return QDF_STATUS_E_NULL_VALUE; 285 } 286 287 if (!mlieseqpayloadlen) { 288 mlo_err("ML seq payload len is 0"); 289 return QDF_STATUS_E_INVAL; 290 } 291 292 if (mlieseqpayloadlen < WLAN_ML_CTRL_SIZE) { 293 mlo_err_rl("ML seq payload len %zu < ML Control size %u", 294 mlieseqpayloadlen, WLAN_ML_CTRL_SIZE); 295 return QDF_STATUS_E_PROTO; 296 } 297 298 parsed_payload_len = 0; 299 300 qdf_mem_copy(&mlcontrol, mlieseqpayload, WLAN_ML_CTRL_SIZE); 301 mlcontrol = qdf_le16_to_cpu(mlcontrol); 302 parsed_payload_len += WLAN_ML_CTRL_SIZE; 303 304 presence_bm = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 305 WLAN_ML_CTRL_PBM_BITS); 306 307 if (mlieseqpayloadlen < 308 (parsed_payload_len + WLAN_ML_PRV_CINFO_LENGTH_SIZE)) { 309 mlo_err_rl("ML seq payload len %zu insufficient for common info length size %u after parsed payload len %zu.", 310 mlieseqpayloadlen, 311 WLAN_ML_PRV_CINFO_LENGTH_SIZE, 312 parsed_payload_len); 313 return QDF_STATUS_E_PROTO; 314 } 315 316 cinfo_len = *(mlieseqpayload + parsed_payload_len); 317 parsed_payload_len += WLAN_ML_PRV_CINFO_LENGTH_SIZE; 318 319 /* Check if MLD ID is present */ 320 if (presence_bm & WLAN_ML_PRV_CTRL_PBM_MLDID_P) { 321 if (mlieseqpayloadlen < 322 (parsed_payload_len + 323 WLAN_ML_PRV_CINFO_MLDID_SIZE)) { 324 mlo_err_rl("ML seq payload len %zu insufficient for MLD ID size %u after parsed payload len %zu.", 325 mlieseqpayloadlen, 326 WLAN_ML_PRV_CINFO_MLDID_SIZE, 327 parsed_payload_len); 328 return QDF_STATUS_E_PROTO; 329 } 330 331 parsed_payload_len += WLAN_ML_PRV_CINFO_MLDID_SIZE; 332 } 333 334 exp_cinfo_len = parsed_payload_len - WLAN_ML_CTRL_SIZE; 335 if (cinfo_len != exp_cinfo_len) { 336 mlo_err_rl("ML seq common info len %u doesn't match with expected common info len %u", 337 cinfo_len, exp_cinfo_len); 338 return QDF_STATUS_E_PROTO; 339 } 340 341 if (link_info_len) { 342 *link_info_len = mlieseqpayloadlen - parsed_payload_len; 343 mlo_debug("link_info_len:%zu, parsed_payload_len:%zu", 344 *link_info_len, parsed_payload_len); 345 } 346 347 if (mlieseqpayloadlen == parsed_payload_len) { 348 mlo_debug("No Link Info field present"); 349 if (link_info) 350 *link_info = NULL; 351 return QDF_STATUS_SUCCESS; 352 } 353 354 if (link_info) 355 *link_info = mlieseqpayload + parsed_payload_len; 356 357 return QDF_STATUS_SUCCESS; 358 } 359 360 static QDF_STATUS 361 util_parse_bvmlie_perstaprofile_stactrl(uint8_t *subelempayload, 362 qdf_size_t subelempayloadlen, 363 uint8_t *linkid, 364 uint16_t *beaconinterval, 365 bool *is_beaconinterval_valid, 366 uint64_t *tsfoffset, 367 bool *is_tsfoffset_valid, 368 bool *is_complete_profile, 369 bool *is_macaddr_valid, 370 struct qdf_mac_addr *macaddr, 371 bool is_staprof_reqd, 372 uint8_t **staprof, 373 qdf_size_t *staprof_len) 374 { 375 qdf_size_t parsed_payload_len = 0; 376 uint16_t stacontrol; 377 uint8_t completeprofile; 378 uint8_t nstrlppresent; 379 enum wlan_ml_bv_linfo_perstaprof_stactrl_nstrbmsz nstrbmsz; 380 381 /* This helper returns the location(s) and where required, the length(s) 382 * of (sub)field(s) inferable after parsing the STA Control field in the 383 * per-STA profile subelement. These location(s) and length(s) is/are in 384 * reference to the payload section of the per-STA profile subelement 385 * (after defragmentation, if applicable). Here, the payload is the 386 * point after the subelement length in the subelement, and includes the 387 * payloads of all subsequent fragments (if any) but not the headers of 388 * those fragments. 389 * 390 * Currently, the helper returns the link ID, MAC address, and STA 391 * profile. More (sub)fields can be added when required. 392 */ 393 394 if (!subelempayload) { 395 mlo_err("Pointer to subelement payload is NULL"); 396 return QDF_STATUS_E_NULL_VALUE; 397 } 398 399 if (!subelempayloadlen) { 400 mlo_err("Length of subelement payload is zero"); 401 return QDF_STATUS_E_INVAL; 402 } 403 404 if (subelempayloadlen < WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE) { 405 mlo_err_rl("Subelement payload length %zu octets is smaller than STA control field of per-STA profile subelement %u octets", 406 subelempayloadlen, 407 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE); 408 return QDF_STATUS_E_PROTO; 409 } 410 411 parsed_payload_len = 0; 412 413 qdf_mem_copy(&stacontrol, 414 subelempayload, 415 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE); 416 stacontrol = le16toh(stacontrol); 417 parsed_payload_len += WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE; 418 419 if (linkid) { 420 *linkid = QDF_GET_BITS(stacontrol, 421 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_LINKID_IDX, 422 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_LINKID_BITS); 423 } 424 425 /* Check if this a complete profile */ 426 completeprofile = QDF_GET_BITS(stacontrol, 427 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_IDX, 428 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_BITS); 429 430 if (completeprofile && is_complete_profile) 431 *is_complete_profile = true; 432 433 /* Check STA Info Length */ 434 if (subelempayloadlen < 435 parsed_payload_len + WLAN_ML_BV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE) { 436 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.", 437 subelempayloadlen, 438 WLAN_ML_BV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE, 439 parsed_payload_len); 440 return QDF_STATUS_E_PROTO; 441 } 442 443 parsed_payload_len += WLAN_ML_BV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE; 444 445 if (is_macaddr_valid) 446 *is_macaddr_valid = false; 447 448 /* Check STA MAC address present bit */ 449 if (QDF_GET_BITS(stacontrol, 450 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_MACADDRP_IDX, 451 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_MACADDRP_BITS)) { 452 if (subelempayloadlen < 453 (parsed_payload_len + QDF_MAC_ADDR_SIZE)) { 454 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.", 455 subelempayloadlen, 456 QDF_MAC_ADDR_SIZE, 457 parsed_payload_len); 458 return QDF_STATUS_E_PROTO; 459 } 460 461 if (macaddr) { 462 qdf_mem_copy(macaddr->bytes, 463 subelempayload + parsed_payload_len, 464 QDF_MAC_ADDR_SIZE); 465 466 mlo_nofl_debug("Copied MAC address: " QDF_MAC_ADDR_FMT, 467 subelempayload + parsed_payload_len); 468 469 if (is_macaddr_valid) 470 *is_macaddr_valid = true; 471 } 472 473 parsed_payload_len += QDF_MAC_ADDR_SIZE; 474 } 475 476 /* Check Beacon Interval present bit */ 477 if (QDF_GET_BITS(stacontrol, 478 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_BCNINTP_IDX, 479 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_BCNINTP_BITS)) { 480 if (subelempayloadlen < 481 (parsed_payload_len + 482 WLAN_BEACONINTERVAL_LEN)) { 483 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.", 484 subelempayloadlen, 485 WLAN_BEACONINTERVAL_LEN, 486 parsed_payload_len); 487 return QDF_STATUS_E_PROTO; 488 } 489 490 if (beaconinterval) { 491 qdf_mem_copy(beaconinterval, 492 subelempayload + parsed_payload_len, 493 WLAN_BEACONINTERVAL_LEN); 494 *beaconinterval = qdf_le16_to_cpu(*beaconinterval); 495 496 if (is_beaconinterval_valid) 497 *is_beaconinterval_valid = true; 498 } 499 parsed_payload_len += WLAN_BEACONINTERVAL_LEN; 500 } 501 502 /* Check TSF Offset present bit */ 503 if (QDF_GET_BITS(stacontrol, 504 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_TSFOFFSETP_IDX, 505 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_TSFOFFSETP_BITS)) { 506 if (!completeprofile) { 507 mlo_err_rl("TSF offset is expected only for complete profiles"); 508 return QDF_STATUS_E_PROTO; 509 } 510 511 if (subelempayloadlen < 512 (parsed_payload_len + 513 WLAN_ML_TSF_OFFSET_SIZE)) { 514 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.", 515 subelempayloadlen, 516 WLAN_ML_TSF_OFFSET_SIZE, 517 parsed_payload_len); 518 return QDF_STATUS_E_PROTO; 519 } 520 521 if (tsfoffset) { 522 qdf_mem_copy(tsfoffset, 523 subelempayload + parsed_payload_len, 524 WLAN_TIMESTAMP_LEN); 525 *tsfoffset = qdf_le64_to_cpu(*tsfoffset); 526 527 if (is_tsfoffset_valid) 528 *is_tsfoffset_valid = true; 529 } 530 531 parsed_payload_len += WLAN_ML_TSF_OFFSET_SIZE; 532 } 533 534 /* Check DTIM Info present bit */ 535 if (QDF_GET_BITS(stacontrol, 536 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_DTIMINFOP_IDX, 537 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_DTIMINFOP_BITS)) { 538 if (subelempayloadlen < 539 (parsed_payload_len + 540 sizeof(struct wlan_ml_bv_linfo_perstaprof_stainfo_dtiminfo))) { 541 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.", 542 subelempayloadlen, 543 sizeof(struct wlan_ml_bv_linfo_perstaprof_stainfo_dtiminfo), 544 parsed_payload_len); 545 return QDF_STATUS_E_PROTO; 546 } 547 548 parsed_payload_len += 549 sizeof(struct wlan_ml_bv_linfo_perstaprof_stainfo_dtiminfo); 550 } 551 552 /* Check NTSR Link pair present bit */ 553 nstrlppresent = 554 QDF_GET_BITS(stacontrol, 555 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRLINKPRP_IDX, 556 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRLINKPRP_BITS); 557 558 if (completeprofile && nstrlppresent) { 559 /* Check NTSR Bitmap Size bit */ 560 nstrbmsz = 561 QDF_GET_BITS(stacontrol, 562 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_IDX, 563 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_BITS); 564 565 if (nstrbmsz == WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_1_OCTET) { 566 if (subelempayloadlen < 567 (parsed_payload_len + 1)) { 568 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.", 569 subelempayloadlen, 570 parsed_payload_len); 571 return QDF_STATUS_E_PROTO; 572 } 573 574 parsed_payload_len += 1; 575 } else if (nstrbmsz == WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_2_OCTETS) { 576 if (subelempayloadlen < 577 (parsed_payload_len + 2)) { 578 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.", 579 subelempayloadlen, 580 parsed_payload_len); 581 return QDF_STATUS_E_PROTO; 582 } 583 584 parsed_payload_len += 2; 585 } else { 586 /* Though an invalid value cannot occur if only 1 bit is 587 * used, we check for it in a generic manner in case the 588 * number of bits is increased in the future. 589 */ 590 mlo_err_rl("Invalid NSTR Bitmap size %u", nstrbmsz); 591 return QDF_STATUS_E_PROTO; 592 } 593 } 594 595 /* Check BSS Parameters Change Count Present bit */ 596 if (QDF_GET_BITS(stacontrol, 597 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_BSSPARAMCHNGCNTP_IDX, 598 WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_BSSPARAMCHNGCNTP_BITS)) { 599 if (subelempayloadlen < 600 (parsed_payload_len + 601 WLAN_ML_BSSPARAMCHNGCNT_SIZE)) { 602 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.", 603 subelempayloadlen, 604 WLAN_ML_BSSPARAMCHNGCNT_SIZE, 605 parsed_payload_len); 606 return QDF_STATUS_E_PROTO; 607 } 608 609 parsed_payload_len += WLAN_ML_BSSPARAMCHNGCNT_SIZE; 610 } 611 612 /* Note: Some implementation versions of hostapd/wpa_supplicant may 613 * provide a per-STA profile without STA profile. Let the caller 614 * indicate whether a STA profile is required to be found. This may be 615 * revisited as upstreaming progresses. 616 */ 617 if (!is_staprof_reqd) 618 return QDF_STATUS_SUCCESS; 619 620 if (subelempayloadlen == parsed_payload_len) { 621 mlo_err_rl("Subelement payload length %zu == parsed payload length %zu. Unable to get STA profile.", 622 subelempayloadlen, 623 parsed_payload_len); 624 return QDF_STATUS_E_PROTO; 625 } 626 627 if (staprof_len) 628 *staprof_len = subelempayloadlen - parsed_payload_len; 629 630 if (staprof) 631 *staprof = subelempayload + parsed_payload_len; 632 633 return QDF_STATUS_SUCCESS; 634 } 635 636 static QDF_STATUS 637 util_parse_prvmlie_perstaprofile_stactrl(uint8_t *subelempayload, 638 qdf_size_t subelempayloadlen, 639 uint8_t *linkid, 640 bool is_staprof_reqd, 641 uint8_t **staprof, 642 qdf_size_t *staprof_len) 643 { 644 qdf_size_t parsed_payload_len = 0; 645 uint16_t stacontrol; 646 uint8_t completeprofile; 647 648 /* This helper returns the location(s) and where required, the length(s) 649 * of (sub)field(s) inferable after parsing the STA Control field in the 650 * per-STA profile subelement. These location(s) and length(s) is/are in 651 * reference to the payload section of the per-STA profile subelement 652 * (after defragmentation, if applicable). Here, the payload is the 653 * point after the subelement length in the subelement, and includes the 654 * payloads of all subsequent fragments (if any) but not the headers of 655 * those fragments. 656 * 657 * Currently, the helper returns the link ID, MAC address, and STA 658 * profile. More (sub)fields can be added when required. 659 */ 660 661 if (!subelempayload) { 662 mlo_err("Pointer to subelement payload is NULL"); 663 return QDF_STATUS_E_NULL_VALUE; 664 } 665 666 if (!subelempayloadlen) { 667 mlo_err("Length of subelement payload is zero"); 668 return QDF_STATUS_E_INVAL; 669 } 670 671 if (subelempayloadlen < WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_SIZE) { 672 mlo_err_rl("Subelement payload length %zu octets is smaller than STA control field of per-STA profile subelement %u octets", 673 subelempayloadlen, 674 WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_SIZE); 675 return QDF_STATUS_E_PROTO; 676 } 677 678 parsed_payload_len = 0; 679 680 qdf_mem_copy(&stacontrol, 681 subelempayload, 682 WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_SIZE); 683 stacontrol = qdf_le16_to_cpu(stacontrol); 684 parsed_payload_len += WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_SIZE; 685 686 if (linkid) { 687 *linkid = QDF_GET_BITS(stacontrol, 688 WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_LINKID_IDX, 689 WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_LINKID_BITS); 690 } 691 692 /* Check if this a complete profile */ 693 completeprofile = QDF_GET_BITS(stacontrol, 694 WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_IDX, 695 WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_BITS); 696 697 /* Note: Some implementation versions of hostapd/wpa_supplicant may 698 * provide a per-STA profile without STA profile. Let the caller 699 * indicate whether a STA profile is required to be found. This may be 700 * revisited as upstreaming progresses. 701 */ 702 if (!is_staprof_reqd) 703 return QDF_STATUS_SUCCESS; 704 705 if (subelempayloadlen == parsed_payload_len) { 706 mlo_err_rl("Subelement payload length %zu == parsed payload length %zu. Unable to get STA profile.", 707 subelempayloadlen, 708 parsed_payload_len); 709 return QDF_STATUS_E_PROTO; 710 } 711 712 if (staprof_len) 713 *staprof_len = subelempayloadlen - parsed_payload_len; 714 715 if (staprof) 716 *staprof = subelempayload + parsed_payload_len; 717 718 return QDF_STATUS_SUCCESS; 719 } 720 721 static 722 uint8_t *util_get_successorfrag(uint8_t *currie, uint8_t *frame, qdf_size_t len) 723 { 724 uint8_t *nextie; 725 726 if (!currie || !frame || !len) 727 return NULL; 728 729 if ((currie + MIN_IE_LEN) > (frame + len)) 730 return NULL; 731 732 /* Check whether there is sufficient space in the frame for the current 733 * IE, plus at least another MIN_IE_LEN bytes for the IE header of a 734 * fragment (if present) that would come just after the current IE. 735 */ 736 if ((currie + MIN_IE_LEN + currie[TAG_LEN_POS] + MIN_IE_LEN) > 737 (frame + len)) 738 return NULL; 739 740 nextie = currie + currie[TAG_LEN_POS] + MIN_IE_LEN; 741 742 /* Check whether there is sufficient space in the frame for the next IE 743 */ 744 if ((nextie + MIN_IE_LEN + nextie[TAG_LEN_POS]) > (frame + len)) 745 return NULL; 746 747 if (nextie[ID_POS] != WLAN_ELEMID_FRAGMENT) 748 return NULL; 749 750 return nextie; 751 } 752 753 static 754 QDF_STATUS util_parse_partner_info_from_linkinfo(uint8_t *linkinfo, 755 qdf_size_t linkinfo_len, 756 struct mlo_partner_info *partner_info) 757 { 758 uint8_t linkid; 759 struct qdf_mac_addr macaddr; 760 bool is_macaddr_valid; 761 uint8_t *linkinfo_currpos; 762 qdf_size_t linkinfo_remlen; 763 bool is_subelemfragseq; 764 uint8_t subelemid; 765 qdf_size_t subelemseqtotallen; 766 qdf_size_t subelemseqpayloadlen; 767 qdf_size_t defragpayload_len; 768 QDF_STATUS ret; 769 770 /* This helper function parses partner info from the per-STA profiles 771 * present (if any) in the Link Info field in the payload of a Multi 772 * Link element (after defragmentation if required). The caller should 773 * pass a copy of the payload so that inline defragmentation of 774 * subelements can be carried out if required. The subelement 775 * defragmentation (if applicable) in this Control Path helper is 776 * required for maintainability, accuracy and eliminating current and 777 * future per-field-access multi-level fragment boundary checks and 778 * adjustments, given the complex format of Multi Link elements. It is 779 * also most likely to be required mainly at the client side. 780 */ 781 782 if (!linkinfo) { 783 mlo_err("linkinfo is NULL"); 784 return QDF_STATUS_E_NULL_VALUE; 785 } 786 787 if (!linkinfo_len) { 788 mlo_err("linkinfo_len is zero"); 789 return QDF_STATUS_E_NULL_VALUE; 790 } 791 792 if (!partner_info) { 793 mlo_err("ML partner info is NULL"); 794 return QDF_STATUS_E_NULL_VALUE; 795 } 796 797 partner_info->num_partner_links = 0; 798 linkinfo_currpos = linkinfo; 799 linkinfo_remlen = linkinfo_len; 800 801 while (linkinfo_remlen) { 802 if (linkinfo_remlen < sizeof(struct subelem_header)) { 803 mlo_err_rl("Remaining length in link info %zu octets is smaller than subelement header length %zu octets", 804 linkinfo_remlen, 805 sizeof(struct subelem_header)); 806 return QDF_STATUS_E_PROTO; 807 } 808 809 subelemid = linkinfo_currpos[ID_POS]; 810 is_subelemfragseq = false; 811 subelemseqtotallen = 0; 812 subelemseqpayloadlen = 0; 813 814 ret = wlan_get_subelem_fragseq_info(WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 815 linkinfo_currpos, 816 linkinfo_remlen, 817 &is_subelemfragseq, 818 &subelemseqtotallen, 819 &subelemseqpayloadlen); 820 if (QDF_IS_STATUS_ERROR(ret)) 821 return ret; 822 823 if (is_subelemfragseq) { 824 if (!subelemseqpayloadlen) { 825 mlo_err_rl("Subelement fragment sequence payload is reported as 0, investigate"); 826 return QDF_STATUS_E_FAILURE; 827 } 828 829 mlo_debug("Subelement fragment sequence found with payload len %zu", 830 subelemseqpayloadlen); 831 832 ret = wlan_defrag_subelem_fragseq(true, 833 WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 834 linkinfo_currpos, 835 linkinfo_remlen, 836 NULL, 837 0, 838 &defragpayload_len); 839 if (QDF_IS_STATUS_ERROR(ret)) 840 return ret; 841 842 if (defragpayload_len != subelemseqpayloadlen) { 843 mlo_err_rl("Length of defragmented payload %zu octets is not equal to length of subelement fragment sequence payload %zu octets", 844 defragpayload_len, 845 subelemseqpayloadlen); 846 return QDF_STATUS_E_FAILURE; 847 } 848 849 /* Adjust linkinfo_remlen to reflect removal of all 850 * subelement headers except the header of the lead 851 * subelement. 852 */ 853 linkinfo_remlen -= (subelemseqtotallen - 854 subelemseqpayloadlen - 855 sizeof(struct subelem_header)); 856 } else { 857 if (linkinfo_remlen < 858 (sizeof(struct subelem_header) + 859 linkinfo_currpos[TAG_LEN_POS])) { 860 mlo_err_rl("Remaining length in link info %zu octets is smaller than total size of current subelement %zu octets", 861 linkinfo_remlen, 862 sizeof(struct subelem_header) + 863 linkinfo_currpos[TAG_LEN_POS]); 864 return QDF_STATUS_E_PROTO; 865 } 866 867 subelemseqpayloadlen = linkinfo_currpos[TAG_LEN_POS]; 868 } 869 870 if (subelemid == WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE) { 871 is_macaddr_valid = false; 872 873 ret = util_parse_bvmlie_perstaprofile_stactrl(linkinfo_currpos + 874 sizeof(struct subelem_header), 875 subelemseqpayloadlen, 876 &linkid, 877 NULL, 878 NULL, 879 NULL, 880 NULL, 881 NULL, 882 &is_macaddr_valid, 883 &macaddr, 884 false, 885 NULL, 886 NULL); 887 if (QDF_IS_STATUS_ERROR(ret)) { 888 return ret; 889 } 890 891 if (is_macaddr_valid) { 892 if (partner_info->num_partner_links >= 893 QDF_ARRAY_SIZE(partner_info->partner_link_info)) { 894 mlo_err_rl("Insufficient size %zu of array for partner link info", 895 QDF_ARRAY_SIZE(partner_info->partner_link_info)); 896 return QDF_STATUS_E_NOMEM; 897 } 898 899 partner_info->partner_link_info[partner_info->num_partner_links].link_id = 900 linkid; 901 qdf_mem_copy(&partner_info->partner_link_info[partner_info->num_partner_links].link_addr, 902 &macaddr, 903 sizeof(partner_info->partner_link_info[partner_info->num_partner_links].link_addr)); 904 905 partner_info->num_partner_links++; 906 } else { 907 mlo_warn_rl("MAC address not found in STA Info field of per-STA profile with link ID %u", 908 linkid); 909 } 910 } 911 912 linkinfo_remlen -= (sizeof(struct subelem_header) + 913 subelemseqpayloadlen); 914 linkinfo_currpos += (sizeof(struct subelem_header) + 915 subelemseqpayloadlen); 916 } 917 918 mlo_debug("Number of ML partner links found=%u", 919 partner_info->num_partner_links); 920 921 return QDF_STATUS_SUCCESS; 922 } 923 924 static QDF_STATUS 925 util_parse_probereq_info_from_linkinfo(uint8_t *linkinfo, 926 qdf_size_t linkinfo_len, 927 struct mlo_probereq_info *probereq_info) 928 { 929 uint8_t linkid; 930 uint8_t *linkinfo_currpos; 931 qdf_size_t linkinfo_remlen; 932 bool is_subelemfragseq; 933 uint8_t subelemid; 934 qdf_size_t subelemseqtotallen; 935 qdf_size_t subelemseqpayloadlen; 936 qdf_size_t defragpayload_len; 937 QDF_STATUS ret; 938 939 /* This helper function parses probe request info from the per-STA prof 940 * present (if any) in the Link Info field in the payload of a Multi 941 * Link element (after defragmentation if required). The caller should 942 * pass a copy of the payload so that inline defragmentation of 943 * subelements can be carried out if required. The subelement 944 * defragmentation (if applicable) in this Control Path helper is 945 * required for maintainability, accuracy and eliminating current and 946 * future per-field-access multi-level fragment boundary checks and 947 * adjustments, given the complex format of Multi Link elements. It is 948 * also most likely to be required mainly at the client side. 949 */ 950 951 if (!linkinfo) { 952 mlo_err("linkinfo is NULL"); 953 return QDF_STATUS_E_NULL_VALUE; 954 } 955 956 if (!linkinfo_len) { 957 mlo_err("linkinfo_len is zero"); 958 return QDF_STATUS_E_NULL_VALUE; 959 } 960 961 if (!probereq_info) { 962 mlo_err("ML probe req info is NULL"); 963 return QDF_STATUS_E_NULL_VALUE; 964 } 965 966 probereq_info->num_links = 0; 967 linkinfo_currpos = linkinfo; 968 linkinfo_remlen = linkinfo_len; 969 970 while (linkinfo_remlen) { 971 if (linkinfo_remlen < sizeof(struct subelem_header)) { 972 mlo_err_rl("Remaining length in link info %zu octets is smaller than subelement header length %zu octets", 973 linkinfo_remlen, 974 sizeof(struct subelem_header)); 975 return QDF_STATUS_E_PROTO; 976 } 977 978 subelemid = linkinfo_currpos[ID_POS]; 979 is_subelemfragseq = false; 980 subelemseqtotallen = 0; 981 subelemseqpayloadlen = 0; 982 983 ret = wlan_get_subelem_fragseq_info(WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 984 linkinfo_currpos, 985 linkinfo_remlen, 986 &is_subelemfragseq, 987 &subelemseqtotallen, 988 &subelemseqpayloadlen); 989 if (QDF_IS_STATUS_ERROR(ret)) 990 return ret; 991 992 if (is_subelemfragseq) { 993 if (!subelemseqpayloadlen) { 994 mlo_err_rl("Subelement fragment sequence payload is reported as 0, investigate"); 995 return QDF_STATUS_E_FAILURE; 996 } 997 998 mlo_debug("Subelement fragment sequence found with payload len %zu", 999 subelemseqpayloadlen); 1000 1001 ret = wlan_defrag_subelem_fragseq(true, 1002 WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 1003 linkinfo_currpos, 1004 linkinfo_remlen, 1005 NULL, 1006 0, 1007 &defragpayload_len); 1008 if (QDF_IS_STATUS_ERROR(ret)) 1009 return ret; 1010 1011 if (defragpayload_len != subelemseqpayloadlen) { 1012 mlo_err_rl("Length of defragmented payload %zu octets is not equal to length of subelement fragment sequence payload %zu octets", 1013 defragpayload_len, 1014 subelemseqpayloadlen); 1015 return QDF_STATUS_E_FAILURE; 1016 } 1017 1018 /* Adjust linkinfo_remlen to reflect removal of all 1019 * subelement headers except the header of the lead 1020 * subelement. 1021 */ 1022 linkinfo_remlen -= (subelemseqtotallen - 1023 subelemseqpayloadlen - 1024 sizeof(struct subelem_header)); 1025 } else { 1026 if (linkinfo_remlen < 1027 (sizeof(struct subelem_header) + 1028 linkinfo_currpos[TAG_LEN_POS])) { 1029 mlo_err_rl("Remaining length in link info %zu octets is smaller than total size of current subelement %zu octets", 1030 linkinfo_remlen, 1031 sizeof(struct subelem_header) + 1032 linkinfo_currpos[TAG_LEN_POS]); 1033 return QDF_STATUS_E_PROTO; 1034 } 1035 1036 subelemseqpayloadlen = linkinfo_currpos[TAG_LEN_POS]; 1037 } 1038 1039 if (subelemid == WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE) { 1040 ret = util_parse_prvmlie_perstaprofile_stactrl(linkinfo_currpos + 1041 sizeof(struct subelem_header), 1042 subelemseqpayloadlen, 1043 &linkid, 1044 false, 1045 NULL, 1046 NULL); 1047 if (QDF_IS_STATUS_ERROR(ret)) 1048 return ret; 1049 1050 if (probereq_info->num_links >= 1051 QDF_ARRAY_SIZE(probereq_info->link_id)) { 1052 mlo_err_rl("Insufficient size %zu of array for probe req link id", 1053 QDF_ARRAY_SIZE(probereq_info->link_id)); 1054 return QDF_STATUS_E_NOMEM; 1055 } 1056 1057 probereq_info->link_id[probereq_info->num_links] = linkid; 1058 1059 probereq_info->num_links++; 1060 } 1061 1062 linkinfo_remlen -= (sizeof(struct subelem_header) + 1063 subelemseqpayloadlen); 1064 linkinfo_currpos += (sizeof(struct subelem_header) + 1065 subelemseqpayloadlen); 1066 } 1067 1068 mlo_debug("Number of ML probe request links found=%u", 1069 probereq_info->num_links); 1070 1071 return QDF_STATUS_SUCCESS; 1072 } 1073 1074 static 1075 QDF_STATUS util_get_noninheritlists(uint8_t *buff, qdf_size_t buff_len, 1076 uint8_t **ninherit_elemlist, 1077 qdf_size_t *ninherit_elemlist_len, 1078 uint8_t **ninherit_elemextlist, 1079 qdf_size_t *ninherit_elemextlist_len) 1080 { 1081 uint8_t *ninherit_ie; 1082 qdf_size_t unparsed_len; 1083 1084 /* Note: This funtionality provided by this helper may be combined with 1085 * other, older non-inheritance parsing helper functionality and exposed 1086 * as a common API as part of future efforts once the older 1087 * functionality can be made generic. 1088 */ 1089 1090 if (!buff) { 1091 mlo_err("Pointer to buffer for IEs is NULL"); 1092 return QDF_STATUS_E_NULL_VALUE; 1093 } 1094 1095 if (!buff_len) { 1096 mlo_err("IE buffer length is zero"); 1097 return QDF_STATUS_E_INVAL; 1098 } 1099 1100 if (!ninherit_elemlist) { 1101 mlo_err("Pointer to Non-Inheritance element ID list array is NULL"); 1102 return QDF_STATUS_E_NULL_VALUE; 1103 } 1104 1105 if (!ninherit_elemlist_len) { 1106 mlo_err("Pointer to Non-Inheritance element ID list array length is NULL"); 1107 return QDF_STATUS_E_NULL_VALUE; 1108 } 1109 1110 if (!ninherit_elemextlist) { 1111 mlo_err("Pointer to Non-Inheritance element ID extension list array is NULL"); 1112 return QDF_STATUS_E_NULL_VALUE; 1113 } 1114 1115 if (!ninherit_elemextlist_len) { 1116 mlo_err("Pointer to Non-Inheritance element ID extension list array length is NULL"); 1117 return QDF_STATUS_E_NULL_VALUE; 1118 } 1119 1120 ninherit_ie = NULL; 1121 *ninherit_elemlist_len = 0; 1122 *ninherit_elemlist = NULL; 1123 *ninherit_elemextlist_len = 0; 1124 *ninherit_elemextlist = NULL; 1125 1126 ninherit_ie = 1127 (uint8_t *)util_find_extn_eid(WLAN_ELEMID_EXTN_ELEM, 1128 WLAN_EXTN_ELEMID_NONINHERITANCE, 1129 buff, 1130 buff_len); 1131 1132 if (ninherit_ie) { 1133 if ((ninherit_ie + TAG_LEN_POS) > (buff + buff_len - 1)) { 1134 mlo_err_rl("Position of length field of Non-Inheritance element would exceed IE buffer boundary"); 1135 return QDF_STATUS_E_PROTO; 1136 } 1137 1138 if ((ninherit_ie + ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN) > 1139 (buff + buff_len)) { 1140 mlo_err_rl("Non-Inheritance element with total length %u would exceed IE buffer boundary", 1141 ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN); 1142 return QDF_STATUS_E_PROTO; 1143 } 1144 1145 if ((ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN) < 1146 MIN_NONINHERITANCEELEM_LEN) { 1147 mlo_err_rl("Non-Inheritance element size %u is smaller than the minimum required %u", 1148 ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN, 1149 MIN_NONINHERITANCEELEM_LEN); 1150 return QDF_STATUS_E_PROTO; 1151 } 1152 1153 /* Track the number of unparsed octets, excluding the IE header. 1154 */ 1155 unparsed_len = ninherit_ie[TAG_LEN_POS]; 1156 1157 /* Mark the element ID extension as parsed */ 1158 unparsed_len--; 1159 1160 *ninherit_elemlist_len = ninherit_ie[ELEM_ID_LIST_LEN_POS]; 1161 unparsed_len--; 1162 1163 /* While checking if the Non-Inheritance element ID list length 1164 * exceeds the remaining unparsed IE space, we factor in one 1165 * octet for the element extension ID list length and subtract 1166 * this from the unparsed IE space. 1167 */ 1168 if (*ninherit_elemlist_len > (unparsed_len - 1)) { 1169 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", 1170 *ninherit_elemlist_len, unparsed_len - 1); 1171 1172 return QDF_STATUS_E_PROTO; 1173 } 1174 1175 if (*ninherit_elemlist_len != 0) { 1176 *ninherit_elemlist = ninherit_ie + ELEM_ID_LIST_POS; 1177 unparsed_len -= *ninherit_elemlist_len; 1178 } 1179 1180 *ninherit_elemextlist_len = 1181 ninherit_ie[ELEM_ID_LIST_LEN_POS + *ninherit_elemlist_len + 1]; 1182 unparsed_len--; 1183 1184 if (*ninherit_elemextlist_len > unparsed_len) { 1185 mlo_err_rl("Non-Inheritance element ID extension list length %zu exceeds remaining unparsed IE space %zu", 1186 *ninherit_elemextlist_len, unparsed_len); 1187 1188 return QDF_STATUS_E_PROTO; 1189 } 1190 1191 if (*ninherit_elemextlist_len != 0) { 1192 *ninherit_elemextlist = ninherit_ie + 1193 ELEM_ID_LIST_LEN_POS + (*ninherit_elemlist_len) 1194 + 2; 1195 unparsed_len -= *ninherit_elemextlist_len; 1196 } 1197 1198 if (unparsed_len > 0) { 1199 mlo_err_rl("Unparsed length is %zu, expected 0", 1200 unparsed_len); 1201 return QDF_STATUS_E_PROTO; 1202 } 1203 } 1204 1205 /* If Non-Inheritance element is not found, we still return success, 1206 * with the list lengths kept at zero. 1207 */ 1208 mlo_debug("Non-Inheritance element ID list array length=%zu", 1209 *ninherit_elemlist_len); 1210 mlo_debug("Non-Inheritance element ID extension list array length=%zu", 1211 *ninherit_elemextlist_len); 1212 1213 return QDF_STATUS_SUCCESS; 1214 } 1215 1216 static 1217 QDF_STATUS util_eval_ie_in_noninheritlist(uint8_t *ie, qdf_size_t total_ie_len, 1218 uint8_t *ninherit_elemlist, 1219 qdf_size_t ninherit_elemlist_len, 1220 uint8_t *ninherit_elemextlist, 1221 qdf_size_t ninherit_elemextlist_len, 1222 bool *is_in_noninheritlist) 1223 { 1224 int i; 1225 1226 /* Evaluate whether the given IE is in the given Non-Inheritance element 1227 * ID list or Non-Inheritance element ID extension list, and update the 1228 * result into is_in_noninheritlist. If any list is empty, then the IE 1229 * is considered to not be present in that list. Both lists can be 1230 * empty. 1231 * 1232 * If QDF_STATUS_SUCCESS is returned, it means that the evaluation is 1233 * successful, and that is_in_noninheritlist contains a valid value 1234 * (which could be true or false). If a QDF_STATUS error value is 1235 * returned, the value in is_in_noninheritlist is invalid and the caller 1236 * should ignore it. 1237 */ 1238 1239 /* Note: The funtionality provided by this helper may be combined with 1240 * other, older non-inheritance parsing helper functionality and exposed 1241 * as a common API as part of future efforts once the older 1242 * functionality can be made generic. 1243 */ 1244 1245 /* Except for is_in_noninheritlist and ie, other pointer arguments are 1246 * permitted to be NULL if they are inapplicable. If they are 1247 * applicable, they will be checked to ensure they are not NULL. 1248 */ 1249 1250 if (!is_in_noninheritlist) { 1251 mlo_err("NULL pointer to flag that indicates if element is in a Non-Inheritance list"); 1252 return QDF_STATUS_E_NULL_VALUE; 1253 } 1254 1255 /* If ninherit_elemlist_len and ninherit_elemextlist_len are both zero 1256 * as checked soon in this function, we won't be accessing the IE. 1257 * However, we still check right-away if the pointer to the IE is 1258 * non-NULL and whether the total IE length is sane enough to access the 1259 * element ID and if applicable, the element ID extension, since it 1260 * doesn't make sense to set the flag in is_in_noninheritlist for a NULL 1261 * IE pointer or an IE whose total length is not sane enough to 1262 * distinguish the identity of the IE. 1263 */ 1264 if (!ie) { 1265 mlo_err("NULL pointer to IE"); 1266 return QDF_STATUS_E_NULL_VALUE; 1267 } 1268 1269 if (total_ie_len < (ID_POS + 1)) { 1270 mlo_err("Total IE length %zu is smaller than minimum required to access element ID %u", 1271 total_ie_len, ID_POS + 1); 1272 return QDF_STATUS_E_INVAL; 1273 } 1274 1275 if ((ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) && 1276 (total_ie_len < (IDEXT_POS + 1))) { 1277 mlo_err("Total IE length %zu is smaller than minimum required to access element ID extension %u", 1278 total_ie_len, IDEXT_POS + 1); 1279 return QDF_STATUS_E_INVAL; 1280 } 1281 1282 *is_in_noninheritlist = false; 1283 1284 /* If both the Non-Inheritance element list and Non-Inheritance element 1285 * ID extension list are empty, then return success since we can 1286 * conclude immediately that the given element does not occur in any 1287 * Non-Inheritance list. The is_in_noninheritlist remains set to false 1288 * as required. 1289 */ 1290 if (!ninherit_elemlist_len && !ninherit_elemextlist_len) 1291 return QDF_STATUS_SUCCESS; 1292 1293 if (ie[ID_POS] != WLAN_ELEMID_EXTN_ELEM) { 1294 if (!ninherit_elemlist_len) 1295 return QDF_STATUS_SUCCESS; 1296 1297 if (!ninherit_elemlist) { 1298 mlo_err("NULL pointer to Non-Inheritance element ID list though length of element ID list is %zu", 1299 ninherit_elemlist_len); 1300 return QDF_STATUS_E_NULL_VALUE; 1301 } 1302 1303 for (i = 0; i < ninherit_elemlist_len; i++) { 1304 if (ie[ID_POS] == ninherit_elemlist[i]) { 1305 *is_in_noninheritlist = true; 1306 return QDF_STATUS_SUCCESS; 1307 } 1308 } 1309 } else { 1310 if (!ninherit_elemextlist_len) 1311 return QDF_STATUS_SUCCESS; 1312 1313 if (!ninherit_elemextlist) { 1314 mlo_err("NULL pointer to Non-Inheritance element ID extension list though length of element ID extension list is %zu", 1315 ninherit_elemextlist_len); 1316 return QDF_STATUS_E_NULL_VALUE; 1317 } 1318 1319 for (i = 0; i < ninherit_elemextlist_len; i++) { 1320 if (ie[IDEXT_POS] == ninherit_elemextlist[i]) { 1321 *is_in_noninheritlist = true; 1322 return QDF_STATUS_SUCCESS; 1323 } 1324 } 1325 } 1326 1327 return QDF_STATUS_SUCCESS; 1328 } 1329 1330 static inline 1331 QDF_STATUS util_validate_reportingsta_ie(const uint8_t *reportingsta_ie, 1332 const uint8_t *frame_iesection, 1333 const qdf_size_t frame_iesection_len) 1334 { 1335 qdf_size_t reportingsta_ie_size; 1336 1337 if (!reportingsta_ie) { 1338 mlo_err("Pointer to reporting STA IE is NULL"); 1339 return QDF_STATUS_E_NULL_VALUE; 1340 } 1341 1342 if (!frame_iesection) { 1343 mlo_err("Pointer to start of IE section in reporting frame is NULL"); 1344 return QDF_STATUS_E_NULL_VALUE; 1345 } 1346 1347 if (!frame_iesection_len) { 1348 mlo_err("Length of IE section in reporting frame is zero"); 1349 return QDF_STATUS_E_INVAL; 1350 } 1351 1352 if ((reportingsta_ie + ID_POS) > (frame_iesection + 1353 frame_iesection_len - 1)) { 1354 mlo_err_rl("Position of element ID field of element for reporting STA would exceed frame IE section boundary"); 1355 return QDF_STATUS_E_PROTO; 1356 } 1357 1358 if ((reportingsta_ie + TAG_LEN_POS) > (frame_iesection + 1359 frame_iesection_len - 1)) { 1360 mlo_err_rl("Position of length field of element with element ID %u for reporting STA would exceed frame IE section boundary", 1361 reportingsta_ie[ID_POS]); 1362 return QDF_STATUS_E_PROTO; 1363 } 1364 1365 if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) && 1366 ((reportingsta_ie + IDEXT_POS) > (frame_iesection + 1367 frame_iesection_len - 1))) { 1368 mlo_err_rl("Position of element ID extension field of element would exceed frame IE section boundary"); 1369 return QDF_STATUS_E_PROTO; 1370 } 1371 1372 reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] + MIN_IE_LEN; 1373 1374 if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) && 1375 (reportingsta_ie_size < (IDEXT_POS + 1))) { 1376 mlo_err_rl("Total length %zu of element for reporting STA is smaller than minimum required to access element ID extension %u", 1377 reportingsta_ie_size, IDEXT_POS + 1); 1378 return QDF_STATUS_E_PROTO; 1379 } 1380 1381 if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_VENDOR) && 1382 (reportingsta_ie_size < (PAYLOAD_START_POS + OUI_LEN))) { 1383 mlo_err_rl("Total length %zu of element for reporting STA is smaller than minimum required to access vendor EID %u", 1384 reportingsta_ie_size, PAYLOAD_START_POS + OUI_LEN); 1385 return QDF_STATUS_E_PROTO; 1386 } 1387 1388 if ((reportingsta_ie + reportingsta_ie_size) > 1389 (frame_iesection + frame_iesection_len)) { 1390 if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 1391 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", 1392 reportingsta_ie_size, 1393 reportingsta_ie[ID_POS], 1394 reportingsta_ie[IDEXT_POS]); 1395 } else { 1396 mlo_err_rl("Total size %zu octets of element with element ID %u for reporting STA would exceed frame IE section boundary", 1397 reportingsta_ie_size, 1398 reportingsta_ie[ID_POS]); 1399 } 1400 1401 return QDF_STATUS_E_PROTO; 1402 } 1403 1404 return QDF_STATUS_SUCCESS; 1405 } 1406 1407 static inline 1408 QDF_STATUS util_validate_sta_prof_ie(const uint8_t *sta_prof_ie, 1409 const uint8_t *sta_prof_iesection, 1410 const qdf_size_t sta_prof_iesection_len) 1411 { 1412 qdf_size_t sta_prof_ie_size; 1413 1414 if (!sta_prof_ie) { 1415 mlo_err("Pointer to STA profile IE is NULL"); 1416 return QDF_STATUS_E_NULL_VALUE; 1417 } 1418 1419 if (!sta_prof_iesection) { 1420 mlo_err("Pointer to start of IE section in STA profile is NULL"); 1421 return QDF_STATUS_E_NULL_VALUE; 1422 } 1423 1424 if (!sta_prof_iesection_len) { 1425 mlo_err("Length of IE section in STA profile is zero"); 1426 return QDF_STATUS_E_INVAL; 1427 } 1428 1429 if ((sta_prof_ie + ID_POS) > (sta_prof_iesection + 1430 sta_prof_iesection_len - 1)) { 1431 mlo_err_rl("Position of element ID field of STA profile element would exceed STA profile IE section boundary"); 1432 return QDF_STATUS_E_PROTO; 1433 } 1434 1435 if ((sta_prof_ie + TAG_LEN_POS) > (sta_prof_iesection + 1436 sta_prof_iesection_len - 1)) { 1437 mlo_err_rl("Position of length field of element with element ID %u in STA profile would exceed STA profile IE section boundary", 1438 sta_prof_ie[ID_POS]); 1439 return QDF_STATUS_E_PROTO; 1440 } 1441 1442 if ((sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) && 1443 ((sta_prof_ie + IDEXT_POS) > (sta_prof_iesection + 1444 sta_prof_iesection_len - 1))) { 1445 mlo_err_rl("Position of element ID extension field of element would exceed STA profile IE section boundary"); 1446 return QDF_STATUS_E_PROTO; 1447 } 1448 1449 sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] + MIN_IE_LEN; 1450 1451 if ((sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) && 1452 (sta_prof_ie_size < (IDEXT_POS + 1))) { 1453 mlo_err_rl("Total length %zu of STA profile element is smaller than minimum required to access element ID extension %u", 1454 sta_prof_ie_size, IDEXT_POS + 1); 1455 return QDF_STATUS_E_PROTO; 1456 } 1457 1458 if ((sta_prof_ie + sta_prof_ie_size) > 1459 (sta_prof_iesection + sta_prof_iesection_len)) { 1460 if (sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 1461 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", 1462 sta_prof_ie_size, 1463 sta_prof_ie[ID_POS], 1464 sta_prof_ie[IDEXT_POS]); 1465 } else { 1466 mlo_err_rl("Total size %zu octets of element with element ID %u in STA profile would exceed STA profile IE section boundary", 1467 sta_prof_ie_size, 1468 sta_prof_ie[ID_POS]); 1469 } 1470 1471 return QDF_STATUS_E_PROTO; 1472 } 1473 1474 return QDF_STATUS_SUCCESS; 1475 } 1476 1477 #define MLO_LINKSPECIFIC_ASSOC_REQ_FC0 0x00 1478 #define MLO_LINKSPECIFIC_ASSOC_REQ_FC1 0x00 1479 #define MLO_LINKSPECIFIC_ASSOC_RESP_FC0 0x10 1480 #define MLO_LINKSPECIFIC_ASSOC_RESP_FC1 0x00 1481 #define MLO_LINKSPECIFIC_PROBE_RESP_FC0 0x50 1482 #define MLO_LINKSPECIFIC_PROBE_RESP_FC1 0x00 1483 1484 static 1485 QDF_STATUS util_gen_link_reqrsp_cmn(uint8_t *frame, qdf_size_t frame_len, 1486 uint8_t subtype, 1487 struct qdf_mac_addr link_addr, 1488 uint8_t *link_frame, 1489 qdf_size_t link_frame_maxsize, 1490 qdf_size_t *link_frame_len) 1491 { 1492 /* Please see documentation for util_gen_link_assoc_req() and 1493 * util_gen_link_assoc_resp() for information on the inputs to and 1494 * output from this helper, since those APIs are essentially wrappers 1495 * over this helper. 1496 */ 1497 1498 /* Pointer to Multi-Link element/Multi-Link element fragment sequence */ 1499 uint8_t *mlieseq; 1500 /* Total length of Multi-Link element sequence (including fragements if 1501 * any) 1502 */ 1503 qdf_size_t mlieseqlen; 1504 /* Variant (i.e. type) of the Multi-Link element */ 1505 enum wlan_ml_variant variant; 1506 1507 /* Length of the payload of the Multi-Link element (inclusive of 1508 * fragment payloads if any) without IE headers and element ID extension 1509 */ 1510 qdf_size_t mlieseqpayloadlen; 1511 /* Pointer to copy of the payload of the Multi-Link element (inclusive 1512 * of fragment payloads if any) without IE headers and element ID 1513 * extension 1514 */ 1515 uint8_t *mlieseqpayload_copy; 1516 1517 /* Pointer to start of Link Info within the copy of the payload of the 1518 * Multi-Link element 1519 */ 1520 uint8_t *link_info; 1521 /* Length of the Link Info */ 1522 qdf_size_t link_info_len; 1523 1524 /* Pointer to the IE section that occurs after the fixed fields in the 1525 * original frame for the reporting STA. 1526 */ 1527 uint8_t *frame_iesection; 1528 /* Offset to the start of the IE section in the original frame for the 1529 * reporting STA. 1530 */ 1531 qdf_size_t frame_iesection_offset; 1532 /* Total length of the IE section in the original frame for the 1533 * reporting STA. 1534 */ 1535 qdf_size_t frame_iesection_len; 1536 1537 /* Pointer to the IEEE802.11 frame header in the link specific frame 1538 * being generated for the reported STA. 1539 */ 1540 struct wlan_frame_hdr *link_frame_hdr; 1541 /* Current position in the link specific frame being generated for the 1542 * reported STA. 1543 */ 1544 uint8_t *link_frame_currpos; 1545 /* Current length of the link specific frame being generated for the 1546 * reported STA. 1547 */ 1548 qdf_size_t link_frame_currlen; 1549 1550 /* Pointer to IE for reporting STA */ 1551 const uint8_t *reportingsta_ie; 1552 /* Total size of IE for reporting STA, inclusive of the element header 1553 */ 1554 qdf_size_t reportingsta_ie_size; 1555 1556 /* Pointer to current position in STA profile */ 1557 uint8_t *sta_prof_currpos; 1558 /* Remaining length of STA profile */ 1559 qdf_size_t sta_prof_remlen; 1560 /* Pointer to start of IE section in STA profile that occurs after fixed 1561 * fields. 1562 */ 1563 uint8_t *sta_prof_iesection; 1564 /* Total length of IE section in STA profile */ 1565 qdf_size_t sta_prof_iesection_len; 1566 /* Pointer to current position being processed in IE section in STA 1567 * profile. 1568 */ 1569 uint8_t *sta_prof_iesection_currpos; 1570 /* Remaining length of IE section in STA profile */ 1571 qdf_size_t sta_prof_iesection_remlen; 1572 1573 /* Pointer to IE in STA profile, that occurs within IE section */ 1574 uint8_t *sta_prof_ie; 1575 /* Total size of IE in STA profile, inclusive of the element header */ 1576 qdf_size_t sta_prof_ie_size; 1577 1578 /* Pointer to element ID list in Non-Inheritance IE */ 1579 uint8_t *ninherit_elemlist; 1580 /* Length of element ID list in Non-Inheritance IE */ 1581 qdf_size_t ninherit_elemlist_len; 1582 /* Pointer to element ID extension list in Non-Inheritance IE */ 1583 uint8_t *ninherit_elemextlist; 1584 /* Length of element ID extension list in Non-Inheritance IE */ 1585 qdf_size_t ninherit_elemextlist_len; 1586 /* Whether a given IE is in a non-inheritance list */ 1587 bool is_in_noninheritlist; 1588 1589 /* Whether MAC address of reported STA is valid */ 1590 bool is_reportedmacaddr_valid; 1591 /* MAC address of reported STA */ 1592 struct qdf_mac_addr reportedmacaddr; 1593 1594 /* Pointer to per-STA profile */ 1595 uint8_t *persta_prof; 1596 /* Length of the containing buffer which starts with the per-STA profile 1597 */ 1598 qdf_size_t persta_prof_bufflen; 1599 1600 /* Other variables for temporary purposes */ 1601 1602 /* Variable into which API for determining fragment information will 1603 * indicate whether the element is the start of a fragment sequence or 1604 * not. 1605 */ 1606 bool is_elemfragseq; 1607 /* De-fragmented payload length returned by API for element 1608 * defragmentation. 1609 */ 1610 qdf_size_t defragpayload_len; 1611 /* Variable into which API for determining fragment information will 1612 * indicate whether the subelement is the start of a fragment sequence 1613 * or not. 1614 */ 1615 bool is_subelemfragseq; 1616 /* Total length of the subelement fragment sequence, inclusive of 1617 * subelement header and the headers of fragments if any. 1618 */ 1619 qdf_size_t subelemseqtotallen; 1620 /* Total length of the subelement fragment sequence payload, excluding 1621 * subelement header and fragment headers if any. 1622 */ 1623 qdf_size_t subelemseqpayloadlen; 1624 /* Pointer to Beacon interval in STA info field */ 1625 uint16_t beaconinterval; 1626 /* Whether Beacon interval value valid */ 1627 bool is_beaconinterval_valid; 1628 /* TSF timer of the reporting AP */ 1629 uint64_t tsf; 1630 /* TSF offset of the reproted AP */ 1631 uint64_t tsfoffset; 1632 /* TSF offset value valid */ 1633 bool is_tsfoffset_valid; 1634 /* If Complete Profile or not*/ 1635 bool is_completeprofile; 1636 qdf_size_t tmplen; 1637 QDF_STATUS ret; 1638 1639 if (!frame) { 1640 mlo_err("Pointer to original frame is NULL"); 1641 return QDF_STATUS_E_NULL_VALUE; 1642 } 1643 1644 if (!frame_len) { 1645 mlo_err("Length of original frame is zero"); 1646 return QDF_STATUS_E_INVAL; 1647 } 1648 1649 if ((subtype != WLAN_FC0_STYPE_ASSOC_REQ) && 1650 (subtype != WLAN_FC0_STYPE_REASSOC_REQ) && 1651 (subtype != WLAN_FC0_STYPE_ASSOC_RESP) && 1652 (subtype != WLAN_FC0_STYPE_REASSOC_RESP) && 1653 (subtype != WLAN_FC0_STYPE_PROBE_RESP)) { 1654 mlo_err("802.11 frame subtype %u is invalid", subtype); 1655 return QDF_STATUS_E_INVAL; 1656 } 1657 1658 if (!link_frame) { 1659 mlo_err("Pointer to secondary link specific frame is NULL"); 1660 return QDF_STATUS_E_NULL_VALUE; 1661 } 1662 1663 if (!link_frame_maxsize) { 1664 mlo_err("Maximum size of secondary link specific frame is zero"); 1665 return QDF_STATUS_E_INVAL; 1666 } 1667 1668 if (!link_frame_len) { 1669 mlo_err("Pointer to populated length of secondary link specific frame is NULL"); 1670 return QDF_STATUS_E_NULL_VALUE; 1671 } 1672 1673 frame_iesection_offset = 0; 1674 1675 if (subtype == WLAN_FC0_STYPE_ASSOC_REQ) { 1676 frame_iesection_offset = WLAN_ASSOC_REQ_IES_OFFSET; 1677 } else if (subtype == WLAN_FC0_STYPE_REASSOC_REQ) { 1678 frame_iesection_offset = WLAN_REASSOC_REQ_IES_OFFSET; 1679 } else if (subtype == WLAN_FC0_STYPE_PROBE_RESP) { 1680 frame_iesection_offset = WLAN_PROBE_RESP_IES_OFFSET; 1681 qdf_mem_copy(&tsf, frame, WLAN_TIMESTAMP_LEN); 1682 tsf = qdf_le64_to_cpu(tsf); 1683 } else { 1684 /* This is a (re)association response */ 1685 frame_iesection_offset = WLAN_ASSOC_RSP_IES_OFFSET; 1686 } 1687 1688 if (frame_len < frame_iesection_offset) { 1689 /* The caller is supposed to have confirmed that this is a valid 1690 * frame containing a Multi-Link element. Hence we treat this as 1691 * a case of invalid argument being passed to us. 1692 */ 1693 mlo_err("Frame length %zu is smaller than the IE section offset %zu for subtype %u", 1694 frame_len, frame_iesection_offset, subtype); 1695 return QDF_STATUS_E_INVAL; 1696 } 1697 1698 frame_iesection_len = frame_len - frame_iesection_offset; 1699 1700 if (frame_iesection_len == 0) { 1701 /* The caller is supposed to have confirmed that this is a valid 1702 * frame containing a Multi-Link element. Hence we treat this as 1703 * a case of invalid argument being passed to us. 1704 */ 1705 mlo_err("No space left in frame for IE section"); 1706 return QDF_STATUS_E_INVAL; 1707 } 1708 1709 frame_iesection = frame + frame_iesection_offset; 1710 1711 mlieseq = NULL; 1712 mlieseqlen = 0; 1713 1714 ret = util_find_mlie(frame_iesection, frame_iesection_len, &mlieseq, 1715 &mlieseqlen); 1716 if (QDF_IS_STATUS_ERROR(ret)) 1717 return ret; 1718 1719 if (!mlieseq) { 1720 /* The caller is supposed to have confirmed that a Multi-Link 1721 * element is present in the frame. Hence we treat this as a 1722 * case of invalid argument being passed to us. 1723 */ 1724 mlo_err("Invalid original frame since no Multi-Link element found"); 1725 return QDF_STATUS_E_INVAL; 1726 } 1727 1728 /* Sanity check the Multi-Link element sequence length */ 1729 if (!mlieseqlen) { 1730 mlo_err("Length of Multi-Link element sequence is zero. Investigate."); 1731 return QDF_STATUS_E_FAILURE; 1732 } 1733 1734 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) { 1735 mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)", 1736 mlieseqlen, sizeof(struct wlan_ie_multilink)); 1737 return QDF_STATUS_E_PROTO; 1738 } 1739 1740 ret = util_get_mlie_variant(mlieseq, mlieseqlen, (int *)&variant); 1741 if (QDF_IS_STATUS_ERROR(ret)) 1742 return ret; 1743 1744 if (variant != WLAN_ML_VARIANT_BASIC) { 1745 mlo_err_rl("Unexpected variant %u of Multi-Link element.", 1746 variant); 1747 return QDF_STATUS_E_PROTO; 1748 } 1749 1750 mlieseqpayloadlen = 0; 1751 tmplen = 0; 1752 is_elemfragseq = false; 1753 1754 ret = wlan_get_elem_fragseq_info(mlieseq, 1755 mlieseqlen, 1756 &is_elemfragseq, 1757 &tmplen, 1758 &mlieseqpayloadlen); 1759 if (QDF_IS_STATUS_ERROR(ret)) 1760 return ret; 1761 1762 if (is_elemfragseq) { 1763 if (tmplen != mlieseqlen) { 1764 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", 1765 tmplen, mlieseqlen); 1766 return QDF_STATUS_E_FAILURE; 1767 } 1768 1769 if (!mlieseqpayloadlen) { 1770 mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate"); 1771 return QDF_STATUS_E_FAILURE; 1772 } 1773 1774 mlo_debug("Multi-Link element fragment sequence found with payload len %zu", 1775 mlieseqpayloadlen); 1776 } else { 1777 if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) { 1778 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", 1779 mlieseqlen, 1780 sizeof(struct ie_header) + WLAN_MAX_IE_LEN); 1781 return QDF_STATUS_E_FAILURE; 1782 } 1783 1784 mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1); 1785 } 1786 1787 mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen); 1788 1789 if (!mlieseqpayload_copy) { 1790 mlo_err_rl("Could not allocate memory for Multi-Link element payload copy"); 1791 return QDF_STATUS_E_NOMEM; 1792 } 1793 1794 if (is_elemfragseq) { 1795 ret = wlan_defrag_elem_fragseq(false, 1796 mlieseq, 1797 mlieseqlen, 1798 mlieseqpayload_copy, 1799 mlieseqpayloadlen, 1800 &defragpayload_len); 1801 if (QDF_IS_STATUS_ERROR(ret)) { 1802 qdf_mem_free(mlieseqpayload_copy); 1803 return ret; 1804 } 1805 1806 if (defragpayload_len != mlieseqpayloadlen) { 1807 mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets", 1808 defragpayload_len, mlieseqpayloadlen); 1809 qdf_mem_free(mlieseqpayload_copy); 1810 return QDF_STATUS_E_FAILURE; 1811 } 1812 } else { 1813 qdf_mem_copy(mlieseqpayload_copy, 1814 mlieseq + sizeof(struct ie_header) + 1, 1815 mlieseqpayloadlen); 1816 } 1817 1818 link_info = NULL; 1819 link_info_len = 0; 1820 1821 ret = util_parse_multi_link_ctrl(mlieseqpayload_copy, 1822 mlieseqpayloadlen, 1823 &link_info, 1824 &link_info_len); 1825 if (QDF_IS_STATUS_ERROR(ret)) { 1826 qdf_mem_free(mlieseqpayload_copy); 1827 return ret; 1828 } 1829 1830 /* As per the standard, the sender must include Link Info for 1831 * association request/response. Throw an error if we are unable to 1832 * obtain this. 1833 */ 1834 if (!link_info) { 1835 mlo_err_rl("Unable to successfully obtain Link Info"); 1836 qdf_mem_free(mlieseqpayload_copy); 1837 return QDF_STATUS_E_PROTO; 1838 } 1839 1840 mlo_debug("Dumping hex of link info after parsing Multi-Link element control"); 1841 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_MLO, QDF_TRACE_LEVEL_DEBUG, 1842 link_info, link_info_len); 1843 1844 /* Note: We may have a future change to skip subelements which are not 1845 * Per-STA Profile, handle more than two links in MLO, handle cases 1846 * where we unexpectedly find more Per-STA Profiles than expected, etc. 1847 */ 1848 1849 persta_prof = link_info; 1850 persta_prof_bufflen = link_info_len; 1851 1852 is_subelemfragseq = false; 1853 subelemseqtotallen = 0; 1854 subelemseqpayloadlen = 0; 1855 1856 ret = wlan_get_subelem_fragseq_info(WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 1857 persta_prof, 1858 persta_prof_bufflen, 1859 &is_subelemfragseq, 1860 &subelemseqtotallen, 1861 &subelemseqpayloadlen); 1862 if (QDF_IS_STATUS_ERROR(ret)) { 1863 qdf_mem_free(mlieseqpayload_copy); 1864 return ret; 1865 } 1866 1867 if (is_subelemfragseq) { 1868 if (!subelemseqpayloadlen) { 1869 mlo_err_rl("Subelement fragment sequence payload is reported as 0, investigate"); 1870 qdf_mem_free(mlieseqpayload_copy); 1871 return QDF_STATUS_E_FAILURE; 1872 } 1873 1874 mlo_debug("Subelement fragment sequence found with payload len %zu", 1875 subelemseqpayloadlen); 1876 1877 ret = wlan_defrag_subelem_fragseq(true, 1878 WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 1879 persta_prof, 1880 persta_prof_bufflen, 1881 NULL, 1882 0, 1883 &defragpayload_len); 1884 if (QDF_IS_STATUS_ERROR(ret)) { 1885 qdf_mem_free(mlieseqpayload_copy); 1886 return ret; 1887 } 1888 1889 if (defragpayload_len != subelemseqpayloadlen) { 1890 mlo_err_rl("Length of defragmented payload %zu octets is not equal to length of subelement fragment sequence payload %zu octets", 1891 defragpayload_len, 1892 subelemseqpayloadlen); 1893 qdf_mem_free(mlieseqpayload_copy); 1894 return QDF_STATUS_E_FAILURE; 1895 } 1896 } else { 1897 if (persta_prof_bufflen < 1898 (sizeof(struct subelem_header) + 1899 persta_prof[TAG_LEN_POS])) { 1900 mlo_err_rl("Length of buffer containing per-STA profile %zu octets is smaller than total size of current subelement %zu octets", 1901 persta_prof_bufflen, 1902 sizeof(struct subelem_header) + 1903 persta_prof[TAG_LEN_POS]); 1904 return QDF_STATUS_E_PROTO; 1905 } 1906 1907 subelemseqpayloadlen = persta_prof[TAG_LEN_POS]; 1908 } 1909 1910 sta_prof_remlen = 0; 1911 sta_prof_currpos = NULL; 1912 is_reportedmacaddr_valid = false; 1913 is_beaconinterval_valid = false; 1914 is_completeprofile = false; 1915 is_tsfoffset_valid = false; 1916 1917 /* Parse per-STA profile */ 1918 ret = util_parse_bvmlie_perstaprofile_stactrl(persta_prof + 1919 sizeof(struct subelem_header), 1920 subelemseqpayloadlen, 1921 NULL, 1922 &beaconinterval, 1923 &is_beaconinterval_valid, 1924 &tsfoffset, 1925 &is_tsfoffset_valid, 1926 &is_completeprofile, 1927 &is_reportedmacaddr_valid, 1928 &reportedmacaddr, 1929 true, 1930 &sta_prof_currpos, 1931 &sta_prof_remlen); 1932 if (QDF_IS_STATUS_ERROR(ret)) { 1933 qdf_mem_free(mlieseqpayload_copy); 1934 return ret; 1935 } 1936 1937 if (subtype == WLAN_FC0_STYPE_PROBE_RESP && !is_completeprofile) { 1938 mlo_err("Complete profile information is not present in per-STA profile of probe response frame"); 1939 return QDF_STATUS_E_NOSUPPORT; 1940 } 1941 1942 /* We double check for a NULL STA Profile, though the helper function 1943 * above would have taken care of this. We need to get a non-NULL STA 1944 * profile, because we need to get at least the expected fixed fields, 1945 * even if there is an (improbable) total inheritance. 1946 */ 1947 if (!sta_prof_currpos) { 1948 mlo_err_rl("STA profile is NULL"); 1949 qdf_mem_free(mlieseqpayload_copy); 1950 return QDF_STATUS_E_PROTO; 1951 } 1952 1953 /* As per the standard, the sender sets the MAC address in the per-STA 1954 * profile in association request/response. Without this, we cannot 1955 * generate the link specific frame. 1956 */ 1957 if (!is_reportedmacaddr_valid) { 1958 mlo_err_rl("Unable to get MAC address from per-STA profile"); 1959 qdf_mem_free(mlieseqpayload_copy); 1960 return QDF_STATUS_E_PROTO; 1961 } 1962 1963 link_frame_currpos = link_frame; 1964 *link_frame_len = 0; 1965 link_frame_currlen = 0; 1966 1967 if (link_frame_maxsize < WLAN_MAC_HDR_LEN_3A) { 1968 mlo_err("Insufficent space in link specific frame for 802.11 header. Required: %u octets, available: %zu octets", 1969 WLAN_MAC_HDR_LEN_3A, link_frame_maxsize); 1970 1971 qdf_mem_free(mlieseqpayload_copy); 1972 return QDF_STATUS_E_NOMEM; 1973 } 1974 1975 link_frame_currpos += WLAN_MAC_HDR_LEN_3A; 1976 link_frame_currlen += WLAN_MAC_HDR_LEN_3A; 1977 1978 if ((subtype == WLAN_FC0_STYPE_ASSOC_REQ) || 1979 (subtype == WLAN_FC0_STYPE_REASSOC_REQ)) { 1980 mlo_debug("Populating fixed fields for (re)assoc req in link specific frame"); 1981 1982 if (sta_prof_remlen < WLAN_CAPABILITYINFO_LEN) { 1983 mlo_err_rl("Remaining length of STA profile %zu octets is less than length of Capability Info %u", 1984 sta_prof_remlen, 1985 WLAN_CAPABILITYINFO_LEN); 1986 1987 qdf_mem_free(mlieseqpayload_copy); 1988 return QDF_STATUS_E_PROTO; 1989 } 1990 1991 /* Capability information is specific to the link. Copy this 1992 * from the STA profile. 1993 */ 1994 1995 if ((link_frame_maxsize - link_frame_currlen) < 1996 WLAN_CAPABILITYINFO_LEN) { 1997 mlo_err("Insufficent space in link specific frame for Capability Info field. Required: %u octets, available: %zu octets", 1998 WLAN_CAPABILITYINFO_LEN, 1999 (link_frame_maxsize - link_frame_currlen)); 2000 2001 qdf_mem_free(mlieseqpayload_copy); 2002 return QDF_STATUS_E_NOMEM; 2003 } 2004 2005 qdf_mem_copy(link_frame_currpos, sta_prof_currpos, 2006 WLAN_CAPABILITYINFO_LEN); 2007 link_frame_currpos += WLAN_CAPABILITYINFO_LEN; 2008 link_frame_currlen += WLAN_CAPABILITYINFO_LEN; 2009 mlo_debug("Added Capablity Info field (%u octets) to link specific frame", 2010 WLAN_CAPABILITYINFO_LEN); 2011 2012 sta_prof_currpos += WLAN_CAPABILITYINFO_LEN; 2013 sta_prof_remlen -= WLAN_CAPABILITYINFO_LEN; 2014 2015 /* Listen Interval is common between all links. Copy this from 2016 * the reporting section of the frame. 2017 */ 2018 2019 if ((link_frame_maxsize - link_frame_currlen) < 2020 WLAN_LISTENINTERVAL_LEN) { 2021 mlo_err("Insufficent space in link specific frame for Listen Interval field. Required: %u octets, available: %zu octets", 2022 WLAN_LISTENINTERVAL_LEN, 2023 (link_frame_maxsize - link_frame_currlen)); 2024 2025 qdf_mem_free(mlieseqpayload_copy); 2026 return QDF_STATUS_E_NOMEM; 2027 } 2028 2029 qdf_mem_copy(link_frame_currpos, 2030 frame + WLAN_CAPABILITYINFO_LEN, 2031 WLAN_LISTENINTERVAL_LEN); 2032 link_frame_currpos += WLAN_LISTENINTERVAL_LEN; 2033 link_frame_currlen += WLAN_LISTENINTERVAL_LEN; 2034 mlo_debug("Added Listen Interval field (%u octets) to link specific frame", 2035 WLAN_LISTENINTERVAL_LEN); 2036 2037 if (subtype == WLAN_FC0_STYPE_REASSOC_REQ) { 2038 /* Current AP address is common between all links. Copy 2039 * this from the reporting section of the frame. 2040 */ 2041 if ((link_frame_maxsize - link_frame_currlen) < 2042 QDF_MAC_ADDR_SIZE) { 2043 mlo_err("Insufficent space in link specific frame for current AP address. Required: %u octets, available: %zu octets", 2044 QDF_MAC_ADDR_SIZE, 2045 (link_frame_maxsize - 2046 link_frame_currlen)); 2047 2048 qdf_mem_free(mlieseqpayload_copy); 2049 return QDF_STATUS_E_NOMEM; 2050 } 2051 2052 qdf_mem_copy(link_frame_currpos, 2053 frame + WLAN_CAPABILITYINFO_LEN + 2054 WLAN_LISTENINTERVAL_LEN, 2055 QDF_MAC_ADDR_SIZE); 2056 link_frame_currpos += QDF_MAC_ADDR_SIZE; 2057 link_frame_currlen += QDF_MAC_ADDR_SIZE; 2058 mlo_debug("Reassoc req: Added Current AP address field (%u octets) to link specific frame", 2059 QDF_MAC_ADDR_SIZE); 2060 } 2061 } else if (subtype == WLAN_FC0_STYPE_ASSOC_RESP || 2062 subtype == WLAN_FC0_STYPE_REASSOC_RESP) { 2063 /* This is a (re)association response */ 2064 mlo_debug("Populating fixed fields for (re)assoc resp in link specific frame"); 2065 2066 if (sta_prof_remlen < 2067 (WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN)) { 2068 mlo_err_rl("Remaining length of STA profile %zu octets is less than length of Capability Info + length of Status Code %u", 2069 sta_prof_remlen, 2070 WLAN_CAPABILITYINFO_LEN + 2071 WLAN_STATUSCODE_LEN); 2072 2073 qdf_mem_free(mlieseqpayload_copy); 2074 return QDF_STATUS_E_PROTO; 2075 } 2076 2077 /* Capability information and Status Code are specific to the 2078 * link. Copy these from the STA profile. 2079 */ 2080 2081 if ((link_frame_maxsize - link_frame_currlen) < 2082 (WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN)) { 2083 mlo_err("Insufficent space in link specific frame for Capability Info and Status Code fields. Required: %u octets, available: %zu octets", 2084 WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN, 2085 (link_frame_maxsize - link_frame_currlen)); 2086 2087 qdf_mem_free(mlieseqpayload_copy); 2088 return QDF_STATUS_E_NOMEM; 2089 } 2090 2091 qdf_mem_copy(link_frame_currpos, sta_prof_currpos, 2092 (WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN)); 2093 link_frame_currpos += (WLAN_CAPABILITYINFO_LEN + 2094 WLAN_STATUSCODE_LEN); 2095 link_frame_currlen += (WLAN_CAPABILITYINFO_LEN + 2096 WLAN_STATUSCODE_LEN); 2097 mlo_debug("Added Capability Info and Status Code fields (%u octets) to link specific frame", 2098 WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN); 2099 2100 sta_prof_currpos += (WLAN_CAPABILITYINFO_LEN + 2101 WLAN_STATUSCODE_LEN); 2102 sta_prof_remlen -= (WLAN_CAPABILITYINFO_LEN + 2103 WLAN_STATUSCODE_LEN); 2104 2105 /* AID is common between all links. Copy this from the original 2106 * frame. 2107 */ 2108 2109 if ((link_frame_maxsize - link_frame_currlen) < WLAN_AID_LEN) { 2110 mlo_err("Insufficent space in link specific frame for AID field. Required: %u octets, available: %zu octets", 2111 WLAN_AID_LEN, 2112 (link_frame_maxsize - link_frame_currlen)); 2113 2114 qdf_mem_free(mlieseqpayload_copy); 2115 return QDF_STATUS_E_NOMEM; 2116 } 2117 2118 qdf_mem_copy(link_frame_currpos, 2119 frame + WLAN_CAPABILITYINFO_LEN + 2120 WLAN_STATUSCODE_LEN, 2121 WLAN_AID_LEN); 2122 link_frame_currpos += WLAN_AID_LEN; 2123 link_frame_currlen += WLAN_AID_LEN; 2124 mlo_debug("Added AID field (%u octets) to link specific frame", 2125 WLAN_AID_LEN); 2126 } else if (subtype == WLAN_FC0_STYPE_PROBE_RESP) { 2127 /* This is a probe response */ 2128 mlo_debug("Populating fixed fields for probe response in link specific frame"); 2129 2130 if ((link_frame_maxsize - link_frame_currlen) < 2131 WLAN_TIMESTAMP_LEN) { 2132 mlo_err("Insufficent space in link specific frame for Timestamp Info field. Required: %u octets, available: %zu octets", 2133 WLAN_TIMESTAMP_LEN, 2134 (link_frame_maxsize - link_frame_currlen)); 2135 2136 qdf_mem_free(mlieseqpayload_copy); 2137 return QDF_STATUS_E_NOMEM; 2138 } 2139 2140 /* Per spec 11be_D2.1.1, the TSF Offset subfield of the STA Info 2141 * field indicates the offset (Toffset)between the TSF timer of 2142 * the reported AP (TA) and the TSF timer of the reporting 2143 * AP (TB) and is encoded as a 2s complement signed integer 2144 * with units of 2 µs. Toffset is calculated as 2145 * Toffset= Floor((TA – TB)/2). 2146 */ 2147 if (is_tsfoffset_valid) 2148 tsf += tsfoffset * 2; 2149 2150 qdf_mem_copy(link_frame_currpos, &tsf, WLAN_TIMESTAMP_LEN); 2151 link_frame_currpos += WLAN_TIMESTAMP_LEN; 2152 link_frame_currlen += WLAN_TIMESTAMP_LEN; 2153 mlo_debug("Added Timestamp Info field (%u octets) to link specific frame", 2154 WLAN_TIMESTAMP_LEN); 2155 2156 if (!is_beaconinterval_valid) { 2157 mlo_err_rl("Beacon interval information not present in STA info field of per-STA profile"); 2158 qdf_mem_free(mlieseqpayload_copy); 2159 return QDF_STATUS_E_PROTO; 2160 } 2161 2162 /* Beacon Interval information copy this from 2163 * the STA info field. 2164 */ 2165 if ((link_frame_maxsize - link_frame_currlen) < 2166 WLAN_BEACONINTERVAL_LEN) { 2167 mlo_err("Insufficent space in link specific frame for Beacon Interval Info field. Required: %u octets, available: %zu octets", 2168 WLAN_BEACONINTERVAL_LEN, 2169 (link_frame_maxsize - link_frame_currlen)); 2170 2171 qdf_mem_free(mlieseqpayload_copy); 2172 return QDF_STATUS_E_NOMEM; 2173 } 2174 2175 qdf_mem_copy(link_frame_currpos, &beaconinterval, 2176 WLAN_BEACONINTERVAL_LEN); 2177 link_frame_currpos += WLAN_BEACONINTERVAL_LEN; 2178 link_frame_currlen += WLAN_BEACONINTERVAL_LEN; 2179 mlo_debug("Added Beacon Interval Info field (%u octets) to link specific frame", 2180 WLAN_BEACONINTERVAL_LEN); 2181 2182 if (sta_prof_remlen < WLAN_CAPABILITYINFO_LEN) { 2183 mlo_err_rl("Remaining length of STA profile %zu octets is less than length of Capability Info %u", 2184 sta_prof_remlen, 2185 WLAN_CAPABILITYINFO_LEN); 2186 2187 qdf_mem_free(mlieseqpayload_copy); 2188 return QDF_STATUS_E_PROTO; 2189 } 2190 2191 /* Capability information is specific to the link. Copy this 2192 * from the STA profile. 2193 */ 2194 2195 if ((link_frame_maxsize - link_frame_currlen) < 2196 WLAN_CAPABILITYINFO_LEN) { 2197 mlo_err("Insufficent space in link specific frame for Capability Info field. Required: %u octets, available: %zu octets", 2198 WLAN_CAPABILITYINFO_LEN, 2199 (link_frame_maxsize - link_frame_currlen)); 2200 2201 qdf_mem_free(mlieseqpayload_copy); 2202 return QDF_STATUS_E_NOMEM; 2203 } 2204 2205 qdf_mem_copy(link_frame_currpos, sta_prof_currpos, 2206 WLAN_CAPABILITYINFO_LEN); 2207 link_frame_currpos += WLAN_CAPABILITYINFO_LEN; 2208 link_frame_currlen += WLAN_CAPABILITYINFO_LEN; 2209 mlo_debug("Added Capablity Info field (%u octets) to link specific frame", 2210 WLAN_CAPABILITYINFO_LEN); 2211 2212 sta_prof_currpos += WLAN_CAPABILITYINFO_LEN; 2213 sta_prof_remlen -= WLAN_CAPABILITYINFO_LEN; 2214 } 2215 2216 sta_prof_iesection = sta_prof_currpos; 2217 sta_prof_iesection_len = sta_prof_remlen; 2218 2219 /* Populate non-inheritance lists if applicable */ 2220 ninherit_elemlist_len = 0; 2221 ninherit_elemlist = NULL; 2222 ninherit_elemextlist_len = 0; 2223 ninherit_elemextlist = NULL; 2224 2225 ret = util_get_noninheritlists(sta_prof_iesection, 2226 sta_prof_iesection_len, 2227 &ninherit_elemlist, 2228 &ninherit_elemlist_len, 2229 &ninherit_elemextlist, 2230 &ninherit_elemextlist_len); 2231 if (QDF_IS_STATUS_ERROR(ret)) { 2232 qdf_mem_free(mlieseqpayload_copy); 2233 return ret; 2234 } 2235 2236 /* Go through IEs of the reporting STA, and those in STA profile, merge 2237 * them into link_frame (except for elements in the Non-Inheritance 2238 * list). 2239 * 2240 * Note: Currently, only 2-link MLO is supported here. We may have a 2241 * future change to expand to more links. 2242 */ 2243 reportingsta_ie = util_find_eid(WLAN_ELEMID_SSID, frame_iesection, 2244 frame_iesection_len); 2245 2246 if ((subtype == WLAN_FC0_STYPE_ASSOC_REQ) || 2247 (subtype == WLAN_FC0_STYPE_REASSOC_REQ) || 2248 (subtype == WLAN_FC0_STYPE_PROBE_RESP)) { 2249 /* Sanity check that the SSID element is present for the 2250 * reporting STA. There is no stipulation in the standard for 2251 * the STA profile in this regard, so we do not check the STA 2252 * profile for the SSID element. 2253 */ 2254 if (!reportingsta_ie) { 2255 mlo_err_rl("SSID element not found in reporting STA of the frame."); 2256 qdf_mem_free(mlieseqpayload_copy); 2257 return QDF_STATUS_E_PROTO; 2258 } 2259 } else { 2260 /* This is a (re)association response. Sanity check that the 2261 * SSID element is present neither for the reporting STA nor in 2262 * the STA profile. 2263 */ 2264 if (reportingsta_ie) { 2265 mlo_err_rl("SSID element found for reporting STA for (re)association response. It should not be present."); 2266 qdf_mem_free(mlieseqpayload_copy); 2267 return QDF_STATUS_E_PROTO; 2268 } 2269 2270 sta_prof_ie = util_find_eid(WLAN_ELEMID_SSID, 2271 sta_prof_iesection, 2272 sta_prof_iesection_len); 2273 2274 if (sta_prof_ie) { 2275 mlo_err_rl("SSID element found in STA profile for (re)association response. It should not be present."); 2276 qdf_mem_free(mlieseqpayload_copy); 2277 return QDF_STATUS_E_PROTO; 2278 } 2279 } 2280 2281 reportingsta_ie = reportingsta_ie ? reportingsta_ie : frame_iesection; 2282 2283 ret = util_validate_reportingsta_ie(reportingsta_ie, frame_iesection, 2284 frame_iesection_len); 2285 if (QDF_IS_STATUS_ERROR(ret)) { 2286 qdf_mem_free(mlieseqpayload_copy); 2287 return ret; 2288 } 2289 2290 reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] + MIN_IE_LEN; 2291 2292 while (((reportingsta_ie + reportingsta_ie_size) - frame_iesection) 2293 <= frame_iesection_len) { 2294 /* Skip Multi-Link element */ 2295 if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) && 2296 (reportingsta_ie[IDEXT_POS] == 2297 WLAN_EXTN_ELEMID_MULTI_LINK)) { 2298 if (((reportingsta_ie + reportingsta_ie_size) - 2299 frame_iesection) == frame_iesection_len) 2300 break; 2301 2302 reportingsta_ie += reportingsta_ie_size; 2303 2304 ret = util_validate_reportingsta_ie(reportingsta_ie, 2305 frame_iesection, 2306 frame_iesection_len); 2307 if (QDF_IS_STATUS_ERROR(ret)) { 2308 qdf_mem_free(mlieseqpayload_copy); 2309 return ret; 2310 } 2311 2312 reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] + 2313 MIN_IE_LEN; 2314 2315 continue; 2316 } 2317 2318 sta_prof_ie = NULL; 2319 sta_prof_ie_size = 0; 2320 2321 if (sta_prof_iesection_len) { 2322 if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 2323 sta_prof_ie = (uint8_t *)util_find_extn_eid(reportingsta_ie[ID_POS], 2324 reportingsta_ie[IDEXT_POS], 2325 sta_prof_iesection, 2326 sta_prof_iesection_len); 2327 } else { 2328 sta_prof_ie = (uint8_t *)util_find_eid(reportingsta_ie[ID_POS], 2329 sta_prof_iesection, 2330 sta_prof_iesection_len); 2331 } 2332 } 2333 2334 if (!sta_prof_ie) { 2335 /* IE is present for reporting STA, but not in STA 2336 * profile. 2337 */ 2338 2339 is_in_noninheritlist = false; 2340 2341 ret = util_eval_ie_in_noninheritlist((uint8_t *)reportingsta_ie, 2342 reportingsta_ie_size, 2343 ninherit_elemlist, 2344 ninherit_elemlist_len, 2345 ninherit_elemextlist, 2346 ninherit_elemextlist_len, 2347 &is_in_noninheritlist); 2348 2349 if (QDF_IS_STATUS_ERROR(ret)) { 2350 qdf_mem_free(mlieseqpayload_copy); 2351 return ret; 2352 } 2353 2354 if (!is_in_noninheritlist) { 2355 if ((link_frame_currpos + 2356 reportingsta_ie_size) <= 2357 (link_frame + link_frame_maxsize)) { 2358 qdf_mem_copy(link_frame_currpos, 2359 reportingsta_ie, 2360 reportingsta_ie_size); 2361 2362 link_frame_currpos += 2363 reportingsta_ie_size; 2364 link_frame_currlen += 2365 reportingsta_ie_size; 2366 2367 if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 2368 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", 2369 reportingsta_ie[ID_POS], 2370 reportingsta_ie[IDEXT_POS], 2371 reportingsta_ie_size); 2372 } else { 2373 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", 2374 reportingsta_ie[ID_POS], 2375 reportingsta_ie_size); 2376 } 2377 } else { 2378 if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 2379 mlo_err_rl("Insufficent space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets", 2380 reportingsta_ie[ID_POS], 2381 reportingsta_ie[IDEXT_POS], 2382 reportingsta_ie_size, 2383 link_frame_maxsize - 2384 link_frame_currlen); 2385 } else { 2386 mlo_err_rl("Insufficent space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets", 2387 reportingsta_ie[ID_POS], 2388 reportingsta_ie_size, 2389 link_frame_maxsize - 2390 link_frame_currlen); 2391 } 2392 2393 qdf_mem_free(mlieseqpayload_copy); 2394 return QDF_STATUS_E_NOMEM; 2395 } 2396 } else { 2397 if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 2398 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.", 2399 reportingsta_ie[ID_POS], 2400 reportingsta_ie[IDEXT_POS], 2401 reportingsta_ie_size); 2402 } else { 2403 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.", 2404 reportingsta_ie[ID_POS], 2405 reportingsta_ie_size); 2406 } 2407 } 2408 } else { 2409 /* IE is present for reporting STA and also in STA 2410 * profile, copy from STA profile and flag the IE in STA 2411 * profile as copied (by setting EID field to 0). The 2412 * SSID element (with EID 0) is processed first to 2413 * enable this. For vendor IE, compare OUI + type + 2414 * subType to determine if they are the same IE. 2415 */ 2416 /* Note: This may be revisited in a future change, to 2417 * adhere to provisions in the standard for multiple 2418 * occurrences of a given element ID/extension element 2419 * ID. 2420 */ 2421 2422 ret = util_validate_sta_prof_ie(sta_prof_ie, 2423 sta_prof_iesection, 2424 sta_prof_iesection_len); 2425 if (QDF_IS_STATUS_ERROR(ret)) { 2426 qdf_mem_free(mlieseqpayload_copy); 2427 return ret; 2428 } 2429 2430 sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] + 2431 MIN_IE_LEN; 2432 2433 sta_prof_iesection_remlen = 2434 sta_prof_iesection_len - 2435 (sta_prof_ie - sta_prof_iesection); 2436 2437 if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_VENDOR) && 2438 (sta_prof_iesection_remlen >= MIN_VENDOR_TAG_LEN)) { 2439 /* If Vendor IE also presents in STA profile, 2440 * then ignore the Vendor IE which is for 2441 * reporting STA. It only needs to copy Vendor 2442 * IE from STA profile to link specific frame. 2443 * The copy happens when going through the 2444 * remaining IEs. 2445 */ 2446 ; 2447 } else { 2448 /* Copy IE from STA profile into link specific 2449 * frame. 2450 */ 2451 if ((link_frame_currpos + sta_prof_ie_size) <= 2452 (link_frame + link_frame_maxsize)) { 2453 qdf_mem_copy(link_frame_currpos, 2454 sta_prof_ie, 2455 sta_prof_ie_size); 2456 2457 link_frame_currpos += sta_prof_ie_size; 2458 link_frame_currlen += 2459 sta_prof_ie_size; 2460 2461 if (reportingsta_ie[ID_POS] == 2462 WLAN_ELEMID_EXTN_ELEM) { 2463 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", 2464 sta_prof_ie[ID_POS], 2465 sta_prof_ie[IDEXT_POS], 2466 sta_prof_ie_size); 2467 } else { 2468 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", 2469 sta_prof_ie[ID_POS], 2470 sta_prof_ie_size); 2471 } 2472 2473 sta_prof_ie[0] = 0; 2474 } else { 2475 if (sta_prof_ie[ID_POS] == 2476 WLAN_ELEMID_EXTN_ELEM) { 2477 mlo_err_rl("Insufficent space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets", 2478 sta_prof_ie[ID_POS], 2479 sta_prof_ie[IDEXT_POS], 2480 sta_prof_ie_size, 2481 link_frame_maxsize - 2482 link_frame_currlen); 2483 } else { 2484 mlo_err_rl("Insufficent space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets", 2485 sta_prof_ie[ID_POS], 2486 sta_prof_ie_size, 2487 link_frame_maxsize - 2488 link_frame_currlen); 2489 } 2490 2491 qdf_mem_free(mlieseqpayload_copy); 2492 return QDF_STATUS_E_NOMEM; 2493 } 2494 } 2495 } 2496 2497 if (((reportingsta_ie + reportingsta_ie_size) - 2498 frame_iesection) == frame_iesection_len) 2499 break; 2500 2501 reportingsta_ie += reportingsta_ie_size; 2502 2503 ret = util_validate_reportingsta_ie(reportingsta_ie, 2504 frame_iesection, 2505 frame_iesection_len); 2506 if (QDF_IS_STATUS_ERROR(ret)) { 2507 qdf_mem_free(mlieseqpayload_copy); 2508 return ret; 2509 } 2510 2511 reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] + 2512 MIN_IE_LEN; 2513 } 2514 2515 /* Go through the remaining unprocessed IEs in STA profile and copy them 2516 * to the link specific frame. The processed ones are marked with 0 in 2517 * the first octet. The first octet corresponds to the element ID. In 2518 * the case of (re)association request, the element with actual ID 2519 * WLAN_ELEMID_SSID(0) has already been copied to the link specific 2520 * frame. In the case of (re)association response, it has been verified 2521 * that the element with actual ID WLAN_ELEMID_SSID(0) is present 2522 * neither for the reporting STA nor in the STA profile. 2523 */ 2524 sta_prof_iesection_currpos = sta_prof_iesection; 2525 sta_prof_iesection_remlen = sta_prof_iesection_len; 2526 2527 while (sta_prof_iesection_remlen > 0) { 2528 sta_prof_ie = sta_prof_iesection_currpos; 2529 ret = util_validate_sta_prof_ie(sta_prof_ie, 2530 sta_prof_iesection_currpos, 2531 sta_prof_iesection_remlen); 2532 if (QDF_IS_STATUS_ERROR(ret)) { 2533 qdf_mem_free(mlieseqpayload_copy); 2534 return ret; 2535 } 2536 2537 sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] + MIN_IE_LEN; 2538 2539 if (!sta_prof_ie[0]) { 2540 /* Skip this, since it has already been processed */ 2541 sta_prof_iesection_currpos += sta_prof_ie_size; 2542 sta_prof_iesection_remlen -= sta_prof_ie_size; 2543 continue; 2544 } 2545 2546 /* Copy IE from STA profile into link specific frame. */ 2547 if ((link_frame_currpos + sta_prof_ie_size) <= 2548 (link_frame + link_frame_maxsize)) { 2549 qdf_mem_copy(link_frame_currpos, 2550 sta_prof_ie, 2551 sta_prof_ie_size); 2552 2553 link_frame_currpos += sta_prof_ie_size; 2554 link_frame_currlen += 2555 sta_prof_ie_size; 2556 2557 if (reportingsta_ie[ID_POS] == 2558 WLAN_ELEMID_EXTN_ELEM) { 2559 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", 2560 sta_prof_ie[ID_POS], 2561 sta_prof_ie[IDEXT_POS], 2562 sta_prof_ie_size); 2563 } else { 2564 mlo_debug("IE with element ID : %u (%zu octets) is present only in STA profile. Copied IE from STA profile to link specific frame", 2565 sta_prof_ie[ID_POS], 2566 sta_prof_ie_size); 2567 } 2568 2569 sta_prof_ie[0] = 0; 2570 } else { 2571 if (sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 2572 mlo_err_rl("Insufficent space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets", 2573 sta_prof_ie[ID_POS], 2574 sta_prof_ie[IDEXT_POS], 2575 sta_prof_ie_size, 2576 link_frame_maxsize - 2577 link_frame_currlen); 2578 } else { 2579 mlo_err_rl("Insufficent space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets", 2580 sta_prof_ie[ID_POS], 2581 sta_prof_ie_size, 2582 link_frame_maxsize - 2583 link_frame_currlen); 2584 } 2585 2586 qdf_mem_free(mlieseqpayload_copy); 2587 return QDF_STATUS_E_NOMEM; 2588 } 2589 2590 sta_prof_iesection_currpos += sta_prof_ie_size; 2591 sta_prof_iesection_remlen -= sta_prof_ie_size; 2592 } 2593 2594 /* Copy the link MAC addr */ 2595 link_frame_hdr = (struct wlan_frame_hdr *)link_frame; 2596 2597 if ((subtype == WLAN_FC0_STYPE_ASSOC_REQ) || 2598 (subtype == WLAN_FC0_STYPE_REASSOC_REQ)) { 2599 qdf_mem_copy(link_frame_hdr->i_addr3, &link_addr, 2600 QDF_MAC_ADDR_SIZE); 2601 qdf_mem_copy(link_frame_hdr->i_addr2, reportedmacaddr.bytes, 2602 QDF_MAC_ADDR_SIZE); 2603 qdf_mem_copy(link_frame_hdr->i_addr1, &link_addr, 2604 QDF_MAC_ADDR_SIZE); 2605 2606 link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_ASSOC_REQ_FC0; 2607 link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_ASSOC_REQ_FC1; 2608 } else if (subtype == WLAN_FC0_STYPE_PROBE_RESP) { 2609 qdf_mem_copy(link_frame_hdr->i_addr3, &link_addr, 2610 QDF_MAC_ADDR_SIZE); 2611 qdf_mem_copy(link_frame_hdr->i_addr2, reportedmacaddr.bytes, 2612 QDF_MAC_ADDR_SIZE); 2613 qdf_mem_copy(link_frame_hdr->i_addr1, &link_addr, 2614 QDF_MAC_ADDR_SIZE); 2615 2616 link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_PROBE_RESP_FC0; 2617 link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_PROBE_RESP_FC1; 2618 } else { 2619 /* This is a (re)association response */ 2620 2621 qdf_mem_copy(link_frame_hdr->i_addr3, reportedmacaddr.bytes, 2622 QDF_MAC_ADDR_SIZE); 2623 qdf_mem_copy(link_frame_hdr->i_addr2, reportedmacaddr.bytes, 2624 QDF_MAC_ADDR_SIZE); 2625 qdf_mem_copy(link_frame_hdr->i_addr1, &link_addr, 2626 QDF_MAC_ADDR_SIZE); 2627 2628 link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_ASSOC_RESP_FC0; 2629 link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_ASSOC_RESP_FC1; 2630 } 2631 2632 /* Seq num not used so not populated */ 2633 2634 qdf_mem_free(mlieseqpayload_copy); 2635 2636 *link_frame_len = link_frame_currlen; 2637 2638 return QDF_STATUS_SUCCESS; 2639 } 2640 2641 QDF_STATUS 2642 util_gen_link_assoc_req(uint8_t *frame, qdf_size_t frame_len, bool isreassoc, 2643 struct qdf_mac_addr link_addr, 2644 uint8_t *link_frame, 2645 qdf_size_t link_frame_maxsize, 2646 qdf_size_t *link_frame_len) 2647 { 2648 return util_gen_link_reqrsp_cmn(frame, frame_len, 2649 (isreassoc ? WLAN_FC0_STYPE_REASSOC_REQ : 2650 WLAN_FC0_STYPE_ASSOC_REQ), 2651 link_addr, link_frame, link_frame_maxsize, 2652 link_frame_len); 2653 } 2654 2655 QDF_STATUS 2656 util_gen_link_assoc_rsp(uint8_t *frame, qdf_size_t frame_len, bool isreassoc, 2657 struct qdf_mac_addr link_addr, 2658 uint8_t *link_frame, 2659 qdf_size_t link_frame_maxsize, 2660 qdf_size_t *link_frame_len) 2661 { 2662 return util_gen_link_reqrsp_cmn(frame, frame_len, 2663 (isreassoc ? WLAN_FC0_STYPE_REASSOC_RESP : 2664 WLAN_FC0_STYPE_ASSOC_RESP), 2665 link_addr, link_frame, link_frame_maxsize, 2666 link_frame_len); 2667 } 2668 2669 QDF_STATUS 2670 util_gen_link_probe_rsp(uint8_t *frame, qdf_size_t frame_len, 2671 struct qdf_mac_addr link_addr, 2672 uint8_t *link_frame, 2673 qdf_size_t link_frame_maxsize, 2674 qdf_size_t *link_frame_len) 2675 { 2676 return util_gen_link_reqrsp_cmn(frame, frame_len, 2677 WLAN_FC0_STYPE_PROBE_RESP, 2678 link_addr, link_frame, link_frame_maxsize, 2679 link_frame_len); 2680 } 2681 2682 QDF_STATUS 2683 util_find_mlie(uint8_t *buf, qdf_size_t buflen, uint8_t **mlieseq, 2684 qdf_size_t *mlieseqlen) 2685 { 2686 uint8_t *bufboundary; 2687 uint8_t *ieseq; 2688 qdf_size_t ieseqlen; 2689 uint8_t *currie; 2690 uint8_t *successorfrag; 2691 2692 if (!buf || !buflen || !mlieseq || !mlieseqlen) 2693 return QDF_STATUS_E_NULL_VALUE; 2694 2695 *mlieseq = NULL; 2696 *mlieseqlen = 0; 2697 2698 /* Find Multi-Link element. In case a fragment sequence is present, 2699 * this element will be the leading fragment. 2700 */ 2701 ieseq = util_find_extn_eid(WLAN_ELEMID_EXTN_ELEM, 2702 WLAN_EXTN_ELEMID_MULTI_LINK, buf, 2703 buflen); 2704 2705 /* Even if the element is not found, we have successfully examined the 2706 * buffer. The caller will be provided a NULL value for the starting of 2707 * the Multi-Link element. Hence, we return success. 2708 */ 2709 if (!ieseq) 2710 return QDF_STATUS_SUCCESS; 2711 2712 bufboundary = buf + buflen; 2713 2714 if ((ieseq + MIN_IE_LEN) > bufboundary) 2715 return QDF_STATUS_E_INVAL; 2716 2717 ieseqlen = MIN_IE_LEN + ieseq[TAG_LEN_POS]; 2718 2719 if (ieseqlen < sizeof(struct wlan_ie_multilink)) 2720 return QDF_STATUS_E_PROTO; 2721 2722 if ((ieseq + ieseqlen) > bufboundary) 2723 return QDF_STATUS_E_INVAL; 2724 2725 /* In the next sequence of checks, if there is no space in the buffer 2726 * for another element after the Multi-Link element/element fragment 2727 * sequence, it could indicate an issue since non-MLO EHT elements 2728 * would be expected to follow the Multi-Link element/element fragment 2729 * sequence. However, this is outside of the purview of this function, 2730 * hence we ignore it. 2731 */ 2732 2733 currie = ieseq; 2734 successorfrag = util_get_successorfrag(currie, buf, buflen); 2735 2736 /* Fragmentation definitions as of IEEE802.11be D1.0 and 2737 * IEEE802.11REVme D0.2 are applied. Only the case where Multi-Link 2738 * element is present in a buffer from the core frame is considered. 2739 * Future changes to fragmentation, cases where the Multi-Link element 2740 * is present in a subelement, etc. to be reflected here if applicable 2741 * as and when the rules evolve. 2742 */ 2743 while (successorfrag) { 2744 /* We should not be seeing a successor fragment if the length 2745 * of the current IE is lesser than the max. 2746 */ 2747 if (currie[TAG_LEN_POS] != WLAN_MAX_IE_LEN) 2748 return QDF_STATUS_E_PROTO; 2749 2750 if (successorfrag[TAG_LEN_POS] == 0) 2751 return QDF_STATUS_E_PROTO; 2752 2753 ieseqlen += (MIN_IE_LEN + successorfrag[TAG_LEN_POS]); 2754 2755 currie = successorfrag; 2756 successorfrag = util_get_successorfrag(currie, buf, buflen); 2757 } 2758 2759 *mlieseq = ieseq; 2760 *mlieseqlen = ieseqlen; 2761 return QDF_STATUS_SUCCESS; 2762 } 2763 2764 QDF_STATUS 2765 util_get_mlie_common_info_len(uint8_t *mlieseq, qdf_size_t mlieseqlen, 2766 uint8_t *commoninfo_len) 2767 { 2768 struct wlan_ie_multilink *mlie_fixed; 2769 enum wlan_ml_variant variant; 2770 uint16_t mlcontrol; 2771 2772 if (!mlieseq || !mlieseqlen || !commoninfo_len) 2773 return QDF_STATUS_E_NULL_VALUE; 2774 2775 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 2776 return QDF_STATUS_E_INVAL; 2777 2778 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 2779 2780 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 2781 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) 2782 return QDF_STATUS_E_INVAL; 2783 2784 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 2785 2786 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 2787 WLAN_ML_CTRL_TYPE_BITS); 2788 2789 if (variant != WLAN_ML_VARIANT_BASIC) 2790 return QDF_STATUS_E_INVAL; 2791 2792 /* Common Info starts at mlieseq + sizeof(struct wlan_ie_multilink). 2793 * Check if there is sufficient space in the buffer for the Common Info 2794 * Length and MLD MAC address. 2795 */ 2796 if ((sizeof(struct wlan_ie_multilink) + WLAN_ML_BV_CINFO_LENGTH_SIZE + 2797 QDF_MAC_ADDR_SIZE) > mlieseqlen) 2798 return QDF_STATUS_E_PROTO; 2799 2800 *commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink)); 2801 2802 return QDF_STATUS_SUCCESS; 2803 } 2804 2805 QDF_STATUS 2806 util_get_bvmlie_bssparamchangecnt(uint8_t *mlieseq, qdf_size_t mlieseqlen, 2807 bool *bssparamchangecntfound, 2808 uint8_t *bssparamchangecnt) 2809 { 2810 struct wlan_ie_multilink *mlie_fixed; 2811 enum wlan_ml_variant variant; 2812 uint16_t mlcontrol; 2813 uint16_t presencebitmap; 2814 uint8_t *commoninfo; 2815 qdf_size_t commoninfolen; 2816 2817 if (!mlieseq || !mlieseqlen || !bssparamchangecntfound || 2818 !bssparamchangecnt) 2819 return QDF_STATUS_E_NULL_VALUE; 2820 2821 *bssparamchangecntfound = false; 2822 *bssparamchangecnt = 0; 2823 2824 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 2825 return QDF_STATUS_E_INVAL; 2826 2827 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 2828 2829 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 2830 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) 2831 return QDF_STATUS_E_INVAL; 2832 2833 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 2834 2835 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 2836 WLAN_ML_CTRL_TYPE_BITS); 2837 2838 if (variant != WLAN_ML_VARIANT_BASIC) 2839 return QDF_STATUS_E_NOSUPPORT; 2840 2841 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 2842 WLAN_ML_CTRL_PBM_BITS); 2843 2844 commoninfo = mlieseq + sizeof(struct wlan_ie_multilink); 2845 commoninfolen = WLAN_ML_BV_CINFO_LENGTH_SIZE; 2846 2847 commoninfolen += QDF_MAC_ADDR_SIZE; 2848 2849 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) { 2850 commoninfolen += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; 2851 2852 if ((sizeof(struct wlan_ie_multilink) + commoninfolen) > 2853 mlieseqlen) 2854 return QDF_STATUS_E_PROTO; 2855 } 2856 2857 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) { 2858 *bssparamchangecntfound = true; 2859 *bssparamchangecnt = *(commoninfo + commoninfolen); 2860 } 2861 2862 return QDF_STATUS_SUCCESS; 2863 } 2864 2865 QDF_STATUS 2866 util_get_mlie_variant(uint8_t *mlieseq, qdf_size_t mlieseqlen, 2867 int *variant) 2868 { 2869 struct wlan_ie_multilink *mlie_fixed; 2870 enum wlan_ml_variant var; 2871 uint16_t mlcontrol; 2872 2873 if (!mlieseq || !mlieseqlen || !variant) 2874 return QDF_STATUS_E_NULL_VALUE; 2875 2876 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 2877 return QDF_STATUS_E_INVAL; 2878 2879 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 2880 2881 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 2882 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) 2883 return QDF_STATUS_E_INVAL; 2884 2885 mlcontrol = le16toh(mlie_fixed->mlcontrol); 2886 var = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 2887 WLAN_ML_CTRL_TYPE_BITS); 2888 2889 if (var >= WLAN_ML_VARIANT_INVALIDSTART) 2890 return QDF_STATUS_E_PROTO; 2891 2892 *variant = var; 2893 return QDF_STATUS_SUCCESS; 2894 } 2895 2896 QDF_STATUS 2897 util_get_bvmlie_eml_cap(uint8_t *mlieseq, qdf_size_t mlieseqlen, 2898 bool *eml_cap_found, 2899 uint16_t *eml_cap) 2900 { 2901 struct wlan_ie_multilink *mlie_fixed; 2902 enum wlan_ml_variant variant; 2903 uint16_t mlcontrol; 2904 uint8_t eml_cap_offset; 2905 uint8_t commoninfo_len; 2906 uint16_t presencebitmap; 2907 2908 if (!mlieseq || !mlieseqlen || !eml_cap_found || !eml_cap) 2909 return QDF_STATUS_E_NULL_VALUE; 2910 2911 *eml_cap = 0; 2912 *eml_cap_found = false; 2913 2914 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 2915 return QDF_STATUS_E_INVAL; 2916 2917 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 2918 2919 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 2920 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) 2921 return QDF_STATUS_E_INVAL; 2922 2923 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 2924 2925 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 2926 WLAN_ML_CTRL_TYPE_BITS); 2927 2928 if (variant != WLAN_ML_VARIANT_BASIC) 2929 return QDF_STATUS_E_INVAL; 2930 2931 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 2932 WLAN_ML_CTRL_PBM_BITS); 2933 2934 /* eml_cap_offset stores the offset of EML Capabilities within 2935 * Common Info 2936 */ 2937 eml_cap_offset = WLAN_ML_BV_CINFO_LENGTH_SIZE + QDF_MAC_ADDR_SIZE; 2938 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) 2939 eml_cap_offset += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; 2940 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) 2941 eml_cap_offset += WLAN_ML_BSSPARAMCHNGCNT_SIZE; 2942 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P) 2943 eml_cap_offset += WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE; 2944 2945 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_EMLCAP_P) { 2946 /* Common Info starts at 2947 * mlieseq + sizeof(struct wlan_ie_multilink). 2948 * Check if there is sufficient space in the buffer for 2949 * the Common Info Length. 2950 */ 2951 if (mlieseqlen < (sizeof(struct wlan_ie_multilink) + 2952 WLAN_ML_BV_CINFO_LENGTH_SIZE)) 2953 return QDF_STATUS_E_PROTO; 2954 2955 /* Check if the value indicated in the Common Info Length 2956 * subfield is sufficient to access the EML capabilities. 2957 */ 2958 commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink)); 2959 if (commoninfo_len < (eml_cap_offset + 2960 WLAN_ML_BV_CINFO_EMLCAP_SIZE)) 2961 return QDF_STATUS_E_PROTO; 2962 2963 /* Common Info starts at mlieseq + sizeof(struct 2964 * wlan_ie_multilink). Check if there is sufficient space in 2965 * Common Info for the EML capability. 2966 */ 2967 if (mlieseqlen < (sizeof(struct wlan_ie_multilink) + 2968 eml_cap_offset + 2969 WLAN_ML_BV_CINFO_EMLCAP_SIZE)) 2970 return QDF_STATUS_E_PROTO; 2971 2972 *eml_cap_found = true; 2973 *eml_cap = qdf_le16_to_cpu(*(uint16_t *)(mlieseq + 2974 sizeof(struct wlan_ie_multilink) + 2975 eml_cap_offset)); 2976 } 2977 return QDF_STATUS_SUCCESS; 2978 } 2979 2980 QDF_STATUS 2981 util_get_bvmlie_msd_cap(uint8_t *mlieseq, qdf_size_t mlieseqlen, 2982 bool *msd_cap_found, 2983 uint16_t *msd_cap) 2984 { 2985 struct wlan_ie_multilink *mlie_fixed; 2986 enum wlan_ml_variant variant; 2987 uint16_t mlcontrol; 2988 uint8_t msd_cap_offset; 2989 uint8_t commoninfo_len; 2990 uint16_t presencebitmap; 2991 2992 if (!mlieseq || !mlieseqlen || !msd_cap_found || !msd_cap) 2993 return QDF_STATUS_E_NULL_VALUE; 2994 2995 *msd_cap = 0; 2996 *msd_cap_found = false; 2997 2998 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 2999 return QDF_STATUS_E_INVAL; 3000 3001 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3002 3003 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3004 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) 3005 return QDF_STATUS_E_INVAL; 3006 3007 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3008 3009 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3010 WLAN_ML_CTRL_TYPE_BITS); 3011 3012 if (variant != WLAN_ML_VARIANT_BASIC) 3013 return QDF_STATUS_E_INVAL; 3014 3015 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3016 WLAN_ML_CTRL_PBM_BITS); 3017 3018 /* msd_cap_offset stores the offset of MSD capabilities within 3019 * Common Info 3020 */ 3021 msd_cap_offset = WLAN_ML_BV_CINFO_LENGTH_SIZE + QDF_MAC_ADDR_SIZE; 3022 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) 3023 msd_cap_offset += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; 3024 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) 3025 msd_cap_offset += WLAN_ML_BSSPARAMCHNGCNT_SIZE; 3026 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P) { 3027 /* Common Info starts at 3028 * mlieseq + sizeof(struct wlan_ie_multilink). 3029 * Check if there is sufficient space in the buffer for 3030 * the Common Info Length. 3031 */ 3032 if (mlieseqlen < (sizeof(struct wlan_ie_multilink) + 3033 WLAN_ML_BV_CINFO_LENGTH_SIZE)) 3034 return QDF_STATUS_E_PROTO; 3035 3036 /* Check if the value indicated in the Common Info Length 3037 * subfield is sufficient to access the MSD capabilities. 3038 */ 3039 commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink)); 3040 if (commoninfo_len < (msd_cap_offset + 3041 WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE)) 3042 return QDF_STATUS_E_PROTO; 3043 3044 /* Common Info starts at mlieseq + sizeof(struct 3045 * wlan_ie_multilink). Check if there is sufficient space in 3046 * Common Info for the MSD capability. 3047 */ 3048 if (mlieseqlen < (sizeof(struct wlan_ie_multilink) + 3049 msd_cap_offset + 3050 WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE)) 3051 return QDF_STATUS_E_PROTO; 3052 3053 *msd_cap_found = true; 3054 *msd_cap = qdf_le16_to_cpu(*(uint16_t *)(mlieseq + 3055 sizeof(struct wlan_ie_multilink) + 3056 msd_cap_offset)); 3057 } else { 3058 mlo_debug("MSD caps not found in assoc rsp"); 3059 } 3060 3061 return QDF_STATUS_SUCCESS; 3062 } 3063 3064 QDF_STATUS 3065 util_get_bvmlie_mldmacaddr(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3066 struct qdf_mac_addr *mldmacaddr) 3067 { 3068 struct wlan_ie_multilink *mlie_fixed; 3069 enum wlan_ml_variant variant; 3070 uint16_t mlcontrol; 3071 uint8_t commoninfo_len; 3072 3073 if (!mlieseq || !mlieseqlen || !mldmacaddr) 3074 return QDF_STATUS_E_NULL_VALUE; 3075 3076 qdf_mem_zero(mldmacaddr, sizeof(*mldmacaddr)); 3077 3078 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3079 return QDF_STATUS_E_INVAL; 3080 3081 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3082 3083 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3084 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) 3085 return QDF_STATUS_E_INVAL; 3086 3087 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3088 3089 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3090 WLAN_ML_CTRL_TYPE_BITS); 3091 3092 if (variant != WLAN_ML_VARIANT_BASIC) 3093 return QDF_STATUS_E_INVAL; 3094 3095 /* Common Info starts at mlieseq + sizeof(struct wlan_ie_multilink). 3096 * Check if there is sufficient space in the buffer for the Common Info 3097 * Length and MLD MAC address. 3098 */ 3099 if ((sizeof(struct wlan_ie_multilink) + WLAN_ML_BV_CINFO_LENGTH_SIZE + 3100 QDF_MAC_ADDR_SIZE) > mlieseqlen) 3101 return QDF_STATUS_E_PROTO; 3102 3103 /* Check if the value indicated in the Common Info Length subfield is 3104 * sufficient to access the MLD MAC address. 3105 */ 3106 commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink)); 3107 if (commoninfo_len < (WLAN_ML_BV_CINFO_LENGTH_SIZE + QDF_MAC_ADDR_SIZE)) 3108 return QDF_STATUS_E_PROTO; 3109 3110 qdf_mem_copy(mldmacaddr->bytes, 3111 mlieseq + sizeof(struct wlan_ie_multilink) + 3112 WLAN_ML_BV_CINFO_LENGTH_SIZE, 3113 QDF_MAC_ADDR_SIZE); 3114 3115 return QDF_STATUS_SUCCESS; 3116 } 3117 3118 QDF_STATUS 3119 util_get_bvmlie_primary_linkid(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3120 bool *linkidfound, uint8_t *linkid) 3121 { 3122 struct wlan_ie_multilink *mlie_fixed; 3123 enum wlan_ml_variant variant; 3124 uint16_t mlcontrol; 3125 uint16_t presencebitmap; 3126 uint8_t *commoninfo; 3127 qdf_size_t commoninfolen; 3128 uint8_t *linkidinfo; 3129 3130 if (!mlieseq || !mlieseqlen || !linkidfound || !linkid) 3131 return QDF_STATUS_E_NULL_VALUE; 3132 3133 *linkidfound = false; 3134 *linkid = 0; 3135 3136 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3137 return QDF_STATUS_E_INVAL; 3138 3139 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3140 3141 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3142 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) 3143 return QDF_STATUS_E_INVAL; 3144 3145 mlcontrol = le16toh(mlie_fixed->mlcontrol); 3146 3147 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3148 WLAN_ML_CTRL_TYPE_BITS); 3149 3150 if (variant != WLAN_ML_VARIANT_BASIC) 3151 return QDF_STATUS_E_INVAL; 3152 3153 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3154 WLAN_ML_CTRL_PBM_BITS); 3155 3156 commoninfo = mlieseq + sizeof(struct wlan_ie_multilink); 3157 commoninfolen = 0; 3158 commoninfolen += WLAN_ML_BV_CINFO_LENGTH_SIZE; 3159 if ((sizeof(struct wlan_ie_multilink) + commoninfolen) > 3160 mlieseqlen) 3161 return QDF_STATUS_E_PROTO; 3162 3163 commoninfolen += QDF_MAC_ADDR_SIZE; 3164 if ((sizeof(struct wlan_ie_multilink) + commoninfolen) > 3165 mlieseqlen) 3166 return QDF_STATUS_E_PROTO; 3167 3168 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) { 3169 linkidinfo = commoninfo + commoninfolen; 3170 commoninfolen += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; 3171 3172 if ((sizeof(struct wlan_ie_multilink) + commoninfolen) > 3173 mlieseqlen) 3174 return QDF_STATUS_E_PROTO; 3175 3176 *linkidfound = true; 3177 *linkid = QDF_GET_BITS(linkidinfo[0], 3178 WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_IDX, 3179 WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_BITS); 3180 } 3181 3182 return QDF_STATUS_SUCCESS; 3183 } 3184 3185 QDF_STATUS 3186 util_get_bvmlie_mldcap(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3187 bool *mldcapfound, uint16_t *mldcap) 3188 { 3189 struct wlan_ie_multilink *mlie_fixed; 3190 enum wlan_ml_variant variant; 3191 uint16_t mlcontrol; 3192 uint16_t presencebitmap; 3193 uint8_t *commoninfo; 3194 uint8_t commoninfo_len; 3195 qdf_size_t mldcap_offset; 3196 3197 if (!mlieseq || !mlieseqlen || !mldcapfound || !mldcap) 3198 return QDF_STATUS_E_NULL_VALUE; 3199 3200 *mldcapfound = false; 3201 *mldcap = 0; 3202 3203 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3204 return QDF_STATUS_E_INVAL; 3205 3206 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3207 3208 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 3209 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) 3210 return QDF_STATUS_E_INVAL; 3211 3212 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3213 3214 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3215 WLAN_ML_CTRL_TYPE_BITS); 3216 3217 if (variant != WLAN_ML_VARIANT_BASIC) 3218 return QDF_STATUS_E_NOSUPPORT; 3219 3220 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3221 WLAN_ML_CTRL_PBM_BITS); 3222 3223 commoninfo = mlieseq + sizeof(struct wlan_ie_multilink); 3224 commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink)); 3225 /* mldcap_offset stores the offset of MLD Capabilities within 3226 * Common Info 3227 */ 3228 mldcap_offset = WLAN_ML_BV_CINFO_LENGTH_SIZE; 3229 mldcap_offset += QDF_MAC_ADDR_SIZE; 3230 3231 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) { 3232 mldcap_offset += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; 3233 3234 if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) > 3235 mlieseqlen) 3236 return QDF_STATUS_E_PROTO; 3237 } 3238 3239 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) { 3240 mldcap_offset += WLAN_ML_BSSPARAMCHNGCNT_SIZE; 3241 3242 if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) > 3243 mlieseqlen) 3244 return QDF_STATUS_E_PROTO; 3245 } 3246 3247 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P) { 3248 mldcap_offset += WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE; 3249 3250 if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) > 3251 mlieseqlen) 3252 return QDF_STATUS_E_PROTO; 3253 } 3254 3255 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_EMLCAP_P) { 3256 mldcap_offset += WLAN_ML_BV_CINFO_EMLCAP_SIZE; 3257 3258 if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) > 3259 mlieseqlen) 3260 return QDF_STATUS_E_PROTO; 3261 } 3262 3263 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MLDCAPANDOP_P) { 3264 /* Check if the value indicated in the Common Info Length 3265 * subfield is sufficient to access the MLD capabilities. 3266 */ 3267 if (commoninfo_len < (mldcap_offset + 3268 WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE)) 3269 return QDF_STATUS_E_PROTO; 3270 3271 if ((sizeof(struct wlan_ie_multilink) + mldcap_offset + 3272 WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE) > 3273 mlieseqlen) 3274 return QDF_STATUS_E_PROTO; 3275 3276 *mldcap = qdf_le16_to_cpu(*((uint16_t *)(commoninfo + mldcap_offset))); 3277 *mldcapfound = true; 3278 } 3279 3280 return QDF_STATUS_SUCCESS; 3281 } 3282 3283 QDF_STATUS 3284 util_get_bvmlie_persta_partner_info(uint8_t *mlieseq, 3285 qdf_size_t mlieseqlen, 3286 struct mlo_partner_info *partner_info) 3287 { 3288 struct wlan_ie_multilink *mlie_fixed; 3289 uint16_t mlcontrol; 3290 enum wlan_ml_variant variant; 3291 uint8_t *linkinfo; 3292 qdf_size_t linkinfo_len; 3293 struct mlo_partner_info pinfo = {0}; 3294 qdf_size_t mlieseqpayloadlen; 3295 uint8_t *mlieseqpayload_copy; 3296 bool is_elemfragseq; 3297 qdf_size_t defragpayload_len; 3298 3299 qdf_size_t tmplen; 3300 QDF_STATUS ret; 3301 3302 if (!mlieseq) { 3303 mlo_err("Pointer to Multi-Link element sequence is NULL"); 3304 return QDF_STATUS_E_NULL_VALUE; 3305 } 3306 3307 if (!mlieseqlen) { 3308 mlo_err("Length of Multi-Link element sequence is zero"); 3309 return QDF_STATUS_E_INVAL; 3310 } 3311 3312 if (!partner_info) { 3313 mlo_err("partner_info is NULL"); 3314 return QDF_STATUS_E_NULL_VALUE; 3315 } 3316 3317 partner_info->num_partner_links = 0; 3318 3319 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) { 3320 mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)", 3321 mlieseqlen, sizeof(struct wlan_ie_multilink)); 3322 return QDF_STATUS_E_INVAL; 3323 } 3324 3325 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3326 3327 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3328 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) { 3329 mlo_err("The element is not a Multi-Link element"); 3330 return QDF_STATUS_E_INVAL; 3331 } 3332 3333 mlcontrol = le16toh(mlie_fixed->mlcontrol); 3334 3335 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3336 WLAN_ML_CTRL_TYPE_BITS); 3337 3338 if (variant != WLAN_ML_VARIANT_BASIC) { 3339 mlo_err("The variant value %u does not correspond to Basic Variant value %u", 3340 variant, WLAN_ML_VARIANT_BASIC); 3341 return QDF_STATUS_E_INVAL; 3342 } 3343 3344 mlieseqpayloadlen = 0; 3345 tmplen = 0; 3346 is_elemfragseq = false; 3347 3348 ret = wlan_get_elem_fragseq_info(mlieseq, 3349 mlieseqlen, 3350 &is_elemfragseq, 3351 &tmplen, 3352 &mlieseqpayloadlen); 3353 if (QDF_IS_STATUS_ERROR(ret)) 3354 return ret; 3355 3356 if (is_elemfragseq) { 3357 if (tmplen != mlieseqlen) { 3358 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", 3359 tmplen, mlieseqlen); 3360 return QDF_STATUS_E_INVAL; 3361 } 3362 3363 if (!mlieseqpayloadlen) { 3364 mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate"); 3365 return QDF_STATUS_E_FAILURE; 3366 } 3367 3368 mlo_debug("Multi-Link element fragment sequence found with payload len %zu", 3369 mlieseqpayloadlen); 3370 } else { 3371 if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) { 3372 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", 3373 mlieseqlen, 3374 sizeof(struct ie_header) + WLAN_MAX_IE_LEN); 3375 return QDF_STATUS_E_FAILURE; 3376 } 3377 3378 mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1); 3379 } 3380 3381 mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen); 3382 3383 if (!mlieseqpayload_copy) { 3384 mlo_err_rl("Could not allocate memory for Multi-Link element payload copy"); 3385 return QDF_STATUS_E_NOMEM; 3386 } 3387 3388 if (is_elemfragseq) { 3389 ret = wlan_defrag_elem_fragseq(false, 3390 mlieseq, 3391 mlieseqlen, 3392 mlieseqpayload_copy, 3393 mlieseqpayloadlen, 3394 &defragpayload_len); 3395 if (QDF_IS_STATUS_ERROR(ret)) { 3396 qdf_mem_free(mlieseqpayload_copy); 3397 return ret; 3398 } 3399 3400 if (defragpayload_len != mlieseqpayloadlen) { 3401 mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets", 3402 defragpayload_len, mlieseqpayloadlen); 3403 qdf_mem_free(mlieseqpayload_copy); 3404 return QDF_STATUS_E_FAILURE; 3405 } 3406 } else { 3407 qdf_mem_copy(mlieseqpayload_copy, 3408 mlieseq + sizeof(struct ie_header) + 1, 3409 mlieseqpayloadlen); 3410 } 3411 3412 linkinfo = NULL; 3413 linkinfo_len = 0; 3414 3415 ret = util_parse_multi_link_ctrl(mlieseqpayload_copy, 3416 mlieseqpayloadlen, 3417 &linkinfo, 3418 &linkinfo_len); 3419 if (QDF_IS_STATUS_ERROR(ret)) { 3420 qdf_mem_free(mlieseqpayload_copy); 3421 return ret; 3422 } 3423 3424 /* In case Link Info is absent, the number of partner links will remain 3425 * zero. 3426 */ 3427 if (!linkinfo) { 3428 qdf_mem_free(mlieseqpayload_copy); 3429 return QDF_STATUS_SUCCESS; 3430 } 3431 3432 ret = util_parse_partner_info_from_linkinfo(linkinfo, 3433 linkinfo_len, 3434 &pinfo); 3435 3436 if (QDF_IS_STATUS_ERROR(ret)) { 3437 qdf_mem_free(mlieseqpayload_copy); 3438 return ret; 3439 } 3440 3441 qdf_mem_copy(partner_info, &pinfo, sizeof(*partner_info)); 3442 3443 qdf_mem_free(mlieseqpayload_copy); 3444 3445 return QDF_STATUS_SUCCESS; 3446 } 3447 3448 QDF_STATUS 3449 util_get_prvmlie_persta_link_id(uint8_t *mlieseq, 3450 qdf_size_t mlieseqlen, 3451 struct mlo_probereq_info *probereq_info) 3452 { 3453 struct wlan_ie_multilink *mlie_fixed; 3454 uint16_t mlcontrol; 3455 enum wlan_ml_variant variant; 3456 uint8_t *linkinfo; 3457 qdf_size_t linkinfo_len; 3458 struct mlo_probereq_info pinfo = {0}; 3459 qdf_size_t mlieseqpayloadlen; 3460 uint8_t *mlieseqpayload_copy; 3461 bool is_elemfragseq; 3462 qdf_size_t defragpayload_len; 3463 3464 qdf_size_t tmplen; 3465 QDF_STATUS ret; 3466 3467 if (!mlieseq) { 3468 mlo_err("Pointer to Multi-Link element sequence is NULL"); 3469 return QDF_STATUS_E_NULL_VALUE; 3470 } 3471 3472 if (!mlieseqlen) { 3473 mlo_err("Length of Multi-Link element sequence is zero"); 3474 return QDF_STATUS_E_INVAL; 3475 } 3476 3477 if (!probereq_info) { 3478 mlo_err("probe request_info is NULL"); 3479 return QDF_STATUS_E_NULL_VALUE; 3480 } 3481 3482 probereq_info->num_links = 0; 3483 3484 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) { 3485 mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)", 3486 mlieseqlen, sizeof(struct wlan_ie_multilink)); 3487 return QDF_STATUS_E_INVAL; 3488 } 3489 3490 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3491 3492 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3493 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) { 3494 mlo_err("The element is not a Multi-Link element"); 3495 return QDF_STATUS_E_INVAL; 3496 } 3497 3498 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3499 3500 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3501 WLAN_ML_CTRL_TYPE_BITS); 3502 3503 if (variant != WLAN_ML_VARIANT_PROBEREQ) { 3504 mlo_err("The variant value %u does not correspond to Probe Request Variant value %u", 3505 variant, WLAN_ML_VARIANT_PROBEREQ); 3506 return QDF_STATUS_E_INVAL; 3507 } 3508 3509 mlieseqpayloadlen = 0; 3510 tmplen = 0; 3511 is_elemfragseq = false; 3512 3513 ret = wlan_get_elem_fragseq_info(mlieseq, 3514 mlieseqlen, 3515 &is_elemfragseq, 3516 &tmplen, 3517 &mlieseqpayloadlen); 3518 if (QDF_IS_STATUS_ERROR(ret)) 3519 return ret; 3520 3521 if (is_elemfragseq) { 3522 if (tmplen != mlieseqlen) { 3523 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", 3524 tmplen, mlieseqlen); 3525 return QDF_STATUS_E_INVAL; 3526 } 3527 3528 if (!mlieseqpayloadlen) { 3529 mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate"); 3530 return QDF_STATUS_E_FAILURE; 3531 } 3532 3533 mlo_debug("Multi-Link element fragment sequence found with payload len %zu", 3534 mlieseqpayloadlen); 3535 } else { 3536 if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) { 3537 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", 3538 mlieseqlen, 3539 sizeof(struct ie_header) + WLAN_MAX_IE_LEN); 3540 return QDF_STATUS_E_FAILURE; 3541 } 3542 3543 mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1); 3544 } 3545 3546 mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen); 3547 3548 if (!mlieseqpayload_copy) { 3549 mlo_err_rl("Could not allocate memory for Multi-Link element payload copy"); 3550 return QDF_STATUS_E_NOMEM; 3551 } 3552 3553 if (is_elemfragseq) { 3554 ret = wlan_defrag_elem_fragseq(false, 3555 mlieseq, 3556 mlieseqlen, 3557 mlieseqpayload_copy, 3558 mlieseqpayloadlen, 3559 &defragpayload_len); 3560 if (QDF_IS_STATUS_ERROR(ret)) { 3561 qdf_mem_free(mlieseqpayload_copy); 3562 return ret; 3563 } 3564 3565 if (defragpayload_len != mlieseqpayloadlen) { 3566 mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets", 3567 defragpayload_len, mlieseqpayloadlen); 3568 qdf_mem_free(mlieseqpayload_copy); 3569 return QDF_STATUS_E_FAILURE; 3570 } 3571 } else { 3572 qdf_mem_copy(mlieseqpayload_copy, 3573 mlieseq + sizeof(struct ie_header) + 1, 3574 mlieseqpayloadlen); 3575 } 3576 3577 linkinfo = NULL; 3578 linkinfo_len = 0; 3579 ret = util_parse_prv_multi_link_ctrl(mlieseqpayload_copy, 3580 mlieseqpayloadlen, 3581 &linkinfo, 3582 &linkinfo_len); 3583 if (QDF_IS_STATUS_ERROR(ret)) { 3584 qdf_mem_free(mlieseqpayload_copy); 3585 return ret; 3586 } 3587 3588 /* In case Link Info is absent, the number of links will remain 3589 * zero. 3590 */ 3591 if (!linkinfo) { 3592 qdf_mem_free(mlieseqpayload_copy); 3593 return QDF_STATUS_SUCCESS; 3594 } 3595 3596 ret = util_parse_probereq_info_from_linkinfo(linkinfo, 3597 linkinfo_len, 3598 &pinfo); 3599 3600 if (QDF_IS_STATUS_ERROR(ret)) { 3601 qdf_mem_free(mlieseqpayload_copy); 3602 return ret; 3603 } 3604 3605 qdf_mem_copy(probereq_info, &pinfo, sizeof(*probereq_info)); 3606 3607 qdf_mem_free(mlieseqpayload_copy); 3608 3609 return QDF_STATUS_SUCCESS; 3610 } 3611 3612 QDF_STATUS 3613 util_get_prvmlie_mldid(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3614 bool *mldidfound, uint8_t *mldid) 3615 { 3616 struct wlan_ie_multilink *mlie_fixed; 3617 enum wlan_ml_variant variant; 3618 uint16_t mlcontrol; 3619 uint16_t presencebitmap; 3620 uint8_t *commoninfo; 3621 qdf_size_t commoninfolen; 3622 3623 if (!mlieseq || !mlieseqlen || !mldidfound || !mldid) 3624 return QDF_STATUS_E_NULL_VALUE; 3625 3626 *mldidfound = false; 3627 *mldid = 0; 3628 3629 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3630 return QDF_STATUS_E_INVAL; 3631 3632 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3633 3634 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 3635 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) 3636 return QDF_STATUS_E_INVAL; 3637 3638 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3639 3640 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3641 WLAN_ML_CTRL_TYPE_BITS); 3642 3643 if (variant != WLAN_ML_VARIANT_PROBEREQ) 3644 return QDF_STATUS_E_NOSUPPORT; 3645 3646 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3647 WLAN_ML_CTRL_PBM_BITS); 3648 3649 commoninfo = mlieseq + sizeof(struct wlan_ie_multilink); 3650 commoninfolen = WLAN_ML_PRV_CINFO_LENGTH_SIZE; 3651 3652 if (presencebitmap & WLAN_ML_PRV_CTRL_PBM_MLDID_P) { 3653 if ((sizeof(struct wlan_ie_multilink) + commoninfolen + 3654 WLAN_ML_PRV_CINFO_MLDID_SIZE) > 3655 mlieseqlen) 3656 return QDF_STATUS_E_PROTO; 3657 3658 *mldid = *((uint8_t *)(commoninfo + commoninfolen)); 3659 commoninfolen += WLAN_ML_PRV_CINFO_MLDID_SIZE; 3660 3661 *mldidfound = true; 3662 } 3663 3664 return QDF_STATUS_SUCCESS; 3665 } 3666 3667 #endif 3668