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