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 /** 1610 * util_find_bvmlie_persta_prof_for_linkid() - get per sta profile per link id 1611 * @req_link_id: link id 1612 * @linkinfo: the pointer of link info 1613 * @linkinfo_len: the length of link info 1614 * @persta_prof_frame: the pointer to store the address of sta profile 1615 * @persta_prof_len: the sta profile length 1616 * 1617 * This helper function parses partner info from the per-STA profiles 1618 * present (if any) in the Link Info field in the payload of a Multi 1619 * Link element (after defragmentation if required). The caller should 1620 * pass a copy of the payload so that inline defragmentation of 1621 * subelements can be carried out if required. The subelement 1622 * defragmentation (if applicable) in this Control Path helper is 1623 * required for maintainability, accuracy and eliminating current and 1624 * future per-field-access multi-level fragment boundary checks and 1625 * adjustments, given the complex format of Multi Link elements. It is 1626 * also most likely to be required mainly at the client side. 1627 * 1628 * Return: QDF_STATUS 1629 */ 1630 static QDF_STATUS 1631 util_find_bvmlie_persta_prof_for_linkid(uint8_t req_link_id, 1632 uint8_t *linkinfo, 1633 qdf_size_t linkinfo_len, 1634 uint8_t **persta_prof_frame, 1635 qdf_size_t *persta_prof_len) 1636 { 1637 uint8_t linkid; 1638 struct qdf_mac_addr macaddr; 1639 bool is_macaddr_valid; 1640 uint8_t *linkinfo_currpos; 1641 qdf_size_t linkinfo_remlen; 1642 bool is_subelemfragseq; 1643 uint8_t subelemid; 1644 qdf_size_t subelemseqtotallen; 1645 qdf_size_t subelemseqpayloadlen; 1646 qdf_size_t defragpayload_len; 1647 QDF_STATUS ret; 1648 1649 if (!linkinfo) { 1650 mlo_err("linkinfo is NULL"); 1651 return QDF_STATUS_E_NULL_VALUE; 1652 } 1653 1654 if (!linkinfo_len) { 1655 mlo_err("linkinfo_len is zero"); 1656 return QDF_STATUS_E_NULL_VALUE; 1657 } 1658 1659 if (!persta_prof_frame) { 1660 mlo_err("Pointer to per-STA prof frame is NULL"); 1661 return QDF_STATUS_E_NULL_VALUE; 1662 } 1663 1664 if (!persta_prof_len) { 1665 mlo_err("Length to per-STA prof frame is 0"); 1666 return QDF_STATUS_E_NULL_VALUE; 1667 } 1668 1669 linkinfo_currpos = linkinfo; 1670 linkinfo_remlen = linkinfo_len; 1671 1672 while (linkinfo_remlen) { 1673 if (linkinfo_remlen < sizeof(struct subelem_header)) { 1674 mlo_err_rl("Remaining length in link info %zu octets is smaller than subelement header length %zu octets", 1675 linkinfo_remlen, 1676 sizeof(struct subelem_header)); 1677 return QDF_STATUS_E_PROTO; 1678 } 1679 1680 subelemid = linkinfo_currpos[ID_POS]; 1681 is_subelemfragseq = false; 1682 subelemseqtotallen = 0; 1683 subelemseqpayloadlen = 0; 1684 1685 ret = wlan_get_subelem_fragseq_info(WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 1686 linkinfo_currpos, 1687 linkinfo_remlen, 1688 &is_subelemfragseq, 1689 &subelemseqtotallen, 1690 &subelemseqpayloadlen); 1691 if (QDF_IS_STATUS_ERROR(ret)) 1692 return ret; 1693 1694 if (is_subelemfragseq) { 1695 if (!subelemseqpayloadlen) { 1696 mlo_err_rl("Subelement fragment sequence payload is reported as 0, investigate"); 1697 return QDF_STATUS_E_FAILURE; 1698 } 1699 1700 mlo_debug("Subelement fragment sequence found with payload len %zu", 1701 subelemseqpayloadlen); 1702 1703 ret = wlan_defrag_subelem_fragseq(true, 1704 WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 1705 linkinfo_currpos, 1706 linkinfo_remlen, 1707 NULL, 1708 0, 1709 &defragpayload_len); 1710 if (QDF_IS_STATUS_ERROR(ret)) 1711 return ret; 1712 1713 if (defragpayload_len != subelemseqpayloadlen) { 1714 mlo_err_rl("Length of defragmented payload %zu octets is not equal to length of subelement fragment sequence payload %zu octets", 1715 defragpayload_len, 1716 subelemseqpayloadlen); 1717 return QDF_STATUS_E_FAILURE; 1718 } 1719 1720 /* Adjust linkinfo_remlen to reflect removal of all 1721 * subelement headers except the header of the lead 1722 * subelement. 1723 */ 1724 linkinfo_remlen -= (subelemseqtotallen - 1725 subelemseqpayloadlen - 1726 sizeof(struct subelem_header)); 1727 } else { 1728 if (linkinfo_remlen < 1729 (sizeof(struct subelem_header) + 1730 linkinfo_currpos[TAG_LEN_POS])) { 1731 mlo_err_rl("Remaining length in link info %zu octets is smaller than total size of current subelement %zu octets", 1732 linkinfo_remlen, 1733 sizeof(struct subelem_header) + 1734 linkinfo_currpos[TAG_LEN_POS]); 1735 return QDF_STATUS_E_PROTO; 1736 } 1737 1738 subelemseqpayloadlen = linkinfo_currpos[TAG_LEN_POS]; 1739 } 1740 1741 if (subelemid == WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE) { 1742 is_macaddr_valid = false; 1743 1744 ret = util_parse_bvmlie_perstaprofile_stactrl(linkinfo_currpos + 1745 sizeof(struct subelem_header), 1746 subelemseqpayloadlen, 1747 &linkid, 1748 NULL, 1749 NULL, 1750 NULL, 1751 NULL, 1752 NULL, 1753 &is_macaddr_valid, 1754 &macaddr, 1755 false, 1756 NULL, 1757 NULL); 1758 if (QDF_IS_STATUS_ERROR(ret)) 1759 return ret; 1760 1761 if (req_link_id == linkid) { 1762 mlo_debug("Found requested per-STA prof for linkid %u, len %zu", 1763 linkid, subelemseqpayloadlen); 1764 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_MLO, 1765 QDF_TRACE_LEVEL_DEBUG, 1766 linkinfo_currpos, 1767 subelemseqpayloadlen + 1768 sizeof(struct subelem_header)); 1769 *persta_prof_frame = linkinfo_currpos; 1770 *persta_prof_len = subelemseqpayloadlen; 1771 return QDF_STATUS_SUCCESS; 1772 } 1773 } 1774 1775 linkinfo_remlen -= (sizeof(struct subelem_header) + 1776 subelemseqpayloadlen); 1777 linkinfo_currpos += (sizeof(struct subelem_header) + 1778 subelemseqpayloadlen); 1779 } 1780 1781 return QDF_STATUS_E_PROTO; 1782 } 1783 1784 #define MLO_LINKSPECIFIC_ASSOC_REQ_FC0 0x00 1785 #define MLO_LINKSPECIFIC_ASSOC_REQ_FC1 0x00 1786 #define MLO_LINKSPECIFIC_ASSOC_RESP_FC0 0x10 1787 #define MLO_LINKSPECIFIC_ASSOC_RESP_FC1 0x00 1788 #define MLO_LINKSPECIFIC_PROBE_RESP_FC0 0x50 1789 #define MLO_LINKSPECIFIC_PROBE_RESP_FC1 0x00 1790 1791 static 1792 QDF_STATUS util_gen_link_reqrsp_cmn(uint8_t *frame, qdf_size_t frame_len, 1793 uint8_t subtype, 1794 uint8_t req_link_id, 1795 struct qdf_mac_addr link_addr, 1796 uint8_t *link_frame, 1797 qdf_size_t link_frame_maxsize, 1798 qdf_size_t *link_frame_len) 1799 { 1800 /* Please see documentation for util_gen_link_assoc_req() and 1801 * util_gen_link_assoc_resp() for information on the inputs to and 1802 * output from this helper, since those APIs are essentially wrappers 1803 * over this helper. 1804 */ 1805 1806 /* Pointer to Multi-Link element/Multi-Link element fragment sequence */ 1807 uint8_t *mlieseq; 1808 /* Total length of Multi-Link element sequence (including fragments if 1809 * any) 1810 */ 1811 qdf_size_t mlieseqlen; 1812 /* Variant (i.e. type) of the Multi-Link element */ 1813 enum wlan_ml_variant variant; 1814 1815 /* Length of the payload of the Multi-Link element (inclusive of 1816 * fragment payloads if any) without IE headers and element ID extension 1817 */ 1818 qdf_size_t mlieseqpayloadlen; 1819 /* Pointer to copy of the payload of the Multi-Link element (inclusive 1820 * of fragment payloads if any) without IE headers and element ID 1821 * extension 1822 */ 1823 uint8_t *mlieseqpayload_copy; 1824 1825 /* Pointer to start of Link Info within the copy of the payload of the 1826 * Multi-Link element 1827 */ 1828 uint8_t *link_info; 1829 /* Length of the Link Info */ 1830 qdf_size_t link_info_len; 1831 1832 /* Pointer to the IE section that occurs after the fixed fields in the 1833 * original frame for the reporting STA. 1834 */ 1835 uint8_t *frame_iesection; 1836 /* Offset to the start of the IE section in the original frame for the 1837 * reporting STA. 1838 */ 1839 qdf_size_t frame_iesection_offset; 1840 /* Total length of the IE section in the original frame for the 1841 * reporting STA. 1842 */ 1843 qdf_size_t frame_iesection_len; 1844 1845 /* Pointer to the IEEE802.11 frame header in the link specific frame 1846 * being generated for the reported STA. 1847 */ 1848 struct wlan_frame_hdr *link_frame_hdr; 1849 /* Current position in the link specific frame being generated for the 1850 * reported STA. 1851 */ 1852 uint8_t *link_frame_currpos; 1853 /* Current length of the link specific frame being generated for the 1854 * reported STA. 1855 */ 1856 qdf_size_t link_frame_currlen; 1857 1858 /* Pointer to IE for reporting STA */ 1859 const uint8_t *reportingsta_ie; 1860 /* Total size of IE for reporting STA, inclusive of the element header 1861 */ 1862 qdf_size_t reportingsta_ie_size; 1863 1864 /* Pointer to current position in STA profile */ 1865 uint8_t *sta_prof_currpos; 1866 /* Remaining length of STA profile */ 1867 qdf_size_t sta_prof_remlen; 1868 /* Pointer to start of IE section in STA profile that occurs after fixed 1869 * fields. 1870 */ 1871 uint8_t *sta_prof_iesection; 1872 /* Total length of IE section in STA profile */ 1873 qdf_size_t sta_prof_iesection_len; 1874 /* Pointer to current position being processed in IE section in STA 1875 * profile. 1876 */ 1877 uint8_t *sta_prof_iesection_currpos; 1878 /* Remaining length of IE section in STA profile */ 1879 qdf_size_t sta_prof_iesection_remlen; 1880 1881 /* Pointer to IE in STA profile, that occurs within IE section */ 1882 uint8_t *sta_prof_ie; 1883 /* Total size of IE in STA profile, inclusive of the element header */ 1884 qdf_size_t sta_prof_ie_size; 1885 1886 /* Pointer to element ID list in Non-Inheritance IE */ 1887 uint8_t *ninherit_elemlist; 1888 /* Length of element ID list in Non-Inheritance IE */ 1889 qdf_size_t ninherit_elemlist_len; 1890 /* Pointer to element ID extension list in Non-Inheritance IE */ 1891 uint8_t *ninherit_elemextlist; 1892 /* Length of element ID extension list in Non-Inheritance IE */ 1893 qdf_size_t ninherit_elemextlist_len; 1894 /* Whether a given IE is in a non-inheritance list */ 1895 bool is_in_noninheritlist; 1896 1897 /* Whether MAC address of reported STA is valid */ 1898 bool is_reportedmacaddr_valid; 1899 /* MAC address of reported STA */ 1900 struct qdf_mac_addr reportedmacaddr; 1901 1902 /* Pointer to per-STA profile */ 1903 uint8_t *persta_prof; 1904 /* Length of the containing buffer which starts with the per-STA profile 1905 */ 1906 qdf_size_t persta_prof_bufflen; 1907 1908 /* Other variables for temporary purposes */ 1909 1910 /* Variable into which API for determining fragment information will 1911 * indicate whether the element is the start of a fragment sequence or 1912 * not. 1913 */ 1914 bool is_elemfragseq; 1915 /* De-fragmented payload length returned by API for element 1916 * defragmentation. 1917 */ 1918 qdf_size_t defragpayload_len; 1919 /* Pointer to Beacon interval in STA info field */ 1920 uint16_t beaconinterval; 1921 /* Whether Beacon interval value valid */ 1922 bool is_beaconinterval_valid; 1923 /* TSF timer of the reporting AP */ 1924 uint64_t tsf; 1925 /* TSF offset of the reproted AP */ 1926 uint64_t tsfoffset; 1927 /* TSF offset value valid */ 1928 bool is_tsfoffset_valid; 1929 /* If Complete Profile or not*/ 1930 bool is_completeprofile; 1931 qdf_size_t tmplen; 1932 QDF_STATUS ret; 1933 uint8_t linkid = 0xFF; 1934 1935 if (!frame) { 1936 mlo_err("Pointer to original frame is NULL"); 1937 return QDF_STATUS_E_NULL_VALUE; 1938 } 1939 1940 if (!frame_len) { 1941 mlo_err("Length of original frame is zero"); 1942 return QDF_STATUS_E_INVAL; 1943 } 1944 1945 if ((subtype != WLAN_FC0_STYPE_ASSOC_REQ) && 1946 (subtype != WLAN_FC0_STYPE_REASSOC_REQ) && 1947 (subtype != WLAN_FC0_STYPE_ASSOC_RESP) && 1948 (subtype != WLAN_FC0_STYPE_REASSOC_RESP) && 1949 (subtype != WLAN_FC0_STYPE_PROBE_RESP)) { 1950 mlo_err("802.11 frame subtype %u is invalid", subtype); 1951 return QDF_STATUS_E_INVAL; 1952 } 1953 1954 if (!link_frame) { 1955 mlo_err("Pointer to secondary link specific frame is NULL"); 1956 return QDF_STATUS_E_NULL_VALUE; 1957 } 1958 1959 if (!link_frame_maxsize) { 1960 mlo_err("Maximum size of secondary link specific frame is zero"); 1961 return QDF_STATUS_E_INVAL; 1962 } 1963 1964 if (!link_frame_len) { 1965 mlo_err("Pointer to populated length of secondary link specific frame is NULL"); 1966 return QDF_STATUS_E_NULL_VALUE; 1967 } 1968 1969 frame_iesection_offset = 0; 1970 1971 if (subtype == WLAN_FC0_STYPE_ASSOC_REQ) { 1972 frame_iesection_offset = WLAN_ASSOC_REQ_IES_OFFSET; 1973 } else if (subtype == WLAN_FC0_STYPE_REASSOC_REQ) { 1974 frame_iesection_offset = WLAN_REASSOC_REQ_IES_OFFSET; 1975 } else if (subtype == WLAN_FC0_STYPE_PROBE_RESP) { 1976 frame_iesection_offset = WLAN_PROBE_RESP_IES_OFFSET; 1977 qdf_mem_copy(&tsf, frame, WLAN_TIMESTAMP_LEN); 1978 tsf = qdf_le64_to_cpu(tsf); 1979 } else { 1980 /* This is a (re)association response */ 1981 frame_iesection_offset = WLAN_ASSOC_RSP_IES_OFFSET; 1982 } 1983 1984 if (frame_len < frame_iesection_offset) { 1985 /* The caller is supposed to have confirmed that this is a valid 1986 * frame containing a Multi-Link element. Hence we treat this as 1987 * a case of invalid argument being passed to us. 1988 */ 1989 mlo_err("Frame length %zu is smaller than the IE section offset %zu for subtype %u", 1990 frame_len, frame_iesection_offset, subtype); 1991 return QDF_STATUS_E_INVAL; 1992 } 1993 1994 frame_iesection_len = frame_len - frame_iesection_offset; 1995 1996 if (frame_iesection_len == 0) { 1997 /* The caller is supposed to have confirmed that this is a valid 1998 * frame containing a Multi-Link element. Hence we treat this as 1999 * a case of invalid argument being passed to us. 2000 */ 2001 mlo_err("No space left in frame for IE section"); 2002 return QDF_STATUS_E_INVAL; 2003 } 2004 2005 frame_iesection = frame + frame_iesection_offset; 2006 2007 mlieseq = NULL; 2008 mlieseqlen = 0; 2009 2010 ret = util_find_mlie(frame_iesection, frame_iesection_len, &mlieseq, 2011 &mlieseqlen); 2012 if (QDF_IS_STATUS_ERROR(ret)) 2013 return ret; 2014 2015 if (!mlieseq) { 2016 /* The caller is supposed to have confirmed that a Multi-Link 2017 * element is present in the frame. Hence we treat this as a 2018 * case of invalid argument being passed to us. 2019 */ 2020 mlo_err("Invalid original frame since no Multi-Link element found"); 2021 return QDF_STATUS_E_INVAL; 2022 } 2023 2024 /* Sanity check the Multi-Link element sequence length */ 2025 if (!mlieseqlen) { 2026 mlo_err("Length of Multi-Link element sequence is zero. Investigate."); 2027 return QDF_STATUS_E_FAILURE; 2028 } 2029 2030 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) { 2031 mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)", 2032 mlieseqlen, sizeof(struct wlan_ie_multilink)); 2033 return QDF_STATUS_E_PROTO; 2034 } 2035 2036 ret = util_get_mlie_variant(mlieseq, mlieseqlen, (int *)&variant); 2037 if (QDF_IS_STATUS_ERROR(ret)) 2038 return ret; 2039 2040 if (variant != WLAN_ML_VARIANT_BASIC) { 2041 mlo_err_rl("Unexpected variant %u of Multi-Link element.", 2042 variant); 2043 return QDF_STATUS_E_PROTO; 2044 } 2045 2046 mlieseqpayloadlen = 0; 2047 tmplen = 0; 2048 is_elemfragseq = false; 2049 2050 ret = wlan_get_elem_fragseq_info(mlieseq, 2051 mlieseqlen, 2052 &is_elemfragseq, 2053 &tmplen, 2054 &mlieseqpayloadlen); 2055 if (QDF_IS_STATUS_ERROR(ret)) 2056 return ret; 2057 2058 if (is_elemfragseq) { 2059 if (tmplen != mlieseqlen) { 2060 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", 2061 tmplen, mlieseqlen); 2062 return QDF_STATUS_E_FAILURE; 2063 } 2064 2065 if (!mlieseqpayloadlen) { 2066 mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate"); 2067 return QDF_STATUS_E_FAILURE; 2068 } 2069 2070 mlo_debug("Multi-Link element fragment sequence found with payload len %zu", 2071 mlieseqpayloadlen); 2072 } else { 2073 if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) { 2074 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", 2075 mlieseqlen, 2076 sizeof(struct ie_header) + WLAN_MAX_IE_LEN); 2077 return QDF_STATUS_E_FAILURE; 2078 } 2079 2080 mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1); 2081 } 2082 2083 mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen); 2084 2085 if (!mlieseqpayload_copy) { 2086 mlo_err_rl("Could not allocate memory for Multi-Link element payload copy"); 2087 return QDF_STATUS_E_NOMEM; 2088 } 2089 2090 if (is_elemfragseq) { 2091 ret = wlan_defrag_elem_fragseq(false, 2092 mlieseq, 2093 mlieseqlen, 2094 mlieseqpayload_copy, 2095 mlieseqpayloadlen, 2096 &defragpayload_len); 2097 if (QDF_IS_STATUS_ERROR(ret)) { 2098 qdf_mem_free(mlieseqpayload_copy); 2099 return ret; 2100 } 2101 2102 if (defragpayload_len != mlieseqpayloadlen) { 2103 mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets", 2104 defragpayload_len, mlieseqpayloadlen); 2105 qdf_mem_free(mlieseqpayload_copy); 2106 return QDF_STATUS_E_FAILURE; 2107 } 2108 } else { 2109 qdf_mem_copy(mlieseqpayload_copy, 2110 mlieseq + sizeof(struct ie_header) + 1, 2111 mlieseqpayloadlen); 2112 } 2113 2114 link_info = NULL; 2115 link_info_len = 0; 2116 2117 ret = util_parse_multi_link_ctrl(mlieseqpayload_copy, 2118 mlieseqpayloadlen, 2119 &link_info, 2120 &link_info_len); 2121 if (QDF_IS_STATUS_ERROR(ret)) { 2122 qdf_mem_free(mlieseqpayload_copy); 2123 return ret; 2124 } 2125 2126 /* As per the standard, the sender must include Link Info for 2127 * association request/response. Throw an error if we are unable to 2128 * obtain this. 2129 */ 2130 if (!link_info) { 2131 mlo_err_rl("Unable to successfully obtain Link Info"); 2132 qdf_mem_free(mlieseqpayload_copy); 2133 return QDF_STATUS_E_PROTO; 2134 } 2135 2136 mlo_debug("Dumping hex of link info after parsing Multi-Link element control"); 2137 QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_MLO, QDF_TRACE_LEVEL_DEBUG, 2138 link_info, link_info_len); 2139 2140 /* Note: We may have a future change to skip subelements which are not 2141 * Per-STA Profile, handle more than two links in MLO, handle cases 2142 * where we unexpectedly find more Per-STA Profiles than expected, etc. 2143 */ 2144 2145 persta_prof = NULL; 2146 persta_prof_bufflen = 0; 2147 2148 ret = util_find_bvmlie_persta_prof_for_linkid(req_link_id, 2149 link_info, 2150 link_info_len, 2151 &persta_prof, 2152 &persta_prof_bufflen); 2153 2154 if (QDF_IS_STATUS_ERROR(ret)) { 2155 mlo_err_rl("Per STA profile not found for link id %d", 2156 req_link_id); 2157 qdf_mem_free(mlieseqpayload_copy); 2158 return ret; 2159 } 2160 2161 sta_prof_remlen = 0; 2162 sta_prof_currpos = NULL; 2163 is_reportedmacaddr_valid = false; 2164 is_beaconinterval_valid = false; 2165 is_completeprofile = false; 2166 is_tsfoffset_valid = false; 2167 2168 /* Parse per-STA profile */ 2169 ret = util_parse_bvmlie_perstaprofile_stactrl(persta_prof + 2170 sizeof(struct subelem_header), 2171 persta_prof_bufflen, 2172 &linkid, 2173 &beaconinterval, 2174 &is_beaconinterval_valid, 2175 &tsfoffset, 2176 &is_tsfoffset_valid, 2177 &is_completeprofile, 2178 &is_reportedmacaddr_valid, 2179 &reportedmacaddr, 2180 true, 2181 &sta_prof_currpos, 2182 &sta_prof_remlen); 2183 if (QDF_IS_STATUS_ERROR(ret)) { 2184 qdf_mem_free(mlieseqpayload_copy); 2185 return ret; 2186 } 2187 2188 if (subtype == WLAN_FC0_STYPE_PROBE_RESP && !is_completeprofile) { 2189 mlo_err("Complete profile information is not present in per-STA profile of probe response frame"); 2190 return QDF_STATUS_E_NOSUPPORT; 2191 } 2192 2193 /* We double check for a NULL STA Profile, though the helper function 2194 * above would have taken care of this. We need to get a non-NULL STA 2195 * profile, because we need to get at least the expected fixed fields, 2196 * even if there is an (improbable) total inheritance. 2197 */ 2198 if (!sta_prof_currpos) { 2199 mlo_err_rl("STA profile is NULL"); 2200 qdf_mem_free(mlieseqpayload_copy); 2201 return QDF_STATUS_E_PROTO; 2202 } 2203 2204 /* As per the standard, the sender sets the MAC address in the per-STA 2205 * profile in association request/response. Without this, we cannot 2206 * generate the link specific frame. 2207 */ 2208 if (!is_reportedmacaddr_valid) { 2209 mlo_err_rl("Unable to get MAC address from per-STA profile"); 2210 qdf_mem_free(mlieseqpayload_copy); 2211 return QDF_STATUS_E_PROTO; 2212 } 2213 2214 link_frame_currpos = link_frame; 2215 *link_frame_len = 0; 2216 link_frame_currlen = 0; 2217 2218 if (link_frame_maxsize < WLAN_MAC_HDR_LEN_3A) { 2219 mlo_err("Insufficient space in link specific frame for 802.11 header. Required: %u octets, available: %zu octets", 2220 WLAN_MAC_HDR_LEN_3A, link_frame_maxsize); 2221 2222 qdf_mem_free(mlieseqpayload_copy); 2223 return QDF_STATUS_E_NOMEM; 2224 } 2225 2226 link_frame_currpos += WLAN_MAC_HDR_LEN_3A; 2227 link_frame_currlen += WLAN_MAC_HDR_LEN_3A; 2228 2229 if ((subtype == WLAN_FC0_STYPE_ASSOC_REQ) || 2230 (subtype == WLAN_FC0_STYPE_REASSOC_REQ)) { 2231 mlo_debug("Populating fixed fields for (re)assoc req in link specific frame"); 2232 2233 if (sta_prof_remlen < WLAN_CAPABILITYINFO_LEN) { 2234 mlo_err_rl("Remaining length of STA profile %zu octets is less than length of Capability Info %u", 2235 sta_prof_remlen, 2236 WLAN_CAPABILITYINFO_LEN); 2237 2238 qdf_mem_free(mlieseqpayload_copy); 2239 return QDF_STATUS_E_PROTO; 2240 } 2241 2242 /* Capability information is specific to the link. Copy this 2243 * from the STA profile. 2244 */ 2245 2246 if ((link_frame_maxsize - link_frame_currlen) < 2247 WLAN_CAPABILITYINFO_LEN) { 2248 mlo_err("Insufficient space in link specific frame for Capability Info field. Required: %u octets, available: %zu octets", 2249 WLAN_CAPABILITYINFO_LEN, 2250 (link_frame_maxsize - link_frame_currlen)); 2251 2252 qdf_mem_free(mlieseqpayload_copy); 2253 return QDF_STATUS_E_NOMEM; 2254 } 2255 2256 qdf_mem_copy(link_frame_currpos, sta_prof_currpos, 2257 WLAN_CAPABILITYINFO_LEN); 2258 link_frame_currpos += WLAN_CAPABILITYINFO_LEN; 2259 link_frame_currlen += WLAN_CAPABILITYINFO_LEN; 2260 mlo_debug("Added Capability Info field (%u octets) to link specific frame", 2261 WLAN_CAPABILITYINFO_LEN); 2262 2263 sta_prof_currpos += WLAN_CAPABILITYINFO_LEN; 2264 sta_prof_remlen -= WLAN_CAPABILITYINFO_LEN; 2265 2266 /* Listen Interval is common between all links. Copy this from 2267 * the reporting section of the frame. 2268 */ 2269 2270 if ((link_frame_maxsize - link_frame_currlen) < 2271 WLAN_LISTENINTERVAL_LEN) { 2272 mlo_err("Insufficient space in link specific frame for Listen Interval field. Required: %u octets, available: %zu octets", 2273 WLAN_LISTENINTERVAL_LEN, 2274 (link_frame_maxsize - link_frame_currlen)); 2275 2276 qdf_mem_free(mlieseqpayload_copy); 2277 return QDF_STATUS_E_NOMEM; 2278 } 2279 2280 qdf_mem_copy(link_frame_currpos, 2281 frame + WLAN_CAPABILITYINFO_LEN, 2282 WLAN_LISTENINTERVAL_LEN); 2283 link_frame_currpos += WLAN_LISTENINTERVAL_LEN; 2284 link_frame_currlen += WLAN_LISTENINTERVAL_LEN; 2285 mlo_debug("Added Listen Interval field (%u octets) to link specific frame", 2286 WLAN_LISTENINTERVAL_LEN); 2287 2288 if (subtype == WLAN_FC0_STYPE_REASSOC_REQ) { 2289 /* Current AP address is common between all links. Copy 2290 * this from the reporting section of the frame. 2291 */ 2292 if ((link_frame_maxsize - link_frame_currlen) < 2293 QDF_MAC_ADDR_SIZE) { 2294 mlo_err("Insufficient space in link specific frame for current AP address. Required: %u octets, available: %zu octets", 2295 QDF_MAC_ADDR_SIZE, 2296 (link_frame_maxsize - 2297 link_frame_currlen)); 2298 2299 qdf_mem_free(mlieseqpayload_copy); 2300 return QDF_STATUS_E_NOMEM; 2301 } 2302 2303 qdf_mem_copy(link_frame_currpos, 2304 frame + WLAN_CAPABILITYINFO_LEN + 2305 WLAN_LISTENINTERVAL_LEN, 2306 QDF_MAC_ADDR_SIZE); 2307 link_frame_currpos += QDF_MAC_ADDR_SIZE; 2308 link_frame_currlen += QDF_MAC_ADDR_SIZE; 2309 mlo_debug("Reassoc req: Added Current AP address field (%u octets) to link specific frame", 2310 QDF_MAC_ADDR_SIZE); 2311 } 2312 } else if (subtype == WLAN_FC0_STYPE_ASSOC_RESP || 2313 subtype == WLAN_FC0_STYPE_REASSOC_RESP) { 2314 /* This is a (re)association response */ 2315 mlo_debug("Populating fixed fields for (re)assoc resp in link specific frame"); 2316 2317 if (sta_prof_remlen < 2318 (WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN)) { 2319 mlo_err_rl("Remaining length of STA profile %zu octets is less than length of Capability Info + length of Status Code %u", 2320 sta_prof_remlen, 2321 WLAN_CAPABILITYINFO_LEN + 2322 WLAN_STATUSCODE_LEN); 2323 2324 qdf_mem_free(mlieseqpayload_copy); 2325 return QDF_STATUS_E_PROTO; 2326 } 2327 2328 /* Capability information and Status Code are specific to the 2329 * link. Copy these from the STA profile. 2330 */ 2331 2332 if ((link_frame_maxsize - link_frame_currlen) < 2333 (WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN)) { 2334 mlo_err("Insufficient space in link specific frame for Capability Info and Status Code fields. Required: %u octets, available: %zu octets", 2335 WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN, 2336 (link_frame_maxsize - link_frame_currlen)); 2337 2338 qdf_mem_free(mlieseqpayload_copy); 2339 return QDF_STATUS_E_NOMEM; 2340 } 2341 2342 qdf_mem_copy(link_frame_currpos, sta_prof_currpos, 2343 (WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN)); 2344 link_frame_currpos += (WLAN_CAPABILITYINFO_LEN + 2345 WLAN_STATUSCODE_LEN); 2346 link_frame_currlen += (WLAN_CAPABILITYINFO_LEN + 2347 WLAN_STATUSCODE_LEN); 2348 mlo_debug("Added Capability Info and Status Code fields (%u octets) to link specific frame", 2349 WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN); 2350 2351 sta_prof_currpos += (WLAN_CAPABILITYINFO_LEN + 2352 WLAN_STATUSCODE_LEN); 2353 sta_prof_remlen -= (WLAN_CAPABILITYINFO_LEN + 2354 WLAN_STATUSCODE_LEN); 2355 2356 /* AID is common between all links. Copy this from the original 2357 * frame. 2358 */ 2359 2360 if ((link_frame_maxsize - link_frame_currlen) < WLAN_AID_LEN) { 2361 mlo_err("Insufficient space in link specific frame for AID field. Required: %u octets, available: %zu octets", 2362 WLAN_AID_LEN, 2363 (link_frame_maxsize - link_frame_currlen)); 2364 2365 qdf_mem_free(mlieseqpayload_copy); 2366 return QDF_STATUS_E_NOMEM; 2367 } 2368 2369 qdf_mem_copy(link_frame_currpos, 2370 frame + WLAN_CAPABILITYINFO_LEN + 2371 WLAN_STATUSCODE_LEN, 2372 WLAN_AID_LEN); 2373 link_frame_currpos += WLAN_AID_LEN; 2374 link_frame_currlen += WLAN_AID_LEN; 2375 mlo_debug("Added AID field (%u octets) to link specific frame", 2376 WLAN_AID_LEN); 2377 } else if (subtype == WLAN_FC0_STYPE_PROBE_RESP) { 2378 /* This is a probe response */ 2379 mlo_debug("Populating fixed fields for probe response in link specific frame"); 2380 2381 if ((link_frame_maxsize - link_frame_currlen) < 2382 WLAN_TIMESTAMP_LEN) { 2383 mlo_err("Insufficient space in link specific frame for Timestamp Info field. Required: %u octets, available: %zu octets", 2384 WLAN_TIMESTAMP_LEN, 2385 (link_frame_maxsize - link_frame_currlen)); 2386 2387 qdf_mem_free(mlieseqpayload_copy); 2388 return QDF_STATUS_E_NOMEM; 2389 } 2390 2391 /* Per spec 11be_D2.1.1, the TSF Offset subfield of the STA Info 2392 * field indicates the offset (Toffset)between the TSF timer of 2393 * the reported AP (TA) and the TSF timer of the reporting 2394 * AP (TB) and is encoded as a 2s complement signed integer 2395 * with units of 2 µs. Toffset is calculated as 2396 * Toffset= Floor((TA – TB)/2). 2397 */ 2398 if (is_tsfoffset_valid) 2399 tsf += tsfoffset * 2; 2400 2401 qdf_mem_copy(link_frame_currpos, &tsf, WLAN_TIMESTAMP_LEN); 2402 link_frame_currpos += WLAN_TIMESTAMP_LEN; 2403 link_frame_currlen += WLAN_TIMESTAMP_LEN; 2404 mlo_debug("Added Timestamp Info field (%u octets) to link specific frame", 2405 WLAN_TIMESTAMP_LEN); 2406 2407 if (!is_beaconinterval_valid) { 2408 mlo_err_rl("Beacon interval information not present in STA info field of per-STA profile"); 2409 qdf_mem_free(mlieseqpayload_copy); 2410 return QDF_STATUS_E_PROTO; 2411 } 2412 2413 /* Beacon Interval information copy this from 2414 * the STA info field. 2415 */ 2416 if ((link_frame_maxsize - link_frame_currlen) < 2417 WLAN_BEACONINTERVAL_LEN) { 2418 mlo_err("Insufficient space in link specific frame for Beacon Interval Info field. Required: %u octets, available: %zu octets", 2419 WLAN_BEACONINTERVAL_LEN, 2420 (link_frame_maxsize - link_frame_currlen)); 2421 2422 qdf_mem_free(mlieseqpayload_copy); 2423 return QDF_STATUS_E_NOMEM; 2424 } 2425 2426 qdf_mem_copy(link_frame_currpos, &beaconinterval, 2427 WLAN_BEACONINTERVAL_LEN); 2428 link_frame_currpos += WLAN_BEACONINTERVAL_LEN; 2429 link_frame_currlen += WLAN_BEACONINTERVAL_LEN; 2430 mlo_debug("Added Beacon Interval Info field (%u octets) to link specific frame", 2431 WLAN_BEACONINTERVAL_LEN); 2432 2433 if (sta_prof_remlen < WLAN_CAPABILITYINFO_LEN) { 2434 mlo_err_rl("Remaining length of STA profile %zu octets is less than length of Capability Info %u", 2435 sta_prof_remlen, 2436 WLAN_CAPABILITYINFO_LEN); 2437 2438 qdf_mem_free(mlieseqpayload_copy); 2439 return QDF_STATUS_E_PROTO; 2440 } 2441 2442 /* Capability information is specific to the link. Copy this 2443 * from the STA profile. 2444 */ 2445 2446 if ((link_frame_maxsize - link_frame_currlen) < 2447 WLAN_CAPABILITYINFO_LEN) { 2448 mlo_err("Insufficient space in link specific frame for Capability Info field. Required: %u octets, available: %zu octets", 2449 WLAN_CAPABILITYINFO_LEN, 2450 (link_frame_maxsize - link_frame_currlen)); 2451 2452 qdf_mem_free(mlieseqpayload_copy); 2453 return QDF_STATUS_E_NOMEM; 2454 } 2455 2456 qdf_mem_copy(link_frame_currpos, sta_prof_currpos, 2457 WLAN_CAPABILITYINFO_LEN); 2458 link_frame_currpos += WLAN_CAPABILITYINFO_LEN; 2459 link_frame_currlen += WLAN_CAPABILITYINFO_LEN; 2460 mlo_debug("Added Capability Info field (%u octets) to link specific frame", 2461 WLAN_CAPABILITYINFO_LEN); 2462 2463 sta_prof_currpos += WLAN_CAPABILITYINFO_LEN; 2464 sta_prof_remlen -= WLAN_CAPABILITYINFO_LEN; 2465 } 2466 2467 sta_prof_iesection = sta_prof_currpos; 2468 sta_prof_iesection_len = sta_prof_remlen; 2469 2470 /* Populate non-inheritance lists if applicable */ 2471 ninherit_elemlist_len = 0; 2472 ninherit_elemlist = NULL; 2473 ninherit_elemextlist_len = 0; 2474 ninherit_elemextlist = NULL; 2475 2476 ret = util_get_noninheritlists(sta_prof_iesection, 2477 sta_prof_iesection_len, 2478 &ninherit_elemlist, 2479 &ninherit_elemlist_len, 2480 &ninherit_elemextlist, 2481 &ninherit_elemextlist_len); 2482 if (QDF_IS_STATUS_ERROR(ret)) { 2483 qdf_mem_free(mlieseqpayload_copy); 2484 return ret; 2485 } 2486 2487 /* Go through IEs of the reporting STA, and those in STA profile, merge 2488 * them into link_frame (except for elements in the Non-Inheritance 2489 * list). 2490 * 2491 * Note: Currently, only 2-link MLO is supported here. We may have a 2492 * future change to expand to more links. 2493 */ 2494 reportingsta_ie = util_find_eid(WLAN_ELEMID_SSID, frame_iesection, 2495 frame_iesection_len); 2496 2497 if ((subtype == WLAN_FC0_STYPE_ASSOC_REQ) || 2498 (subtype == WLAN_FC0_STYPE_REASSOC_REQ) || 2499 (subtype == WLAN_FC0_STYPE_PROBE_RESP)) { 2500 /* Sanity check that the SSID element is present for the 2501 * reporting STA. There is no stipulation in the standard for 2502 * the STA profile in this regard, so we do not check the STA 2503 * profile for the SSID element. 2504 */ 2505 if (!reportingsta_ie) { 2506 mlo_err_rl("SSID element not found in reporting STA of the frame."); 2507 qdf_mem_free(mlieseqpayload_copy); 2508 return QDF_STATUS_E_PROTO; 2509 } 2510 } else { 2511 /* This is a (re)association response. Sanity check that the 2512 * SSID element is present neither for the reporting STA nor in 2513 * the STA profile. 2514 */ 2515 if (reportingsta_ie) { 2516 mlo_err_rl("SSID element found for reporting STA for (re)association response. It should not be present."); 2517 qdf_mem_free(mlieseqpayload_copy); 2518 return QDF_STATUS_E_PROTO; 2519 } 2520 2521 sta_prof_ie = util_find_eid(WLAN_ELEMID_SSID, 2522 sta_prof_iesection, 2523 sta_prof_iesection_len); 2524 2525 if (sta_prof_ie) { 2526 mlo_err_rl("SSID element found in STA profile for (re)association response. It should not be present."); 2527 qdf_mem_free(mlieseqpayload_copy); 2528 return QDF_STATUS_E_PROTO; 2529 } 2530 } 2531 2532 reportingsta_ie = reportingsta_ie ? reportingsta_ie : frame_iesection; 2533 2534 ret = util_validate_reportingsta_ie(reportingsta_ie, frame_iesection, 2535 frame_iesection_len); 2536 if (QDF_IS_STATUS_ERROR(ret)) { 2537 qdf_mem_free(mlieseqpayload_copy); 2538 return ret; 2539 } 2540 2541 reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] + MIN_IE_LEN; 2542 2543 while (((reportingsta_ie + reportingsta_ie_size) - frame_iesection) 2544 <= frame_iesection_len) { 2545 /* Skip Multi-Link element */ 2546 if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) && 2547 (reportingsta_ie[IDEXT_POS] == 2548 WLAN_EXTN_ELEMID_MULTI_LINK)) { 2549 if (((reportingsta_ie + reportingsta_ie_size) - 2550 frame_iesection) == frame_iesection_len) 2551 break; 2552 2553 /* Add BV ML IE for link specific probe response */ 2554 if (subtype == WLAN_FC0_STYPE_PROBE_RESP) { 2555 ret = util_add_mlie_for_prb_rsp_gen( 2556 reportingsta_ie, 2557 reportingsta_ie[TAG_LEN_POS], 2558 &link_frame_currpos, 2559 &link_frame_currlen, 2560 link_frame_maxsize, 2561 linkid); 2562 if (QDF_IS_STATUS_ERROR(ret)) { 2563 qdf_mem_free(mlieseqpayload_copy); 2564 return ret; 2565 } 2566 } 2567 reportingsta_ie += reportingsta_ie_size; 2568 2569 ret = util_validate_reportingsta_ie(reportingsta_ie, 2570 frame_iesection, 2571 frame_iesection_len); 2572 if (QDF_IS_STATUS_ERROR(ret)) { 2573 qdf_mem_free(mlieseqpayload_copy); 2574 return ret; 2575 } 2576 2577 reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] + 2578 MIN_IE_LEN; 2579 2580 continue; 2581 } 2582 2583 sta_prof_ie = NULL; 2584 sta_prof_ie_size = 0; 2585 2586 if (sta_prof_iesection_len) { 2587 if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 2588 sta_prof_ie = (uint8_t *)util_find_extn_eid(reportingsta_ie[ID_POS], 2589 reportingsta_ie[IDEXT_POS], 2590 sta_prof_iesection, 2591 sta_prof_iesection_len); 2592 } else { 2593 sta_prof_ie = (uint8_t *)util_find_eid(reportingsta_ie[ID_POS], 2594 sta_prof_iesection, 2595 sta_prof_iesection_len); 2596 } 2597 } 2598 2599 if (!sta_prof_ie) { 2600 /* IE is present for reporting STA, but not in STA 2601 * profile. 2602 */ 2603 2604 is_in_noninheritlist = false; 2605 2606 ret = util_eval_ie_in_noninheritlist((uint8_t *)reportingsta_ie, 2607 reportingsta_ie_size, 2608 ninherit_elemlist, 2609 ninherit_elemlist_len, 2610 ninherit_elemextlist, 2611 ninherit_elemextlist_len, 2612 &is_in_noninheritlist); 2613 2614 if (QDF_IS_STATUS_ERROR(ret)) { 2615 qdf_mem_free(mlieseqpayload_copy); 2616 return ret; 2617 } 2618 2619 if (!is_in_noninheritlist) { 2620 if ((link_frame_currpos + 2621 reportingsta_ie_size) <= 2622 (link_frame + link_frame_maxsize)) { 2623 qdf_mem_copy(link_frame_currpos, 2624 reportingsta_ie, 2625 reportingsta_ie_size); 2626 2627 link_frame_currpos += 2628 reportingsta_ie_size; 2629 link_frame_currlen += 2630 reportingsta_ie_size; 2631 2632 if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 2633 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", 2634 reportingsta_ie[ID_POS], 2635 reportingsta_ie[IDEXT_POS], 2636 reportingsta_ie_size); 2637 } else { 2638 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", 2639 reportingsta_ie[ID_POS], 2640 reportingsta_ie_size); 2641 } 2642 } else { 2643 if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 2644 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", 2645 reportingsta_ie[ID_POS], 2646 reportingsta_ie[IDEXT_POS], 2647 reportingsta_ie_size, 2648 link_frame_maxsize - 2649 link_frame_currlen); 2650 } else { 2651 mlo_err_rl("Insufficient space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets", 2652 reportingsta_ie[ID_POS], 2653 reportingsta_ie_size, 2654 link_frame_maxsize - 2655 link_frame_currlen); 2656 } 2657 2658 qdf_mem_free(mlieseqpayload_copy); 2659 return QDF_STATUS_E_NOMEM; 2660 } 2661 } else { 2662 if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 2663 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.", 2664 reportingsta_ie[ID_POS], 2665 reportingsta_ie[IDEXT_POS], 2666 reportingsta_ie_size); 2667 } else { 2668 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.", 2669 reportingsta_ie[ID_POS], 2670 reportingsta_ie_size); 2671 } 2672 } 2673 } else { 2674 /* IE is present for reporting STA and also in STA 2675 * profile, copy from STA profile and flag the IE in STA 2676 * profile as copied (by setting EID field to 0). The 2677 * SSID element (with EID 0) is processed first to 2678 * enable this. For vendor IE, compare OUI + type + 2679 * subType to determine if they are the same IE. 2680 */ 2681 /* Note: This may be revisited in a future change, to 2682 * adhere to provisions in the standard for multiple 2683 * occurrences of a given element ID/extension element 2684 * ID. 2685 */ 2686 2687 ret = util_validate_sta_prof_ie(sta_prof_ie, 2688 sta_prof_iesection, 2689 sta_prof_iesection_len); 2690 if (QDF_IS_STATUS_ERROR(ret)) { 2691 qdf_mem_free(mlieseqpayload_copy); 2692 return ret; 2693 } 2694 2695 sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] + 2696 MIN_IE_LEN; 2697 2698 sta_prof_iesection_remlen = 2699 sta_prof_iesection_len - 2700 (sta_prof_ie - sta_prof_iesection); 2701 2702 if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_VENDOR) && 2703 (sta_prof_iesection_remlen >= MIN_VENDOR_TAG_LEN)) { 2704 /* If Vendor IE also presents in STA profile, 2705 * then ignore the Vendor IE which is for 2706 * reporting STA. It only needs to copy Vendor 2707 * IE from STA profile to link specific frame. 2708 * The copy happens when going through the 2709 * remaining IEs. 2710 */ 2711 ; 2712 } else { 2713 /* Copy IE from STA profile into link specific 2714 * frame. 2715 */ 2716 if ((link_frame_currpos + sta_prof_ie_size) <= 2717 (link_frame + link_frame_maxsize)) { 2718 qdf_mem_copy(link_frame_currpos, 2719 sta_prof_ie, 2720 sta_prof_ie_size); 2721 2722 link_frame_currpos += sta_prof_ie_size; 2723 link_frame_currlen += 2724 sta_prof_ie_size; 2725 2726 if (reportingsta_ie[ID_POS] == 2727 WLAN_ELEMID_EXTN_ELEM) { 2728 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", 2729 sta_prof_ie[ID_POS], 2730 sta_prof_ie[IDEXT_POS], 2731 sta_prof_ie_size); 2732 } else { 2733 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", 2734 sta_prof_ie[ID_POS], 2735 sta_prof_ie_size); 2736 } 2737 2738 sta_prof_ie[0] = 0; 2739 } else { 2740 if (sta_prof_ie[ID_POS] == 2741 WLAN_ELEMID_EXTN_ELEM) { 2742 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", 2743 sta_prof_ie[ID_POS], 2744 sta_prof_ie[IDEXT_POS], 2745 sta_prof_ie_size, 2746 link_frame_maxsize - 2747 link_frame_currlen); 2748 } else { 2749 mlo_err_rl("Insufficient space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets", 2750 sta_prof_ie[ID_POS], 2751 sta_prof_ie_size, 2752 link_frame_maxsize - 2753 link_frame_currlen); 2754 } 2755 2756 qdf_mem_free(mlieseqpayload_copy); 2757 return QDF_STATUS_E_NOMEM; 2758 } 2759 } 2760 } 2761 2762 if (((reportingsta_ie + reportingsta_ie_size) - 2763 frame_iesection) == frame_iesection_len) 2764 break; 2765 2766 reportingsta_ie += reportingsta_ie_size; 2767 2768 ret = util_validate_reportingsta_ie(reportingsta_ie, 2769 frame_iesection, 2770 frame_iesection_len); 2771 if (QDF_IS_STATUS_ERROR(ret)) { 2772 qdf_mem_free(mlieseqpayload_copy); 2773 return ret; 2774 } 2775 2776 reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] + 2777 MIN_IE_LEN; 2778 } 2779 2780 /* Go through the remaining unprocessed IEs in STA profile and copy them 2781 * to the link specific frame. The processed ones are marked with 0 in 2782 * the first octet. The first octet corresponds to the element ID. In 2783 * the case of (re)association request, the element with actual ID 2784 * WLAN_ELEMID_SSID(0) has already been copied to the link specific 2785 * frame. In the case of (re)association response, it has been verified 2786 * that the element with actual ID WLAN_ELEMID_SSID(0) is present 2787 * neither for the reporting STA nor in the STA profile. 2788 */ 2789 sta_prof_iesection_currpos = sta_prof_iesection; 2790 sta_prof_iesection_remlen = sta_prof_iesection_len; 2791 2792 while (sta_prof_iesection_remlen > 0) { 2793 sta_prof_ie = sta_prof_iesection_currpos; 2794 ret = util_validate_sta_prof_ie(sta_prof_ie, 2795 sta_prof_iesection_currpos, 2796 sta_prof_iesection_remlen); 2797 if (QDF_IS_STATUS_ERROR(ret)) { 2798 qdf_mem_free(mlieseqpayload_copy); 2799 return ret; 2800 } 2801 2802 sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] + MIN_IE_LEN; 2803 2804 if (!sta_prof_ie[0]) { 2805 /* Skip this, since it has already been processed */ 2806 sta_prof_iesection_currpos += sta_prof_ie_size; 2807 sta_prof_iesection_remlen -= sta_prof_ie_size; 2808 continue; 2809 } 2810 2811 /* Copy IE from STA profile into link specific frame. */ 2812 if ((link_frame_currpos + sta_prof_ie_size) <= 2813 (link_frame + link_frame_maxsize)) { 2814 qdf_mem_copy(link_frame_currpos, 2815 sta_prof_ie, 2816 sta_prof_ie_size); 2817 2818 link_frame_currpos += sta_prof_ie_size; 2819 link_frame_currlen += 2820 sta_prof_ie_size; 2821 2822 if (reportingsta_ie[ID_POS] == 2823 WLAN_ELEMID_EXTN_ELEM) { 2824 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", 2825 sta_prof_ie[ID_POS], 2826 sta_prof_ie[IDEXT_POS], 2827 sta_prof_ie_size); 2828 } else { 2829 mlo_debug("IE with element ID : %u (%zu octets) is present only in STA profile. Copied IE from STA profile to link specific frame", 2830 sta_prof_ie[ID_POS], 2831 sta_prof_ie_size); 2832 } 2833 2834 sta_prof_ie[0] = 0; 2835 } else { 2836 if (sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) { 2837 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", 2838 sta_prof_ie[ID_POS], 2839 sta_prof_ie[IDEXT_POS], 2840 sta_prof_ie_size, 2841 link_frame_maxsize - 2842 link_frame_currlen); 2843 } else { 2844 mlo_err_rl("Insufficient space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets", 2845 sta_prof_ie[ID_POS], 2846 sta_prof_ie_size, 2847 link_frame_maxsize - 2848 link_frame_currlen); 2849 } 2850 2851 qdf_mem_free(mlieseqpayload_copy); 2852 return QDF_STATUS_E_NOMEM; 2853 } 2854 2855 sta_prof_iesection_currpos += sta_prof_ie_size; 2856 sta_prof_iesection_remlen -= sta_prof_ie_size; 2857 } 2858 2859 /* Copy the link MAC addr */ 2860 link_frame_hdr = (struct wlan_frame_hdr *)link_frame; 2861 2862 if ((subtype == WLAN_FC0_STYPE_ASSOC_REQ) || 2863 (subtype == WLAN_FC0_STYPE_REASSOC_REQ)) { 2864 qdf_mem_copy(link_frame_hdr->i_addr3, &link_addr, 2865 QDF_MAC_ADDR_SIZE); 2866 qdf_mem_copy(link_frame_hdr->i_addr2, reportedmacaddr.bytes, 2867 QDF_MAC_ADDR_SIZE); 2868 qdf_mem_copy(link_frame_hdr->i_addr1, &link_addr, 2869 QDF_MAC_ADDR_SIZE); 2870 2871 link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_ASSOC_REQ_FC0; 2872 link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_ASSOC_REQ_FC1; 2873 } else if (subtype == WLAN_FC0_STYPE_PROBE_RESP) { 2874 qdf_mem_copy(link_frame_hdr->i_addr3, reportedmacaddr.bytes, 2875 QDF_MAC_ADDR_SIZE); 2876 qdf_mem_copy(link_frame_hdr->i_addr2, reportedmacaddr.bytes, 2877 QDF_MAC_ADDR_SIZE); 2878 qdf_mem_copy(link_frame_hdr->i_addr1, &link_addr, 2879 QDF_MAC_ADDR_SIZE); 2880 2881 link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_PROBE_RESP_FC0; 2882 link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_PROBE_RESP_FC1; 2883 } else { 2884 /* This is a (re)association response */ 2885 2886 qdf_mem_copy(link_frame_hdr->i_addr3, reportedmacaddr.bytes, 2887 QDF_MAC_ADDR_SIZE); 2888 qdf_mem_copy(link_frame_hdr->i_addr2, reportedmacaddr.bytes, 2889 QDF_MAC_ADDR_SIZE); 2890 qdf_mem_copy(link_frame_hdr->i_addr1, &link_addr, 2891 QDF_MAC_ADDR_SIZE); 2892 2893 link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_ASSOC_RESP_FC0; 2894 link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_ASSOC_RESP_FC1; 2895 } 2896 2897 mlo_debug("subtype:%u addr3:" QDF_MAC_ADDR_FMT " addr2:" 2898 QDF_MAC_ADDR_FMT " addr1:" QDF_MAC_ADDR_FMT, 2899 subtype, 2900 QDF_MAC_ADDR_REF(link_frame_hdr->i_addr3), 2901 QDF_MAC_ADDR_REF(link_frame_hdr->i_addr2), 2902 QDF_MAC_ADDR_REF(link_frame_hdr->i_addr1)); 2903 2904 /* Seq num not used so not populated */ 2905 2906 qdf_mem_free(mlieseqpayload_copy); 2907 2908 *link_frame_len = link_frame_currlen; 2909 2910 return QDF_STATUS_SUCCESS; 2911 } 2912 2913 QDF_STATUS 2914 util_gen_link_assoc_req(uint8_t *frame, qdf_size_t frame_len, bool isreassoc, 2915 uint8_t link_id, 2916 struct qdf_mac_addr link_addr, 2917 uint8_t *link_frame, 2918 qdf_size_t link_frame_maxsize, 2919 qdf_size_t *link_frame_len) 2920 { 2921 return util_gen_link_reqrsp_cmn(frame, frame_len, 2922 (isreassoc ? WLAN_FC0_STYPE_REASSOC_REQ : 2923 WLAN_FC0_STYPE_ASSOC_REQ), 2924 link_id, link_addr, link_frame, 2925 link_frame_maxsize, link_frame_len); 2926 } 2927 2928 QDF_STATUS 2929 util_gen_link_assoc_rsp(uint8_t *frame, qdf_size_t frame_len, bool isreassoc, 2930 uint8_t link_id, 2931 struct qdf_mac_addr link_addr, 2932 uint8_t *link_frame, 2933 qdf_size_t link_frame_maxsize, 2934 qdf_size_t *link_frame_len) 2935 { 2936 return util_gen_link_reqrsp_cmn(frame, frame_len, 2937 (isreassoc ? WLAN_FC0_STYPE_REASSOC_RESP : 2938 WLAN_FC0_STYPE_ASSOC_RESP), 2939 link_id, link_addr, link_frame, 2940 link_frame_maxsize, link_frame_len); 2941 } 2942 2943 QDF_STATUS 2944 util_gen_link_probe_rsp(uint8_t *frame, qdf_size_t frame_len, 2945 uint8_t link_id, 2946 struct qdf_mac_addr link_addr, 2947 uint8_t *link_frame, 2948 qdf_size_t link_frame_maxsize, 2949 qdf_size_t *link_frame_len) 2950 { 2951 return util_gen_link_reqrsp_cmn(frame, frame_len, 2952 WLAN_FC0_STYPE_PROBE_RESP, link_id, 2953 link_addr, link_frame, link_frame_maxsize, 2954 link_frame_len); 2955 } 2956 2957 QDF_STATUS 2958 util_find_mlie(uint8_t *buf, qdf_size_t buflen, uint8_t **mlieseq, 2959 qdf_size_t *mlieseqlen) 2960 { 2961 uint8_t *bufboundary; 2962 uint8_t *ieseq; 2963 qdf_size_t ieseqlen; 2964 uint8_t *currie; 2965 uint8_t *successorfrag; 2966 2967 if (!buf || !buflen || !mlieseq || !mlieseqlen) 2968 return QDF_STATUS_E_NULL_VALUE; 2969 2970 *mlieseq = NULL; 2971 *mlieseqlen = 0; 2972 2973 /* Find Multi-Link element. In case a fragment sequence is present, 2974 * this element will be the leading fragment. 2975 */ 2976 ieseq = util_find_extn_eid(WLAN_ELEMID_EXTN_ELEM, 2977 WLAN_EXTN_ELEMID_MULTI_LINK, buf, 2978 buflen); 2979 2980 /* Even if the element is not found, we have successfully examined the 2981 * buffer. The caller will be provided a NULL value for the starting of 2982 * the Multi-Link element. Hence, we return success. 2983 */ 2984 if (!ieseq) 2985 return QDF_STATUS_SUCCESS; 2986 2987 bufboundary = buf + buflen; 2988 2989 if ((ieseq + MIN_IE_LEN) > bufboundary) 2990 return QDF_STATUS_E_INVAL; 2991 2992 ieseqlen = MIN_IE_LEN + ieseq[TAG_LEN_POS]; 2993 2994 if (ieseqlen < sizeof(struct wlan_ie_multilink)) 2995 return QDF_STATUS_E_PROTO; 2996 2997 if ((ieseq + ieseqlen) > bufboundary) 2998 return QDF_STATUS_E_INVAL; 2999 3000 /* In the next sequence of checks, if there is no space in the buffer 3001 * for another element after the Multi-Link element/element fragment 3002 * sequence, it could indicate an issue since non-MLO EHT elements 3003 * would be expected to follow the Multi-Link element/element fragment 3004 * sequence. However, this is outside of the purview of this function, 3005 * hence we ignore it. 3006 */ 3007 3008 currie = ieseq; 3009 successorfrag = util_get_successorfrag(currie, buf, buflen); 3010 3011 /* Fragmentation definitions as of IEEE802.11be D1.0 and 3012 * IEEE802.11REVme D0.2 are applied. Only the case where Multi-Link 3013 * element is present in a buffer from the core frame is considered. 3014 * Future changes to fragmentation, cases where the Multi-Link element 3015 * is present in a subelement, etc. to be reflected here if applicable 3016 * as and when the rules evolve. 3017 */ 3018 while (successorfrag) { 3019 /* We should not be seeing a successor fragment if the length 3020 * of the current IE is lesser than the max. 3021 */ 3022 if (currie[TAG_LEN_POS] != WLAN_MAX_IE_LEN) 3023 return QDF_STATUS_E_PROTO; 3024 3025 if (successorfrag[TAG_LEN_POS] == 0) 3026 return QDF_STATUS_E_PROTO; 3027 3028 ieseqlen += (MIN_IE_LEN + successorfrag[TAG_LEN_POS]); 3029 3030 currie = successorfrag; 3031 successorfrag = util_get_successorfrag(currie, buf, buflen); 3032 } 3033 3034 *mlieseq = ieseq; 3035 *mlieseqlen = ieseqlen; 3036 return QDF_STATUS_SUCCESS; 3037 } 3038 3039 QDF_STATUS 3040 util_find_mlie_by_variant(uint8_t *buf, qdf_size_t buflen, uint8_t **mlieseq, 3041 qdf_size_t *mlieseqlen, int variant) 3042 { 3043 uint8_t *ieseq; 3044 qdf_size_t ieseqlen; 3045 QDF_STATUS status; 3046 int ml_variant; 3047 qdf_size_t buf_parsed_len; 3048 3049 if (!buf || !buflen || !mlieseq || !mlieseqlen) 3050 return QDF_STATUS_E_NULL_VALUE; 3051 3052 if (variant >= WLAN_ML_VARIANT_INVALIDSTART) 3053 return QDF_STATUS_E_PROTO; 3054 3055 ieseq = NULL; 3056 ieseqlen = 0; 3057 *mlieseq = NULL; 3058 *mlieseqlen = 0; 3059 buf_parsed_len = 0; 3060 3061 while (buflen > buf_parsed_len) { 3062 status = util_find_mlie(buf + buf_parsed_len, 3063 buflen - buf_parsed_len, 3064 &ieseq, &ieseqlen); 3065 3066 if (QDF_IS_STATUS_ERROR(status)) 3067 return status; 3068 3069 /* Even if the element is not found, we have successfully 3070 * examined the buffer. The caller will be provided a NULL value 3071 * for the starting of the Multi-Link element. Hence, we return 3072 * success. 3073 */ 3074 if (!ieseq) 3075 return QDF_STATUS_SUCCESS; 3076 3077 status = util_get_mlie_variant(ieseq, ieseqlen, 3078 &ml_variant); 3079 if (QDF_IS_STATUS_ERROR(status)) { 3080 mlo_err("Unable to get Multi-link element variant"); 3081 return status; 3082 } 3083 3084 if (ml_variant == variant) { 3085 *mlieseq = ieseq; 3086 *mlieseqlen = ieseqlen; 3087 return QDF_STATUS_SUCCESS; 3088 } 3089 3090 buf_parsed_len = ieseq + ieseqlen - buf; 3091 } 3092 3093 return QDF_STATUS_E_INVAL; 3094 } 3095 3096 QDF_STATUS 3097 util_get_mlie_common_info_len(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3098 uint8_t *commoninfo_len) 3099 { 3100 struct wlan_ie_multilink *mlie_fixed; 3101 enum wlan_ml_variant variant; 3102 uint16_t mlcontrol; 3103 3104 if (!mlieseq || !mlieseqlen || !commoninfo_len) 3105 return QDF_STATUS_E_NULL_VALUE; 3106 3107 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3108 return QDF_STATUS_E_INVAL; 3109 3110 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3111 3112 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 3113 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) 3114 return QDF_STATUS_E_INVAL; 3115 3116 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3117 3118 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3119 WLAN_ML_CTRL_TYPE_BITS); 3120 3121 if (variant != WLAN_ML_VARIANT_BASIC) 3122 return QDF_STATUS_E_INVAL; 3123 3124 /* Common Info starts at mlieseq + sizeof(struct wlan_ie_multilink). 3125 * Check if there is sufficient space in the buffer for the Common Info 3126 * Length and MLD MAC address. 3127 */ 3128 if ((sizeof(struct wlan_ie_multilink) + WLAN_ML_BV_CINFO_LENGTH_SIZE + 3129 QDF_MAC_ADDR_SIZE) > mlieseqlen) 3130 return QDF_STATUS_E_PROTO; 3131 3132 *commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink)); 3133 3134 return QDF_STATUS_SUCCESS; 3135 } 3136 3137 QDF_STATUS 3138 util_get_bvmlie_bssparamchangecnt(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3139 bool *bssparamchangecntfound, 3140 uint8_t *bssparamchangecnt) 3141 { 3142 struct wlan_ie_multilink *mlie_fixed; 3143 enum wlan_ml_variant variant; 3144 uint16_t mlcontrol; 3145 uint16_t presencebitmap; 3146 uint8_t *commoninfo; 3147 qdf_size_t commoninfolen; 3148 3149 if (!mlieseq || !mlieseqlen || !bssparamchangecntfound || 3150 !bssparamchangecnt) 3151 return QDF_STATUS_E_NULL_VALUE; 3152 3153 *bssparamchangecntfound = false; 3154 *bssparamchangecnt = 0; 3155 3156 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3157 return QDF_STATUS_E_INVAL; 3158 3159 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3160 3161 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 3162 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) 3163 return QDF_STATUS_E_INVAL; 3164 3165 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3166 3167 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3168 WLAN_ML_CTRL_TYPE_BITS); 3169 3170 if (variant != WLAN_ML_VARIANT_BASIC) 3171 return QDF_STATUS_E_NOSUPPORT; 3172 3173 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3174 WLAN_ML_CTRL_PBM_BITS); 3175 3176 commoninfo = mlieseq + sizeof(struct wlan_ie_multilink); 3177 commoninfolen = WLAN_ML_BV_CINFO_LENGTH_SIZE; 3178 3179 commoninfolen += QDF_MAC_ADDR_SIZE; 3180 3181 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) { 3182 commoninfolen += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; 3183 3184 if ((sizeof(struct wlan_ie_multilink) + commoninfolen) > 3185 mlieseqlen) 3186 return QDF_STATUS_E_PROTO; 3187 } 3188 3189 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) { 3190 *bssparamchangecntfound = true; 3191 *bssparamchangecnt = *(commoninfo + commoninfolen); 3192 } 3193 3194 return QDF_STATUS_SUCCESS; 3195 } 3196 3197 QDF_STATUS 3198 util_get_mlie_variant(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3199 int *variant) 3200 { 3201 struct wlan_ie_multilink *mlie_fixed; 3202 enum wlan_ml_variant var; 3203 uint16_t mlcontrol; 3204 3205 if (!mlieseq || !mlieseqlen || !variant) 3206 return QDF_STATUS_E_NULL_VALUE; 3207 3208 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3209 return QDF_STATUS_E_INVAL; 3210 3211 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3212 3213 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3214 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) 3215 return QDF_STATUS_E_INVAL; 3216 3217 mlcontrol = le16toh(mlie_fixed->mlcontrol); 3218 var = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3219 WLAN_ML_CTRL_TYPE_BITS); 3220 3221 if (var >= WLAN_ML_VARIANT_INVALIDSTART) 3222 return QDF_STATUS_E_PROTO; 3223 3224 *variant = var; 3225 return QDF_STATUS_SUCCESS; 3226 } 3227 3228 QDF_STATUS 3229 util_get_bvmlie_eml_cap(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3230 bool *eml_cap_found, 3231 uint16_t *eml_cap) 3232 { 3233 struct wlan_ie_multilink *mlie_fixed; 3234 enum wlan_ml_variant variant; 3235 uint16_t mlcontrol; 3236 uint8_t eml_cap_offset; 3237 uint8_t commoninfo_len; 3238 uint16_t presencebitmap; 3239 3240 if (!mlieseq || !mlieseqlen || !eml_cap_found || !eml_cap) 3241 return QDF_STATUS_E_NULL_VALUE; 3242 3243 *eml_cap = 0; 3244 *eml_cap_found = false; 3245 3246 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3247 return QDF_STATUS_E_INVAL; 3248 3249 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3250 3251 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3252 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) 3253 return QDF_STATUS_E_INVAL; 3254 3255 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3256 3257 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3258 WLAN_ML_CTRL_TYPE_BITS); 3259 3260 if (variant != WLAN_ML_VARIANT_BASIC) 3261 return QDF_STATUS_E_INVAL; 3262 3263 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3264 WLAN_ML_CTRL_PBM_BITS); 3265 3266 /* eml_cap_offset stores the offset of EML Capabilities within 3267 * Common Info 3268 */ 3269 eml_cap_offset = WLAN_ML_BV_CINFO_LENGTH_SIZE + QDF_MAC_ADDR_SIZE; 3270 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) 3271 eml_cap_offset += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; 3272 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) 3273 eml_cap_offset += WLAN_ML_BSSPARAMCHNGCNT_SIZE; 3274 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P) 3275 eml_cap_offset += WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE; 3276 3277 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_EMLCAP_P) { 3278 /* Common Info starts at 3279 * mlieseq + sizeof(struct wlan_ie_multilink). 3280 * Check if there is sufficient space in the buffer for 3281 * the Common Info Length. 3282 */ 3283 if (mlieseqlen < (sizeof(struct wlan_ie_multilink) + 3284 WLAN_ML_BV_CINFO_LENGTH_SIZE)) 3285 return QDF_STATUS_E_PROTO; 3286 3287 /* Check if the value indicated in the Common Info Length 3288 * subfield is sufficient to access the EML capabilities. 3289 */ 3290 commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink)); 3291 if (commoninfo_len < (eml_cap_offset + 3292 WLAN_ML_BV_CINFO_EMLCAP_SIZE)) 3293 return QDF_STATUS_E_PROTO; 3294 3295 /* Common Info starts at mlieseq + sizeof(struct 3296 * wlan_ie_multilink). Check if there is sufficient space in 3297 * Common Info for the EML capability. 3298 */ 3299 if (mlieseqlen < (sizeof(struct wlan_ie_multilink) + 3300 eml_cap_offset + 3301 WLAN_ML_BV_CINFO_EMLCAP_SIZE)) 3302 return QDF_STATUS_E_PROTO; 3303 3304 *eml_cap_found = true; 3305 *eml_cap = qdf_le16_to_cpu(*(uint16_t *)(mlieseq + 3306 sizeof(struct wlan_ie_multilink) + 3307 eml_cap_offset)); 3308 } 3309 return QDF_STATUS_SUCCESS; 3310 } 3311 3312 QDF_STATUS 3313 util_get_bvmlie_msd_cap(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3314 bool *msd_cap_found, 3315 uint16_t *msd_cap) 3316 { 3317 struct wlan_ie_multilink *mlie_fixed; 3318 enum wlan_ml_variant variant; 3319 uint16_t mlcontrol; 3320 uint8_t msd_cap_offset; 3321 uint8_t commoninfo_len; 3322 uint16_t presencebitmap; 3323 3324 if (!mlieseq || !mlieseqlen || !msd_cap_found || !msd_cap) 3325 return QDF_STATUS_E_NULL_VALUE; 3326 3327 *msd_cap = 0; 3328 *msd_cap_found = false; 3329 3330 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3331 return QDF_STATUS_E_INVAL; 3332 3333 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3334 3335 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3336 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) 3337 return QDF_STATUS_E_INVAL; 3338 3339 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3340 3341 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3342 WLAN_ML_CTRL_TYPE_BITS); 3343 3344 if (variant != WLAN_ML_VARIANT_BASIC) 3345 return QDF_STATUS_E_INVAL; 3346 3347 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3348 WLAN_ML_CTRL_PBM_BITS); 3349 3350 /* msd_cap_offset stores the offset of MSD capabilities within 3351 * Common Info 3352 */ 3353 msd_cap_offset = WLAN_ML_BV_CINFO_LENGTH_SIZE + QDF_MAC_ADDR_SIZE; 3354 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) 3355 msd_cap_offset += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; 3356 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) 3357 msd_cap_offset += WLAN_ML_BSSPARAMCHNGCNT_SIZE; 3358 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P) { 3359 /* Common Info starts at 3360 * mlieseq + sizeof(struct wlan_ie_multilink). 3361 * Check if there is sufficient space in the buffer for 3362 * the Common Info Length. 3363 */ 3364 if (mlieseqlen < (sizeof(struct wlan_ie_multilink) + 3365 WLAN_ML_BV_CINFO_LENGTH_SIZE)) 3366 return QDF_STATUS_E_PROTO; 3367 3368 /* Check if the value indicated in the Common Info Length 3369 * subfield is sufficient to access the MSD capabilities. 3370 */ 3371 commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink)); 3372 if (commoninfo_len < (msd_cap_offset + 3373 WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE)) 3374 return QDF_STATUS_E_PROTO; 3375 3376 /* Common Info starts at mlieseq + sizeof(struct 3377 * wlan_ie_multilink). Check if there is sufficient space in 3378 * Common Info for the MSD capability. 3379 */ 3380 if (mlieseqlen < (sizeof(struct wlan_ie_multilink) + 3381 msd_cap_offset + 3382 WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE)) 3383 return QDF_STATUS_E_PROTO; 3384 3385 *msd_cap_found = true; 3386 *msd_cap = qdf_le16_to_cpu(*(uint16_t *)(mlieseq + 3387 sizeof(struct wlan_ie_multilink) + 3388 msd_cap_offset)); 3389 } else { 3390 mlo_debug("MSD caps not found in assoc rsp"); 3391 } 3392 3393 return QDF_STATUS_SUCCESS; 3394 } 3395 3396 QDF_STATUS 3397 util_get_bvmlie_mldmacaddr(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3398 struct qdf_mac_addr *mldmacaddr) 3399 { 3400 struct wlan_ie_multilink *mlie_fixed; 3401 enum wlan_ml_variant variant; 3402 uint16_t mlcontrol; 3403 uint8_t commoninfo_len; 3404 3405 if (!mlieseq || !mlieseqlen || !mldmacaddr) 3406 return QDF_STATUS_E_NULL_VALUE; 3407 3408 qdf_mem_zero(mldmacaddr, sizeof(*mldmacaddr)); 3409 3410 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3411 return QDF_STATUS_E_INVAL; 3412 3413 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3414 3415 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3416 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) 3417 return QDF_STATUS_E_INVAL; 3418 3419 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3420 3421 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3422 WLAN_ML_CTRL_TYPE_BITS); 3423 3424 if (variant != WLAN_ML_VARIANT_BASIC) 3425 return QDF_STATUS_E_INVAL; 3426 3427 /* Common Info starts at mlieseq + sizeof(struct wlan_ie_multilink). 3428 * Check if there is sufficient space in the buffer for the Common Info 3429 * Length and MLD MAC address. 3430 */ 3431 if ((sizeof(struct wlan_ie_multilink) + WLAN_ML_BV_CINFO_LENGTH_SIZE + 3432 QDF_MAC_ADDR_SIZE) > mlieseqlen) 3433 return QDF_STATUS_E_PROTO; 3434 3435 /* Check if the value indicated in the Common Info Length subfield is 3436 * sufficient to access the MLD MAC address. 3437 */ 3438 commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink)); 3439 if (commoninfo_len < (WLAN_ML_BV_CINFO_LENGTH_SIZE + QDF_MAC_ADDR_SIZE)) 3440 return QDF_STATUS_E_PROTO; 3441 3442 qdf_mem_copy(mldmacaddr->bytes, 3443 mlieseq + sizeof(struct wlan_ie_multilink) + 3444 WLAN_ML_BV_CINFO_LENGTH_SIZE, 3445 QDF_MAC_ADDR_SIZE); 3446 3447 return QDF_STATUS_SUCCESS; 3448 } 3449 3450 QDF_STATUS 3451 util_get_bvmlie_primary_linkid(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3452 bool *linkidfound, uint8_t *linkid) 3453 { 3454 struct wlan_ie_multilink *mlie_fixed; 3455 enum wlan_ml_variant variant; 3456 uint16_t mlcontrol; 3457 uint16_t presencebitmap; 3458 uint8_t *commoninfo; 3459 qdf_size_t commoninfolen; 3460 uint8_t *linkidinfo; 3461 3462 if (!mlieseq || !mlieseqlen || !linkidfound || !linkid) 3463 return QDF_STATUS_E_NULL_VALUE; 3464 3465 *linkidfound = false; 3466 *linkid = 0; 3467 3468 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3469 return QDF_STATUS_E_INVAL; 3470 3471 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3472 3473 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3474 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) 3475 return QDF_STATUS_E_INVAL; 3476 3477 mlcontrol = le16toh(mlie_fixed->mlcontrol); 3478 3479 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3480 WLAN_ML_CTRL_TYPE_BITS); 3481 3482 if (variant != WLAN_ML_VARIANT_BASIC) 3483 return QDF_STATUS_E_INVAL; 3484 3485 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3486 WLAN_ML_CTRL_PBM_BITS); 3487 3488 commoninfo = mlieseq + sizeof(struct wlan_ie_multilink); 3489 commoninfolen = 0; 3490 commoninfolen += WLAN_ML_BV_CINFO_LENGTH_SIZE; 3491 if ((sizeof(struct wlan_ie_multilink) + commoninfolen) > 3492 mlieseqlen) 3493 return QDF_STATUS_E_PROTO; 3494 3495 commoninfolen += QDF_MAC_ADDR_SIZE; 3496 if ((sizeof(struct wlan_ie_multilink) + commoninfolen) > 3497 mlieseqlen) 3498 return QDF_STATUS_E_PROTO; 3499 3500 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) { 3501 linkidinfo = commoninfo + commoninfolen; 3502 commoninfolen += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; 3503 3504 if ((sizeof(struct wlan_ie_multilink) + commoninfolen) > 3505 mlieseqlen) 3506 return QDF_STATUS_E_PROTO; 3507 3508 *linkidfound = true; 3509 *linkid = QDF_GET_BITS(linkidinfo[0], 3510 WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_IDX, 3511 WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_BITS); 3512 } 3513 3514 return QDF_STATUS_SUCCESS; 3515 } 3516 3517 QDF_STATUS 3518 util_get_bvmlie_mldcap(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3519 bool *mldcapfound, uint16_t *mldcap) 3520 { 3521 struct wlan_ie_multilink *mlie_fixed; 3522 enum wlan_ml_variant variant; 3523 uint16_t mlcontrol; 3524 uint16_t presencebitmap; 3525 uint8_t *commoninfo; 3526 uint8_t commoninfo_len; 3527 qdf_size_t mldcap_offset; 3528 3529 if (!mlieseq || !mlieseqlen || !mldcapfound || !mldcap) 3530 return QDF_STATUS_E_NULL_VALUE; 3531 3532 *mldcapfound = false; 3533 *mldcap = 0; 3534 3535 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3536 return QDF_STATUS_E_INVAL; 3537 3538 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3539 3540 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 3541 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) 3542 return QDF_STATUS_E_INVAL; 3543 3544 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3545 3546 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3547 WLAN_ML_CTRL_TYPE_BITS); 3548 3549 if (variant != WLAN_ML_VARIANT_BASIC) 3550 return QDF_STATUS_E_NOSUPPORT; 3551 3552 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3553 WLAN_ML_CTRL_PBM_BITS); 3554 3555 commoninfo = mlieseq + sizeof(struct wlan_ie_multilink); 3556 commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink)); 3557 /* mldcap_offset stores the offset of MLD Capabilities within 3558 * Common Info 3559 */ 3560 mldcap_offset = WLAN_ML_BV_CINFO_LENGTH_SIZE; 3561 mldcap_offset += QDF_MAC_ADDR_SIZE; 3562 3563 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) { 3564 mldcap_offset += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; 3565 3566 if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) > 3567 mlieseqlen) 3568 return QDF_STATUS_E_PROTO; 3569 } 3570 3571 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) { 3572 mldcap_offset += WLAN_ML_BSSPARAMCHNGCNT_SIZE; 3573 3574 if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) > 3575 mlieseqlen) 3576 return QDF_STATUS_E_PROTO; 3577 } 3578 3579 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P) { 3580 mldcap_offset += WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE; 3581 3582 if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) > 3583 mlieseqlen) 3584 return QDF_STATUS_E_PROTO; 3585 } 3586 3587 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_EMLCAP_P) { 3588 mldcap_offset += WLAN_ML_BV_CINFO_EMLCAP_SIZE; 3589 3590 if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) > 3591 mlieseqlen) 3592 return QDF_STATUS_E_PROTO; 3593 } 3594 3595 if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MLDCAPANDOP_P) { 3596 /* Check if the value indicated in the Common Info Length 3597 * subfield is sufficient to access the MLD capabilities. 3598 */ 3599 if (commoninfo_len < (mldcap_offset + 3600 WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE)) 3601 return QDF_STATUS_E_PROTO; 3602 3603 if ((sizeof(struct wlan_ie_multilink) + mldcap_offset + 3604 WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE) > 3605 mlieseqlen) 3606 return QDF_STATUS_E_PROTO; 3607 3608 *mldcap = qdf_le16_to_cpu(*((uint16_t *)(commoninfo + mldcap_offset))); 3609 *mldcapfound = true; 3610 } 3611 3612 return QDF_STATUS_SUCCESS; 3613 } 3614 3615 QDF_STATUS 3616 util_get_bvmlie_persta_partner_info(uint8_t *mlieseq, 3617 qdf_size_t mlieseqlen, 3618 struct mlo_partner_info *partner_info) 3619 { 3620 struct wlan_ie_multilink *mlie_fixed; 3621 uint16_t mlcontrol; 3622 enum wlan_ml_variant variant; 3623 uint8_t *linkinfo; 3624 qdf_size_t linkinfo_len; 3625 struct mlo_partner_info pinfo = {0}; 3626 qdf_size_t mlieseqpayloadlen; 3627 uint8_t *mlieseqpayload_copy; 3628 bool is_elemfragseq; 3629 qdf_size_t defragpayload_len; 3630 3631 qdf_size_t tmplen; 3632 QDF_STATUS ret; 3633 3634 if (!mlieseq) { 3635 mlo_err("Pointer to Multi-Link element sequence is NULL"); 3636 return QDF_STATUS_E_NULL_VALUE; 3637 } 3638 3639 if (!mlieseqlen) { 3640 mlo_err("Length of Multi-Link element sequence is zero"); 3641 return QDF_STATUS_E_INVAL; 3642 } 3643 3644 if (!partner_info) { 3645 mlo_err("partner_info is NULL"); 3646 return QDF_STATUS_E_NULL_VALUE; 3647 } 3648 3649 partner_info->num_partner_links = 0; 3650 3651 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) { 3652 mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)", 3653 mlieseqlen, sizeof(struct wlan_ie_multilink)); 3654 return QDF_STATUS_E_INVAL; 3655 } 3656 3657 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3658 3659 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3660 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) { 3661 mlo_err("The element is not a Multi-Link element"); 3662 return QDF_STATUS_E_INVAL; 3663 } 3664 3665 mlcontrol = le16toh(mlie_fixed->mlcontrol); 3666 3667 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3668 WLAN_ML_CTRL_TYPE_BITS); 3669 3670 if (variant != WLAN_ML_VARIANT_BASIC) { 3671 mlo_err("The variant value %u does not correspond to Basic Variant value %u", 3672 variant, WLAN_ML_VARIANT_BASIC); 3673 return QDF_STATUS_E_INVAL; 3674 } 3675 3676 mlieseqpayloadlen = 0; 3677 tmplen = 0; 3678 is_elemfragseq = false; 3679 3680 ret = wlan_get_elem_fragseq_info(mlieseq, 3681 mlieseqlen, 3682 &is_elemfragseq, 3683 &tmplen, 3684 &mlieseqpayloadlen); 3685 if (QDF_IS_STATUS_ERROR(ret)) 3686 return ret; 3687 3688 if (is_elemfragseq) { 3689 if (tmplen != mlieseqlen) { 3690 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", 3691 tmplen, mlieseqlen); 3692 return QDF_STATUS_E_INVAL; 3693 } 3694 3695 if (!mlieseqpayloadlen) { 3696 mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate"); 3697 return QDF_STATUS_E_FAILURE; 3698 } 3699 3700 mlo_debug("Multi-Link element fragment sequence found with payload len %zu", 3701 mlieseqpayloadlen); 3702 } else { 3703 if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) { 3704 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", 3705 mlieseqlen, 3706 sizeof(struct ie_header) + WLAN_MAX_IE_LEN); 3707 return QDF_STATUS_E_FAILURE; 3708 } 3709 3710 mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1); 3711 } 3712 3713 mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen); 3714 3715 if (!mlieseqpayload_copy) { 3716 mlo_err_rl("Could not allocate memory for Multi-Link element payload copy"); 3717 return QDF_STATUS_E_NOMEM; 3718 } 3719 3720 if (is_elemfragseq) { 3721 ret = wlan_defrag_elem_fragseq(false, 3722 mlieseq, 3723 mlieseqlen, 3724 mlieseqpayload_copy, 3725 mlieseqpayloadlen, 3726 &defragpayload_len); 3727 if (QDF_IS_STATUS_ERROR(ret)) { 3728 qdf_mem_free(mlieseqpayload_copy); 3729 return ret; 3730 } 3731 3732 if (defragpayload_len != mlieseqpayloadlen) { 3733 mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets", 3734 defragpayload_len, mlieseqpayloadlen); 3735 qdf_mem_free(mlieseqpayload_copy); 3736 return QDF_STATUS_E_FAILURE; 3737 } 3738 } else { 3739 qdf_mem_copy(mlieseqpayload_copy, 3740 mlieseq + sizeof(struct ie_header) + 1, 3741 mlieseqpayloadlen); 3742 } 3743 3744 linkinfo = NULL; 3745 linkinfo_len = 0; 3746 3747 ret = util_parse_multi_link_ctrl(mlieseqpayload_copy, 3748 mlieseqpayloadlen, 3749 &linkinfo, 3750 &linkinfo_len); 3751 if (QDF_IS_STATUS_ERROR(ret)) { 3752 qdf_mem_free(mlieseqpayload_copy); 3753 return ret; 3754 } 3755 3756 /* 3757 * If Probe Request variant Multi-Link element in the Multi-Link probe 3758 * request does not include any per-STA profile, then all APs affiliated 3759 * with the same AP MLD as the AP identified in the Addr 1 or Addr 3 3760 * field or AP MLD ID of the Multi-Link probe request are requested 3761 * APs return success here 3762 */ 3763 if (!linkinfo) { 3764 qdf_mem_free(mlieseqpayload_copy); 3765 return QDF_STATUS_SUCCESS; 3766 } 3767 3768 ret = util_parse_partner_info_from_linkinfo(linkinfo, 3769 linkinfo_len, 3770 &pinfo); 3771 3772 if (QDF_IS_STATUS_ERROR(ret)) { 3773 qdf_mem_free(mlieseqpayload_copy); 3774 return ret; 3775 } 3776 3777 qdf_mem_copy(partner_info, &pinfo, sizeof(*partner_info)); 3778 3779 qdf_mem_free(mlieseqpayload_copy); 3780 3781 return QDF_STATUS_SUCCESS; 3782 } 3783 3784 QDF_STATUS 3785 util_get_prvmlie_persta_link_id(uint8_t *mlieseq, 3786 qdf_size_t mlieseqlen, 3787 struct mlo_probereq_info *probereq_info) 3788 { 3789 struct wlan_ie_multilink *mlie_fixed; 3790 uint16_t mlcontrol; 3791 enum wlan_ml_variant variant; 3792 uint8_t *linkinfo; 3793 qdf_size_t linkinfo_len; 3794 qdf_size_t mlieseqpayloadlen; 3795 uint8_t *mlieseqpayload_copy; 3796 bool is_elemfragseq; 3797 qdf_size_t defragpayload_len; 3798 3799 qdf_size_t tmplen; 3800 QDF_STATUS ret; 3801 3802 if (!mlieseq) { 3803 mlo_err("Pointer to Multi-Link element sequence is NULL"); 3804 return QDF_STATUS_E_NULL_VALUE; 3805 } 3806 3807 if (!mlieseqlen) { 3808 mlo_err("Length of Multi-Link element sequence is zero"); 3809 return QDF_STATUS_E_INVAL; 3810 } 3811 3812 if (!probereq_info) { 3813 mlo_err("probe request_info is NULL"); 3814 return QDF_STATUS_E_NULL_VALUE; 3815 } 3816 3817 probereq_info->num_links = 0; 3818 3819 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) { 3820 mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)", 3821 mlieseqlen, sizeof(struct wlan_ie_multilink)); 3822 return QDF_STATUS_E_INVAL; 3823 } 3824 3825 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3826 3827 if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) || 3828 (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) { 3829 mlo_err("The element is not a Multi-Link element"); 3830 return QDF_STATUS_E_INVAL; 3831 } 3832 3833 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3834 3835 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3836 WLAN_ML_CTRL_TYPE_BITS); 3837 3838 if (variant != WLAN_ML_VARIANT_PROBEREQ) { 3839 mlo_err("The variant value %u does not correspond to Probe Request Variant value %u", 3840 variant, WLAN_ML_VARIANT_PROBEREQ); 3841 return QDF_STATUS_E_INVAL; 3842 } 3843 3844 mlieseqpayloadlen = 0; 3845 tmplen = 0; 3846 is_elemfragseq = false; 3847 3848 ret = wlan_get_elem_fragseq_info(mlieseq, 3849 mlieseqlen, 3850 &is_elemfragseq, 3851 &tmplen, 3852 &mlieseqpayloadlen); 3853 if (QDF_IS_STATUS_ERROR(ret)) 3854 return ret; 3855 3856 if (is_elemfragseq) { 3857 if (tmplen != mlieseqlen) { 3858 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", 3859 tmplen, mlieseqlen); 3860 return QDF_STATUS_E_INVAL; 3861 } 3862 3863 if (!mlieseqpayloadlen) { 3864 mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate"); 3865 return QDF_STATUS_E_FAILURE; 3866 } 3867 3868 mlo_debug("Multi-Link element fragment sequence found with payload len %zu", 3869 mlieseqpayloadlen); 3870 } else { 3871 if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) { 3872 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", 3873 mlieseqlen, 3874 sizeof(struct ie_header) + WLAN_MAX_IE_LEN); 3875 return QDF_STATUS_E_FAILURE; 3876 } 3877 3878 mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1); 3879 } 3880 3881 mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen); 3882 3883 if (!mlieseqpayload_copy) { 3884 mlo_err_rl("Could not allocate memory for Multi-Link element payload copy"); 3885 return QDF_STATUS_E_NOMEM; 3886 } 3887 3888 if (is_elemfragseq) { 3889 ret = wlan_defrag_elem_fragseq(false, 3890 mlieseq, 3891 mlieseqlen, 3892 mlieseqpayload_copy, 3893 mlieseqpayloadlen, 3894 &defragpayload_len); 3895 if (QDF_IS_STATUS_ERROR(ret)) { 3896 qdf_mem_free(mlieseqpayload_copy); 3897 return ret; 3898 } 3899 3900 if (defragpayload_len != mlieseqpayloadlen) { 3901 mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets", 3902 defragpayload_len, mlieseqpayloadlen); 3903 qdf_mem_free(mlieseqpayload_copy); 3904 return QDF_STATUS_E_FAILURE; 3905 } 3906 } else { 3907 qdf_mem_copy(mlieseqpayload_copy, 3908 mlieseq + sizeof(struct ie_header) + 1, 3909 mlieseqpayloadlen); 3910 } 3911 3912 linkinfo = NULL; 3913 linkinfo_len = 0; 3914 ret = util_parse_prv_multi_link_ctrl(mlieseqpayload_copy, 3915 mlieseqpayloadlen, 3916 &linkinfo, 3917 &linkinfo_len); 3918 if (QDF_IS_STATUS_ERROR(ret)) { 3919 qdf_mem_free(mlieseqpayload_copy); 3920 return ret; 3921 } 3922 3923 /* In case Link Info is absent, the number of links will remain 3924 * zero. 3925 */ 3926 if (!linkinfo) { 3927 mlo_debug("No link info present"); 3928 qdf_mem_free(mlieseqpayload_copy); 3929 return QDF_STATUS_SUCCESS; 3930 } 3931 3932 ret = util_parse_probereq_info_from_linkinfo(linkinfo, 3933 linkinfo_len, 3934 probereq_info); 3935 3936 if (QDF_IS_STATUS_ERROR(ret)) { 3937 qdf_mem_free(mlieseqpayload_copy); 3938 return ret; 3939 } 3940 3941 qdf_mem_free(mlieseqpayload_copy); 3942 3943 return QDF_STATUS_SUCCESS; 3944 } 3945 3946 QDF_STATUS 3947 util_get_prvmlie_mldid(uint8_t *mlieseq, qdf_size_t mlieseqlen, 3948 bool *mldidfound, uint8_t *mldid) 3949 { 3950 struct wlan_ie_multilink *mlie_fixed; 3951 enum wlan_ml_variant variant; 3952 uint16_t mlcontrol; 3953 uint16_t presencebitmap; 3954 uint8_t *commoninfo; 3955 qdf_size_t commoninfolen; 3956 3957 if (!mlieseq || !mlieseqlen || !mldidfound || !mldid) 3958 return QDF_STATUS_E_NULL_VALUE; 3959 3960 *mldidfound = false; 3961 *mldid = 0; 3962 3963 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 3964 return QDF_STATUS_E_INVAL; 3965 3966 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 3967 3968 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 3969 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) 3970 return QDF_STATUS_E_INVAL; 3971 3972 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 3973 3974 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 3975 WLAN_ML_CTRL_TYPE_BITS); 3976 3977 if (variant != WLAN_ML_VARIANT_PROBEREQ) 3978 return QDF_STATUS_E_NOSUPPORT; 3979 3980 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 3981 WLAN_ML_CTRL_PBM_BITS); 3982 3983 commoninfo = mlieseq + sizeof(struct wlan_ie_multilink); 3984 commoninfolen = WLAN_ML_PRV_CINFO_LENGTH_SIZE; 3985 3986 if (presencebitmap & WLAN_ML_PRV_CTRL_PBM_MLDID_P) { 3987 if ((sizeof(struct wlan_ie_multilink) + commoninfolen + 3988 WLAN_ML_PRV_CINFO_MLDID_SIZE) > 3989 mlieseqlen) 3990 return QDF_STATUS_E_PROTO; 3991 3992 *mldid = *((uint8_t *)(commoninfo + commoninfolen)); 3993 commoninfolen += WLAN_ML_PRV_CINFO_MLDID_SIZE; 3994 3995 *mldidfound = true; 3996 } 3997 3998 return QDF_STATUS_SUCCESS; 3999 } 4000 4001 QDF_STATUS util_get_rvmlie_mldmacaddr(uint8_t *mlieseq, qdf_size_t mlieseqlen, 4002 struct qdf_mac_addr *mldmacaddr) 4003 { 4004 struct wlan_ie_multilink *mlie_fixed; 4005 enum wlan_ml_variant variant; 4006 uint16_t mlcontrol; 4007 uint16_t presencebitmap; 4008 4009 if (!mlieseq || !mlieseqlen || !mldmacaddr) 4010 return QDF_STATUS_E_NULL_VALUE; 4011 4012 qdf_mem_zero(mldmacaddr, sizeof(*mldmacaddr)); 4013 4014 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) 4015 return QDF_STATUS_E_INVAL; 4016 4017 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 4018 4019 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 4020 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) 4021 return QDF_STATUS_E_INVAL; 4022 4023 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 4024 4025 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 4026 WLAN_ML_CTRL_TYPE_BITS); 4027 4028 if (variant != WLAN_ML_VARIANT_RECONFIG) 4029 return QDF_STATUS_E_INVAL; 4030 4031 presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 4032 WLAN_ML_CTRL_PBM_BITS); 4033 4034 /* Check if MLD mac address is present */ 4035 if (presencebitmap & WLAN_ML_RV_CTRL_PBM_MLDMACADDR_P) { 4036 if ((sizeof(struct wlan_ie_multilink) + QDF_MAC_ADDR_SIZE) > 4037 mlieseqlen) 4038 return QDF_STATUS_E_PROTO; 4039 4040 qdf_mem_copy(mldmacaddr->bytes, 4041 mlieseq + sizeof(struct wlan_ie_multilink), 4042 QDF_MAC_ADDR_SIZE); 4043 } 4044 4045 return QDF_STATUS_SUCCESS; 4046 } 4047 4048 static QDF_STATUS 4049 util_parse_rv_multi_link_ctrl(uint8_t *mlieseqpayload, 4050 qdf_size_t mlieseqpayloadlen, 4051 uint8_t **link_info, 4052 qdf_size_t *link_info_len) 4053 { 4054 qdf_size_t parsed_payload_len; 4055 uint16_t mlcontrol; 4056 uint16_t presence_bm; 4057 4058 /* This helper returns the location(s) and length(s) of (sub)field(s) 4059 * inferable after parsing the Multi Link element Control field. These 4060 * location(s) and length(s) is/are in reference to the payload section 4061 * of the Multi Link element (after defragmentation, if applicable). 4062 * Here, the payload is the point after the element ID extension of the 4063 * Multi Link element, and includes the payloads of all subsequent 4064 * fragments (if any) but not the headers of those fragments. 4065 * 4066 * Currently, the helper returns the location and length of the Link 4067 * Info field in the Multi Link element sequence. Other (sub)field(s) 4068 * can be added later as required. 4069 */ 4070 if (!mlieseqpayload) { 4071 mlo_err("ML seq payload pointer is NULL"); 4072 return QDF_STATUS_E_NULL_VALUE; 4073 } 4074 4075 if (!mlieseqpayloadlen) { 4076 mlo_err("ML seq payload len is 0"); 4077 return QDF_STATUS_E_INVAL; 4078 } 4079 4080 if (mlieseqpayloadlen < WLAN_ML_CTRL_SIZE) { 4081 mlo_err_rl("ML seq payload len %zu < ML Control size %u", 4082 mlieseqpayloadlen, WLAN_ML_CTRL_SIZE); 4083 return QDF_STATUS_E_PROTO; 4084 } 4085 4086 parsed_payload_len = 0; 4087 4088 qdf_mem_copy(&mlcontrol, mlieseqpayload, WLAN_ML_CTRL_SIZE); 4089 mlcontrol = qdf_le16_to_cpu(mlcontrol); 4090 parsed_payload_len += WLAN_ML_CTRL_SIZE; 4091 4092 presence_bm = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX, 4093 WLAN_ML_CTRL_PBM_BITS); 4094 4095 /* Check if MLD MAC address is present */ 4096 if (presence_bm & WLAN_ML_RV_CTRL_PBM_MLDMACADDR_P) { 4097 if (mlieseqpayloadlen < 4098 (parsed_payload_len + 4099 QDF_MAC_ADDR_SIZE)) { 4100 mlo_err_rl("ML seq payload len %zu insufficient for MLD ID size %u after parsed payload len %zu.", 4101 mlieseqpayloadlen, 4102 WLAN_ML_PRV_CINFO_MLDID_SIZE, 4103 parsed_payload_len); 4104 return QDF_STATUS_E_PROTO; 4105 } 4106 4107 parsed_payload_len += QDF_MAC_ADDR_SIZE; 4108 } 4109 4110 if (link_info_len) { 4111 *link_info_len = mlieseqpayloadlen - parsed_payload_len; 4112 mlo_debug("link_info_len:%zu, parsed_payload_len:%zu", 4113 *link_info_len, parsed_payload_len); 4114 } 4115 4116 if (mlieseqpayloadlen == parsed_payload_len) { 4117 mlo_debug("No Link Info field present"); 4118 if (link_info) 4119 *link_info = NULL; 4120 4121 return QDF_STATUS_SUCCESS; 4122 } 4123 4124 if (link_info) 4125 *link_info = mlieseqpayload + parsed_payload_len; 4126 4127 return QDF_STATUS_SUCCESS; 4128 } 4129 4130 static QDF_STATUS 4131 util_parse_rvmlie_perstaprofile_stactrl(uint8_t *subelempayload, 4132 qdf_size_t subelempayloadlen, 4133 uint8_t *linkid, 4134 bool *is_macaddr_valid, 4135 struct qdf_mac_addr *macaddr, 4136 bool *is_delete_timer_valid, 4137 uint16_t *delete_timer) 4138 { 4139 qdf_size_t parsed_payload_len = 0; 4140 uint16_t stacontrol; 4141 uint8_t completeprofile; 4142 4143 /* This helper returns the location(s) and where required, the length(s) 4144 * of (sub)field(s) inferable after parsing the STA Control field in the 4145 * per-STA profile subelement. These location(s) and length(s) is/are in 4146 * reference to the payload section of the per-STA profile subelement 4147 * (after defragmentation, if applicable). Here, the payload is the 4148 * point after the subelement length in the subelement, and includes the 4149 * payloads of all subsequent fragments (if any) but not the headers of 4150 * those fragments. 4151 * 4152 * Currently, the helper returns the link ID, MAC address, Delete timer 4153 * and STA profile. More (sub)fields can be added when required. 4154 */ 4155 if (!subelempayload) { 4156 mlo_err("Pointer to subelement payload is NULL"); 4157 return QDF_STATUS_E_NULL_VALUE; 4158 } 4159 4160 if (!subelempayloadlen) { 4161 mlo_err("Length of subelement payload is zero"); 4162 return QDF_STATUS_E_INVAL; 4163 } 4164 4165 if (subelempayloadlen < WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_SIZE) { 4166 mlo_err_rl("Subelement payload length %zu octets is smaller than STA control field of per-STA profile subelement %u octets", 4167 subelempayloadlen, 4168 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_SIZE); 4169 return QDF_STATUS_E_PROTO; 4170 } 4171 4172 parsed_payload_len = 0; 4173 qdf_mem_copy(&stacontrol, 4174 subelempayload, 4175 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_SIZE); 4176 4177 stacontrol = qdf_le16_to_cpu(stacontrol); 4178 parsed_payload_len += WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE; 4179 4180 if (linkid) 4181 *linkid = QDF_GET_BITS(stacontrol, 4182 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_LINKID_IDX, 4183 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_LINKID_BITS); 4184 4185 /* Check if this a complete profile */ 4186 completeprofile = QDF_GET_BITS(stacontrol, 4187 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_IDX, 4188 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_BITS); 4189 4190 if (is_macaddr_valid) 4191 *is_macaddr_valid = false; 4192 4193 /* Check STA MAC address present bit */ 4194 if (QDF_GET_BITS(stacontrol, 4195 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_MACADDRP_IDX, 4196 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_MACADDRP_BITS)) { 4197 if (subelempayloadlen < 4198 (parsed_payload_len + QDF_MAC_ADDR_SIZE)) { 4199 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.", 4200 subelempayloadlen, QDF_MAC_ADDR_SIZE, 4201 parsed_payload_len); 4202 return QDF_STATUS_E_PROTO; 4203 } 4204 4205 if (macaddr) { 4206 qdf_mem_copy(macaddr->bytes, 4207 subelempayload + parsed_payload_len, 4208 QDF_MAC_ADDR_SIZE); 4209 mlo_nofl_debug("Copied MAC address: " QDF_MAC_ADDR_FMT, 4210 subelempayload + parsed_payload_len); 4211 4212 if (is_macaddr_valid) 4213 *is_macaddr_valid = true; 4214 } 4215 4216 parsed_payload_len += QDF_MAC_ADDR_SIZE; 4217 } 4218 4219 /* Check Delete timer present bit */ 4220 if (QDF_GET_BITS(stacontrol, 4221 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_DELTIMERP_IDX, 4222 WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_DELTIMERP_BITS)) { 4223 if (subelempayloadlen < 4224 (parsed_payload_len + 4225 WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_DELTIMER_SIZE)) { 4226 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.", 4227 subelempayloadlen, 4228 WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_DELTIMER_SIZE, 4229 parsed_payload_len); 4230 return QDF_STATUS_E_PROTO; 4231 } 4232 4233 if (delete_timer) { 4234 qdf_mem_copy(delete_timer, 4235 subelempayload + parsed_payload_len, 4236 WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_DELTIMER_SIZE); 4237 4238 if (is_delete_timer_valid) 4239 *is_delete_timer_valid = true; 4240 } 4241 4242 parsed_payload_len += WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_DELTIMER_SIZE; 4243 } 4244 4245 return QDF_STATUS_SUCCESS; 4246 } 4247 4248 static QDF_STATUS 4249 util_parse_rv_info_from_linkinfo(uint8_t *linkinfo, 4250 qdf_size_t linkinfo_len, 4251 struct ml_rv_info *reconfig_info) 4252 { 4253 uint8_t linkid; 4254 uint8_t *linkinfo_currpos; 4255 qdf_size_t linkinfo_remlen; 4256 bool is_subelemfragseq; 4257 uint8_t subelemid; 4258 qdf_size_t subelemseqtotallen; 4259 qdf_size_t subelemseqpayloadlen; 4260 qdf_size_t defragpayload_len; 4261 QDF_STATUS ret; 4262 struct qdf_mac_addr mac_addr; 4263 bool is_macaddr_valid; 4264 bool is_delete_timer_valid; 4265 uint16_t delete_timer; 4266 4267 /* This helper function parses probe request info from the per-STA prof 4268 * present (if any) in the Link Info field in the payload of a Multi 4269 * Link element (after defragmentation if required). The caller should 4270 * pass a copy of the payload so that inline defragmentation of 4271 * subelements can be carried out if required. The subelement 4272 * defragmentation (if applicable) in this Control Path helper is 4273 * required for maintainability, accuracy and eliminating current and 4274 * future per-field-access multi-level fragment boundary checks and 4275 * adjustments, given the complex format of Multi Link elements. It is 4276 * also most likely to be required mainly at the client side. 4277 * Fragmentation is currently unlikely to be required for subelements 4278 * in Reconfiguration variant Multi-Link elements, but it should be 4279 * handled in order to be future ready. 4280 */ 4281 if (!linkinfo) { 4282 mlo_err("linkinfo is NULL"); 4283 return QDF_STATUS_E_NULL_VALUE; 4284 } 4285 4286 if (!linkinfo_len) { 4287 mlo_err("linkinfo_len is zero"); 4288 return QDF_STATUS_E_NULL_VALUE; 4289 } 4290 4291 if (!reconfig_info) { 4292 mlo_err("ML reconfig info is NULL"); 4293 return QDF_STATUS_E_NULL_VALUE; 4294 } 4295 4296 reconfig_info->num_links = 0; 4297 linkinfo_currpos = linkinfo; 4298 linkinfo_remlen = linkinfo_len; 4299 4300 while (linkinfo_remlen) { 4301 if (linkinfo_remlen < sizeof(struct subelem_header)) { 4302 mlo_err_rl("Remaining length in link info %zu octets is smaller than subelement header length %zu octets", 4303 linkinfo_remlen, 4304 sizeof(struct subelem_header)); 4305 return QDF_STATUS_E_PROTO; 4306 } 4307 4308 subelemid = linkinfo_currpos[ID_POS]; 4309 is_subelemfragseq = false; 4310 subelemseqtotallen = 0; 4311 subelemseqpayloadlen = 0; 4312 4313 ret = wlan_get_subelem_fragseq_info(WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 4314 linkinfo_currpos, 4315 linkinfo_remlen, 4316 &is_subelemfragseq, 4317 &subelemseqtotallen, 4318 &subelemseqpayloadlen); 4319 if (QDF_IS_STATUS_ERROR(ret)) 4320 return ret; 4321 4322 if (qdf_unlikely(is_subelemfragseq)) { 4323 if (!subelemseqpayloadlen) { 4324 mlo_err_rl("Subelement fragment sequence payload is reported as 0, investigate"); 4325 return QDF_STATUS_E_FAILURE; 4326 } 4327 4328 mlo_debug("Subelement fragment sequence found with payload len %zu", 4329 subelemseqpayloadlen); 4330 4331 ret = wlan_defrag_subelem_fragseq(true, 4332 WLAN_ML_LINFO_SUBELEMID_FRAGMENT, 4333 linkinfo_currpos, 4334 linkinfo_remlen, 4335 NULL, 4336 0, 4337 &defragpayload_len); 4338 4339 if (QDF_IS_STATUS_ERROR(ret)) 4340 return ret; 4341 4342 if (defragpayload_len != subelemseqpayloadlen) { 4343 mlo_err_rl("Length of defragmented payload %zu octets is not equal to length of subelement fragment sequence payload %zu octets", 4344 defragpayload_len, 4345 subelemseqpayloadlen); 4346 return QDF_STATUS_E_FAILURE; 4347 } 4348 4349 /* Adjust linkinfo_remlen to reflect removal of all 4350 * subelement headers except the header of the lead 4351 * subelement. 4352 */ 4353 linkinfo_remlen -= (subelemseqtotallen - 4354 subelemseqpayloadlen - 4355 sizeof(struct subelem_header)); 4356 } else { 4357 if (linkinfo_remlen < 4358 (sizeof(struct subelem_header) + 4359 linkinfo_currpos[TAG_LEN_POS])) { 4360 mlo_err_rl("Remaining length in link info %zu octets is smaller than total size of current subelement %zu octets", 4361 linkinfo_remlen, 4362 sizeof(struct subelem_header) + 4363 linkinfo_currpos[TAG_LEN_POS]); 4364 return QDF_STATUS_E_PROTO; 4365 } 4366 4367 subelemseqpayloadlen = linkinfo_currpos[TAG_LEN_POS]; 4368 } 4369 4370 if (subelemid == WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE) { 4371 is_macaddr_valid = false; 4372 is_delete_timer_valid = false; 4373 ret = util_parse_rvmlie_perstaprofile_stactrl(linkinfo_currpos + 4374 sizeof(struct subelem_header), 4375 subelemseqpayloadlen, 4376 &linkid, 4377 &is_macaddr_valid, 4378 &mac_addr, 4379 &is_delete_timer_valid, 4380 &delete_timer); 4381 if (QDF_IS_STATUS_ERROR(ret)) 4382 return ret; 4383 4384 reconfig_info->link_info[reconfig_info->num_links].link_id = linkid; 4385 reconfig_info->link_info[reconfig_info->num_links].is_delete_timer_p = is_delete_timer_valid; 4386 4387 if (is_delete_timer_valid) 4388 reconfig_info->link_info[reconfig_info->num_links].delete_timer = delete_timer; 4389 else 4390 mlo_warn_rl("Delete timer not found in STA Info field of per-STA profile with link ID %u", 4391 linkid); 4392 4393 mlo_debug("Per-STA Profile Link ID: %u Delete timer present: %d Delete timer: %u", 4394 reconfig_info->link_info[reconfig_info->num_links].link_id, 4395 reconfig_info->link_info[reconfig_info->num_links].is_delete_timer_p, 4396 reconfig_info->link_info[reconfig_info->num_links].delete_timer); 4397 4398 reconfig_info->num_links++; 4399 } 4400 4401 linkinfo_remlen -= (sizeof(struct subelem_header) + 4402 subelemseqpayloadlen); 4403 linkinfo_currpos += (sizeof(struct subelem_header) + 4404 subelemseqpayloadlen); 4405 } 4406 4407 mlo_debug("Number of ML probe request links found=%u", 4408 reconfig_info->num_links); 4409 4410 return QDF_STATUS_SUCCESS; 4411 } 4412 4413 QDF_STATUS util_get_rvmlie_persta_link_info(uint8_t *mlieseq, 4414 qdf_size_t mlieseqlen, 4415 struct ml_rv_info *reconfig_info) 4416 { 4417 struct wlan_ie_multilink *mlie_fixed; 4418 uint16_t mlcontrol; 4419 enum wlan_ml_variant variant; 4420 uint8_t *linkinfo; 4421 qdf_size_t linkinfo_len; 4422 struct ml_rv_info rinfo = {0}; 4423 qdf_size_t mlieseqpayloadlen; 4424 uint8_t *mlieseqpayload_copy; 4425 bool is_elemfragseq; 4426 qdf_size_t defragpayload_len; 4427 qdf_size_t tmplen; 4428 QDF_STATUS ret; 4429 4430 if (!mlieseq) { 4431 mlo_err("Pointer to Multi-Link element sequence is NULL"); 4432 return QDF_STATUS_E_NULL_VALUE; 4433 } 4434 4435 if (!mlieseqlen) { 4436 mlo_err("Length of Multi-Link element sequence is zero"); 4437 return QDF_STATUS_E_INVAL; 4438 } 4439 4440 if (!reconfig_info) { 4441 mlo_err("reconfig_info is NULL"); 4442 return QDF_STATUS_E_NULL_VALUE; 4443 } 4444 4445 reconfig_info->num_links = 0; 4446 4447 if (mlieseqlen < sizeof(struct wlan_ie_multilink)) { 4448 mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)", 4449 mlieseqlen, sizeof(struct wlan_ie_multilink)); 4450 return QDF_STATUS_E_INVAL; 4451 } 4452 4453 mlie_fixed = (struct wlan_ie_multilink *)mlieseq; 4454 if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM || 4455 mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) { 4456 mlo_err("The element is not a Multi-Link element"); 4457 return QDF_STATUS_E_INVAL; 4458 } 4459 4460 mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol); 4461 4462 variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX, 4463 WLAN_ML_CTRL_TYPE_BITS); 4464 4465 if (variant != WLAN_ML_VARIANT_RECONFIG) { 4466 mlo_err("The variant value %u does not correspond to Reconfig Variant value %u", 4467 variant, WLAN_ML_VARIANT_RECONFIG); 4468 return QDF_STATUS_E_INVAL; 4469 } 4470 4471 mlieseqpayloadlen = 0; 4472 tmplen = 0; 4473 is_elemfragseq = false; 4474 4475 ret = wlan_get_elem_fragseq_info(mlieseq, 4476 mlieseqlen, 4477 &is_elemfragseq, 4478 &tmplen, 4479 &mlieseqpayloadlen); 4480 4481 if (QDF_IS_STATUS_ERROR(ret)) 4482 return ret; 4483 4484 if (qdf_unlikely(is_elemfragseq)) { 4485 if (tmplen != mlieseqlen) { 4486 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", 4487 tmplen, mlieseqlen); 4488 return QDF_STATUS_E_INVAL; 4489 } 4490 4491 if (!mlieseqpayloadlen) { 4492 mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate"); 4493 return QDF_STATUS_E_FAILURE; 4494 } 4495 4496 mlo_debug("Multi-Link element fragment sequence found with payload len %zu", 4497 mlieseqpayloadlen); 4498 } else { 4499 if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) { 4500 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", 4501 mlieseqlen, 4502 sizeof(struct ie_header) + WLAN_MAX_IE_LEN); 4503 return QDF_STATUS_E_FAILURE; 4504 } 4505 4506 mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1); 4507 } 4508 4509 mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen); 4510 4511 if (!mlieseqpayload_copy) { 4512 mlo_err_rl("Could not allocate memory for Multi-Link element payload copy"); 4513 return QDF_STATUS_E_NOMEM; 4514 } 4515 4516 if (qdf_unlikely(is_elemfragseq)) { 4517 ret = wlan_defrag_elem_fragseq(false, 4518 mlieseq, 4519 mlieseqlen, 4520 mlieseqpayload_copy, 4521 mlieseqpayloadlen, 4522 &defragpayload_len); 4523 if (QDF_IS_STATUS_ERROR(ret)) { 4524 qdf_mem_free(mlieseqpayload_copy); 4525 return ret; 4526 } 4527 4528 if (defragpayload_len != mlieseqpayloadlen) { 4529 mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets", 4530 defragpayload_len, mlieseqpayloadlen); 4531 qdf_mem_free(mlieseqpayload_copy); 4532 return QDF_STATUS_E_FAILURE; 4533 } 4534 } else { 4535 qdf_mem_copy(mlieseqpayload_copy, 4536 mlieseq + sizeof(struct ie_header) + 1, 4537 mlieseqpayloadlen); 4538 } 4539 4540 linkinfo = NULL; 4541 linkinfo_len = 0; 4542 4543 ret = util_parse_rv_multi_link_ctrl(mlieseqpayload_copy, 4544 mlieseqpayloadlen, 4545 &linkinfo, 4546 &linkinfo_len); 4547 if (QDF_IS_STATUS_ERROR(ret)) { 4548 qdf_mem_free(mlieseqpayload_copy); 4549 return ret; 4550 } 4551 4552 /* In case Link Info is absent, the number of links will remain 4553 * zero. 4554 */ 4555 if (!linkinfo) { 4556 qdf_mem_free(mlieseqpayload_copy); 4557 return QDF_STATUS_SUCCESS; 4558 } 4559 4560 ret = util_parse_rv_info_from_linkinfo(linkinfo, linkinfo_len, &rinfo); 4561 if (QDF_IS_STATUS_ERROR(ret)) { 4562 qdf_mem_free(mlieseqpayload_copy); 4563 return ret; 4564 } 4565 4566 qdf_mem_copy(reconfig_info, &rinfo, sizeof(*reconfig_info)); 4567 qdf_mem_free(mlieseqpayload_copy); 4568 4569 return QDF_STATUS_SUCCESS; 4570 } 4571 4572 #endif 4573