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