1 /* 2 * Copyright (c) 2021, The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /* 19 * DOC: contains MLO manager util api's 20 */ 21 #include <wlan_cmn.h> 22 #include <wlan_mlo_mgr_sta.h> 23 #include <wlan_cm_public_struct.h> 24 #include <wlan_mlo_mgr_main.h> 25 #include <wlan_cm_api.h> 26 #include "wlan_scan_api.h" 27 #include "qdf_types.h" 28 #include "utils_mlo.h" 29 #include "wlan_mlo_mgr_cmn.h" 30 #include "wlan_utility.h" 31 32 #ifdef WLAN_FEATURE_11BE_MLO 33 34 static uint8_t *util_find_eid(uint8_t eid, uint8_t *frame, qdf_size_t len) 35 { 36 if (!frame) 37 return NULL; 38 39 while (len >= MIN_IE_LEN && len >= frame[TAG_LEN_POS] + MIN_IE_LEN) { 40 if (frame[ID_POS] == eid) 41 return frame; 42 43 len -= frame[TAG_LEN_POS] + MIN_IE_LEN; 44 frame += frame[TAG_LEN_POS] + MIN_IE_LEN; 45 } 46 47 return NULL; 48 } 49 50 static 51 uint8_t *util_find_extn_eid(uint8_t eid, uint8_t extn_eid, 52 uint8_t *frame, qdf_size_t len) 53 { 54 if (!frame) 55 return NULL; 56 57 while (len > MIN_IE_LEN && len >= frame[TAG_LEN_POS] + MIN_IE_LEN) { 58 if ((frame[ID_POS] == eid) && 59 (frame[ELEM_ID_EXTN_POS] == extn_eid)) 60 return frame; 61 62 len -= frame[TAG_LEN_POS] + MIN_IE_LEN; 63 frame += frame[TAG_LEN_POS] + MIN_IE_LEN; 64 } 65 return NULL; 66 } 67 68 static QDF_STATUS 69 util_parse_multi_link_ctrl(uint8_t *mlieseqpayload, 70 qdf_size_t mlieseqpayloadlen, 71 uint8_t **link_info, 72 qdf_size_t *link_info_len) 73 { 74 qdf_size_t parsed_payload_len; 75 uint16_t mlcontrol; 76 uint16_t presence_bm; 77 uint16_t cinfo_len = 0; 78 uint16_t exp_cinfo_len = 0; 79 80 /* This helper returns the location(s) and length(s) of (sub)field(s) 81 * inferable after parsing the Multi Link element Control field. These 82 * location(s) and length(s) is/are in reference to the payload section 83 * of the Multi Link element (after defragmentation, if applicable). 84 * Here, the payload is the point after the element ID extension of the 85 * Multi Link element, and includes the payloads of all subsequent 86 * fragments (if any) but not the headers of those fragments. 87 * 88 * Currently, the helper returns the location and length of the Link 89 * Info field in the Multi Link element sequence. Other (sub)field(s) 90 * can be added later as required. 91 */ 92 93 if (!mlieseqpayload) { 94 mlo_err("ML seq payload pointer is NULL"); 95 return QDF_STATUS_E_NULL_VALUE; 96 } 97 98 if (!mlieseqpayloadlen) { 99 mlo_err("ML seq payload len is 0"); 100 return QDF_STATUS_E_INVAL; 101 } 102 103 if (mlieseqpayloadlen < WLAN_ML_CTRL_SIZE) { 104 mlo_err_rl("ML seq payload len %zu < ML Control size %u", 105 mlieseqpayloadlen, WLAN_ML_CTRL_SIZE); 106 return QDF_STATUS_E_PROTO; 107 } 108 109 parsed_payload_len = 0; 110 111 qdf_mem_copy(&mlcontrol, mlieseqpayload, WLAN_ML_CTRL_SIZE); 112 mlcontrol = qdf_le16_to_cpu(mlcontrol); 113 parsed_payload_len += WLAN_ML_CTRL_SIZE; 114 115 presence_bm = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 116 WLAN_ML_CTRL_PBM_BITS); 117 118 if (mlieseqpayloadlen < 119 (parsed_payload_len + WLAN_ML_BV_CINFO_LENGTH_SIZE)) { 120 mlo_err_rl("ML seq payload len %zu insufficient for common info length size %u after parsed payload len %zu.", 121 mlieseqpayloadlen, 122 WLAN_ML_BV_CINFO_LENGTH_SIZE, 123 parsed_payload_len); 124 return QDF_STATUS_E_PROTO; 125 } 126 127 cinfo_len = *(mlieseqpayload + parsed_payload_len); 128 parsed_payload_len += WLAN_ML_BV_CINFO_LENGTH_SIZE; 129 130 if (mlieseqpayloadlen < 131 (parsed_payload_len + QDF_MAC_ADDR_SIZE)) { 132 mlo_err_rl("ML seq payload len %zu insufficient for MAC address size %u after parsed payload len %zu.", 133 mlieseqpayloadlen, 134 QDF_MAC_ADDR_SIZE, 135 parsed_payload_len); 136 return QDF_STATUS_E_PROTO; 137 } 138 139 parsed_payload_len += QDF_MAC_ADDR_SIZE; 140 141 /* Check if Link ID info is present */ 142 if (presence_bm & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) { 143 if (mlieseqpayloadlen < 144 (parsed_payload_len + 145 WLAN_ML_BV_CINFO_LINKIDINFO_SIZE)) { 146 mlo_err_rl("ML seq payload len %zu insufficient for Link ID info size %u after parsed payload len %zu.", 147 mlieseqpayloadlen, 148 WLAN_ML_BV_CINFO_LINKIDINFO_SIZE, 149 parsed_payload_len); 150 return QDF_STATUS_E_PROTO; 151 } 152 153 parsed_payload_len += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; 154 } 155 156 /* Check if BSS parameter change count is present */ 157 if (presence_bm & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) { 158 if (mlieseqpayloadlen < 159 (parsed_payload_len + 160 WLAN_ML_BSSPARAMCHNGCNT_SIZE)) { 161 mlo_err_rl("ML seq payload len %zu insufficient for BSS parameter change count size %u after parsed payload len %zu.", 162 mlieseqpayloadlen, 163 WLAN_ML_BSSPARAMCHNGCNT_SIZE, 164 parsed_payload_len); 165 return QDF_STATUS_E_PROTO; 166 } 167 168 parsed_payload_len += WLAN_ML_BSSPARAMCHNGCNT_SIZE; 169 } 170 171 /* Check if Medium Sync Delay Info is present */ 172 if (presence_bm & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P) { 173 if (mlieseqpayloadlen < 174 (parsed_payload_len + 175 WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE)) { 176 mlo_err_rl("ML seq payload len %zu insufficient for Medium Sync Delay Info size %u after parsed payload len %zu.", 177 mlieseqpayloadlen, 178 WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE, 179 parsed_payload_len); 180 return QDF_STATUS_E_PROTO; 181 } 182 183 parsed_payload_len += WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE; 184 } 185 186 /* Check if EML cap is present */ 187 if (presence_bm & WLAN_ML_BV_CTRL_PBM_EMLCAP_P) { 188 if (mlieseqpayloadlen < 189 (parsed_payload_len + 190 WLAN_ML_BV_CINFO_EMLCAP_SIZE)) { 191 mlo_err_rl("ML seq payload len %zu insufficient for EML cap size %u after parsed payload len %zu.", 192 mlieseqpayloadlen, 193 WLAN_ML_BV_CINFO_EMLCAP_SIZE, 194 parsed_payload_len); 195 return QDF_STATUS_E_PROTO; 196 } 197 198 parsed_payload_len += WLAN_ML_BV_CINFO_EMLCAP_SIZE; 199 } 200 201 /* Check if MLD cap is present */ 202 if (presence_bm & WLAN_ML_BV_CTRL_PBM_MLDCAPANDOP_P) { 203 if (mlieseqpayloadlen < 204 (parsed_payload_len + 205 WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE)) { 206 mlo_err_rl("ML seq payload len %zu insufficient for MLD cap size %u after parsed payload len %zu.", 207 mlieseqpayloadlen, 208 WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE, 209 parsed_payload_len); 210 return QDF_STATUS_E_PROTO; 211 } 212 213 parsed_payload_len += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; 214 } 215 216 /* Check if MLD ID is present */ 217 if (presence_bm & WLAN_ML_BV_CTRL_PBM_MLDID_P) { 218 if (mlieseqpayloadlen < 219 (parsed_payload_len + 220 WLAN_ML_BV_CINFO_MLDID_SIZE)) { 221 mlo_err_rl("ML seq payload len %zu insufficient for MLD ID size %u after parsed payload len %zu.", 222 mlieseqpayloadlen, 223 WLAN_ML_BV_CINFO_MLDID_SIZE, 224 parsed_payload_len); 225 return QDF_STATUS_E_PROTO; 226 } 227 228 parsed_payload_len += WLAN_ML_BV_CINFO_MLDID_SIZE; 229 } 230 231 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 mlo_debug("LINK ID requested is = %u", linkid); 1061 } 1062 1063 linkinfo_remlen -= (sizeof(struct subelem_header) + 1064 subelemseqpayloadlen); 1065 linkinfo_currpos += (sizeof(struct subelem_header) + 1066 subelemseqpayloadlen); 1067 } 1068 1069 mlo_debug("Number of ML probe request links found=%u", 1070 probereq_info->num_links); 1071 1072 return QDF_STATUS_SUCCESS; 1073 } 1074 1075 static 1076 QDF_STATUS util_get_noninheritlists(uint8_t *buff, qdf_size_t buff_len, 1077 uint8_t **ninherit_elemlist, 1078 qdf_size_t *ninherit_elemlist_len, 1079 uint8_t **ninherit_elemextlist, 1080 qdf_size_t *ninherit_elemextlist_len) 1081 { 1082 uint8_t *ninherit_ie; 1083 qdf_size_t unparsed_len; 1084 1085 /* Note: This functionality provided by this helper may be combined with 1086 * other, older non-inheritance parsing helper functionality and exposed 1087 * as a common API as part of future efforts once the older 1088 * functionality can be made generic. 1089 */ 1090 1091 if (!buff) { 1092 mlo_err("Pointer to buffer for IEs is NULL"); 1093 return QDF_STATUS_E_NULL_VALUE; 1094 } 1095 1096 if (!buff_len) { 1097 mlo_err("IE buffer length is zero"); 1098 return QDF_STATUS_E_INVAL; 1099 } 1100 1101 if (!ninherit_elemlist) { 1102 mlo_err("Pointer to Non-Inheritance element ID list array is NULL"); 1103 return QDF_STATUS_E_NULL_VALUE; 1104 } 1105 1106 if (!ninherit_elemlist_len) { 1107 mlo_err("Pointer to Non-Inheritance element ID list array length is NULL"); 1108 return QDF_STATUS_E_NULL_VALUE; 1109 } 1110 1111 if (!ninherit_elemextlist) { 1112 mlo_err("Pointer to Non-Inheritance element ID extension list array is NULL"); 1113 return QDF_STATUS_E_NULL_VALUE; 1114 } 1115 1116 if (!ninherit_elemextlist_len) { 1117 mlo_err("Pointer to Non-Inheritance element ID extension list array length is NULL"); 1118 return QDF_STATUS_E_NULL_VALUE; 1119 } 1120 1121 ninherit_ie = NULL; 1122 *ninherit_elemlist_len = 0; 1123 *ninherit_elemlist = NULL; 1124 *ninherit_elemextlist_len = 0; 1125 *ninherit_elemextlist = NULL; 1126 1127 ninherit_ie = 1128 (uint8_t *)util_find_extn_eid(WLAN_ELEMID_EXTN_ELEM, 1129 WLAN_EXTN_ELEMID_NONINHERITANCE, 1130 buff, 1131 buff_len); 1132 1133 if (ninherit_ie) { 1134 if ((ninherit_ie + TAG_LEN_POS) > (buff + buff_len - 1)) { 1135 mlo_err_rl("Position of length field of Non-Inheritance element would exceed IE buffer boundary"); 1136 return QDF_STATUS_E_PROTO; 1137 } 1138 1139 if ((ninherit_ie + ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN) > 1140 (buff + buff_len)) { 1141 mlo_err_rl("Non-Inheritance element with total length %u would exceed IE buffer boundary", 1142 ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN); 1143 return QDF_STATUS_E_PROTO; 1144 } 1145 1146 if ((ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN) < 1147 MIN_NONINHERITANCEELEM_LEN) { 1148 mlo_err_rl("Non-Inheritance element size %u is smaller than the minimum required %u", 1149 ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN, 1150 MIN_NONINHERITANCEELEM_LEN); 1151 return QDF_STATUS_E_PROTO; 1152 } 1153 1154 /* Track the number of unparsed octets, excluding the IE header. 1155 */ 1156 unparsed_len = ninherit_ie[TAG_LEN_POS]; 1157 1158 /* Mark the element ID extension as parsed */ 1159 unparsed_len--; 1160 1161 *ninherit_elemlist_len = ninherit_ie[ELEM_ID_LIST_LEN_POS]; 1162 unparsed_len--; 1163 1164 /* While checking if the Non-Inheritance element ID list length 1165 * exceeds the remaining unparsed IE space, we factor in one 1166 * octet for the element extension ID list length and subtract 1167 * this from the unparsed IE space. 1168 */ 1169 if (*ninherit_elemlist_len > (unparsed_len - 1)) { 1170 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", 1171 *ninherit_elemlist_len, unparsed_len - 1); 1172 1173 return QDF_STATUS_E_PROTO; 1174 } 1175 1176 if (*ninherit_elemlist_len != 0) { 1177 *ninherit_elemlist = ninherit_ie + ELEM_ID_LIST_POS; 1178 unparsed_len -= *ninherit_elemlist_len; 1179 } 1180 1181 *ninherit_elemextlist_len = 1182 ninherit_ie[ELEM_ID_LIST_LEN_POS + *ninherit_elemlist_len + 1]; 1183 unparsed_len--; 1184 1185 if (*ninherit_elemextlist_len > unparsed_len) { 1186 mlo_err_rl("Non-Inheritance element ID extension list length %zu exceeds remaining unparsed IE space %zu", 1187 *ninherit_elemextlist_len, unparsed_len); 1188 1189 return QDF_STATUS_E_PROTO; 1190 } 1191 1192 if (*ninherit_elemextlist_len != 0) { 1193 *ninherit_elemextlist = ninherit_ie + 1194 ELEM_ID_LIST_LEN_POS + (*ninherit_elemlist_len) 1195 + 2; 1196 unparsed_len -= *ninherit_elemextlist_len; 1197 } 1198 1199 if (unparsed_len > 0) { 1200 mlo_err_rl("Unparsed length is %zu, expected 0", 1201 unparsed_len); 1202 return QDF_STATUS_E_PROTO; 1203 } 1204 } 1205 1206 /* If Non-Inheritance element is not found, we still return success, 1207 * with the list lengths kept at zero. 1208 */ 1209 mlo_debug("Non-Inheritance element ID list array length=%zu", 1210 *ninherit_elemlist_len); 1211 mlo_debug("Non-Inheritance element ID extension list array length=%zu", 1212 *ninherit_elemextlist_len); 1213 1214 return QDF_STATUS_SUCCESS; 1215 } 1216 1217 static 1218 QDF_STATUS util_eval_ie_in_noninheritlist(uint8_t *ie, qdf_size_t total_ie_len, 1219 uint8_t *ninherit_elemlist, 1220 qdf_size_t ninherit_elemlist_len, 1221 uint8_t *ninherit_elemextlist, 1222 qdf_size_t ninherit_elemextlist_len, 1223 bool *is_in_noninheritlist) 1224 { 1225 int i; 1226 1227 /* Evaluate whether the given IE is in the given Non-Inheritance element 1228 * ID list or Non-Inheritance element ID extension list, and update the 1229 * result into is_in_noninheritlist. If any list is empty, then the IE 1230 * is considered to not be present in that list. Both lists can be 1231 * empty. 1232 * 1233 * If QDF_STATUS_SUCCESS is returned, it means that the evaluation is 1234 * successful, and that is_in_noninheritlist contains a valid value 1235 * (which could be true or false). If a QDF_STATUS error value is 1236 * returned, the value in is_in_noninheritlist is invalid and the caller 1237 * should ignore it. 1238 */ 1239 1240 /* Note: The functionality provided by this helper may be combined with 1241 * other, older non-inheritance parsing helper functionality and exposed 1242 * as a common API as part of future efforts once the older 1243 * functionality can be made generic. 1244 */ 1245 1246 /* Except for is_in_noninheritlist and ie, other pointer arguments are 1247 * permitted to be NULL if they are inapplicable. If they are 1248 * applicable, they will be checked to ensure they are not NULL. 1249 */ 1250 1251 if (!is_in_noninheritlist) { 1252 mlo_err("NULL pointer to flag that indicates if element is in a Non-Inheritance list"); 1253 return QDF_STATUS_E_NULL_VALUE; 1254 } 1255 1256 /* If ninherit_elemlist_len and ninherit_elemextlist_len are both zero 1257 * as checked soon in this function, we won't be accessing the IE. 1258 * However, we still check right-away if the pointer to the IE is 1259 * non-NULL and whether the total IE length is sane enough to access the 1260 * element ID and if applicable, the element ID extension, since it 1261 * doesn't make sense to set the flag in is_in_noninheritlist for a NULL 1262 * IE pointer or an IE whose total length is not sane enough to 1263 * distinguish the identity of the IE. 1264 */ 1265 if (!ie) { 1266 mlo_err("NULL pointer to IE"); 1267 return QDF_STATUS_E_NULL_VALUE; 1268 } 1269 1270 if (total_ie_len < (ID_POS + 1)) { 1271 mlo_err("Total IE length %zu is smaller than minimum required to access element ID %u", 1272 total_ie_len, ID_POS + 1); 1273 return QDF_STATUS_E_INVAL; 1274 } 1275 1276 if ((ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) && 1277 (total_ie_len < (IDEXT_POS + 1))) { 1278 mlo_err("Total IE length %zu is smaller than minimum required to access element ID extension %u", 1279 total_ie_len, IDEXT_POS + 1); 1280 return QDF_STATUS_E_INVAL; 1281 } 1282 1283 *is_in_noninheritlist = false; 1284 1285 /* If both the Non-Inheritance element list and Non-Inheritance element 1286 * ID extension list are empty, then return success since we can 1287 * conclude immediately that the given element does not occur in any 1288 * Non-Inheritance list. The is_in_noninheritlist remains set to false 1289 * as required. 1290 */ 1291 if (!ninherit_elemlist_len && !ninherit_elemextlist_len) 1292 return QDF_STATUS_SUCCESS; 1293 1294 if (ie[ID_POS] != WLAN_ELEMID_EXTN_ELEM) { 1295 if (!ninherit_elemlist_len) 1296 return QDF_STATUS_SUCCESS; 1297 1298 if (!ninherit_elemlist) { 1299 mlo_err("NULL pointer to Non-Inheritance element ID list though length of element ID list is %zu", 1300 ninherit_elemlist_len); 1301 return QDF_STATUS_E_NULL_VALUE; 1302 } 1303 1304 for (i = 0; i < ninherit_elemlist_len; i++) { 1305 if (ie[ID_POS] == ninherit_elemlist[i]) { 1306 *is_in_noninheritlist = true; 1307 return QDF_STATUS_SUCCESS; 1308 } 1309 } 1310 } else { 1311 if (!ninherit_elemextlist_len) 1312 return QDF_STATUS_SUCCESS; 1313 1314 if (!ninherit_elemextlist) { 1315 mlo_err("NULL pointer to Non-Inheritance element ID extension list though length of element ID extension list is %zu", 1316 ninherit_elemextlist_len); 1317 return QDF_STATUS_E_NULL_VALUE; 1318 } 1319 1320 for (i = 0; i < ninherit_elemextlist_len; i++) { 1321 if (ie[IDEXT_POS] == ninherit_elemextlist[i]) { 1322 *is_in_noninheritlist = true; 1323 return QDF_STATUS_SUCCESS; 1324 } 1325 } 1326 } 1327 1328 return QDF_STATUS_SUCCESS; 1329 } 1330 1331 static inline 1332 QDF_STATUS util_validate_reportingsta_ie(const uint8_t *reportingsta_ie, 1333 const uint8_t *frame_iesection, 1334 const qdf_size_t frame_iesection_len) 1335 { 1336 qdf_size_t reportingsta_ie_size; 1337 1338 if (!reportingsta_ie) { 1339 mlo_err("Pointer to reporting STA IE is NULL"); 1340 return QDF_STATUS_E_NULL_VALUE; 1341 } 1342 1343 if (!frame_iesection) { 1344 mlo_err("Pointer to start of IE section in reporting frame is NULL"); 1345 return QDF_STATUS_E_NULL_VALUE; 1346 } 1347 1348 if (!frame_iesection_len) { 1349 mlo_err("Length of IE section in reporting frame is zero"); 1350 return QDF_STATUS_E_INVAL; 1351 } 1352 1353 if ((reportingsta_ie + ID_POS) > (frame_iesection + 1354 frame_iesection_len - 1)) { 1355 mlo_err_rl("Position of element ID field of element for reporting STA would exceed frame IE section boundary"); 1356 return QDF_STATUS_E_PROTO; 1357 } 1358 1359 if ((reportingsta_ie + TAG_LEN_POS) > (frame_iesection + 1360 frame_iesection_len - 1)) { 1361 mlo_err_rl("Position of length field of element with element ID %u for reporting STA would exceed frame IE section boundary", 1362 reportingsta_ie[ID_POS]); 1363 return QDF_STATUS_E_PROTO; 1364 } 1365 1366 if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) && 1367 ((reportingsta_ie + IDEXT_POS) > (frame_iesection + 1368 frame_iesection_len - 1))) { 1369 mlo_err_rl("Position of element ID extension field of element would exceed frame IE section boundary"); 1370 return QDF_STATUS_E_PROTO; 1371 } 1372 1373 reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] + MIN_IE_LEN; 1374 1375 if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) && 1376 (reportingsta_ie_size < (IDEXT_POS + 1))) { 1377 mlo_err_rl("Total length %zu of element for reporting STA is smaller than minimum required to access element ID extension %u", 1378 reportingsta_ie_size, IDEXT_POS + 1); 1379 return QDF_STATUS_E_PROTO; 1380 } 1381 1382 if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_VENDOR) && 1383 (reportingsta_ie_size < (PAYLOAD_START_POS + OUI_LEN))) { 1384 mlo_err_rl("Total length %zu of element for reporting STA is smaller than minimum required to access vendor EID %u", 1385 reportingsta_ie_size, PAYLOAD_START_POS + OUI_LEN); 1386 return QDF_STATUS_E_PROTO; 1387 } 1388 1389 if ((reportingsta_ie + reportingsta_ie_size) > 1390 (frame_iesection + frame_iesection_len)) { 1391 if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 1392 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", 1393 reportingsta_ie_size, 1394 reportingsta_ie[ID_POS], 1395 reportingsta_ie[IDEXT_POS]); 1396 } else { 1397 mlo_err_rl("Total size %zu octets of element with element ID %u for reporting STA would exceed frame IE section boundary", 1398 reportingsta_ie_size, 1399 reportingsta_ie[ID_POS]); 1400 } 1401 1402 return QDF_STATUS_E_PROTO; 1403 } 1404 1405 return QDF_STATUS_SUCCESS; 1406 } 1407 1408 static inline 1409 QDF_STATUS util_validate_sta_prof_ie(const uint8_t *sta_prof_ie, 1410 const uint8_t *sta_prof_iesection, 1411 const qdf_size_t sta_prof_iesection_len) 1412 { 1413 qdf_size_t sta_prof_ie_size; 1414 1415 if (!sta_prof_ie) { 1416 mlo_err("Pointer to STA profile IE is NULL"); 1417 return QDF_STATUS_E_NULL_VALUE; 1418 } 1419 1420 if (!sta_prof_iesection) { 1421 mlo_err("Pointer to start of IE section in STA profile is NULL"); 1422 return QDF_STATUS_E_NULL_VALUE; 1423 } 1424 1425 if (!sta_prof_iesection_len) { 1426 mlo_err("Length of IE section in STA profile is zero"); 1427 return QDF_STATUS_E_INVAL; 1428 } 1429 1430 if ((sta_prof_ie + ID_POS) > (sta_prof_iesection + 1431 sta_prof_iesection_len - 1)) { 1432 mlo_err_rl("Position of element ID field of STA profile element would exceed STA profile IE section boundary"); 1433 return QDF_STATUS_E_PROTO; 1434 } 1435 1436 if ((sta_prof_ie + TAG_LEN_POS) > (sta_prof_iesection + 1437 sta_prof_iesection_len - 1)) { 1438 mlo_err_rl("Position of length field of element with element ID %u in STA profile would exceed STA profile IE section boundary", 1439 sta_prof_ie[ID_POS]); 1440 return QDF_STATUS_E_PROTO; 1441 } 1442 1443 if ((sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) && 1444 ((sta_prof_ie + IDEXT_POS) > (sta_prof_iesection + 1445 sta_prof_iesection_len - 1))) { 1446 mlo_err_rl("Position of element ID extension field of element would exceed STA profile IE section boundary"); 1447 return QDF_STATUS_E_PROTO; 1448 } 1449 1450 sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] + MIN_IE_LEN; 1451 1452 if ((sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) && 1453 (sta_prof_ie_size < (IDEXT_POS + 1))) { 1454 mlo_err_rl("Total length %zu of STA profile element is smaller than minimum required to access element ID extension %u", 1455 sta_prof_ie_size, IDEXT_POS + 1); 1456 return QDF_STATUS_E_PROTO; 1457 } 1458 1459 if ((sta_prof_ie + sta_prof_ie_size) > 1460 (sta_prof_iesection + sta_prof_iesection_len)) { 1461 if (sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 1462 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", 1463 sta_prof_ie_size, 1464 sta_prof_ie[ID_POS], 1465 sta_prof_ie[IDEXT_POS]); 1466 } else { 1467 mlo_err_rl("Total size %zu octets of element with element ID %u in STA profile would exceed STA profile IE section boundary", 1468 sta_prof_ie_size, 1469 sta_prof_ie[ID_POS]); 1470 } 1471 1472 return QDF_STATUS_E_PROTO; 1473 } 1474 1475 return QDF_STATUS_SUCCESS; 1476 } 1477 1478 #ifdef CONN_MGR_ADV_FEATURE 1479 /** 1480 * util_add_mlie_for_prb_rsp_gen - Add the basic variant Multi-Link element 1481 * when generating link specific probe response. 1482 * @reportingsta_ie: Pointer to the reportingsta ie 1483 * @reportingsta_ie_len: Length for reporting sta ie 1484 * @plink_frame_currpos: Pointer to Link frame current pos 1485 * @plink_frame_currlen: Current length of link frame. 1486 * @link_frame_maxsize: Maximum size of the frame to be generated 1487 * @linkid: Link Id value 1488 * 1489 * Add the basic variant Multi-Link element when 1490 * generating link specific probe response. 1491 * 1492 * Return: QDF_STATUS_SUCCESS in the case of success, QDF_STATUS value giving 1493 * the reason for error in the case of failure 1494 */ 1495 static QDF_STATUS 1496 util_add_mlie_for_prb_rsp_gen(const uint8_t *reportingsta_ie, 1497 qdf_size_t reportingsta_ie_len, 1498 uint8_t **plink_frame_currpos, 1499 qdf_size_t *plink_frame_currlen, 1500 qdf_size_t link_frame_maxsize, 1501 uint8_t linkid) 1502 { 1503 uint8_t mlie_len = 0; 1504 uint8_t common_info_len = 0; 1505 struct wlan_ie_multilink ml_ie_ff; 1506 uint16_t mlcontrol; 1507 uint16_t presencebm; 1508 uint8_t *mlie_frame = NULL; 1509 uint8_t link_id_offset = sizeof(struct wlan_ie_multilink) + 1510 QDF_MAC_ADDR_SIZE + 1511 WLAN_ML_BV_CINFO_LENGTH_SIZE; 1512 uint8_t *link_frame_currpos = *plink_frame_currpos; 1513 qdf_size_t link_frame_currlen = *plink_frame_currlen; 1514 QDF_STATUS status = QDF_STATUS_SUCCESS; 1515 1516 status = util_get_mlie_common_info_len((uint8_t *)reportingsta_ie, 1517 reportingsta_ie_len, 1518 &common_info_len); 1519 if (QDF_IS_STATUS_ERROR(status)) { 1520 mlo_err("Failed while parsing the common info length"); 1521 return status; 1522 } 1523 1524 /* common info len + bvmlie fixed fields */ 1525 mlie_len = common_info_len + sizeof(struct wlan_ie_multilink); 1526 1527 mlo_debug_rl("mlie_len %d, common_info_len %d, link_id_offset %d", 1528 mlie_len, 1529 common_info_len, 1530 link_id_offset); 1531 1532 /* 1533 * Validate the buffer available before copying ML IE. 1534 * Incase if mlie_len is modified at later place, move this validation 1535 * there to make sure no buffer overflow happens. 1536 */ 1537 if ((link_frame_maxsize - link_frame_currlen) < mlie_len) { 1538 mlo_err("Insufficient space in link specific frame for ML IE. Required: %u octets, available: %zu octets", 1539 mlie_len, (link_frame_maxsize - link_frame_currlen)); 1540 return QDF_STATUS_E_NOMEM; 1541 } 1542 1543 mlie_frame = qdf_mem_malloc(mlie_len); 1544 if (!mlie_frame) 1545 return QDF_STATUS_E_NOMEM; 1546 1547 /* Copy ml ie fixed fields */ 1548 qdf_mem_copy(&ml_ie_ff, 1549 reportingsta_ie, 1550 sizeof(struct wlan_ie_multilink)); 1551 1552 ml_ie_ff.elem_len = mlie_len - sizeof(struct ie_header); 1553 1554 mlcontrol = qdf_le16_to_cpu(ml_ie_ff.mlcontrol); 1555 presencebm = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 1556 WLAN_ML_CTRL_PBM_BITS); 1557 qdf_set_bit(WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P, 1558 (unsigned long *)&presencebm); 1559 1560 QDF_SET_BITS(ml_ie_ff.mlcontrol, 1561 WLAN_ML_CTRL_PBM_IDX, 1562 WLAN_ML_CTRL_PBM_BITS, 1563 presencebm); 1564 1565 qdf_mem_copy(mlie_frame, 1566 &ml_ie_ff, 1567 sizeof(struct wlan_ie_multilink)); 1568 1569 qdf_mem_copy(mlie_frame + sizeof(struct wlan_ie_multilink), 1570 reportingsta_ie + sizeof(struct wlan_ie_multilink), 1571 mlie_len - sizeof(struct wlan_ie_multilink)); 1572 1573 if (linkid == 0xFF) { 1574 qdf_mem_free(mlie_frame); 1575 mlo_err("Link id is invalid"); 1576 return QDF_STATUS_E_INVAL; 1577 } 1578 mlie_frame[link_id_offset] = (mlie_frame[link_id_offset] & ~0x0f) | 1579 (linkid & 0x0f); 1580 qdf_mem_copy(link_frame_currpos, 1581 mlie_frame, 1582 mlie_len); 1583 1584 mlo_debug("Add mlie for link id %d", linkid); 1585 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, 1586 mlie_frame, mlie_len); 1587 1588 link_frame_currpos += mlie_len; 1589 link_frame_currlen += mlie_len; 1590 *plink_frame_currpos = link_frame_currpos; 1591 *plink_frame_currlen = link_frame_currlen; 1592 qdf_mem_free(mlie_frame); 1593 1594 return QDF_STATUS_SUCCESS; 1595 } 1596 #else 1597 static QDF_STATUS 1598 util_add_mlie_for_prb_rsp_gen(const uint8_t *reportingsta_ie, 1599 qdf_size_t reportingsta_ie_len, 1600 uint8_t **plink_frame_currpos, 1601 qdf_size_t *plink_frame_currlen, 1602 qdf_size_t link_frame_maxsize, 1603 uint8_t linkid) 1604 { 1605 return QDF_STATUS_SUCCESS; 1606 } 1607 #endif 1608 1609 #define MLO_LINKSPECIFIC_ASSOC_REQ_FC0 0x00 1610 #define MLO_LINKSPECIFIC_ASSOC_REQ_FC1 0x00 1611 #define MLO_LINKSPECIFIC_ASSOC_RESP_FC0 0x10 1612 #define MLO_LINKSPECIFIC_ASSOC_RESP_FC1 0x00 1613 #define MLO_LINKSPECIFIC_PROBE_RESP_FC0 0x50 1614 #define MLO_LINKSPECIFIC_PROBE_RESP_FC1 0x00 1615 1616 static 1617 QDF_STATUS util_gen_link_reqrsp_cmn(uint8_t *frame, qdf_size_t frame_len, 1618 uint8_t subtype, 1619 struct qdf_mac_addr link_addr, 1620 uint8_t *link_frame, 1621 qdf_size_t link_frame_maxsize, 1622 qdf_size_t *link_frame_len) 1623 { 1624 /* Please see documentation for util_gen_link_assoc_req() and 1625 * util_gen_link_assoc_resp() for information on the inputs to and 1626 * output from this helper, since those APIs are essentially wrappers 1627 * over this helper. 1628 */ 1629 1630 /* Pointer to Multi-Link element/Multi-Link element fragment sequence */ 1631 uint8_t *mlieseq; 1632 /* Total length of Multi-Link element sequence (including fragments if 1633 * any) 1634 */ 1635 qdf_size_t mlieseqlen; 1636 /* Variant (i.e. type) of the Multi-Link element */ 1637 enum wlan_ml_variant variant; 1638 1639 /* Length of the payload of the Multi-Link element (inclusive of 1640 * fragment payloads if any) without IE headers and element ID extension 1641 */ 1642 qdf_size_t mlieseqpayloadlen; 1643 /* Pointer to copy of the payload of the Multi-Link element (inclusive 1644 * of fragment payloads if any) without IE headers and element ID 1645 * extension 1646 */ 1647 uint8_t *mlieseqpayload_copy; 1648 1649 /* Pointer to start of Link Info within the copy of the payload of the 1650 * Multi-Link element 1651 */ 1652 uint8_t *link_info; 1653 /* Length of the Link Info */ 1654 qdf_size_t link_info_len; 1655 1656 /* Pointer to the IE section that occurs after the fixed fields in the 1657 * original frame for the reporting STA. 1658 */ 1659 uint8_t *frame_iesection; 1660 /* Offset to the start of the IE section in the original frame for the 1661 * reporting STA. 1662 */ 1663 qdf_size_t frame_iesection_offset; 1664 /* Total length of the IE section in the original frame for the 1665 * reporting STA. 1666 */ 1667 qdf_size_t frame_iesection_len; 1668 1669 /* Pointer to the IEEE802.11 frame header in the link specific frame 1670 * being generated for the reported STA. 1671 */ 1672 struct wlan_frame_hdr *link_frame_hdr; 1673 /* Current position in the link specific frame being generated for the 1674 * reported STA. 1675 */ 1676 uint8_t *link_frame_currpos; 1677 /* Current length of the link specific frame being generated for the 1678 * reported STA. 1679 */ 1680 qdf_size_t link_frame_currlen; 1681 1682 /* Pointer to IE for reporting STA */ 1683 const uint8_t *reportingsta_ie; 1684 /* Total size of IE for reporting STA, inclusive of the element header 1685 */ 1686 qdf_size_t reportingsta_ie_size; 1687 1688 /* Pointer to current position in STA profile */ 1689 uint8_t *sta_prof_currpos; 1690 /* Remaining length of STA profile */ 1691 qdf_size_t sta_prof_remlen; 1692 /* Pointer to start of IE section in STA profile that occurs after fixed 1693 * fields. 1694 */ 1695 uint8_t *sta_prof_iesection; 1696 /* Total length of IE section in STA profile */ 1697 qdf_size_t sta_prof_iesection_len; 1698 /* Pointer to current position being processed in IE section in STA 1699 * profile. 1700 */ 1701 uint8_t *sta_prof_iesection_currpos; 1702 /* Remaining length of IE section in STA profile */ 1703 qdf_size_t sta_prof_iesection_remlen; 1704 1705 /* Pointer to IE in STA profile, that occurs within IE section */ 1706 uint8_t *sta_prof_ie; 1707 /* Total size of IE in STA profile, inclusive of the element header */ 1708 qdf_size_t sta_prof_ie_size; 1709 1710 /* Pointer to element ID list in Non-Inheritance IE */ 1711 uint8_t *ninherit_elemlist; 1712 /* Length of element ID list in Non-Inheritance IE */ 1713 qdf_size_t ninherit_elemlist_len; 1714 /* Pointer to element ID extension list in Non-Inheritance IE */ 1715 uint8_t *ninherit_elemextlist; 1716 /* Length of element ID extension list in Non-Inheritance IE */ 1717 qdf_size_t ninherit_elemextlist_len; 1718 /* Whether a given IE is in a non-inheritance list */ 1719 bool is_in_noninheritlist; 1720 1721 /* Whether MAC address of reported STA is valid */ 1722 bool is_reportedmacaddr_valid; 1723 /* MAC address of reported STA */ 1724 struct qdf_mac_addr reportedmacaddr; 1725 1726 /* Pointer to per-STA profile */ 1727 uint8_t *persta_prof; 1728 /* Length of the containing buffer which starts with the per-STA profile 1729 */ 1730 qdf_size_t persta_prof_bufflen; 1731 1732 /* Other variables for temporary purposes */ 1733 1734 /* Variable into which API for determining fragment information will 1735 * indicate whether the element is the start of a fragment sequence or 1736 * not. 1737 */ 1738 bool is_elemfragseq; 1739 /* De-fragmented payload length returned by API for element 1740 * defragmentation. 1741 */ 1742 qdf_size_t defragpayload_len; 1743 /* Variable into which API for determining fragment information will 1744 * indicate whether the subelement is the start of a fragment sequence 1745 * or not. 1746 */ 1747 bool is_subelemfragseq; 1748 /* Total length of the subelement fragment sequence, inclusive of 1749 * subelement header and the headers of fragments if any. 1750 */ 1751 qdf_size_t subelemseqtotallen; 1752 /* Total length of the subelement fragment sequence payload, excluding 1753 * subelement header and fragment headers if any. 1754 */ 1755 qdf_size_t subelemseqpayloadlen; 1756 /* Pointer to Beacon interval in STA info field */ 1757 uint16_t beaconinterval; 1758 /* Whether Beacon interval value valid */ 1759 bool is_beaconinterval_valid; 1760 /* TSF timer of the reporting AP */ 1761 uint64_t tsf; 1762 /* TSF offset of the reproted AP */ 1763 uint64_t tsfoffset; 1764 /* TSF offset value valid */ 1765 bool is_tsfoffset_valid; 1766 /* If Complete Profile or not*/ 1767 bool is_completeprofile; 1768 qdf_size_t tmplen; 1769 QDF_STATUS ret; 1770 uint8_t linkid = 0xFF; 1771 1772 if (!frame) { 1773 mlo_err("Pointer to original frame is NULL"); 1774 return QDF_STATUS_E_NULL_VALUE; 1775 } 1776 1777 if (!frame_len) { 1778 mlo_err("Length of original frame is zero"); 1779 return QDF_STATUS_E_INVAL; 1780 } 1781 1782 if ((subtype != WLAN_FC0_STYPE_ASSOC_REQ) && 1783 (subtype != WLAN_FC0_STYPE_REASSOC_REQ) && 1784 (subtype != WLAN_FC0_STYPE_ASSOC_RESP) && 1785 (subtype != WLAN_FC0_STYPE_REASSOC_RESP) && 1786 (subtype != WLAN_FC0_STYPE_PROBE_RESP)) { 1787 mlo_err("802.11 frame subtype %u is invalid", subtype); 1788 return QDF_STATUS_E_INVAL; 1789 } 1790 1791 if (!link_frame) { 1792 mlo_err("Pointer to secondary link specific frame is NULL"); 1793 return QDF_STATUS_E_NULL_VALUE; 1794 } 1795 1796 if (!link_frame_maxsize) { 1797 mlo_err("Maximum size of secondary link specific frame is zero"); 1798 return QDF_STATUS_E_INVAL; 1799 } 1800 1801 if (!link_frame_len) { 1802 mlo_err("Pointer to populated length of secondary link specific frame is NULL"); 1803 return QDF_STATUS_E_NULL_VALUE; 1804 } 1805 1806 frame_iesection_offset = 0; 1807 1808 if (subtype == WLAN_FC0_STYPE_ASSOC_REQ) { 1809 frame_iesection_offset = WLAN_ASSOC_REQ_IES_OFFSET; 1810 } else if (subtype == WLAN_FC0_STYPE_REASSOC_REQ) { 1811 frame_iesection_offset = WLAN_REASSOC_REQ_IES_OFFSET; 1812 } else if (subtype == WLAN_FC0_STYPE_PROBE_RESP) { 1813 frame_iesection_offset = WLAN_PROBE_RESP_IES_OFFSET; 1814 qdf_mem_copy(&tsf, frame, WLAN_TIMESTAMP_LEN); 1815 tsf = qdf_le64_to_cpu(tsf); 1816 } else { 1817 /* This is a (re)association response */ 1818 frame_iesection_offset = WLAN_ASSOC_RSP_IES_OFFSET; 1819 } 1820 1821 if (frame_len < frame_iesection_offset) { 1822 /* The caller is supposed to have confirmed that this is a valid 1823 * frame containing a Multi-Link element. Hence we treat this as 1824 * a case of invalid argument being passed to us. 1825 */ 1826 mlo_err("Frame length %zu is smaller than the IE section offset %zu for subtype %u", 1827 frame_len, frame_iesection_offset, subtype); 1828 return QDF_STATUS_E_INVAL; 1829 } 1830 1831 frame_iesection_len = frame_len - frame_iesection_offset; 1832 1833 if (frame_iesection_len == 0) { 1834 /* The caller is supposed to have confirmed that this is a valid 1835 * frame containing a Multi-Link element. Hence we treat this as 1836 * a case of invalid argument being passed to us. 1837 */ 1838 mlo_err("No space left in frame for IE section"); 1839 return QDF_STATUS_E_INVAL; 1840 } 1841 1842 frame_iesection = frame + frame_iesection_offset; 1843 1844 mlieseq = NULL; 1845 mlieseqlen = 0; 1846 1847 ret = util_find_mlie(frame_iesection, frame_iesection_len, &mlieseq, 1848 &mlieseqlen); 1849 if (QDF_IS_STATUS_ERROR(ret)) 1850 return ret; 1851 1852 if (!mlieseq) { 1853 /* The caller is supposed to have confirmed that a Multi-Link 1854 * element is present in the frame. Hence we treat this as a 1855 * case of invalid argument being passed to us. 1856 */ 1857 mlo_err("Invalid original frame since no Multi-Link element found"); 1858 return QDF_STATUS_E_INVAL; 1859 } 1860 1861 /* Sanity check the Multi-Link element sequence length */ 1862 if (!mlieseqlen) { 1863 mlo_err("Length of Multi-Link element sequence is zero. Investigate."); 1864 return QDF_STATUS_E_FAILURE; 1865 } 1866 1867 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) { 1868 mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)", 1869 mlieseqlen, sizeof(struct wlan_ie_multilink)); 1870 return QDF_STATUS_E_PROTO; 1871 } 1872 1873 ret = util_get_mlie_variant(mlieseq, mlieseqlen, (int *)&variant); 1874 if (QDF_IS_STATUS_ERROR(ret)) 1875 return ret; 1876 1877 if (variant != WLAN_ML_VARIANT_BASIC) { 1878 mlo_err_rl("Unexpected variant %u of Multi-Link element.", 1879 variant); 1880 return QDF_STATUS_E_PROTO; 1881 } 1882 1883 mlieseqpayloadlen = 0; 1884 tmplen = 0; 1885 is_elemfragseq = false; 1886 1887 ret = wlan_get_elem_fragseq_info(mlieseq, 1888 mlieseqlen, 1889 &is_elemfragseq, 1890 &tmplen, 1891 &mlieseqpayloadlen); 1892 if (QDF_IS_STATUS_ERROR(ret)) 1893 return ret; 1894 1895 if (is_elemfragseq) { 1896 if (tmplen != mlieseqlen) { 1897 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", 1898 tmplen, mlieseqlen); 1899 return QDF_STATUS_E_FAILURE; 1900 } 1901 1902 if (!mlieseqpayloadlen) { 1903 mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate"); 1904 return QDF_STATUS_E_FAILURE; 1905 } 1906 1907 mlo_debug("Multi-Link element fragment sequence found with payload len %zu", 1908 mlieseqpayloadlen); 1909 } else { 1910 if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) { 1911 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", 1912 mlieseqlen, 1913 sizeof(struct ie_header) + WLAN_MAX_IE_LEN); 1914 return QDF_STATUS_E_FAILURE; 1915 } 1916 1917 mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1); 1918 } 1919 1920 mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen); 1921 1922 if (!mlieseqpayload_copy) { 1923 mlo_err_rl("Could not allocate memory for Multi-Link element payload copy"); 1924 return QDF_STATUS_E_NOMEM; 1925 } 1926 1927 if (is_elemfragseq) { 1928 ret = wlan_defrag_elem_fragseq(false, 1929 mlieseq, 1930 mlieseqlen, 1931 mlieseqpayload_copy, 1932 mlieseqpayloadlen, 1933 &defragpayload_len); 1934 if (QDF_IS_STATUS_ERROR(ret)) { 1935 qdf_mem_free(mlieseqpayload_copy); 1936 return ret; 1937 } 1938 1939 if (defragpayload_len != mlieseqpayloadlen) { 1940 mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets", 1941 defragpayload_len, mlieseqpayloadlen); 1942 qdf_mem_free(mlieseqpayload_copy); 1943 return QDF_STATUS_E_FAILURE; 1944 } 1945 } else { 1946 qdf_mem_copy(mlieseqpayload_copy, 1947 mlieseq + sizeof(struct ie_header) + 1, 1948 mlieseqpayloadlen); 1949 } 1950 1951 link_info = NULL; 1952 link_info_len = 0; 1953 1954 ret = util_parse_multi_link_ctrl(mlieseqpayload_copy, 1955 mlieseqpayloadlen, 1956 &link_info, 1957 &link_info_len); 1958 if (QDF_IS_STATUS_ERROR(ret)) { 1959 qdf_mem_free(mlieseqpayload_copy); 1960 return ret; 1961 } 1962 1963 /* As per the standard, the sender must include Link Info for 1964 * association request/response. Throw an error if we are unable to 1965 * obtain this. 1966 */ 1967 if (!link_info) { 1968 mlo_err_rl("Unable to successfully obtain Link Info"); 1969 qdf_mem_free(mlieseqpayload_copy); 1970 return QDF_STATUS_E_PROTO; 1971 } 1972 1973 mlo_debug("Dumping hex of link info after parsing Multi-Link element control"); 1974 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_MLO, QDF_TRACE_LEVEL_DEBUG, 1975 link_info, link_info_len); 1976 1977 /* Note: We may have a future change to skip subelements which are not 1978 * Per-STA Profile, handle more than two links in MLO, handle cases 1979 * where we unexpectedly find more Per-STA Profiles than expected, etc. 1980 */ 1981 1982 persta_prof = link_info; 1983 persta_prof_bufflen = link_info_len; 1984 1985 is_subelemfragseq = false; 1986 subelemseqtotallen = 0; 1987 subelemseqpayloadlen = 0; 1988 1989 ret = wlan_get_subelem_fragseq_info(WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 1990 persta_prof, 1991 persta_prof_bufflen, 1992 &is_subelemfragseq, 1993 &subelemseqtotallen, 1994 &subelemseqpayloadlen); 1995 if (QDF_IS_STATUS_ERROR(ret)) { 1996 qdf_mem_free(mlieseqpayload_copy); 1997 return ret; 1998 } 1999 2000 if (is_subelemfragseq) { 2001 if (!subelemseqpayloadlen) { 2002 mlo_err_rl("Subelement fragment sequence payload is reported as 0, investigate"); 2003 qdf_mem_free(mlieseqpayload_copy); 2004 return QDF_STATUS_E_FAILURE; 2005 } 2006 2007 mlo_debug("Subelement fragment sequence found with payload len %zu", 2008 subelemseqpayloadlen); 2009 2010 ret = wlan_defrag_subelem_fragseq(true, 2011 WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 2012 persta_prof, 2013 persta_prof_bufflen, 2014 NULL, 2015 0, 2016 &defragpayload_len); 2017 if (QDF_IS_STATUS_ERROR(ret)) { 2018 qdf_mem_free(mlieseqpayload_copy); 2019 return ret; 2020 } 2021 2022 if (defragpayload_len != subelemseqpayloadlen) { 2023 mlo_err_rl("Length of defragmented payload %zu octets is not equal to length of subelement fragment sequence payload %zu octets", 2024 defragpayload_len, 2025 subelemseqpayloadlen); 2026 qdf_mem_free(mlieseqpayload_copy); 2027 return QDF_STATUS_E_FAILURE; 2028 } 2029 } else { 2030 if (persta_prof_bufflen < 2031 (sizeof(struct subelem_header) + 2032 persta_prof[TAG_LEN_POS])) { 2033 mlo_err_rl("Length of buffer containing per-STA profile %zu octets is smaller than total size of current subelement %zu octets", 2034 persta_prof_bufflen, 2035 sizeof(struct subelem_header) + 2036 persta_prof[TAG_LEN_POS]); 2037 return QDF_STATUS_E_PROTO; 2038 } 2039 2040 subelemseqpayloadlen = persta_prof[TAG_LEN_POS]; 2041 } 2042 2043 sta_prof_remlen = 0; 2044 sta_prof_currpos = NULL; 2045 is_reportedmacaddr_valid = false; 2046 is_beaconinterval_valid = false; 2047 is_completeprofile = false; 2048 is_tsfoffset_valid = false; 2049 2050 /* Parse per-STA profile */ 2051 ret = util_parse_bvmlie_perstaprofile_stactrl(persta_prof + 2052 sizeof(struct subelem_header), 2053 subelemseqpayloadlen, 2054 &linkid, 2055 &beaconinterval, 2056 &is_beaconinterval_valid, 2057 &tsfoffset, 2058 &is_tsfoffset_valid, 2059 &is_completeprofile, 2060 &is_reportedmacaddr_valid, 2061 &reportedmacaddr, 2062 true, 2063 &sta_prof_currpos, 2064 &sta_prof_remlen); 2065 if (QDF_IS_STATUS_ERROR(ret)) { 2066 qdf_mem_free(mlieseqpayload_copy); 2067 return ret; 2068 } 2069 2070 if (subtype == WLAN_FC0_STYPE_PROBE_RESP && !is_completeprofile) { 2071 mlo_err("Complete profile information is not present in per-STA profile of probe response frame"); 2072 return QDF_STATUS_E_NOSUPPORT; 2073 } 2074 2075 /* We double check for a NULL STA Profile, though the helper function 2076 * above would have taken care of this. We need to get a non-NULL STA 2077 * profile, because we need to get at least the expected fixed fields, 2078 * even if there is an (improbable) total inheritance. 2079 */ 2080 if (!sta_prof_currpos) { 2081 mlo_err_rl("STA profile is NULL"); 2082 qdf_mem_free(mlieseqpayload_copy); 2083 return QDF_STATUS_E_PROTO; 2084 } 2085 2086 /* As per the standard, the sender sets the MAC address in the per-STA 2087 * profile in association request/response. Without this, we cannot 2088 * generate the link specific frame. 2089 */ 2090 if (!is_reportedmacaddr_valid) { 2091 mlo_err_rl("Unable to get MAC address from per-STA profile"); 2092 qdf_mem_free(mlieseqpayload_copy); 2093 return QDF_STATUS_E_PROTO; 2094 } 2095 2096 link_frame_currpos = link_frame; 2097 *link_frame_len = 0; 2098 link_frame_currlen = 0; 2099 2100 if (link_frame_maxsize < WLAN_MAC_HDR_LEN_3A) { 2101 mlo_err("Insufficient space in link specific frame for 802.11 header. Required: %u octets, available: %zu octets", 2102 WLAN_MAC_HDR_LEN_3A, link_frame_maxsize); 2103 2104 qdf_mem_free(mlieseqpayload_copy); 2105 return QDF_STATUS_E_NOMEM; 2106 } 2107 2108 link_frame_currpos += WLAN_MAC_HDR_LEN_3A; 2109 link_frame_currlen += WLAN_MAC_HDR_LEN_3A; 2110 2111 if ((subtype == WLAN_FC0_STYPE_ASSOC_REQ) || 2112 (subtype == WLAN_FC0_STYPE_REASSOC_REQ)) { 2113 mlo_debug("Populating fixed fields for (re)assoc req in link specific frame"); 2114 2115 if (sta_prof_remlen < WLAN_CAPABILITYINFO_LEN) { 2116 mlo_err_rl("Remaining length of STA profile %zu octets is less than length of Capability Info %u", 2117 sta_prof_remlen, 2118 WLAN_CAPABILITYINFO_LEN); 2119 2120 qdf_mem_free(mlieseqpayload_copy); 2121 return QDF_STATUS_E_PROTO; 2122 } 2123 2124 /* Capability information is specific to the link. Copy this 2125 * from the STA profile. 2126 */ 2127 2128 if ((link_frame_maxsize - link_frame_currlen) < 2129 WLAN_CAPABILITYINFO_LEN) { 2130 mlo_err("Insufficient space in link specific frame for Capability Info field. Required: %u octets, available: %zu octets", 2131 WLAN_CAPABILITYINFO_LEN, 2132 (link_frame_maxsize - link_frame_currlen)); 2133 2134 qdf_mem_free(mlieseqpayload_copy); 2135 return QDF_STATUS_E_NOMEM; 2136 } 2137 2138 qdf_mem_copy(link_frame_currpos, sta_prof_currpos, 2139 WLAN_CAPABILITYINFO_LEN); 2140 link_frame_currpos += WLAN_CAPABILITYINFO_LEN; 2141 link_frame_currlen += WLAN_CAPABILITYINFO_LEN; 2142 mlo_debug("Added Capability Info field (%u octets) to link specific frame", 2143 WLAN_CAPABILITYINFO_LEN); 2144 2145 sta_prof_currpos += WLAN_CAPABILITYINFO_LEN; 2146 sta_prof_remlen -= WLAN_CAPABILITYINFO_LEN; 2147 2148 /* Listen Interval is common between all links. Copy this from 2149 * the reporting section of the frame. 2150 */ 2151 2152 if ((link_frame_maxsize - link_frame_currlen) < 2153 WLAN_LISTENINTERVAL_LEN) { 2154 mlo_err("Insufficient space in link specific frame for Listen Interval field. Required: %u octets, available: %zu octets", 2155 WLAN_LISTENINTERVAL_LEN, 2156 (link_frame_maxsize - link_frame_currlen)); 2157 2158 qdf_mem_free(mlieseqpayload_copy); 2159 return QDF_STATUS_E_NOMEM; 2160 } 2161 2162 qdf_mem_copy(link_frame_currpos, 2163 frame + WLAN_CAPABILITYINFO_LEN, 2164 WLAN_LISTENINTERVAL_LEN); 2165 link_frame_currpos += WLAN_LISTENINTERVAL_LEN; 2166 link_frame_currlen += WLAN_LISTENINTERVAL_LEN; 2167 mlo_debug("Added Listen Interval field (%u octets) to link specific frame", 2168 WLAN_LISTENINTERVAL_LEN); 2169 2170 if (subtype == WLAN_FC0_STYPE_REASSOC_REQ) { 2171 /* Current AP address is common between all links. Copy 2172 * this from the reporting section of the frame. 2173 */ 2174 if ((link_frame_maxsize - link_frame_currlen) < 2175 QDF_MAC_ADDR_SIZE) { 2176 mlo_err("Insufficient space in link specific frame for current AP address. Required: %u octets, available: %zu octets", 2177 QDF_MAC_ADDR_SIZE, 2178 (link_frame_maxsize - 2179 link_frame_currlen)); 2180 2181 qdf_mem_free(mlieseqpayload_copy); 2182 return QDF_STATUS_E_NOMEM; 2183 } 2184 2185 qdf_mem_copy(link_frame_currpos, 2186 frame + WLAN_CAPABILITYINFO_LEN + 2187 WLAN_LISTENINTERVAL_LEN, 2188 QDF_MAC_ADDR_SIZE); 2189 link_frame_currpos += QDF_MAC_ADDR_SIZE; 2190 link_frame_currlen += QDF_MAC_ADDR_SIZE; 2191 mlo_debug("Reassoc req: Added Current AP address field (%u octets) to link specific frame", 2192 QDF_MAC_ADDR_SIZE); 2193 } 2194 } else if (subtype == WLAN_FC0_STYPE_ASSOC_RESP || 2195 subtype == WLAN_FC0_STYPE_REASSOC_RESP) { 2196 /* This is a (re)association response */ 2197 mlo_debug("Populating fixed fields for (re)assoc resp in link specific frame"); 2198 2199 if (sta_prof_remlen < 2200 (WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN)) { 2201 mlo_err_rl("Remaining length of STA profile %zu octets is less than length of Capability Info + length of Status Code %u", 2202 sta_prof_remlen, 2203 WLAN_CAPABILITYINFO_LEN + 2204 WLAN_STATUSCODE_LEN); 2205 2206 qdf_mem_free(mlieseqpayload_copy); 2207 return QDF_STATUS_E_PROTO; 2208 } 2209 2210 /* Capability information and Status Code are specific to the 2211 * link. Copy these from the STA profile. 2212 */ 2213 2214 if ((link_frame_maxsize - link_frame_currlen) < 2215 (WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN)) { 2216 mlo_err("Insufficient space in link specific frame for Capability Info and Status Code fields. Required: %u octets, available: %zu octets", 2217 WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN, 2218 (link_frame_maxsize - link_frame_currlen)); 2219 2220 qdf_mem_free(mlieseqpayload_copy); 2221 return QDF_STATUS_E_NOMEM; 2222 } 2223 2224 qdf_mem_copy(link_frame_currpos, sta_prof_currpos, 2225 (WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN)); 2226 link_frame_currpos += (WLAN_CAPABILITYINFO_LEN + 2227 WLAN_STATUSCODE_LEN); 2228 link_frame_currlen += (WLAN_CAPABILITYINFO_LEN + 2229 WLAN_STATUSCODE_LEN); 2230 mlo_debug("Added Capability Info and Status Code fields (%u octets) to link specific frame", 2231 WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN); 2232 2233 sta_prof_currpos += (WLAN_CAPABILITYINFO_LEN + 2234 WLAN_STATUSCODE_LEN); 2235 sta_prof_remlen -= (WLAN_CAPABILITYINFO_LEN + 2236 WLAN_STATUSCODE_LEN); 2237 2238 /* AID is common between all links. Copy this from the original 2239 * frame. 2240 */ 2241 2242 if ((link_frame_maxsize - link_frame_currlen) < WLAN_AID_LEN) { 2243 mlo_err("Insufficient space in link specific frame for AID field. Required: %u octets, available: %zu octets", 2244 WLAN_AID_LEN, 2245 (link_frame_maxsize - link_frame_currlen)); 2246 2247 qdf_mem_free(mlieseqpayload_copy); 2248 return QDF_STATUS_E_NOMEM; 2249 } 2250 2251 qdf_mem_copy(link_frame_currpos, 2252 frame + WLAN_CAPABILITYINFO_LEN + 2253 WLAN_STATUSCODE_LEN, 2254 WLAN_AID_LEN); 2255 link_frame_currpos += WLAN_AID_LEN; 2256 link_frame_currlen += WLAN_AID_LEN; 2257 mlo_debug("Added AID field (%u octets) to link specific frame", 2258 WLAN_AID_LEN); 2259 } else if (subtype == WLAN_FC0_STYPE_PROBE_RESP) { 2260 /* This is a probe response */ 2261 mlo_debug("Populating fixed fields for probe response in link specific frame"); 2262 2263 if ((link_frame_maxsize - link_frame_currlen) < 2264 WLAN_TIMESTAMP_LEN) { 2265 mlo_err("Insufficient space in link specific frame for Timestamp Info field. Required: %u octets, available: %zu octets", 2266 WLAN_TIMESTAMP_LEN, 2267 (link_frame_maxsize - link_frame_currlen)); 2268 2269 qdf_mem_free(mlieseqpayload_copy); 2270 return QDF_STATUS_E_NOMEM; 2271 } 2272 2273 /* Per spec 11be_D2.1.1, the TSF Offset subfield of the STA Info 2274 * field indicates the offset (Toffset)between the TSF timer of 2275 * the reported AP (TA) and the TSF timer of the reporting 2276 * AP (TB) and is encoded as a 2s complement signed integer 2277 * with units of 2 µs. Toffset is calculated as 2278 * Toffset= Floor((TA – TB)/2). 2279 */ 2280 if (is_tsfoffset_valid) 2281 tsf += tsfoffset * 2; 2282 2283 qdf_mem_copy(link_frame_currpos, &tsf, WLAN_TIMESTAMP_LEN); 2284 link_frame_currpos += WLAN_TIMESTAMP_LEN; 2285 link_frame_currlen += WLAN_TIMESTAMP_LEN; 2286 mlo_debug("Added Timestamp Info field (%u octets) to link specific frame", 2287 WLAN_TIMESTAMP_LEN); 2288 2289 if (!is_beaconinterval_valid) { 2290 mlo_err_rl("Beacon interval information not present in STA info field of per-STA profile"); 2291 qdf_mem_free(mlieseqpayload_copy); 2292 return QDF_STATUS_E_PROTO; 2293 } 2294 2295 /* Beacon Interval information copy this from 2296 * the STA info field. 2297 */ 2298 if ((link_frame_maxsize - link_frame_currlen) < 2299 WLAN_BEACONINTERVAL_LEN) { 2300 mlo_err("Insufficient space in link specific frame for Beacon Interval Info field. Required: %u octets, available: %zu octets", 2301 WLAN_BEACONINTERVAL_LEN, 2302 (link_frame_maxsize - link_frame_currlen)); 2303 2304 qdf_mem_free(mlieseqpayload_copy); 2305 return QDF_STATUS_E_NOMEM; 2306 } 2307 2308 qdf_mem_copy(link_frame_currpos, &beaconinterval, 2309 WLAN_BEACONINTERVAL_LEN); 2310 link_frame_currpos += WLAN_BEACONINTERVAL_LEN; 2311 link_frame_currlen += WLAN_BEACONINTERVAL_LEN; 2312 mlo_debug("Added Beacon Interval Info field (%u octets) to link specific frame", 2313 WLAN_BEACONINTERVAL_LEN); 2314 2315 if (sta_prof_remlen < WLAN_CAPABILITYINFO_LEN) { 2316 mlo_err_rl("Remaining length of STA profile %zu octets is less than length of Capability Info %u", 2317 sta_prof_remlen, 2318 WLAN_CAPABILITYINFO_LEN); 2319 2320 qdf_mem_free(mlieseqpayload_copy); 2321 return QDF_STATUS_E_PROTO; 2322 } 2323 2324 /* Capability information is specific to the link. Copy this 2325 * from the STA profile. 2326 */ 2327 2328 if ((link_frame_maxsize - link_frame_currlen) < 2329 WLAN_CAPABILITYINFO_LEN) { 2330 mlo_err("Insufficient space in link specific frame for Capability Info field. Required: %u octets, available: %zu octets", 2331 WLAN_CAPABILITYINFO_LEN, 2332 (link_frame_maxsize - link_frame_currlen)); 2333 2334 qdf_mem_free(mlieseqpayload_copy); 2335 return QDF_STATUS_E_NOMEM; 2336 } 2337 2338 qdf_mem_copy(link_frame_currpos, sta_prof_currpos, 2339 WLAN_CAPABILITYINFO_LEN); 2340 link_frame_currpos += WLAN_CAPABILITYINFO_LEN; 2341 link_frame_currlen += WLAN_CAPABILITYINFO_LEN; 2342 mlo_debug("Added Capability Info field (%u octets) to link specific frame", 2343 WLAN_CAPABILITYINFO_LEN); 2344 2345 sta_prof_currpos += WLAN_CAPABILITYINFO_LEN; 2346 sta_prof_remlen -= WLAN_CAPABILITYINFO_LEN; 2347 } 2348 2349 sta_prof_iesection = sta_prof_currpos; 2350 sta_prof_iesection_len = sta_prof_remlen; 2351 2352 /* Populate non-inheritance lists if applicable */ 2353 ninherit_elemlist_len = 0; 2354 ninherit_elemlist = NULL; 2355 ninherit_elemextlist_len = 0; 2356 ninherit_elemextlist = NULL; 2357 2358 ret = util_get_noninheritlists(sta_prof_iesection, 2359 sta_prof_iesection_len, 2360 &ninherit_elemlist, 2361 &ninherit_elemlist_len, 2362 &ninherit_elemextlist, 2363 &ninherit_elemextlist_len); 2364 if (QDF_IS_STATUS_ERROR(ret)) { 2365 qdf_mem_free(mlieseqpayload_copy); 2366 return ret; 2367 } 2368 2369 /* Go through IEs of the reporting STA, and those in STA profile, merge 2370 * them into link_frame (except for elements in the Non-Inheritance 2371 * list). 2372 * 2373 * Note: Currently, only 2-link MLO is supported here. We may have a 2374 * future change to expand to more links. 2375 */ 2376 reportingsta_ie = util_find_eid(WLAN_ELEMID_SSID, frame_iesection, 2377 frame_iesection_len); 2378 2379 if ((subtype == WLAN_FC0_STYPE_ASSOC_REQ) || 2380 (subtype == WLAN_FC0_STYPE_REASSOC_REQ) || 2381 (subtype == WLAN_FC0_STYPE_PROBE_RESP)) { 2382 /* Sanity check that the SSID element is present for the 2383 * reporting STA. There is no stipulation in the standard for 2384 * the STA profile in this regard, so we do not check the STA 2385 * profile for the SSID element. 2386 */ 2387 if (!reportingsta_ie) { 2388 mlo_err_rl("SSID element not found in reporting STA of the frame."); 2389 qdf_mem_free(mlieseqpayload_copy); 2390 return QDF_STATUS_E_PROTO; 2391 } 2392 } else { 2393 /* This is a (re)association response. Sanity check that the 2394 * SSID element is present neither for the reporting STA nor in 2395 * the STA profile. 2396 */ 2397 if (reportingsta_ie) { 2398 mlo_err_rl("SSID element found for reporting STA for (re)association response. It should not be present."); 2399 qdf_mem_free(mlieseqpayload_copy); 2400 return QDF_STATUS_E_PROTO; 2401 } 2402 2403 sta_prof_ie = util_find_eid(WLAN_ELEMID_SSID, 2404 sta_prof_iesection, 2405 sta_prof_iesection_len); 2406 2407 if (sta_prof_ie) { 2408 mlo_err_rl("SSID element found in STA profile for (re)association response. It should not be present."); 2409 qdf_mem_free(mlieseqpayload_copy); 2410 return QDF_STATUS_E_PROTO; 2411 } 2412 } 2413 2414 reportingsta_ie = reportingsta_ie ? reportingsta_ie : frame_iesection; 2415 2416 ret = util_validate_reportingsta_ie(reportingsta_ie, frame_iesection, 2417 frame_iesection_len); 2418 if (QDF_IS_STATUS_ERROR(ret)) { 2419 qdf_mem_free(mlieseqpayload_copy); 2420 return ret; 2421 } 2422 2423 reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] + MIN_IE_LEN; 2424 2425 while (((reportingsta_ie + reportingsta_ie_size) - frame_iesection) 2426 <= frame_iesection_len) { 2427 /* Skip Multi-Link element */ 2428 if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) && 2429 (reportingsta_ie[IDEXT_POS] == 2430 WLAN_EXTN_ELEMID_MULTI_LINK)) { 2431 if (((reportingsta_ie + reportingsta_ie_size) - 2432 frame_iesection) == frame_iesection_len) 2433 break; 2434 2435 /* Add BV ML IE for link specific probe response */ 2436 if (subtype == WLAN_FC0_STYPE_PROBE_RESP) { 2437 ret = util_add_mlie_for_prb_rsp_gen( 2438 reportingsta_ie, 2439 reportingsta_ie[TAG_LEN_POS], 2440 &link_frame_currpos, 2441 &link_frame_currlen, 2442 link_frame_maxsize, 2443 linkid); 2444 if (QDF_IS_STATUS_ERROR(ret)) { 2445 qdf_mem_free(mlieseqpayload_copy); 2446 return ret; 2447 } 2448 } 2449 reportingsta_ie += reportingsta_ie_size; 2450 2451 ret = util_validate_reportingsta_ie(reportingsta_ie, 2452 frame_iesection, 2453 frame_iesection_len); 2454 if (QDF_IS_STATUS_ERROR(ret)) { 2455 qdf_mem_free(mlieseqpayload_copy); 2456 return ret; 2457 } 2458 2459 reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] + 2460 MIN_IE_LEN; 2461 2462 continue; 2463 } 2464 2465 sta_prof_ie = NULL; 2466 sta_prof_ie_size = 0; 2467 2468 if (sta_prof_iesection_len) { 2469 if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 2470 sta_prof_ie = (uint8_t *)util_find_extn_eid(reportingsta_ie[ID_POS], 2471 reportingsta_ie[IDEXT_POS], 2472 sta_prof_iesection, 2473 sta_prof_iesection_len); 2474 } else { 2475 sta_prof_ie = (uint8_t *)util_find_eid(reportingsta_ie[ID_POS], 2476 sta_prof_iesection, 2477 sta_prof_iesection_len); 2478 } 2479 } 2480 2481 if (!sta_prof_ie) { 2482 /* IE is present for reporting STA, but not in STA 2483 * profile. 2484 */ 2485 2486 is_in_noninheritlist = false; 2487 2488 ret = util_eval_ie_in_noninheritlist((uint8_t *)reportingsta_ie, 2489 reportingsta_ie_size, 2490 ninherit_elemlist, 2491 ninherit_elemlist_len, 2492 ninherit_elemextlist, 2493 ninherit_elemextlist_len, 2494 &is_in_noninheritlist); 2495 2496 if (QDF_IS_STATUS_ERROR(ret)) { 2497 qdf_mem_free(mlieseqpayload_copy); 2498 return ret; 2499 } 2500 2501 if (!is_in_noninheritlist) { 2502 if ((link_frame_currpos + 2503 reportingsta_ie_size) <= 2504 (link_frame + link_frame_maxsize)) { 2505 qdf_mem_copy(link_frame_currpos, 2506 reportingsta_ie, 2507 reportingsta_ie_size); 2508 2509 link_frame_currpos += 2510 reportingsta_ie_size; 2511 link_frame_currlen += 2512 reportingsta_ie_size; 2513 2514 if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 2515 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", 2516 reportingsta_ie[ID_POS], 2517 reportingsta_ie[IDEXT_POS], 2518 reportingsta_ie_size); 2519 } else { 2520 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", 2521 reportingsta_ie[ID_POS], 2522 reportingsta_ie_size); 2523 } 2524 } else { 2525 if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 2526 mlo_err_rl("Insufficient space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets", 2527 reportingsta_ie[ID_POS], 2528 reportingsta_ie[IDEXT_POS], 2529 reportingsta_ie_size, 2530 link_frame_maxsize - 2531 link_frame_currlen); 2532 } else { 2533 mlo_err_rl("Insufficient space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets", 2534 reportingsta_ie[ID_POS], 2535 reportingsta_ie_size, 2536 link_frame_maxsize - 2537 link_frame_currlen); 2538 } 2539 2540 qdf_mem_free(mlieseqpayload_copy); 2541 return QDF_STATUS_E_NOMEM; 2542 } 2543 } else { 2544 if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 2545 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.", 2546 reportingsta_ie[ID_POS], 2547 reportingsta_ie[IDEXT_POS], 2548 reportingsta_ie_size); 2549 } else { 2550 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.", 2551 reportingsta_ie[ID_POS], 2552 reportingsta_ie_size); 2553 } 2554 } 2555 } else { 2556 /* IE is present for reporting STA and also in STA 2557 * profile, copy from STA profile and flag the IE in STA 2558 * profile as copied (by setting EID field to 0). The 2559 * SSID element (with EID 0) is processed first to 2560 * enable this. For vendor IE, compare OUI + type + 2561 * subType to determine if they are the same IE. 2562 */ 2563 /* Note: This may be revisited in a future change, to 2564 * adhere to provisions in the standard for multiple 2565 * occurrences of a given element ID/extension element 2566 * ID. 2567 */ 2568 2569 ret = util_validate_sta_prof_ie(sta_prof_ie, 2570 sta_prof_iesection, 2571 sta_prof_iesection_len); 2572 if (QDF_IS_STATUS_ERROR(ret)) { 2573 qdf_mem_free(mlieseqpayload_copy); 2574 return ret; 2575 } 2576 2577 sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] + 2578 MIN_IE_LEN; 2579 2580 sta_prof_iesection_remlen = 2581 sta_prof_iesection_len - 2582 (sta_prof_ie - sta_prof_iesection); 2583 2584 if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_VENDOR) && 2585 (sta_prof_iesection_remlen >= MIN_VENDOR_TAG_LEN)) { 2586 /* If Vendor IE also presents in STA profile, 2587 * then ignore the Vendor IE which is for 2588 * reporting STA. It only needs to copy Vendor 2589 * IE from STA profile to link specific frame. 2590 * The copy happens when going through the 2591 * remaining IEs. 2592 */ 2593 ; 2594 } else { 2595 /* Copy IE from STA profile into link specific 2596 * frame. 2597 */ 2598 if ((link_frame_currpos + sta_prof_ie_size) <= 2599 (link_frame + link_frame_maxsize)) { 2600 qdf_mem_copy(link_frame_currpos, 2601 sta_prof_ie, 2602 sta_prof_ie_size); 2603 2604 link_frame_currpos += sta_prof_ie_size; 2605 link_frame_currlen += 2606 sta_prof_ie_size; 2607 2608 if (reportingsta_ie[ID_POS] == 2609 WLAN_ELEMID_EXTN_ELEM) { 2610 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", 2611 sta_prof_ie[ID_POS], 2612 sta_prof_ie[IDEXT_POS], 2613 sta_prof_ie_size); 2614 } else { 2615 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", 2616 sta_prof_ie[ID_POS], 2617 sta_prof_ie_size); 2618 } 2619 2620 sta_prof_ie[0] = 0; 2621 } else { 2622 if (sta_prof_ie[ID_POS] == 2623 WLAN_ELEMID_EXTN_ELEM) { 2624 mlo_err_rl("Insufficient space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets", 2625 sta_prof_ie[ID_POS], 2626 sta_prof_ie[IDEXT_POS], 2627 sta_prof_ie_size, 2628 link_frame_maxsize - 2629 link_frame_currlen); 2630 } else { 2631 mlo_err_rl("Insufficient space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets", 2632 sta_prof_ie[ID_POS], 2633 sta_prof_ie_size, 2634 link_frame_maxsize - 2635 link_frame_currlen); 2636 } 2637 2638 qdf_mem_free(mlieseqpayload_copy); 2639 return QDF_STATUS_E_NOMEM; 2640 } 2641 } 2642 } 2643 2644 if (((reportingsta_ie + reportingsta_ie_size) - 2645 frame_iesection) == frame_iesection_len) 2646 break; 2647 2648 reportingsta_ie += reportingsta_ie_size; 2649 2650 ret = util_validate_reportingsta_ie(reportingsta_ie, 2651 frame_iesection, 2652 frame_iesection_len); 2653 if (QDF_IS_STATUS_ERROR(ret)) { 2654 qdf_mem_free(mlieseqpayload_copy); 2655 return ret; 2656 } 2657 2658 reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] + 2659 MIN_IE_LEN; 2660 } 2661 2662 /* Go through the remaining unprocessed IEs in STA profile and copy them 2663 * to the link specific frame. The processed ones are marked with 0 in 2664 * the first octet. The first octet corresponds to the element ID. In 2665 * the case of (re)association request, the element with actual ID 2666 * WLAN_ELEMID_SSID(0) has already been copied to the link specific 2667 * frame. In the case of (re)association response, it has been verified 2668 * that the element with actual ID WLAN_ELEMID_SSID(0) is present 2669 * neither for the reporting STA nor in the STA profile. 2670 */ 2671 sta_prof_iesection_currpos = sta_prof_iesection; 2672 sta_prof_iesection_remlen = sta_prof_iesection_len; 2673 2674 while (sta_prof_iesection_remlen > 0) { 2675 sta_prof_ie = sta_prof_iesection_currpos; 2676 ret = util_validate_sta_prof_ie(sta_prof_ie, 2677 sta_prof_iesection_currpos, 2678 sta_prof_iesection_remlen); 2679 if (QDF_IS_STATUS_ERROR(ret)) { 2680 qdf_mem_free(mlieseqpayload_copy); 2681 return ret; 2682 } 2683 2684 sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] + MIN_IE_LEN; 2685 2686 if (!sta_prof_ie[0]) { 2687 /* Skip this, since it has already been processed */ 2688 sta_prof_iesection_currpos += sta_prof_ie_size; 2689 sta_prof_iesection_remlen -= sta_prof_ie_size; 2690 continue; 2691 } 2692 2693 /* Copy IE from STA profile into link specific frame. */ 2694 if ((link_frame_currpos + sta_prof_ie_size) <= 2695 (link_frame + link_frame_maxsize)) { 2696 qdf_mem_copy(link_frame_currpos, 2697 sta_prof_ie, 2698 sta_prof_ie_size); 2699 2700 link_frame_currpos += sta_prof_ie_size; 2701 link_frame_currlen += 2702 sta_prof_ie_size; 2703 2704 if (reportingsta_ie[ID_POS] == 2705 WLAN_ELEMID_EXTN_ELEM) { 2706 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", 2707 sta_prof_ie[ID_POS], 2708 sta_prof_ie[IDEXT_POS], 2709 sta_prof_ie_size); 2710 } else { 2711 mlo_debug("IE with element ID : %u (%zu octets) is present only in STA profile. Copied IE from STA profile to link specific frame", 2712 sta_prof_ie[ID_POS], 2713 sta_prof_ie_size); 2714 } 2715 2716 sta_prof_ie[0] = 0; 2717 } else { 2718 if (sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 2719 mlo_err_rl("Insufficient space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets", 2720 sta_prof_ie[ID_POS], 2721 sta_prof_ie[IDEXT_POS], 2722 sta_prof_ie_size, 2723 link_frame_maxsize - 2724 link_frame_currlen); 2725 } else { 2726 mlo_err_rl("Insufficient space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets", 2727 sta_prof_ie[ID_POS], 2728 sta_prof_ie_size, 2729 link_frame_maxsize - 2730 link_frame_currlen); 2731 } 2732 2733 qdf_mem_free(mlieseqpayload_copy); 2734 return QDF_STATUS_E_NOMEM; 2735 } 2736 2737 sta_prof_iesection_currpos += sta_prof_ie_size; 2738 sta_prof_iesection_remlen -= sta_prof_ie_size; 2739 } 2740 2741 /* Copy the link MAC addr */ 2742 link_frame_hdr = (struct wlan_frame_hdr *)link_frame; 2743 2744 if ((subtype == WLAN_FC0_STYPE_ASSOC_REQ) || 2745 (subtype == WLAN_FC0_STYPE_REASSOC_REQ)) { 2746 qdf_mem_copy(link_frame_hdr->i_addr3, &link_addr, 2747 QDF_MAC_ADDR_SIZE); 2748 qdf_mem_copy(link_frame_hdr->i_addr2, reportedmacaddr.bytes, 2749 QDF_MAC_ADDR_SIZE); 2750 qdf_mem_copy(link_frame_hdr->i_addr1, &link_addr, 2751 QDF_MAC_ADDR_SIZE); 2752 2753 link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_ASSOC_REQ_FC0; 2754 link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_ASSOC_REQ_FC1; 2755 } else if (subtype == WLAN_FC0_STYPE_PROBE_RESP) { 2756 qdf_mem_copy(link_frame_hdr->i_addr3, reportedmacaddr.bytes, 2757 QDF_MAC_ADDR_SIZE); 2758 qdf_mem_copy(link_frame_hdr->i_addr2, reportedmacaddr.bytes, 2759 QDF_MAC_ADDR_SIZE); 2760 qdf_mem_copy(link_frame_hdr->i_addr1, &link_addr, 2761 QDF_MAC_ADDR_SIZE); 2762 2763 link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_PROBE_RESP_FC0; 2764 link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_PROBE_RESP_FC1; 2765 } else { 2766 /* This is a (re)association response */ 2767 2768 qdf_mem_copy(link_frame_hdr->i_addr3, reportedmacaddr.bytes, 2769 QDF_MAC_ADDR_SIZE); 2770 qdf_mem_copy(link_frame_hdr->i_addr2, reportedmacaddr.bytes, 2771 QDF_MAC_ADDR_SIZE); 2772 qdf_mem_copy(link_frame_hdr->i_addr1, &link_addr, 2773 QDF_MAC_ADDR_SIZE); 2774 2775 link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_ASSOC_RESP_FC0; 2776 link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_ASSOC_RESP_FC1; 2777 } 2778 2779 mlo_debug("subtype:%u addr3:" QDF_MAC_ADDR_FMT " addr2:" 2780 QDF_MAC_ADDR_FMT " addr1:" QDF_MAC_ADDR_FMT, 2781 subtype, 2782 QDF_MAC_ADDR_REF(link_frame_hdr->i_addr3), 2783 QDF_MAC_ADDR_REF(link_frame_hdr->i_addr2), 2784 QDF_MAC_ADDR_REF(link_frame_hdr->i_addr1)); 2785 2786 /* Seq num not used so not populated */ 2787 2788 qdf_mem_free(mlieseqpayload_copy); 2789 2790 *link_frame_len = link_frame_currlen; 2791 2792 return QDF_STATUS_SUCCESS; 2793 } 2794 2795 QDF_STATUS 2796 util_gen_link_assoc_req(uint8_t *frame, qdf_size_t frame_len, bool isreassoc, 2797 struct qdf_mac_addr link_addr, 2798 uint8_t *link_frame, 2799 qdf_size_t link_frame_maxsize, 2800 qdf_size_t *link_frame_len) 2801 { 2802 return util_gen_link_reqrsp_cmn(frame, frame_len, 2803 (isreassoc ? WLAN_FC0_STYPE_REASSOC_REQ : 2804 WLAN_FC0_STYPE_ASSOC_REQ), 2805 link_addr, link_frame, link_frame_maxsize, 2806 link_frame_len); 2807 } 2808 2809 QDF_STATUS 2810 util_gen_link_assoc_rsp(uint8_t *frame, qdf_size_t frame_len, bool isreassoc, 2811 struct qdf_mac_addr link_addr, 2812 uint8_t *link_frame, 2813 qdf_size_t link_frame_maxsize, 2814 qdf_size_t *link_frame_len) 2815 { 2816 return util_gen_link_reqrsp_cmn(frame, frame_len, 2817 (isreassoc ? WLAN_FC0_STYPE_REASSOC_RESP : 2818 WLAN_FC0_STYPE_ASSOC_RESP), 2819 link_addr, link_frame, link_frame_maxsize, 2820 link_frame_len); 2821 } 2822 2823 QDF_STATUS 2824 util_gen_link_probe_rsp(uint8_t *frame, qdf_size_t frame_len, 2825 struct qdf_mac_addr link_addr, 2826 uint8_t *link_frame, 2827 qdf_size_t link_frame_maxsize, 2828 qdf_size_t *link_frame_len) 2829 { 2830 return util_gen_link_reqrsp_cmn(frame, frame_len, 2831 WLAN_FC0_STYPE_PROBE_RESP, 2832 link_addr, link_frame, link_frame_maxsize, 2833 link_frame_len); 2834 } 2835 2836 QDF_STATUS 2837 util_find_mlie(uint8_t *buf, qdf_size_t buflen, uint8_t **mlieseq, 2838 qdf_size_t *mlieseqlen) 2839 { 2840 uint8_t *bufboundary; 2841 uint8_t *ieseq; 2842 qdf_size_t ieseqlen; 2843 uint8_t *currie; 2844 uint8_t *successorfrag; 2845 2846 if (!buf || !buflen || !mlieseq || !mlieseqlen) 2847 return QDF_STATUS_E_NULL_VALUE; 2848 2849 *mlieseq = NULL; 2850 *mlieseqlen = 0; 2851 2852 /* Find Multi-Link element. In case a fragment sequence is present, 2853 * this element will be the leading fragment. 2854 */ 2855 ieseq = util_find_extn_eid(WLAN_ELEMID_EXTN_ELEM, 2856 WLAN_EXTN_ELEMID_MULTI_LINK, buf, 2857 buflen); 2858 2859 /* Even if the element is not found, we have successfully examined the 2860 * buffer. The caller will be provided a NULL value for the starting of 2861 * the Multi-Link element. Hence, we return success. 2862 */ 2863 if (!ieseq) 2864 return QDF_STATUS_SUCCESS; 2865 2866 bufboundary = buf + buflen; 2867 2868 if ((ieseq + MIN_IE_LEN) > bufboundary) 2869 return QDF_STATUS_E_INVAL; 2870 2871 ieseqlen = MIN_IE_LEN + ieseq[TAG_LEN_POS]; 2872 2873 if (ieseqlen < sizeof(struct wlan_ie_multilink)) 2874 return QDF_STATUS_E_PROTO; 2875 2876 if ((ieseq + ieseqlen) > bufboundary) 2877 return QDF_STATUS_E_INVAL; 2878 2879 /* In the next sequence of checks, if there is no space in the buffer 2880 * for another element after the Multi-Link element/element fragment 2881 * sequence, it could indicate an issue since non-MLO EHT elements 2882 * would be expected to follow the Multi-Link element/element fragment 2883 * sequence. However, this is outside of the purview of this function, 2884 * hence we ignore it. 2885 */ 2886 2887 currie = ieseq; 2888 successorfrag = util_get_successorfrag(currie, buf, buflen); 2889 2890 /* Fragmentation definitions as of IEEE802.11be D1.0 and 2891 * IEEE802.11REVme D0.2 are applied. Only the case where Multi-Link 2892 * element is present in a buffer from the core frame is considered. 2893 * Future changes to fragmentation, cases where the Multi-Link element 2894 * is present in a subelement, etc. to be reflected here if applicable 2895 * as and when the rules evolve. 2896 */ 2897 while (successorfrag) { 2898 /* We should not be seeing a successor fragment if the length 2899 * of the current IE is lesser than the max. 2900 */ 2901 if (currie[TAG_LEN_POS] != WLAN_MAX_IE_LEN) 2902 return QDF_STATUS_E_PROTO; 2903 2904 if (successorfrag[TAG_LEN_POS] == 0) 2905 return QDF_STATUS_E_PROTO; 2906 2907 ieseqlen += (MIN_IE_LEN + successorfrag[TAG_LEN_POS]); 2908 2909 currie = successorfrag; 2910 successorfrag = util_get_successorfrag(currie, buf, buflen); 2911 } 2912 2913 *mlieseq = ieseq; 2914 *mlieseqlen = ieseqlen; 2915 return QDF_STATUS_SUCCESS; 2916 } 2917 2918 QDF_STATUS 2919 util_find_mlie_by_variant(uint8_t *buf, qdf_size_t buflen, uint8_t **mlieseq, 2920 qdf_size_t *mlieseqlen, int variant) 2921 { 2922 uint8_t *ieseq; 2923 qdf_size_t ieseqlen; 2924 QDF_STATUS status; 2925 int ml_variant; 2926 qdf_size_t buf_parsed_len; 2927 2928 if (!buf || !buflen || !mlieseq || !mlieseqlen) 2929 return QDF_STATUS_E_NULL_VALUE; 2930 2931 if (variant >= WLAN_ML_VARIANT_INVALIDSTART) 2932 return QDF_STATUS_E_PROTO; 2933 2934 ieseq = NULL; 2935 ieseqlen = 0; 2936 *mlieseq = NULL; 2937 *mlieseqlen = 0; 2938 buf_parsed_len = 0; 2939 2940 while (buflen > buf_parsed_len) { 2941 status = util_find_mlie(buf + buf_parsed_len, 2942 buflen - buf_parsed_len, 2943 &ieseq, &ieseqlen); 2944 2945 if (QDF_IS_STATUS_ERROR(status)) 2946 return status; 2947 2948 /* Even if the element is not found, we have successfully 2949 * examined the buffer. The caller will be provided a NULL value 2950 * for the starting of the Multi-Link element. Hence, we return 2951 * success. 2952 */ 2953 if (!ieseq) 2954 return QDF_STATUS_SUCCESS; 2955 2956 status = util_get_mlie_variant(ieseq, ieseqlen, 2957 &ml_variant); 2958 if (QDF_IS_STATUS_ERROR(status)) { 2959 mlo_err("Unable to get Multi-link element variant"); 2960 return status; 2961 } 2962 2963 if (ml_variant == variant) { 2964 *mlieseq = ieseq; 2965 *mlieseqlen = ieseqlen; 2966 return QDF_STATUS_SUCCESS; 2967 } 2968 2969 buf_parsed_len = ieseq + ieseqlen - buf; 2970 } 2971 2972 return QDF_STATUS_E_INVAL; 2973 } 2974 2975 QDF_STATUS 2976 util_get_mlie_common_info_len(uint8_t *mlieseq, qdf_size_t mlieseqlen, 2977 uint8_t *commoninfo_len) 2978 { 2979 struct wlan_ie_multilink *mlie_fixed; 2980 enum wlan_ml_variant variant; 2981 uint16_t mlcontrol; 2982 2983 if (!mlieseq || !mlieseqlen || !commoninfo_len) 2984 return QDF_STATUS_E_NULL_VALUE; 2985 2986 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 2987 return QDF_STATUS_E_INVAL; 2988 2989 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 2990 2991 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 2992 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) 2993 return QDF_STATUS_E_INVAL; 2994 2995 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 2996 2997 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 2998 WLAN_ML_CTRL_TYPE_BITS); 2999 3000 if (variant != WLAN_ML_VARIANT_BASIC) 3001 return QDF_STATUS_E_INVAL; 3002 3003 /* Common Info starts at mlieseq + sizeof(struct wlan_ie_multilink). 3004 * Check if there is sufficient space in the buffer for the Common Info 3005 * Length and MLD MAC address. 3006 */ 3007 if ((sizeof(struct wlan_ie_multilink) + WLAN_ML_BV_CINFO_LENGTH_SIZE + 3008 QDF_MAC_ADDR_SIZE) > mlieseqlen) 3009 return QDF_STATUS_E_PROTO; 3010 3011 *commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink)); 3012 3013 return QDF_STATUS_SUCCESS; 3014 } 3015 3016 QDF_STATUS 3017 util_get_bvmlie_bssparamchangecnt(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3018 bool *bssparamchangecntfound, 3019 uint8_t *bssparamchangecnt) 3020 { 3021 struct wlan_ie_multilink *mlie_fixed; 3022 enum wlan_ml_variant variant; 3023 uint16_t mlcontrol; 3024 uint16_t presencebitmap; 3025 uint8_t *commoninfo; 3026 qdf_size_t commoninfolen; 3027 3028 if (!mlieseq || !mlieseqlen || !bssparamchangecntfound || 3029 !bssparamchangecnt) 3030 return QDF_STATUS_E_NULL_VALUE; 3031 3032 *bssparamchangecntfound = false; 3033 *bssparamchangecnt = 0; 3034 3035 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3036 return QDF_STATUS_E_INVAL; 3037 3038 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3039 3040 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 3041 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) 3042 return QDF_STATUS_E_INVAL; 3043 3044 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3045 3046 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3047 WLAN_ML_CTRL_TYPE_BITS); 3048 3049 if (variant != WLAN_ML_VARIANT_BASIC) 3050 return QDF_STATUS_E_NOSUPPORT; 3051 3052 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3053 WLAN_ML_CTRL_PBM_BITS); 3054 3055 commoninfo = mlieseq + sizeof(struct wlan_ie_multilink); 3056 commoninfolen = WLAN_ML_BV_CINFO_LENGTH_SIZE; 3057 3058 commoninfolen += QDF_MAC_ADDR_SIZE; 3059 3060 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) { 3061 commoninfolen += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; 3062 3063 if ((sizeof(struct wlan_ie_multilink) + commoninfolen) > 3064 mlieseqlen) 3065 return QDF_STATUS_E_PROTO; 3066 } 3067 3068 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) { 3069 *bssparamchangecntfound = true; 3070 *bssparamchangecnt = *(commoninfo + commoninfolen); 3071 } 3072 3073 return QDF_STATUS_SUCCESS; 3074 } 3075 3076 QDF_STATUS 3077 util_get_mlie_variant(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3078 int *variant) 3079 { 3080 struct wlan_ie_multilink *mlie_fixed; 3081 enum wlan_ml_variant var; 3082 uint16_t mlcontrol; 3083 3084 if (!mlieseq || !mlieseqlen || !variant) 3085 return QDF_STATUS_E_NULL_VALUE; 3086 3087 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3088 return QDF_STATUS_E_INVAL; 3089 3090 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3091 3092 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3093 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) 3094 return QDF_STATUS_E_INVAL; 3095 3096 mlcontrol = le16toh(mlie_fixed->mlcontrol); 3097 var = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3098 WLAN_ML_CTRL_TYPE_BITS); 3099 3100 if (var >= WLAN_ML_VARIANT_INVALIDSTART) 3101 return QDF_STATUS_E_PROTO; 3102 3103 *variant = var; 3104 return QDF_STATUS_SUCCESS; 3105 } 3106 3107 QDF_STATUS 3108 util_get_bvmlie_eml_cap(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3109 bool *eml_cap_found, 3110 uint16_t *eml_cap) 3111 { 3112 struct wlan_ie_multilink *mlie_fixed; 3113 enum wlan_ml_variant variant; 3114 uint16_t mlcontrol; 3115 uint8_t eml_cap_offset; 3116 uint8_t commoninfo_len; 3117 uint16_t presencebitmap; 3118 3119 if (!mlieseq || !mlieseqlen || !eml_cap_found || !eml_cap) 3120 return QDF_STATUS_E_NULL_VALUE; 3121 3122 *eml_cap = 0; 3123 *eml_cap_found = false; 3124 3125 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3126 return QDF_STATUS_E_INVAL; 3127 3128 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3129 3130 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3131 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) 3132 return QDF_STATUS_E_INVAL; 3133 3134 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3135 3136 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3137 WLAN_ML_CTRL_TYPE_BITS); 3138 3139 if (variant != WLAN_ML_VARIANT_BASIC) 3140 return QDF_STATUS_E_INVAL; 3141 3142 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3143 WLAN_ML_CTRL_PBM_BITS); 3144 3145 /* eml_cap_offset stores the offset of EML Capabilities within 3146 * Common Info 3147 */ 3148 eml_cap_offset = WLAN_ML_BV_CINFO_LENGTH_SIZE + QDF_MAC_ADDR_SIZE; 3149 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) 3150 eml_cap_offset += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; 3151 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) 3152 eml_cap_offset += WLAN_ML_BSSPARAMCHNGCNT_SIZE; 3153 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P) 3154 eml_cap_offset += WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE; 3155 3156 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_EMLCAP_P) { 3157 /* Common Info starts at 3158 * mlieseq + sizeof(struct wlan_ie_multilink). 3159 * Check if there is sufficient space in the buffer for 3160 * the Common Info Length. 3161 */ 3162 if (mlieseqlen < (sizeof(struct wlan_ie_multilink) + 3163 WLAN_ML_BV_CINFO_LENGTH_SIZE)) 3164 return QDF_STATUS_E_PROTO; 3165 3166 /* Check if the value indicated in the Common Info Length 3167 * subfield is sufficient to access the EML capabilities. 3168 */ 3169 commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink)); 3170 if (commoninfo_len < (eml_cap_offset + 3171 WLAN_ML_BV_CINFO_EMLCAP_SIZE)) 3172 return QDF_STATUS_E_PROTO; 3173 3174 /* Common Info starts at mlieseq + sizeof(struct 3175 * wlan_ie_multilink). Check if there is sufficient space in 3176 * Common Info for the EML capability. 3177 */ 3178 if (mlieseqlen < (sizeof(struct wlan_ie_multilink) + 3179 eml_cap_offset + 3180 WLAN_ML_BV_CINFO_EMLCAP_SIZE)) 3181 return QDF_STATUS_E_PROTO; 3182 3183 *eml_cap_found = true; 3184 *eml_cap = qdf_le16_to_cpu(*(uint16_t *)(mlieseq + 3185 sizeof(struct wlan_ie_multilink) + 3186 eml_cap_offset)); 3187 } 3188 return QDF_STATUS_SUCCESS; 3189 } 3190 3191 QDF_STATUS 3192 util_get_bvmlie_msd_cap(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3193 bool *msd_cap_found, 3194 uint16_t *msd_cap) 3195 { 3196 struct wlan_ie_multilink *mlie_fixed; 3197 enum wlan_ml_variant variant; 3198 uint16_t mlcontrol; 3199 uint8_t msd_cap_offset; 3200 uint8_t commoninfo_len; 3201 uint16_t presencebitmap; 3202 3203 if (!mlieseq || !mlieseqlen || !msd_cap_found || !msd_cap) 3204 return QDF_STATUS_E_NULL_VALUE; 3205 3206 *msd_cap = 0; 3207 *msd_cap_found = false; 3208 3209 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3210 return QDF_STATUS_E_INVAL; 3211 3212 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3213 3214 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3215 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) 3216 return QDF_STATUS_E_INVAL; 3217 3218 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3219 3220 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3221 WLAN_ML_CTRL_TYPE_BITS); 3222 3223 if (variant != WLAN_ML_VARIANT_BASIC) 3224 return QDF_STATUS_E_INVAL; 3225 3226 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3227 WLAN_ML_CTRL_PBM_BITS); 3228 3229 /* msd_cap_offset stores the offset of MSD capabilities within 3230 * Common Info 3231 */ 3232 msd_cap_offset = WLAN_ML_BV_CINFO_LENGTH_SIZE + QDF_MAC_ADDR_SIZE; 3233 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) 3234 msd_cap_offset += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; 3235 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) 3236 msd_cap_offset += WLAN_ML_BSSPARAMCHNGCNT_SIZE; 3237 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P) { 3238 /* Common Info starts at 3239 * mlieseq + sizeof(struct wlan_ie_multilink). 3240 * Check if there is sufficient space in the buffer for 3241 * the Common Info Length. 3242 */ 3243 if (mlieseqlen < (sizeof(struct wlan_ie_multilink) + 3244 WLAN_ML_BV_CINFO_LENGTH_SIZE)) 3245 return QDF_STATUS_E_PROTO; 3246 3247 /* Check if the value indicated in the Common Info Length 3248 * subfield is sufficient to access the MSD capabilities. 3249 */ 3250 commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink)); 3251 if (commoninfo_len < (msd_cap_offset + 3252 WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE)) 3253 return QDF_STATUS_E_PROTO; 3254 3255 /* Common Info starts at mlieseq + sizeof(struct 3256 * wlan_ie_multilink). Check if there is sufficient space in 3257 * Common Info for the MSD capability. 3258 */ 3259 if (mlieseqlen < (sizeof(struct wlan_ie_multilink) + 3260 msd_cap_offset + 3261 WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE)) 3262 return QDF_STATUS_E_PROTO; 3263 3264 *msd_cap_found = true; 3265 *msd_cap = qdf_le16_to_cpu(*(uint16_t *)(mlieseq + 3266 sizeof(struct wlan_ie_multilink) + 3267 msd_cap_offset)); 3268 } else { 3269 mlo_debug("MSD caps not found in assoc rsp"); 3270 } 3271 3272 return QDF_STATUS_SUCCESS; 3273 } 3274 3275 QDF_STATUS 3276 util_get_bvmlie_mldmacaddr(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3277 struct qdf_mac_addr *mldmacaddr) 3278 { 3279 struct wlan_ie_multilink *mlie_fixed; 3280 enum wlan_ml_variant variant; 3281 uint16_t mlcontrol; 3282 uint8_t commoninfo_len; 3283 3284 if (!mlieseq || !mlieseqlen || !mldmacaddr) 3285 return QDF_STATUS_E_NULL_VALUE; 3286 3287 qdf_mem_zero(mldmacaddr, sizeof(*mldmacaddr)); 3288 3289 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3290 return QDF_STATUS_E_INVAL; 3291 3292 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3293 3294 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3295 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) 3296 return QDF_STATUS_E_INVAL; 3297 3298 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3299 3300 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3301 WLAN_ML_CTRL_TYPE_BITS); 3302 3303 if (variant != WLAN_ML_VARIANT_BASIC) 3304 return QDF_STATUS_E_INVAL; 3305 3306 /* Common Info starts at mlieseq + sizeof(struct wlan_ie_multilink). 3307 * Check if there is sufficient space in the buffer for the Common Info 3308 * Length and MLD MAC address. 3309 */ 3310 if ((sizeof(struct wlan_ie_multilink) + WLAN_ML_BV_CINFO_LENGTH_SIZE + 3311 QDF_MAC_ADDR_SIZE) > mlieseqlen) 3312 return QDF_STATUS_E_PROTO; 3313 3314 /* Check if the value indicated in the Common Info Length subfield is 3315 * sufficient to access the MLD MAC address. 3316 */ 3317 commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink)); 3318 if (commoninfo_len < (WLAN_ML_BV_CINFO_LENGTH_SIZE + QDF_MAC_ADDR_SIZE)) 3319 return QDF_STATUS_E_PROTO; 3320 3321 qdf_mem_copy(mldmacaddr->bytes, 3322 mlieseq + sizeof(struct wlan_ie_multilink) + 3323 WLAN_ML_BV_CINFO_LENGTH_SIZE, 3324 QDF_MAC_ADDR_SIZE); 3325 3326 return QDF_STATUS_SUCCESS; 3327 } 3328 3329 QDF_STATUS 3330 util_get_bvmlie_primary_linkid(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3331 bool *linkidfound, uint8_t *linkid) 3332 { 3333 struct wlan_ie_multilink *mlie_fixed; 3334 enum wlan_ml_variant variant; 3335 uint16_t mlcontrol; 3336 uint16_t presencebitmap; 3337 uint8_t *commoninfo; 3338 qdf_size_t commoninfolen; 3339 uint8_t *linkidinfo; 3340 3341 if (!mlieseq || !mlieseqlen || !linkidfound || !linkid) 3342 return QDF_STATUS_E_NULL_VALUE; 3343 3344 *linkidfound = false; 3345 *linkid = 0; 3346 3347 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3348 return QDF_STATUS_E_INVAL; 3349 3350 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3351 3352 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3353 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) 3354 return QDF_STATUS_E_INVAL; 3355 3356 mlcontrol = le16toh(mlie_fixed->mlcontrol); 3357 3358 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3359 WLAN_ML_CTRL_TYPE_BITS); 3360 3361 if (variant != WLAN_ML_VARIANT_BASIC) 3362 return QDF_STATUS_E_INVAL; 3363 3364 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3365 WLAN_ML_CTRL_PBM_BITS); 3366 3367 commoninfo = mlieseq + sizeof(struct wlan_ie_multilink); 3368 commoninfolen = 0; 3369 commoninfolen += WLAN_ML_BV_CINFO_LENGTH_SIZE; 3370 if ((sizeof(struct wlan_ie_multilink) + commoninfolen) > 3371 mlieseqlen) 3372 return QDF_STATUS_E_PROTO; 3373 3374 commoninfolen += QDF_MAC_ADDR_SIZE; 3375 if ((sizeof(struct wlan_ie_multilink) + commoninfolen) > 3376 mlieseqlen) 3377 return QDF_STATUS_E_PROTO; 3378 3379 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) { 3380 linkidinfo = commoninfo + commoninfolen; 3381 commoninfolen += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; 3382 3383 if ((sizeof(struct wlan_ie_multilink) + commoninfolen) > 3384 mlieseqlen) 3385 return QDF_STATUS_E_PROTO; 3386 3387 *linkidfound = true; 3388 *linkid = QDF_GET_BITS(linkidinfo[0], 3389 WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_IDX, 3390 WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_BITS); 3391 } 3392 3393 return QDF_STATUS_SUCCESS; 3394 } 3395 3396 QDF_STATUS 3397 util_get_bvmlie_mldcap(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3398 bool *mldcapfound, uint16_t *mldcap) 3399 { 3400 struct wlan_ie_multilink *mlie_fixed; 3401 enum wlan_ml_variant variant; 3402 uint16_t mlcontrol; 3403 uint16_t presencebitmap; 3404 uint8_t *commoninfo; 3405 uint8_t commoninfo_len; 3406 qdf_size_t mldcap_offset; 3407 3408 if (!mlieseq || !mlieseqlen || !mldcapfound || !mldcap) 3409 return QDF_STATUS_E_NULL_VALUE; 3410 3411 *mldcapfound = false; 3412 *mldcap = 0; 3413 3414 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3415 return QDF_STATUS_E_INVAL; 3416 3417 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3418 3419 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 3420 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) 3421 return QDF_STATUS_E_INVAL; 3422 3423 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3424 3425 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3426 WLAN_ML_CTRL_TYPE_BITS); 3427 3428 if (variant != WLAN_ML_VARIANT_BASIC) 3429 return QDF_STATUS_E_NOSUPPORT; 3430 3431 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3432 WLAN_ML_CTRL_PBM_BITS); 3433 3434 commoninfo = mlieseq + sizeof(struct wlan_ie_multilink); 3435 commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink)); 3436 /* mldcap_offset stores the offset of MLD Capabilities within 3437 * Common Info 3438 */ 3439 mldcap_offset = WLAN_ML_BV_CINFO_LENGTH_SIZE; 3440 mldcap_offset += QDF_MAC_ADDR_SIZE; 3441 3442 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) { 3443 mldcap_offset += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; 3444 3445 if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) > 3446 mlieseqlen) 3447 return QDF_STATUS_E_PROTO; 3448 } 3449 3450 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) { 3451 mldcap_offset += WLAN_ML_BSSPARAMCHNGCNT_SIZE; 3452 3453 if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) > 3454 mlieseqlen) 3455 return QDF_STATUS_E_PROTO; 3456 } 3457 3458 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P) { 3459 mldcap_offset += WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE; 3460 3461 if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) > 3462 mlieseqlen) 3463 return QDF_STATUS_E_PROTO; 3464 } 3465 3466 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_EMLCAP_P) { 3467 mldcap_offset += WLAN_ML_BV_CINFO_EMLCAP_SIZE; 3468 3469 if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) > 3470 mlieseqlen) 3471 return QDF_STATUS_E_PROTO; 3472 } 3473 3474 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MLDCAPANDOP_P) { 3475 /* Check if the value indicated in the Common Info Length 3476 * subfield is sufficient to access the MLD capabilities. 3477 */ 3478 if (commoninfo_len < (mldcap_offset + 3479 WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE)) 3480 return QDF_STATUS_E_PROTO; 3481 3482 if ((sizeof(struct wlan_ie_multilink) + mldcap_offset + 3483 WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE) > 3484 mlieseqlen) 3485 return QDF_STATUS_E_PROTO; 3486 3487 *mldcap = qdf_le16_to_cpu(*((uint16_t *)(commoninfo + mldcap_offset))); 3488 *mldcapfound = true; 3489 } 3490 3491 return QDF_STATUS_SUCCESS; 3492 } 3493 3494 QDF_STATUS 3495 util_get_bvmlie_persta_partner_info(uint8_t *mlieseq, 3496 qdf_size_t mlieseqlen, 3497 struct mlo_partner_info *partner_info) 3498 { 3499 struct wlan_ie_multilink *mlie_fixed; 3500 uint16_t mlcontrol; 3501 enum wlan_ml_variant variant; 3502 uint8_t *linkinfo; 3503 qdf_size_t linkinfo_len; 3504 struct mlo_partner_info pinfo = {0}; 3505 qdf_size_t mlieseqpayloadlen; 3506 uint8_t *mlieseqpayload_copy; 3507 bool is_elemfragseq; 3508 qdf_size_t defragpayload_len; 3509 3510 qdf_size_t tmplen; 3511 QDF_STATUS ret; 3512 3513 if (!mlieseq) { 3514 mlo_err("Pointer to Multi-Link element sequence is NULL"); 3515 return QDF_STATUS_E_NULL_VALUE; 3516 } 3517 3518 if (!mlieseqlen) { 3519 mlo_err("Length of Multi-Link element sequence is zero"); 3520 return QDF_STATUS_E_INVAL; 3521 } 3522 3523 if (!partner_info) { 3524 mlo_err("partner_info is NULL"); 3525 return QDF_STATUS_E_NULL_VALUE; 3526 } 3527 3528 partner_info->num_partner_links = 0; 3529 3530 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) { 3531 mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)", 3532 mlieseqlen, sizeof(struct wlan_ie_multilink)); 3533 return QDF_STATUS_E_INVAL; 3534 } 3535 3536 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3537 3538 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3539 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) { 3540 mlo_err("The element is not a Multi-Link element"); 3541 return QDF_STATUS_E_INVAL; 3542 } 3543 3544 mlcontrol = le16toh(mlie_fixed->mlcontrol); 3545 3546 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3547 WLAN_ML_CTRL_TYPE_BITS); 3548 3549 if (variant != WLAN_ML_VARIANT_BASIC) { 3550 mlo_err("The variant value %u does not correspond to Basic Variant value %u", 3551 variant, WLAN_ML_VARIANT_BASIC); 3552 return QDF_STATUS_E_INVAL; 3553 } 3554 3555 mlieseqpayloadlen = 0; 3556 tmplen = 0; 3557 is_elemfragseq = false; 3558 3559 ret = wlan_get_elem_fragseq_info(mlieseq, 3560 mlieseqlen, 3561 &is_elemfragseq, 3562 &tmplen, 3563 &mlieseqpayloadlen); 3564 if (QDF_IS_STATUS_ERROR(ret)) 3565 return ret; 3566 3567 if (is_elemfragseq) { 3568 if (tmplen != mlieseqlen) { 3569 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", 3570 tmplen, mlieseqlen); 3571 return QDF_STATUS_E_INVAL; 3572 } 3573 3574 if (!mlieseqpayloadlen) { 3575 mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate"); 3576 return QDF_STATUS_E_FAILURE; 3577 } 3578 3579 mlo_debug("Multi-Link element fragment sequence found with payload len %zu", 3580 mlieseqpayloadlen); 3581 } else { 3582 if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) { 3583 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", 3584 mlieseqlen, 3585 sizeof(struct ie_header) + WLAN_MAX_IE_LEN); 3586 return QDF_STATUS_E_FAILURE; 3587 } 3588 3589 mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1); 3590 } 3591 3592 mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen); 3593 3594 if (!mlieseqpayload_copy) { 3595 mlo_err_rl("Could not allocate memory for Multi-Link element payload copy"); 3596 return QDF_STATUS_E_NOMEM; 3597 } 3598 3599 if (is_elemfragseq) { 3600 ret = wlan_defrag_elem_fragseq(false, 3601 mlieseq, 3602 mlieseqlen, 3603 mlieseqpayload_copy, 3604 mlieseqpayloadlen, 3605 &defragpayload_len); 3606 if (QDF_IS_STATUS_ERROR(ret)) { 3607 qdf_mem_free(mlieseqpayload_copy); 3608 return ret; 3609 } 3610 3611 if (defragpayload_len != mlieseqpayloadlen) { 3612 mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets", 3613 defragpayload_len, mlieseqpayloadlen); 3614 qdf_mem_free(mlieseqpayload_copy); 3615 return QDF_STATUS_E_FAILURE; 3616 } 3617 } else { 3618 qdf_mem_copy(mlieseqpayload_copy, 3619 mlieseq + sizeof(struct ie_header) + 1, 3620 mlieseqpayloadlen); 3621 } 3622 3623 linkinfo = NULL; 3624 linkinfo_len = 0; 3625 3626 ret = util_parse_multi_link_ctrl(mlieseqpayload_copy, 3627 mlieseqpayloadlen, 3628 &linkinfo, 3629 &linkinfo_len); 3630 if (QDF_IS_STATUS_ERROR(ret)) { 3631 qdf_mem_free(mlieseqpayload_copy); 3632 return ret; 3633 } 3634 3635 /* 3636 * If Probe Request variant Multi-Link element in the Multi-Link probe 3637 * request does not include any per-STA profile, then all APs affiliated 3638 * with the same AP MLD as the AP identified in the Addr 1 or Addr 3 3639 * field or AP MLD ID of the Multi-Link probe request are requested 3640 * APs return success here 3641 */ 3642 if (!linkinfo) { 3643 qdf_mem_free(mlieseqpayload_copy); 3644 return QDF_STATUS_SUCCESS; 3645 } 3646 3647 ret = util_parse_partner_info_from_linkinfo(linkinfo, 3648 linkinfo_len, 3649 &pinfo); 3650 3651 if (QDF_IS_STATUS_ERROR(ret)) { 3652 qdf_mem_free(mlieseqpayload_copy); 3653 return ret; 3654 } 3655 3656 qdf_mem_copy(partner_info, &pinfo, sizeof(*partner_info)); 3657 3658 qdf_mem_free(mlieseqpayload_copy); 3659 3660 return QDF_STATUS_SUCCESS; 3661 } 3662 3663 QDF_STATUS 3664 util_get_prvmlie_persta_link_id(uint8_t *mlieseq, 3665 qdf_size_t mlieseqlen, 3666 struct mlo_probereq_info *probereq_info) 3667 { 3668 struct wlan_ie_multilink *mlie_fixed; 3669 uint16_t mlcontrol; 3670 enum wlan_ml_variant variant; 3671 uint8_t *linkinfo; 3672 qdf_size_t linkinfo_len; 3673 qdf_size_t mlieseqpayloadlen; 3674 uint8_t *mlieseqpayload_copy; 3675 bool is_elemfragseq; 3676 qdf_size_t defragpayload_len; 3677 3678 qdf_size_t tmplen; 3679 QDF_STATUS ret; 3680 3681 if (!mlieseq) { 3682 mlo_err("Pointer to Multi-Link element sequence is NULL"); 3683 return QDF_STATUS_E_NULL_VALUE; 3684 } 3685 3686 if (!mlieseqlen) { 3687 mlo_err("Length of Multi-Link element sequence is zero"); 3688 return QDF_STATUS_E_INVAL; 3689 } 3690 3691 if (!probereq_info) { 3692 mlo_err("probe request_info is NULL"); 3693 return QDF_STATUS_E_NULL_VALUE; 3694 } 3695 3696 probereq_info->num_links = 0; 3697 3698 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) { 3699 mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)", 3700 mlieseqlen, sizeof(struct wlan_ie_multilink)); 3701 return QDF_STATUS_E_INVAL; 3702 } 3703 3704 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3705 3706 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3707 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) { 3708 mlo_err("The element is not a Multi-Link element"); 3709 return QDF_STATUS_E_INVAL; 3710 } 3711 3712 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3713 3714 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3715 WLAN_ML_CTRL_TYPE_BITS); 3716 3717 if (variant != WLAN_ML_VARIANT_PROBEREQ) { 3718 mlo_err("The variant value %u does not correspond to Probe Request Variant value %u", 3719 variant, WLAN_ML_VARIANT_PROBEREQ); 3720 return QDF_STATUS_E_INVAL; 3721 } 3722 3723 mlieseqpayloadlen = 0; 3724 tmplen = 0; 3725 is_elemfragseq = false; 3726 3727 ret = wlan_get_elem_fragseq_info(mlieseq, 3728 mlieseqlen, 3729 &is_elemfragseq, 3730 &tmplen, 3731 &mlieseqpayloadlen); 3732 if (QDF_IS_STATUS_ERROR(ret)) 3733 return ret; 3734 3735 if (is_elemfragseq) { 3736 if (tmplen != mlieseqlen) { 3737 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", 3738 tmplen, mlieseqlen); 3739 return QDF_STATUS_E_INVAL; 3740 } 3741 3742 if (!mlieseqpayloadlen) { 3743 mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate"); 3744 return QDF_STATUS_E_FAILURE; 3745 } 3746 3747 mlo_debug("Multi-Link element fragment sequence found with payload len %zu", 3748 mlieseqpayloadlen); 3749 } else { 3750 if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) { 3751 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", 3752 mlieseqlen, 3753 sizeof(struct ie_header) + WLAN_MAX_IE_LEN); 3754 return QDF_STATUS_E_FAILURE; 3755 } 3756 3757 mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1); 3758 } 3759 3760 mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen); 3761 3762 if (!mlieseqpayload_copy) { 3763 mlo_err_rl("Could not allocate memory for Multi-Link element payload copy"); 3764 return QDF_STATUS_E_NOMEM; 3765 } 3766 3767 if (is_elemfragseq) { 3768 ret = wlan_defrag_elem_fragseq(false, 3769 mlieseq, 3770 mlieseqlen, 3771 mlieseqpayload_copy, 3772 mlieseqpayloadlen, 3773 &defragpayload_len); 3774 if (QDF_IS_STATUS_ERROR(ret)) { 3775 qdf_mem_free(mlieseqpayload_copy); 3776 return ret; 3777 } 3778 3779 if (defragpayload_len != mlieseqpayloadlen) { 3780 mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets", 3781 defragpayload_len, mlieseqpayloadlen); 3782 qdf_mem_free(mlieseqpayload_copy); 3783 return QDF_STATUS_E_FAILURE; 3784 } 3785 } else { 3786 qdf_mem_copy(mlieseqpayload_copy, 3787 mlieseq + sizeof(struct ie_header) + 1, 3788 mlieseqpayloadlen); 3789 } 3790 3791 linkinfo = NULL; 3792 linkinfo_len = 0; 3793 ret = util_parse_prv_multi_link_ctrl(mlieseqpayload_copy, 3794 mlieseqpayloadlen, 3795 &linkinfo, 3796 &linkinfo_len); 3797 if (QDF_IS_STATUS_ERROR(ret)) { 3798 qdf_mem_free(mlieseqpayload_copy); 3799 return ret; 3800 } 3801 3802 /* In case Link Info is absent, the number of links will remain 3803 * zero. 3804 */ 3805 if (!linkinfo) { 3806 mlo_debug("No link info present"); 3807 qdf_mem_free(mlieseqpayload_copy); 3808 return QDF_STATUS_SUCCESS; 3809 } 3810 3811 ret = util_parse_probereq_info_from_linkinfo(linkinfo, 3812 linkinfo_len, 3813 probereq_info); 3814 3815 if (QDF_IS_STATUS_ERROR(ret)) { 3816 qdf_mem_free(mlieseqpayload_copy); 3817 return ret; 3818 } 3819 3820 qdf_mem_free(mlieseqpayload_copy); 3821 3822 return QDF_STATUS_SUCCESS; 3823 } 3824 3825 QDF_STATUS 3826 util_get_prvmlie_mldid(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3827 bool *mldidfound, uint8_t *mldid) 3828 { 3829 struct wlan_ie_multilink *mlie_fixed; 3830 enum wlan_ml_variant variant; 3831 uint16_t mlcontrol; 3832 uint16_t presencebitmap; 3833 uint8_t *commoninfo; 3834 qdf_size_t commoninfolen; 3835 3836 if (!mlieseq || !mlieseqlen || !mldidfound || !mldid) 3837 return QDF_STATUS_E_NULL_VALUE; 3838 3839 *mldidfound = false; 3840 *mldid = 0; 3841 3842 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3843 return QDF_STATUS_E_INVAL; 3844 3845 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3846 3847 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 3848 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) 3849 return QDF_STATUS_E_INVAL; 3850 3851 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3852 3853 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3854 WLAN_ML_CTRL_TYPE_BITS); 3855 3856 if (variant != WLAN_ML_VARIANT_PROBEREQ) 3857 return QDF_STATUS_E_NOSUPPORT; 3858 3859 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3860 WLAN_ML_CTRL_PBM_BITS); 3861 3862 commoninfo = mlieseq + sizeof(struct wlan_ie_multilink); 3863 commoninfolen = WLAN_ML_PRV_CINFO_LENGTH_SIZE; 3864 3865 if (presencebitmap & WLAN_ML_PRV_CTRL_PBM_MLDID_P) { 3866 if ((sizeof(struct wlan_ie_multilink) + commoninfolen + 3867 WLAN_ML_PRV_CINFO_MLDID_SIZE) > 3868 mlieseqlen) 3869 return QDF_STATUS_E_PROTO; 3870 3871 *mldid = *((uint8_t *)(commoninfo + commoninfolen)); 3872 commoninfolen += WLAN_ML_PRV_CINFO_MLDID_SIZE; 3873 3874 *mldidfound = true; 3875 } 3876 3877 return QDF_STATUS_SUCCESS; 3878 } 3879 3880 QDF_STATUS util_get_rvmlie_mldmacaddr(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3881 struct qdf_mac_addr *mldmacaddr) 3882 { 3883 struct wlan_ie_multilink *mlie_fixed; 3884 enum wlan_ml_variant variant; 3885 uint16_t mlcontrol; 3886 uint16_t presencebitmap; 3887 3888 if (!mlieseq || !mlieseqlen || !mldmacaddr) 3889 return QDF_STATUS_E_NULL_VALUE; 3890 3891 qdf_mem_zero(mldmacaddr, sizeof(*mldmacaddr)); 3892 3893 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3894 return QDF_STATUS_E_INVAL; 3895 3896 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3897 3898 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 3899 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) 3900 return QDF_STATUS_E_INVAL; 3901 3902 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3903 3904 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3905 WLAN_ML_CTRL_TYPE_BITS); 3906 3907 if (variant != WLAN_ML_VARIANT_RECONFIG) 3908 return QDF_STATUS_E_INVAL; 3909 3910 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3911 WLAN_ML_CTRL_PBM_BITS); 3912 3913 /* Check if MLD mac address is present */ 3914 if (presencebitmap & WLAN_ML_RV_CTRL_PBM_MLDMACADDR_P) { 3915 if ((sizeof(struct wlan_ie_multilink) + QDF_MAC_ADDR_SIZE) > 3916 mlieseqlen) 3917 return QDF_STATUS_E_PROTO; 3918 3919 qdf_mem_copy(mldmacaddr->bytes, 3920 mlieseq + sizeof(struct wlan_ie_multilink), 3921 QDF_MAC_ADDR_SIZE); 3922 } 3923 3924 return QDF_STATUS_SUCCESS; 3925 } 3926 3927 static QDF_STATUS 3928 util_parse_rv_multi_link_ctrl(uint8_t *mlieseqpayload, 3929 qdf_size_t mlieseqpayloadlen, 3930 uint8_t **link_info, 3931 qdf_size_t *link_info_len) 3932 { 3933 qdf_size_t parsed_payload_len; 3934 uint16_t mlcontrol; 3935 uint16_t presence_bm; 3936 3937 /* This helper returns the location(s) and length(s) of (sub)field(s) 3938 * inferable after parsing the Multi Link element Control field. These 3939 * location(s) and length(s) is/are in reference to the payload section 3940 * of the Multi Link element (after defragmentation, if applicable). 3941 * Here, the payload is the point after the element ID extension of the 3942 * Multi Link element, and includes the payloads of all subsequent 3943 * fragments (if any) but not the headers of those fragments. 3944 * 3945 * Currently, the helper returns the location and length of the Link 3946 * Info field in the Multi Link element sequence. Other (sub)field(s) 3947 * can be added later as required. 3948 */ 3949 if (!mlieseqpayload) { 3950 mlo_err("ML seq payload pointer is NULL"); 3951 return QDF_STATUS_E_NULL_VALUE; 3952 } 3953 3954 if (!mlieseqpayloadlen) { 3955 mlo_err("ML seq payload len is 0"); 3956 return QDF_STATUS_E_INVAL; 3957 } 3958 3959 if (mlieseqpayloadlen < WLAN_ML_CTRL_SIZE) { 3960 mlo_err_rl("ML seq payload len %zu < ML Control size %u", 3961 mlieseqpayloadlen, WLAN_ML_CTRL_SIZE); 3962 return QDF_STATUS_E_PROTO; 3963 } 3964 3965 parsed_payload_len = 0; 3966 3967 qdf_mem_copy(&mlcontrol, mlieseqpayload, WLAN_ML_CTRL_SIZE); 3968 mlcontrol = qdf_le16_to_cpu(mlcontrol); 3969 parsed_payload_len += WLAN_ML_CTRL_SIZE; 3970 3971 presence_bm = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3972 WLAN_ML_CTRL_PBM_BITS); 3973 3974 /* Check if MLD MAC address is present */ 3975 if (presence_bm & WLAN_ML_RV_CTRL_PBM_MLDMACADDR_P) { 3976 if (mlieseqpayloadlen < 3977 (parsed_payload_len + 3978 QDF_MAC_ADDR_SIZE)) { 3979 mlo_err_rl("ML seq payload len %zu insufficient for MLD ID size %u after parsed payload len %zu.", 3980 mlieseqpayloadlen, 3981 WLAN_ML_PRV_CINFO_MLDID_SIZE, 3982 parsed_payload_len); 3983 return QDF_STATUS_E_PROTO; 3984 } 3985 3986 parsed_payload_len += QDF_MAC_ADDR_SIZE; 3987 } 3988 3989 if (link_info_len) { 3990 *link_info_len = mlieseqpayloadlen - parsed_payload_len; 3991 mlo_debug("link_info_len:%zu, parsed_payload_len:%zu", 3992 *link_info_len, parsed_payload_len); 3993 } 3994 3995 if (mlieseqpayloadlen == parsed_payload_len) { 3996 mlo_debug("No Link Info field present"); 3997 if (link_info) 3998 *link_info = NULL; 3999 4000 return QDF_STATUS_SUCCESS; 4001 } 4002 4003 if (link_info) 4004 *link_info = mlieseqpayload + parsed_payload_len; 4005 4006 return QDF_STATUS_SUCCESS; 4007 } 4008 4009 static QDF_STATUS 4010 util_parse_rvmlie_perstaprofile_stactrl(uint8_t *subelempayload, 4011 qdf_size_t subelempayloadlen, 4012 uint8_t *linkid, 4013 bool *is_macaddr_valid, 4014 struct qdf_mac_addr *macaddr, 4015 bool *is_delete_timer_valid, 4016 uint16_t *delete_timer) 4017 { 4018 qdf_size_t parsed_payload_len = 0; 4019 uint16_t stacontrol; 4020 uint8_t completeprofile; 4021 4022 /* This helper returns the location(s) and where required, the length(s) 4023 * of (sub)field(s) inferable after parsing the STA Control field in the 4024 * per-STA profile subelement. These location(s) and length(s) is/are in 4025 * reference to the payload section of the per-STA profile subelement 4026 * (after defragmentation, if applicable). Here, the payload is the 4027 * point after the subelement length in the subelement, and includes the 4028 * payloads of all subsequent fragments (if any) but not the headers of 4029 * those fragments. 4030 * 4031 * Currently, the helper returns the link ID, MAC address, Delete timer 4032 * and STA profile. More (sub)fields can be added when required. 4033 */ 4034 if (!subelempayload) { 4035 mlo_err("Pointer to subelement payload is NULL"); 4036 return QDF_STATUS_E_NULL_VALUE; 4037 } 4038 4039 if (!subelempayloadlen) { 4040 mlo_err("Length of subelement payload is zero"); 4041 return QDF_STATUS_E_INVAL; 4042 } 4043 4044 if (subelempayloadlen < WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_SIZE) { 4045 mlo_err_rl("Subelement payload length %zu octets is smaller than STA control field of per-STA profile subelement %u octets", 4046 subelempayloadlen, 4047 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_SIZE); 4048 return QDF_STATUS_E_PROTO; 4049 } 4050 4051 parsed_payload_len = 0; 4052 qdf_mem_copy(&stacontrol, 4053 subelempayload, 4054 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_SIZE); 4055 4056 stacontrol = qdf_le16_to_cpu(stacontrol); 4057 parsed_payload_len += WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE; 4058 4059 if (linkid) 4060 *linkid = QDF_GET_BITS(stacontrol, 4061 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_LINKID_IDX, 4062 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_LINKID_BITS); 4063 4064 /* Check if this a complete profile */ 4065 completeprofile = QDF_GET_BITS(stacontrol, 4066 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_IDX, 4067 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_BITS); 4068 4069 if (is_macaddr_valid) 4070 *is_macaddr_valid = false; 4071 4072 /* Check STA MAC address present bit */ 4073 if (QDF_GET_BITS(stacontrol, 4074 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_MACADDRP_IDX, 4075 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_MACADDRP_BITS)) { 4076 if (subelempayloadlen < 4077 (parsed_payload_len + QDF_MAC_ADDR_SIZE)) { 4078 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.", 4079 subelempayloadlen, QDF_MAC_ADDR_SIZE, 4080 parsed_payload_len); 4081 return QDF_STATUS_E_PROTO; 4082 } 4083 4084 if (macaddr) { 4085 qdf_mem_copy(macaddr->bytes, 4086 subelempayload + parsed_payload_len, 4087 QDF_MAC_ADDR_SIZE); 4088 mlo_nofl_debug("Copied MAC address: " QDF_MAC_ADDR_FMT, 4089 subelempayload + parsed_payload_len); 4090 4091 if (is_macaddr_valid) 4092 *is_macaddr_valid = true; 4093 } 4094 4095 parsed_payload_len += QDF_MAC_ADDR_SIZE; 4096 } 4097 4098 /* Check Delete timer present bit */ 4099 if (QDF_GET_BITS(stacontrol, 4100 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_DELTIMERP_IDX, 4101 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_DELTIMERP_BITS)) { 4102 if (subelempayloadlen < 4103 (parsed_payload_len + 4104 WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_DELTIMER_SIZE)) { 4105 mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain Delete timer of size %u octets after parsed payload length of %zu octets.", 4106 subelempayloadlen, 4107 WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_DELTIMER_SIZE, 4108 parsed_payload_len); 4109 return QDF_STATUS_E_PROTO; 4110 } 4111 4112 if (delete_timer) { 4113 qdf_mem_copy(delete_timer, 4114 subelempayload + parsed_payload_len, 4115 WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_DELTIMER_SIZE); 4116 4117 if (is_delete_timer_valid) 4118 *is_delete_timer_valid = true; 4119 } 4120 4121 parsed_payload_len += WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_DELTIMER_SIZE; 4122 } 4123 4124 return QDF_STATUS_SUCCESS; 4125 } 4126 4127 static QDF_STATUS 4128 util_parse_rv_info_from_linkinfo(uint8_t *linkinfo, 4129 qdf_size_t linkinfo_len, 4130 struct ml_rv_info *reconfig_info) 4131 { 4132 uint8_t linkid; 4133 uint8_t *linkinfo_currpos; 4134 qdf_size_t linkinfo_remlen; 4135 bool is_subelemfragseq; 4136 uint8_t subelemid; 4137 qdf_size_t subelemseqtotallen; 4138 qdf_size_t subelemseqpayloadlen; 4139 qdf_size_t defragpayload_len; 4140 QDF_STATUS ret; 4141 struct qdf_mac_addr mac_addr; 4142 bool is_macaddr_valid; 4143 bool is_delete_timer_valid; 4144 uint16_t delete_timer; 4145 4146 /* This helper function parses probe request info from the per-STA prof 4147 * present (if any) in the Link Info field in the payload of a Multi 4148 * Link element (after defragmentation if required). The caller should 4149 * pass a copy of the payload so that inline defragmentation of 4150 * subelements can be carried out if required. The subelement 4151 * defragmentation (if applicable) in this Control Path helper is 4152 * required for maintainability, accuracy and eliminating current and 4153 * future per-field-access multi-level fragment boundary checks and 4154 * adjustments, given the complex format of Multi Link elements. It is 4155 * also most likely to be required mainly at the client side. 4156 * Fragmentation is currently unlikely to be required for subelements 4157 * in Reconfiguration variant Multi-Link elements, but it should be 4158 * handled in order to be future ready. 4159 */ 4160 if (!linkinfo) { 4161 mlo_err("linkinfo is NULL"); 4162 return QDF_STATUS_E_NULL_VALUE; 4163 } 4164 4165 if (!linkinfo_len) { 4166 mlo_err("linkinfo_len is zero"); 4167 return QDF_STATUS_E_NULL_VALUE; 4168 } 4169 4170 if (!reconfig_info) { 4171 mlo_err("ML reconfig info is NULL"); 4172 return QDF_STATUS_E_NULL_VALUE; 4173 } 4174 4175 reconfig_info->num_links = 0; 4176 linkinfo_currpos = linkinfo; 4177 linkinfo_remlen = linkinfo_len; 4178 4179 while (linkinfo_remlen) { 4180 if (linkinfo_remlen < sizeof(struct subelem_header)) { 4181 mlo_err_rl("Remaining length in link info %zu octets is smaller than subelement header length %zu octets", 4182 linkinfo_remlen, 4183 sizeof(struct subelem_header)); 4184 return QDF_STATUS_E_PROTO; 4185 } 4186 4187 subelemid = linkinfo_currpos[ID_POS]; 4188 is_subelemfragseq = false; 4189 subelemseqtotallen = 0; 4190 subelemseqpayloadlen = 0; 4191 4192 ret = wlan_get_subelem_fragseq_info(WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 4193 linkinfo_currpos, 4194 linkinfo_remlen, 4195 &is_subelemfragseq, 4196 &subelemseqtotallen, 4197 &subelemseqpayloadlen); 4198 if (QDF_IS_STATUS_ERROR(ret)) 4199 return ret; 4200 4201 if (qdf_unlikely(is_subelemfragseq)) { 4202 if (!subelemseqpayloadlen) { 4203 mlo_err_rl("Subelement fragment sequence payload is reported as 0, investigate"); 4204 return QDF_STATUS_E_FAILURE; 4205 } 4206 4207 mlo_debug("Subelement fragment sequence found with payload len %zu", 4208 subelemseqpayloadlen); 4209 4210 ret = wlan_defrag_subelem_fragseq(true, 4211 WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 4212 linkinfo_currpos, 4213 linkinfo_remlen, 4214 NULL, 4215 0, 4216 &defragpayload_len); 4217 4218 if (QDF_IS_STATUS_ERROR(ret)) 4219 return ret; 4220 4221 if (defragpayload_len != subelemseqpayloadlen) { 4222 mlo_err_rl("Length of defragmented payload %zu octets is not equal to length of subelement fragment sequence payload %zu octets", 4223 defragpayload_len, 4224 subelemseqpayloadlen); 4225 return QDF_STATUS_E_FAILURE; 4226 } 4227 4228 /* Adjust linkinfo_remlen to reflect removal of all 4229 * subelement headers except the header of the lead 4230 * subelement. 4231 */ 4232 linkinfo_remlen -= (subelemseqtotallen - 4233 subelemseqpayloadlen - 4234 sizeof(struct subelem_header)); 4235 } else { 4236 if (linkinfo_remlen < 4237 (sizeof(struct subelem_header) + 4238 linkinfo_currpos[TAG_LEN_POS])) { 4239 mlo_err_rl("Remaining length in link info %zu octets is smaller than total size of current subelement %zu octets", 4240 linkinfo_remlen, 4241 sizeof(struct subelem_header) + 4242 linkinfo_currpos[TAG_LEN_POS]); 4243 return QDF_STATUS_E_PROTO; 4244 } 4245 4246 subelemseqpayloadlen = linkinfo_currpos[TAG_LEN_POS]; 4247 } 4248 4249 if (subelemid == WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE) { 4250 is_macaddr_valid = false; 4251 is_delete_timer_valid = false; 4252 ret = util_parse_rvmlie_perstaprofile_stactrl(linkinfo_currpos + 4253 sizeof(struct subelem_header), 4254 subelemseqpayloadlen, 4255 &linkid, 4256 &is_macaddr_valid, 4257 &mac_addr, 4258 &is_delete_timer_valid, 4259 &delete_timer); 4260 if (QDF_IS_STATUS_ERROR(ret)) 4261 return ret; 4262 4263 reconfig_info->link_info[reconfig_info->num_links].link_id = linkid; 4264 reconfig_info->link_info[reconfig_info->num_links].is_delete_timer_p = is_delete_timer_valid; 4265 4266 if (is_delete_timer_valid) 4267 reconfig_info->link_info[reconfig_info->num_links].delete_timer = delete_timer; 4268 else 4269 mlo_warn_rl("Delete timer not found in STA Info field of per-STA profile with link ID %u", 4270 linkid); 4271 4272 mlo_debug("Per-STA Profile Link ID: %u Delete timer present: %d Delete timer: %u", 4273 reconfig_info->link_info[reconfig_info->num_links].link_id, 4274 reconfig_info->link_info[reconfig_info->num_links].is_delete_timer_p, 4275 reconfig_info->link_info[reconfig_info->num_links].delete_timer); 4276 4277 reconfig_info->num_links++; 4278 } 4279 4280 linkinfo_remlen -= (sizeof(struct subelem_header) + 4281 subelemseqpayloadlen); 4282 linkinfo_currpos += (sizeof(struct subelem_header) + 4283 subelemseqpayloadlen); 4284 } 4285 4286 mlo_debug("Number of ML probe request links found=%u", 4287 reconfig_info->num_links); 4288 4289 return QDF_STATUS_SUCCESS; 4290 } 4291 4292 QDF_STATUS util_get_rvmlie_persta_link_info(uint8_t *mlieseq, 4293 qdf_size_t mlieseqlen, 4294 struct ml_rv_info *reconfig_info) 4295 { 4296 struct wlan_ie_multilink *mlie_fixed; 4297 uint16_t mlcontrol; 4298 enum wlan_ml_variant variant; 4299 uint8_t *linkinfo; 4300 qdf_size_t linkinfo_len; 4301 struct ml_rv_info rinfo = {0}; 4302 qdf_size_t mlieseqpayloadlen; 4303 uint8_t *mlieseqpayload_copy; 4304 bool is_elemfragseq; 4305 qdf_size_t defragpayload_len; 4306 qdf_size_t tmplen; 4307 QDF_STATUS ret; 4308 4309 if (!mlieseq) { 4310 mlo_err("Pointer to Multi-Link element sequence is NULL"); 4311 return QDF_STATUS_E_NULL_VALUE; 4312 } 4313 4314 if (!mlieseqlen) { 4315 mlo_err("Length of Multi-Link element sequence is zero"); 4316 return QDF_STATUS_E_INVAL; 4317 } 4318 4319 if (!reconfig_info) { 4320 mlo_err("reconfig_info is NULL"); 4321 return QDF_STATUS_E_NULL_VALUE; 4322 } 4323 4324 reconfig_info->num_links = 0; 4325 4326 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) { 4327 mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)", 4328 mlieseqlen, sizeof(struct wlan_ie_multilink)); 4329 return QDF_STATUS_E_INVAL; 4330 } 4331 4332 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 4333 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 4334 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) { 4335 mlo_err("The element is not a Multi-Link element"); 4336 return QDF_STATUS_E_INVAL; 4337 } 4338 4339 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 4340 4341 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 4342 WLAN_ML_CTRL_TYPE_BITS); 4343 4344 if (variant != WLAN_ML_VARIANT_RECONFIG) { 4345 mlo_err("The variant value %u does not correspond to Reconfig Variant value %u", 4346 variant, WLAN_ML_VARIANT_RECONFIG); 4347 return QDF_STATUS_E_INVAL; 4348 } 4349 4350 mlieseqpayloadlen = 0; 4351 tmplen = 0; 4352 is_elemfragseq = false; 4353 4354 ret = wlan_get_elem_fragseq_info(mlieseq, 4355 mlieseqlen, 4356 &is_elemfragseq, 4357 &tmplen, 4358 &mlieseqpayloadlen); 4359 4360 if (QDF_IS_STATUS_ERROR(ret)) 4361 return ret; 4362 4363 if (qdf_unlikely(is_elemfragseq)) { 4364 if (tmplen != mlieseqlen) { 4365 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", 4366 tmplen, mlieseqlen); 4367 return QDF_STATUS_E_INVAL; 4368 } 4369 4370 if (!mlieseqpayloadlen) { 4371 mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate"); 4372 return QDF_STATUS_E_FAILURE; 4373 } 4374 4375 mlo_debug("Multi-Link element fragment sequence found with payload len %zu", 4376 mlieseqpayloadlen); 4377 } else { 4378 if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) { 4379 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", 4380 mlieseqlen, 4381 sizeof(struct ie_header) + WLAN_MAX_IE_LEN); 4382 return QDF_STATUS_E_FAILURE; 4383 } 4384 4385 mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1); 4386 } 4387 4388 mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen); 4389 4390 if (!mlieseqpayload_copy) { 4391 mlo_err_rl("Could not allocate memory for Multi-Link element payload copy"); 4392 return QDF_STATUS_E_NOMEM; 4393 } 4394 4395 if (qdf_unlikely(is_elemfragseq)) { 4396 ret = wlan_defrag_elem_fragseq(false, 4397 mlieseq, 4398 mlieseqlen, 4399 mlieseqpayload_copy, 4400 mlieseqpayloadlen, 4401 &defragpayload_len); 4402 if (QDF_IS_STATUS_ERROR(ret)) { 4403 qdf_mem_free(mlieseqpayload_copy); 4404 return ret; 4405 } 4406 4407 if (defragpayload_len != mlieseqpayloadlen) { 4408 mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets", 4409 defragpayload_len, mlieseqpayloadlen); 4410 qdf_mem_free(mlieseqpayload_copy); 4411 return QDF_STATUS_E_FAILURE; 4412 } 4413 } else { 4414 qdf_mem_copy(mlieseqpayload_copy, 4415 mlieseq + sizeof(struct ie_header) + 1, 4416 mlieseqpayloadlen); 4417 } 4418 4419 linkinfo = NULL; 4420 linkinfo_len = 0; 4421 4422 ret = util_parse_rv_multi_link_ctrl(mlieseqpayload_copy, 4423 mlieseqpayloadlen, 4424 &linkinfo, 4425 &linkinfo_len); 4426 if (QDF_IS_STATUS_ERROR(ret)) { 4427 qdf_mem_free(mlieseqpayload_copy); 4428 return ret; 4429 } 4430 4431 /* In case Link Info is absent, the number of links will remain 4432 * zero. 4433 */ 4434 if (!linkinfo) { 4435 qdf_mem_free(mlieseqpayload_copy); 4436 return QDF_STATUS_SUCCESS; 4437 } 4438 4439 ret = util_parse_rv_info_from_linkinfo(linkinfo, linkinfo_len, &rinfo); 4440 if (QDF_IS_STATUS_ERROR(ret)) { 4441 qdf_mem_free(mlieseqpayload_copy); 4442 return ret; 4443 } 4444 4445 qdf_mem_copy(reconfig_info, &rinfo, sizeof(*reconfig_info)); 4446 qdf_mem_free(mlieseqpayload_copy); 4447 4448 return QDF_STATUS_SUCCESS; 4449 } 4450 4451 #endif 4452