1 /* 2 * hostapd / IEEE 802.11be EHT 3 * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "utils/includes.h" 10 #include "utils/common.h" 11 #include "crypto/crypto.h" 12 #include "crypto/dh_groups.h" 13 #include "hostapd.h" 14 #include "sta_info.h" 15 #include "ieee802_11.h" 16 17 18 static u16 ieee80211_eht_ppet_size(u16 ppe_thres_hdr, const u8 *phy_cap_info) 19 { 20 u8 ru; 21 u16 sz = 0; 22 23 if ((phy_cap_info[EHT_PHYCAP_PPE_THRESHOLD_PRESENT_IDX] & 24 EHT_PHYCAP_PPE_THRESHOLD_PRESENT) == 0) 25 return 0; 26 27 ru = (ppe_thres_hdr & 28 EHT_PPE_THRES_RU_INDEX_MASK) >> EHT_PPE_THRES_RU_INDEX_SHIFT; 29 while (ru) { 30 if (ru & 0x1) 31 sz++; 32 ru >>= 1; 33 } 34 35 sz = sz * (1 + ((ppe_thres_hdr & EHT_PPE_THRES_NSS_MASK) >> 36 EHT_PPE_THRES_NSS_SHIFT)); 37 sz = (sz * 6) + 9; 38 if (sz % 8) 39 sz += 8; 40 sz /= 8; 41 42 return sz; 43 } 44 45 46 static u8 ieee80211_eht_mcs_set_size(enum hostapd_hw_mode mode, u8 opclass, 47 int he_oper_chwidth, const u8 *he_phy_cap, 48 const u8 *eht_phy_cap) 49 { 50 u8 sz = EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS; 51 bool band24, band5, band6; 52 u8 he_phy_cap_chwidth = ~HE_PHYCAP_CHANNEL_WIDTH_MASK; 53 u8 cap_chwidth; 54 55 switch (he_oper_chwidth) { 56 case CONF_OPER_CHWIDTH_80P80MHZ: 57 he_phy_cap_chwidth |= 58 HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G; 59 /* fall through */ 60 case CONF_OPER_CHWIDTH_160MHZ: 61 he_phy_cap_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G; 62 /* fall through */ 63 case CONF_OPER_CHWIDTH_80MHZ: 64 case CONF_OPER_CHWIDTH_USE_HT: 65 he_phy_cap_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G | 66 HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; 67 break; 68 } 69 70 cap_chwidth = he_phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX]; 71 if (he_oper_chwidth != -1) 72 he_phy_cap_chwidth &= cap_chwidth; 73 else 74 he_phy_cap_chwidth = cap_chwidth; 75 76 band24 = mode == HOSTAPD_MODE_IEEE80211B || 77 mode == HOSTAPD_MODE_IEEE80211G || 78 mode == NUM_HOSTAPD_MODES; 79 band5 = mode == HOSTAPD_MODE_IEEE80211A || 80 mode == NUM_HOSTAPD_MODES; 81 band6 = is_6ghz_op_class(opclass); 82 83 if (band24 && 84 (he_phy_cap_chwidth & HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G) == 0) 85 return EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY; 86 87 if (band5 && 88 (he_phy_cap_chwidth & 89 (HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 90 HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 91 HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)) == 0) 92 return EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY; 93 94 if (band5 && 95 (he_phy_cap_chwidth & 96 (HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 97 HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G))) 98 sz += EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS; 99 100 if (band6 && 101 (eht_phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] & 102 EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)) 103 sz += EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS; 104 105 return sz; 106 } 107 108 109 size_t hostapd_eid_eht_capab_len(struct hostapd_data *hapd, 110 enum ieee80211_op_mode opmode) 111 { 112 struct hostapd_hw_modes *mode; 113 struct eht_capabilities *eht_cap; 114 size_t len = 3 + 2 + EHT_PHY_CAPAB_LEN; 115 116 mode = hapd->iface->current_mode; 117 if (!mode) 118 return 0; 119 120 eht_cap = &mode->eht_capab[opmode]; 121 if (!eht_cap->eht_supported) 122 return 0; 123 124 len += ieee80211_eht_mcs_set_size(mode->mode, hapd->iconf->op_class, 125 hapd->iconf->he_oper_chwidth, 126 mode->he_capab[opmode].phy_cap, 127 eht_cap->phy_cap); 128 len += ieee80211_eht_ppet_size(WPA_GET_LE16(&eht_cap->ppet[0]), 129 eht_cap->phy_cap); 130 131 return len; 132 } 133 134 135 u8 * hostapd_eid_eht_capab(struct hostapd_data *hapd, u8 *eid, 136 enum ieee80211_op_mode opmode) 137 { 138 struct hostapd_hw_modes *mode; 139 struct eht_capabilities *eht_cap; 140 struct ieee80211_eht_capabilities *cap; 141 size_t mcs_nss_len, ppe_thresh_len; 142 u8 *pos = eid, *length_pos; 143 144 mode = hapd->iface->current_mode; 145 if (!mode) 146 return eid; 147 148 eht_cap = &mode->eht_capab[opmode]; 149 if (!eht_cap->eht_supported) 150 return eid; 151 152 *pos++ = WLAN_EID_EXTENSION; 153 length_pos = pos++; 154 *pos++ = WLAN_EID_EXT_EHT_CAPABILITIES; 155 156 cap = (struct ieee80211_eht_capabilities *) pos; 157 os_memset(cap, 0, sizeof(*cap)); 158 cap->mac_cap = host_to_le16(eht_cap->mac_cap); 159 os_memcpy(cap->phy_cap, eht_cap->phy_cap, EHT_PHY_CAPAB_LEN); 160 161 if (!is_6ghz_op_class(hapd->iconf->op_class)) 162 cap->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &= 163 ~EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK; 164 if (!hapd->iface->conf->eht_phy_capab.su_beamformer) 165 cap->phy_cap[EHT_PHYCAP_SU_BEAMFORMER_IDX] &= 166 ~EHT_PHYCAP_SU_BEAMFORMER; 167 168 if (!hapd->iface->conf->eht_phy_capab.su_beamformee) 169 cap->phy_cap[EHT_PHYCAP_SU_BEAMFORMEE_IDX] &= 170 ~EHT_PHYCAP_SU_BEAMFORMEE; 171 172 if (!hapd->iface->conf->eht_phy_capab.mu_beamformer) 173 cap->phy_cap[EHT_PHYCAP_MU_BEAMFORMER_IDX] &= 174 ~EHT_PHYCAP_MU_BEAMFORMER_MASK; 175 176 pos = cap->optional; 177 178 mcs_nss_len = ieee80211_eht_mcs_set_size(mode->mode, 179 hapd->iconf->op_class, 180 hapd->iconf->he_oper_chwidth, 181 mode->he_capab[opmode].phy_cap, 182 eht_cap->phy_cap); 183 if (mcs_nss_len) { 184 os_memcpy(pos, eht_cap->mcs, mcs_nss_len); 185 pos += mcs_nss_len; 186 } 187 188 ppe_thresh_len = ieee80211_eht_ppet_size( 189 WPA_GET_LE16(&eht_cap->ppet[0]), 190 eht_cap->phy_cap); 191 if (ppe_thresh_len) { 192 os_memcpy(pos, eht_cap->ppet, ppe_thresh_len); 193 pos += ppe_thresh_len; 194 } 195 196 *length_pos = pos - (eid + 2); 197 return pos; 198 } 199 200 201 u8 * hostapd_eid_eht_operation(struct hostapd_data *hapd, u8 *eid) 202 { 203 struct hostapd_config *conf = hapd->iconf; 204 struct ieee80211_eht_operation *oper; 205 u8 *pos = eid, seg0 = 0, seg1 = 0; 206 enum oper_chan_width chwidth; 207 size_t elen = 1 + 4; 208 bool eht_oper_info_present; 209 u16 punct_bitmap = hostapd_get_punct_bitmap(hapd); 210 211 if (!hapd->iface->current_mode) 212 return eid; 213 214 if (is_6ghz_op_class(conf->op_class)) 215 chwidth = op_class_to_ch_width(conf->op_class); 216 else 217 chwidth = conf->eht_oper_chwidth; 218 219 eht_oper_info_present = chwidth == CONF_OPER_CHWIDTH_320MHZ || 220 punct_bitmap; 221 222 if (eht_oper_info_present) 223 elen += 3; 224 225 if (punct_bitmap) 226 elen += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE; 227 228 *pos++ = WLAN_EID_EXTENSION; 229 *pos++ = 1 + elen; 230 *pos++ = WLAN_EID_EXT_EHT_OPERATION; 231 232 oper = (struct ieee80211_eht_operation *) pos; 233 oper->oper_params = 0; 234 235 if (hapd->iconf->eht_default_pe_duration) 236 oper->oper_params |= EHT_OPER_DEFAULT_PE_DURATION; 237 238 /* TODO: Fill in appropriate EHT-MCS max Nss information */ 239 oper->basic_eht_mcs_nss_set[0] = 0x11; 240 oper->basic_eht_mcs_nss_set[1] = 0x00; 241 oper->basic_eht_mcs_nss_set[2] = 0x00; 242 oper->basic_eht_mcs_nss_set[3] = 0x00; 243 244 if (!eht_oper_info_present) 245 return pos + elen; 246 247 oper->oper_params |= EHT_OPER_INFO_PRESENT; 248 seg0 = hostapd_get_oper_centr_freq_seg0_idx(conf); 249 250 switch (chwidth) { 251 case CONF_OPER_CHWIDTH_320MHZ: 252 oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_320MHZ; 253 seg1 = seg0; 254 if (hapd->iconf->channel < seg0) 255 seg0 -= 16; 256 else 257 seg0 += 16; 258 break; 259 case CONF_OPER_CHWIDTH_160MHZ: 260 oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_160MHZ; 261 seg1 = seg0; 262 if (hapd->iconf->channel < seg0) 263 seg0 -= 8; 264 else 265 seg0 += 8; 266 break; 267 case CONF_OPER_CHWIDTH_80MHZ: 268 oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_80MHZ; 269 break; 270 case CONF_OPER_CHWIDTH_USE_HT: 271 if (seg0) 272 oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_40MHZ; 273 break; 274 default: 275 return eid; 276 } 277 278 oper->oper_info.ccfs0 = seg0 ? seg0 : hapd->iconf->channel; 279 oper->oper_info.ccfs1 = seg1; 280 281 if (punct_bitmap) { 282 oper->oper_params |= EHT_OPER_DISABLED_SUBCHAN_BITMAP_PRESENT; 283 oper->oper_info.disabled_chan_bitmap = 284 host_to_le16(punct_bitmap); 285 } 286 287 return pos + elen; 288 } 289 290 291 static bool check_valid_eht_mcs_nss(struct hostapd_data *hapd, const u8 *ap_mcs, 292 const u8 *sta_mcs, u8 mcs_count, u8 map_len) 293 { 294 unsigned int i, j; 295 296 for (i = 0; i < mcs_count; i++) { 297 ap_mcs += i * 3; 298 sta_mcs += i * 3; 299 300 for (j = 0; j < map_len; j++) { 301 if (((ap_mcs[j] >> 4) & 0xFF) == 0) 302 continue; 303 304 if ((sta_mcs[j] & 0xFF) == 0) 305 continue; 306 307 return true; 308 } 309 } 310 311 wpa_printf(MSG_DEBUG, 312 "No matching EHT MCS found between AP TX and STA RX"); 313 return false; 314 } 315 316 317 static bool check_valid_eht_mcs(struct hostapd_data *hapd, 318 const u8 *sta_eht_capab, 319 enum ieee80211_op_mode opmode) 320 { 321 struct hostapd_hw_modes *mode; 322 const struct ieee80211_eht_capabilities *capab; 323 const u8 *ap_mcs, *sta_mcs; 324 u8 mcs_count = 1; 325 326 mode = hapd->iface->current_mode; 327 if (!mode) 328 return true; 329 330 ap_mcs = mode->eht_capab[opmode].mcs; 331 capab = (const struct ieee80211_eht_capabilities *) sta_eht_capab; 332 sta_mcs = capab->optional; 333 334 if (ieee80211_eht_mcs_set_size(mode->mode, hapd->iconf->op_class, 335 hapd->iconf->he_oper_chwidth, 336 mode->he_capab[opmode].phy_cap, 337 mode->eht_capab[opmode].phy_cap) == 338 EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY) 339 return check_valid_eht_mcs_nss( 340 hapd, ap_mcs, sta_mcs, 1, 341 EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY); 342 343 switch (hapd->iface->conf->eht_oper_chwidth) { 344 case CONF_OPER_CHWIDTH_320MHZ: 345 mcs_count++; 346 /* fall through */ 347 case CONF_OPER_CHWIDTH_80P80MHZ: 348 case CONF_OPER_CHWIDTH_160MHZ: 349 mcs_count++; 350 break; 351 default: 352 break; 353 } 354 355 return check_valid_eht_mcs_nss(hapd, ap_mcs, sta_mcs, mcs_count, 356 EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS); 357 } 358 359 360 static bool ieee80211_invalid_eht_cap_size(enum hostapd_hw_mode mode, 361 u8 opclass, const u8 *he_cap, 362 const u8 *eht_cap, size_t len) 363 { 364 const struct ieee80211_he_capabilities *he_capab; 365 struct ieee80211_eht_capabilities *cap; 366 const u8 *he_phy_cap; 367 size_t cap_len; 368 u16 ppe_thres_hdr; 369 370 he_capab = (const struct ieee80211_he_capabilities *) he_cap; 371 he_phy_cap = he_capab->he_phy_capab_info; 372 cap = (struct ieee80211_eht_capabilities *) eht_cap; 373 cap_len = sizeof(*cap) - sizeof(cap->optional); 374 if (len < cap_len) 375 return true; 376 377 cap_len += ieee80211_eht_mcs_set_size(mode, opclass, -1, he_phy_cap, 378 cap->phy_cap); 379 if (len < cap_len) 380 return true; 381 382 ppe_thres_hdr = len > cap_len + 1 ? 383 WPA_GET_LE16(&eht_cap[cap_len]) : 0x01ff; 384 cap_len += ieee80211_eht_ppet_size(ppe_thres_hdr, cap->phy_cap); 385 386 return len < cap_len; 387 } 388 389 390 u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta, 391 enum ieee80211_op_mode opmode, 392 const u8 *he_capab, size_t he_capab_len, 393 const u8 *eht_capab, size_t eht_capab_len) 394 { 395 struct hostapd_hw_modes *c_mode = hapd->iface->current_mode; 396 enum hostapd_hw_mode mode = c_mode ? c_mode->mode : NUM_HOSTAPD_MODES; 397 398 if (!hapd->iconf->ieee80211be || hapd->conf->disable_11be || 399 !he_capab || he_capab_len < IEEE80211_HE_CAPAB_MIN_LEN || 400 !eht_capab || 401 ieee80211_invalid_eht_cap_size(mode, hapd->iconf->op_class, 402 he_capab, eht_capab, 403 eht_capab_len) || 404 !check_valid_eht_mcs(hapd, eht_capab, opmode)) { 405 sta->flags &= ~WLAN_STA_EHT; 406 os_free(sta->eht_capab); 407 sta->eht_capab = NULL; 408 return WLAN_STATUS_SUCCESS; 409 } 410 411 os_free(sta->eht_capab); 412 sta->eht_capab = os_memdup(eht_capab, eht_capab_len); 413 if (!sta->eht_capab) { 414 sta->eht_capab_len = 0; 415 return WLAN_STATUS_UNSPECIFIED_FAILURE; 416 } 417 418 sta->flags |= WLAN_STA_EHT; 419 sta->eht_capab_len = eht_capab_len; 420 421 return WLAN_STATUS_SUCCESS; 422 } 423 424 425 void hostapd_get_eht_capab(struct hostapd_data *hapd, 426 const struct ieee80211_eht_capabilities *src, 427 struct ieee80211_eht_capabilities *dest, 428 size_t len) 429 { 430 if (!src || !dest) 431 return; 432 433 if (len > sizeof(*dest)) 434 len = sizeof(*dest); 435 /* TODO: mask out unsupported features */ 436 437 os_memset(dest, 0, sizeof(*dest)); 438 os_memcpy(dest, src, len); 439 } 440 441 442 static u8 * hostapd_eid_eht_basic_ml_common(struct hostapd_data *hapd, 443 u8 *eid, struct mld_info *mld_info, 444 bool include_mld_id) 445 { 446 struct wpabuf *buf; 447 u16 control; 448 u8 *pos = eid; 449 const u8 *ptr; 450 size_t len, slice_len; 451 u8 link_id; 452 u8 common_info_len; 453 u16 mld_cap; 454 u8 max_simul_links, active_links; 455 456 /* 457 * As the Multi-Link element can exceed the size of 255 bytes need to 458 * first build it and then handle fragmentation. 459 */ 460 buf = wpabuf_alloc(1024); 461 if (!buf) 462 return pos; 463 464 /* Multi-Link Control field */ 465 control = MULTI_LINK_CONTROL_TYPE_BASIC | 466 BASIC_MULTI_LINK_CTRL_PRES_LINK_ID | 467 BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT | 468 BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA | 469 BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA; 470 471 /* 472 * Set the basic Multi-Link common information. Hard code the common 473 * info length to 13 based on the length of the present fields: 474 * Length (1) + MLD address (6) + Link ID (1) + 475 * BSS Parameters Change Count (1) + EML Capabilities (2) + 476 * MLD Capabilities and Operations (2) 477 */ 478 #define EHT_ML_COMMON_INFO_LEN 13 479 common_info_len = EHT_ML_COMMON_INFO_LEN; 480 481 if (include_mld_id) { 482 /* AP MLD ID */ 483 control |= BASIC_MULTI_LINK_CTRL_PRES_AP_MLD_ID; 484 common_info_len++; 485 } 486 487 wpabuf_put_le16(buf, control); 488 489 wpabuf_put_u8(buf, common_info_len); 490 491 /* Own MLD MAC Address */ 492 wpabuf_put_data(buf, hapd->mld->mld_addr, ETH_ALEN); 493 494 /* Own Link ID */ 495 wpabuf_put_u8(buf, hapd->mld_link_id); 496 497 /* Currently hard code the BSS Parameters Change Count to 0x1 */ 498 wpabuf_put_u8(buf, 0x1); 499 500 wpa_printf(MSG_DEBUG, "MLD: EML Capabilities=0x%x", 501 hapd->iface->mld_eml_capa); 502 wpabuf_put_le16(buf, hapd->iface->mld_eml_capa); 503 504 mld_cap = hapd->iface->mld_mld_capa; 505 max_simul_links = mld_cap & EHT_ML_MLD_CAPA_MAX_NUM_SIM_LINKS_MASK; 506 active_links = hapd->mld->num_links - 1; 507 508 if (active_links > max_simul_links) { 509 wpa_printf(MSG_ERROR, 510 "MLD: Error in max simultaneous links, advertised: 0x%x current: 0x%x", 511 max_simul_links, active_links); 512 active_links = max_simul_links; 513 } 514 515 mld_cap &= ~EHT_ML_MLD_CAPA_MAX_NUM_SIM_LINKS_MASK; 516 mld_cap |= active_links & EHT_ML_MLD_CAPA_MAX_NUM_SIM_LINKS_MASK; 517 518 /* TODO: Advertise T2LM based on driver support as well */ 519 mld_cap &= ~EHT_ML_MLD_CAPA_TID_TO_LINK_MAP_NEG_SUPP_MSK; 520 521 wpa_printf(MSG_DEBUG, "MLD: MLD Capabilities and Operations=0x%x", 522 mld_cap); 523 wpabuf_put_le16(buf, mld_cap); 524 525 if (include_mld_id) { 526 wpa_printf(MSG_DEBUG, "MLD: AP MLD ID=0x%x", 527 hostapd_get_mld_id(hapd)); 528 wpabuf_put_u8(buf, hostapd_get_mld_id(hapd)); 529 } 530 531 if (!mld_info) 532 goto out; 533 534 /* Add link info for the other links */ 535 for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { 536 struct mld_link_info *link = &mld_info->links[link_id]; 537 struct hostapd_data *link_bss; 538 539 /* 540 * control (2) + station info length (1) + MAC address (6) + 541 * beacon interval (2) + TSF offset (8) + DTIM info (2) + BSS 542 * parameters change counter (1) + station profile length. 543 */ 544 #define EHT_ML_STA_INFO_LEN 22 545 size_t total_len = EHT_ML_STA_INFO_LEN + 546 link->resp_sta_profile_len; 547 548 /* Skip the local one */ 549 if (link_id == hapd->mld_link_id || !link->valid) 550 continue; 551 552 link_bss = hostapd_mld_get_link_bss(hapd, link_id); 553 if (!link_bss) { 554 wpa_printf(MSG_ERROR, 555 "MLD: Couldn't find link BSS - skip it"); 556 continue; 557 } 558 559 /* Per-STA Profile subelement */ 560 wpabuf_put_u8(buf, EHT_ML_SUB_ELEM_PER_STA_PROFILE); 561 562 if (total_len <= 255) 563 wpabuf_put_u8(buf, total_len); 564 else 565 wpabuf_put_u8(buf, 255); 566 567 /* STA Control */ 568 control = (link_id & 0xf) | 569 EHT_PER_STA_CTRL_MAC_ADDR_PRESENT_MSK | 570 EHT_PER_STA_CTRL_COMPLETE_PROFILE_MSK | 571 EHT_PER_STA_CTRL_TSF_OFFSET_PRESENT_MSK | 572 EHT_PER_STA_CTRL_BEACON_INTERVAL_PRESENT_MSK | 573 EHT_PER_STA_CTRL_DTIM_INFO_PRESENT_MSK | 574 EHT_PER_STA_CTRL_BSS_PARAM_CNT_PRESENT_MSK; 575 wpabuf_put_le16(buf, control); 576 577 /* STA Info */ 578 579 /* STA Info Length */ 580 wpabuf_put_u8(buf, EHT_ML_STA_INFO_LEN - 2); 581 wpabuf_put_data(buf, link->local_addr, ETH_ALEN); 582 wpabuf_put_le16(buf, link_bss->iconf->beacon_int); 583 584 /* TSF Offset */ 585 /* 586 * TODO: Currently setting TSF offset to zero. However, this 587 * information needs to come from the driver. 588 */ 589 wpabuf_put_le64(buf, 0); 590 591 /* DTIM Info */ 592 wpabuf_put_u8(buf, 0); /* DTIM Count */ 593 wpabuf_put_u8(buf, link_bss->conf->dtim_period); 594 595 /* BSS Parameters Change Count */ 596 wpabuf_put_u8(buf, hapd->eht_mld_bss_param_change); 597 598 if (!link->resp_sta_profile) 599 continue; 600 601 /* Fragment the sub element if needed */ 602 if (total_len <= 255) { 603 wpabuf_put_data(buf, link->resp_sta_profile, 604 link->resp_sta_profile_len); 605 } else { 606 ptr = link->resp_sta_profile; 607 len = link->resp_sta_profile_len; 608 609 slice_len = 255 - EHT_ML_STA_INFO_LEN; 610 611 wpabuf_put_data(buf, ptr, slice_len); 612 len -= slice_len; 613 ptr += slice_len; 614 615 while (len) { 616 if (len <= 255) 617 slice_len = len; 618 else 619 slice_len = 255; 620 621 wpabuf_put_u8(buf, EHT_ML_SUB_ELEM_FRAGMENT); 622 wpabuf_put_u8(buf, slice_len); 623 wpabuf_put_data(buf, ptr, slice_len); 624 625 len -= slice_len; 626 ptr += slice_len; 627 } 628 } 629 } 630 631 out: 632 /* Fragment the Multi-Link element, if needed */ 633 len = wpabuf_len(buf); 634 ptr = wpabuf_head(buf); 635 636 if (len <= 254) 637 slice_len = len; 638 else 639 slice_len = 254; 640 641 *pos++ = WLAN_EID_EXTENSION; 642 *pos++ = slice_len + 1; 643 *pos++ = WLAN_EID_EXT_MULTI_LINK; 644 os_memcpy(pos, ptr, slice_len); 645 646 ptr += slice_len; 647 pos += slice_len; 648 len -= slice_len; 649 650 while (len) { 651 if (len <= 255) 652 slice_len = len; 653 else 654 slice_len = 255; 655 656 *pos++ = WLAN_EID_FRAGMENT; 657 *pos++ = slice_len; 658 os_memcpy(pos, ptr, slice_len); 659 660 ptr += slice_len; 661 pos += slice_len; 662 len -= slice_len; 663 } 664 665 wpabuf_free(buf); 666 return pos; 667 } 668 669 670 static u8 * hostapd_eid_eht_reconf_ml(struct hostapd_data *hapd, u8 *eid) 671 { 672 #ifdef CONFIG_TESTING_OPTIONS 673 struct hostapd_data *other_hapd; 674 u16 control; 675 u8 *pos = eid; 676 unsigned int i; 677 678 wpa_printf(MSG_DEBUG, "MLD: Reconfiguration ML"); 679 680 /* First check if the element needs to be added */ 681 for (i = 0; i < hapd->iface->interfaces->count; i++) { 682 other_hapd = hapd->iface->interfaces->iface[i]->bss[0]; 683 684 wpa_printf(MSG_DEBUG, "MLD: Reconfiguration ML: %u", 685 other_hapd->eht_mld_link_removal_count); 686 687 if (other_hapd->eht_mld_link_removal_count) 688 break; 689 } 690 691 /* No link is going to be removed */ 692 if (i == hapd->iface->interfaces->count) 693 return eid; 694 695 wpa_printf(MSG_DEBUG, "MLD: Reconfiguration ML: Adding element"); 696 697 /* The length will be set at the end */ 698 *pos++ = WLAN_EID_EXTENSION; 699 *pos++ = 0; 700 *pos++ = WLAN_EID_EXT_MULTI_LINK; 701 702 /* Set the Multi-Link Control field */ 703 control = MULTI_LINK_CONTROL_TYPE_RECONF; 704 WPA_PUT_LE16(pos, control); 705 pos += 2; 706 707 /* Common Info doesn't include any information */ 708 *pos++ = 1; 709 710 /* Add the per station profiles */ 711 for (i = 0; i < hapd->iface->interfaces->count; i++) { 712 other_hapd = hapd->iface->interfaces->iface[i]->bss[0]; 713 if (!other_hapd->eht_mld_link_removal_count) 714 continue; 715 716 /* Subelement ID is 0 */ 717 *pos++ = 0; 718 *pos++ = 5; 719 720 control = other_hapd->mld_link_id | 721 EHT_PER_STA_RECONF_CTRL_AP_REMOVAL_TIMER; 722 723 WPA_PUT_LE16(pos, control); 724 pos += 2; 725 726 /* STA profile length */ 727 *pos++ = 3; 728 729 WPA_PUT_LE16(pos, other_hapd->eht_mld_link_removal_count); 730 pos += 2; 731 } 732 733 eid[1] = pos - eid - 2; 734 735 wpa_hexdump(MSG_DEBUG, "MLD: Reconfiguration ML", eid, eid[1] + 2); 736 return pos; 737 #else /* CONFIG_TESTING_OPTIONS */ 738 return eid; 739 #endif /* CONFIG_TESTING_OPTIONS */ 740 } 741 742 743 static size_t hostapd_eid_eht_ml_len(struct mld_info *info, 744 bool include_mld_id) 745 { 746 size_t len = 0; 747 size_t eht_ml_len = 2 + EHT_ML_COMMON_INFO_LEN; 748 u8 link_id; 749 750 if (include_mld_id) 751 eht_ml_len++; 752 753 for (link_id = 0; info && link_id < ARRAY_SIZE(info->links); 754 link_id++) { 755 struct mld_link_info *link; 756 size_t sta_len = EHT_ML_STA_INFO_LEN; 757 758 link = &info->links[link_id]; 759 if (!link->valid) 760 continue; 761 762 sta_len += link->resp_sta_profile_len; 763 764 /* Element data and (fragmentation) headers */ 765 eht_ml_len += sta_len; 766 eht_ml_len += 2 + sta_len / 255 * 2; 767 } 768 769 /* Element data */ 770 len += eht_ml_len; 771 772 /* First header (254 bytes of data) */ 773 len += 3; 774 775 /* Fragmentation headers; +1 for shorter first chunk */ 776 len += (eht_ml_len + 1) / 255 * 2; 777 778 return len; 779 } 780 #undef EHT_ML_COMMON_INFO_LEN 781 #undef EHT_ML_STA_INFO_LEN 782 783 784 u8 * hostapd_eid_eht_ml_beacon(struct hostapd_data *hapd, 785 struct mld_info *info, 786 u8 *eid, bool include_mld_id) 787 { 788 eid = hostapd_eid_eht_basic_ml_common(hapd, eid, info, include_mld_id); 789 return hostapd_eid_eht_reconf_ml(hapd, eid); 790 } 791 792 793 794 u8 * hostapd_eid_eht_ml_assoc(struct hostapd_data *hapd, struct sta_info *info, 795 u8 *eid) 796 { 797 if (!ap_sta_is_mld(hapd, info)) 798 return eid; 799 800 eid = hostapd_eid_eht_basic_ml_common(hapd, eid, &info->mld_info, 801 false); 802 ap_sta_free_sta_profile(&info->mld_info); 803 return hostapd_eid_eht_reconf_ml(hapd, eid); 804 } 805 806 807 size_t hostapd_eid_eht_ml_beacon_len(struct hostapd_data *hapd, 808 struct mld_info *info, 809 bool include_mld_id) 810 { 811 return hostapd_eid_eht_ml_len(info, include_mld_id); 812 } 813 814 815 struct wpabuf * hostapd_ml_auth_resp(struct hostapd_data *hapd) 816 { 817 struct wpabuf *buf = wpabuf_alloc(12); 818 819 if (!buf) 820 return NULL; 821 822 wpabuf_put_u8(buf, WLAN_EID_EXTENSION); 823 wpabuf_put_u8(buf, 10); 824 wpabuf_put_u8(buf, WLAN_EID_EXT_MULTI_LINK); 825 wpabuf_put_le16(buf, MULTI_LINK_CONTROL_TYPE_BASIC); 826 wpabuf_put_u8(buf, ETH_ALEN + 1); 827 wpabuf_put_data(buf, hapd->mld->mld_addr, ETH_ALEN); 828 829 return buf; 830 } 831 832 833 #ifdef CONFIG_SAE 834 835 static const u8 * 836 sae_commit_skip_fixed_fields(const struct ieee80211_mgmt *mgmt, size_t len, 837 const u8 *pos, u16 status_code) 838 { 839 u16 group; 840 size_t prime_len; 841 struct crypto_ec *ec; 842 843 if (status_code != WLAN_STATUS_SAE_HASH_TO_ELEMENT) 844 return pos; 845 846 /* SAE H2E commit message (group, scalar, FFE) */ 847 if (len < 2) { 848 wpa_printf(MSG_DEBUG, 849 "EHT: SAE Group is not present"); 850 return NULL; 851 } 852 853 group = WPA_GET_LE16(pos); 854 pos += 2; 855 856 /* TODO: How to parse when the group is unknown? */ 857 ec = crypto_ec_init(group); 858 if (!ec) { 859 const struct dh_group *dh = dh_groups_get(group); 860 861 if (!dh) { 862 wpa_printf(MSG_DEBUG, "EHT: Unknown SAE group %u", 863 group); 864 return NULL; 865 } 866 867 prime_len = dh->prime_len; 868 } else { 869 prime_len = crypto_ec_prime_len(ec); 870 } 871 872 wpa_printf(MSG_DEBUG, "EHT: SAE scalar length is %zu", prime_len); 873 874 /* scalar */ 875 pos += prime_len; 876 877 if (ec) { 878 pos += prime_len * 2; 879 crypto_ec_deinit(ec); 880 } else { 881 pos += prime_len; 882 } 883 884 if (pos - mgmt->u.auth.variable > (int) len) { 885 wpa_printf(MSG_DEBUG, 886 "EHT: Too short SAE commit Authentication frame"); 887 return NULL; 888 } 889 890 wpa_hexdump(MSG_DEBUG, "EHT: SAE: Authentication frame elements", 891 pos, (int) len - (pos - mgmt->u.auth.variable)); 892 893 return pos; 894 } 895 896 897 static const u8 * 898 sae_confirm_skip_fixed_fields(struct hostapd_data *hapd, 899 const struct ieee80211_mgmt *mgmt, size_t len, 900 const u8 *pos, u16 status_code) 901 { 902 struct sta_info *sta; 903 904 if (status_code == WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION) 905 return pos; 906 907 /* send confirm integer */ 908 pos += 2; 909 910 /* 911 * At this stage we should already have an MLD station and actually SA 912 * will be replaced with the MLD MAC address by the driver. 913 */ 914 sta = ap_get_sta(hapd, mgmt->sa); 915 if (!sta) { 916 wpa_printf(MSG_DEBUG, "SAE: No MLD STA for SAE confirm"); 917 return NULL; 918 } 919 920 if (!sta->sae || sta->sae->state < SAE_COMMITTED || !sta->sae->tmp) { 921 if (sta->sae) 922 wpa_printf(MSG_DEBUG, "SAE: Invalid state=%u", 923 sta->sae->state); 924 else 925 wpa_printf(MSG_DEBUG, "SAE: No SAE context"); 926 return NULL; 927 } 928 929 wpa_printf(MSG_DEBUG, "SAE: confirm: kck_len=%zu", 930 sta->sae->tmp->kck_len); 931 932 pos += sta->sae->tmp->kck_len; 933 934 if (pos - mgmt->u.auth.variable > (int) len) { 935 wpa_printf(MSG_DEBUG, 936 "EHT: Too short SAE confirm Authentication frame"); 937 return NULL; 938 } 939 940 return pos; 941 } 942 943 #endif /* CONFIG_SAE */ 944 945 946 static const u8 * auth_skip_fixed_fields(struct hostapd_data *hapd, 947 const struct ieee80211_mgmt *mgmt, 948 size_t len) 949 { 950 u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg); 951 #ifdef CONFIG_SAE 952 u16 auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction); 953 u16 status_code = le_to_host16(mgmt->u.auth.status_code); 954 #endif /* CONFIG_SAE */ 955 const u8 *pos = mgmt->u.auth.variable; 956 957 /* Skip fixed fields as based on IEE P802.11-REVme/D3.0, Table 9-69 958 * (Presence of fields and elements in Authentications frames) */ 959 switch (auth_alg) { 960 case WLAN_AUTH_OPEN: 961 return pos; 962 #ifdef CONFIG_SAE 963 case WLAN_AUTH_SAE: 964 if (auth_transaction == 1) { 965 if (status_code == WLAN_STATUS_SUCCESS) { 966 wpa_printf(MSG_DEBUG, 967 "EHT: SAE H2E is mandatory for MLD"); 968 goto out; 969 } 970 971 return sae_commit_skip_fixed_fields(mgmt, len, pos, 972 status_code); 973 } else if (auth_transaction == 2) { 974 return sae_confirm_skip_fixed_fields(hapd, mgmt, len, 975 pos, status_code); 976 } 977 978 return pos; 979 #endif /* CONFIG_SAE */ 980 /* TODO: Support additional algorithms that can be used for MLO */ 981 case WLAN_AUTH_FT: 982 case WLAN_AUTH_FILS_SK: 983 case WLAN_AUTH_FILS_SK_PFS: 984 case WLAN_AUTH_FILS_PK: 985 case WLAN_AUTH_PASN: 986 default: 987 break; 988 } 989 990 #ifdef CONFIG_SAE 991 out: 992 #endif /* CONFIG_SAE */ 993 wpa_printf(MSG_DEBUG, 994 "TODO: Authentication algorithm %u not supported with MLD", 995 auth_alg); 996 return NULL; 997 } 998 999 1000 const u8 * hostapd_process_ml_auth(struct hostapd_data *hapd, 1001 const struct ieee80211_mgmt *mgmt, 1002 size_t len) 1003 { 1004 struct ieee802_11_elems elems; 1005 const u8 *pos; 1006 1007 if (!hapd->conf->mld_ap) 1008 return NULL; 1009 1010 len -= offsetof(struct ieee80211_mgmt, u.auth.variable); 1011 1012 pos = auth_skip_fixed_fields(hapd, mgmt, len); 1013 if (!pos) 1014 return NULL; 1015 1016 if (ieee802_11_parse_elems(pos, 1017 (int)len - (pos - mgmt->u.auth.variable), 1018 &elems, 0) == ParseFailed) { 1019 wpa_printf(MSG_DEBUG, 1020 "MLD: Failed parsing Authentication frame"); 1021 } 1022 1023 if (!elems.basic_mle || !elems.basic_mle_len) 1024 return NULL; 1025 1026 return get_basic_mle_mld_addr(elems.basic_mle, elems.basic_mle_len); 1027 } 1028 1029 1030 static int hostapd_mld_validate_assoc_info(struct hostapd_data *hapd, 1031 struct sta_info *sta) 1032 { 1033 u8 link_id; 1034 struct mld_info *info = &sta->mld_info; 1035 1036 if (!ap_sta_is_mld(hapd, sta)) { 1037 wpa_printf(MSG_DEBUG, "MLD: Not a non-AP MLD"); 1038 return 0; 1039 } 1040 1041 /* 1042 * Iterate over the links negotiated in the (Re)Association Request 1043 * frame and validate that they are indeed valid links in the local AP 1044 * MLD. 1045 * 1046 * While at it, also update the local address for the links in the 1047 * mld_info, so it could be easily available for later flows, e.g., for 1048 * the RSN Authenticator, etc. 1049 */ 1050 for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { 1051 struct hostapd_data *other_hapd; 1052 1053 if (!info->links[link_id].valid || link_id == hapd->mld_link_id) 1054 continue; 1055 1056 other_hapd = hostapd_mld_get_link_bss(hapd, link_id); 1057 if (!other_hapd) { 1058 wpa_printf(MSG_DEBUG, "MLD: Invalid link ID=%u", 1059 link_id); 1060 return -1; 1061 } 1062 1063 os_memcpy(info->links[link_id].local_addr, other_hapd->own_addr, 1064 ETH_ALEN); 1065 } 1066 1067 return 0; 1068 } 1069 1070 1071 int hostapd_process_ml_assoc_req_addr(struct hostapd_data *hapd, 1072 const u8 *basic_mle, size_t basic_mle_len, 1073 u8 *mld_addr) 1074 { 1075 struct wpabuf *mlbuf = ieee802_11_defrag(basic_mle, basic_mle_len, 1076 true); 1077 struct ieee80211_eht_ml *ml; 1078 struct eht_ml_basic_common_info *common_info; 1079 size_t ml_len, common_info_len; 1080 int ret = -1; 1081 u16 ml_control; 1082 1083 if (!mlbuf) 1084 return WLAN_STATUS_SUCCESS; 1085 1086 ml = (struct ieee80211_eht_ml *) wpabuf_head(mlbuf); 1087 ml_len = wpabuf_len(mlbuf); 1088 1089 if (ml_len < sizeof(*ml)) 1090 goto out; 1091 1092 ml_control = le_to_host16(ml->ml_control); 1093 if ((ml_control & MULTI_LINK_CONTROL_TYPE_MASK) != 1094 MULTI_LINK_CONTROL_TYPE_BASIC) { 1095 wpa_printf(MSG_DEBUG, "MLD: Invalid ML type=%u", 1096 ml_control & MULTI_LINK_CONTROL_TYPE_MASK); 1097 goto out; 1098 } 1099 1100 /* Common Info Length and MLD MAC Address must always be present */ 1101 common_info_len = 1 + ETH_ALEN; 1102 1103 if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_LINK_ID) { 1104 wpa_printf(MSG_DEBUG, "MLD: Link ID Info not expected"); 1105 goto out; 1106 } 1107 1108 if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT) { 1109 wpa_printf(MSG_DEBUG, 1110 "MLD: BSS Parameters Change Count not expected"); 1111 goto out; 1112 } 1113 1114 if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MSD_INFO) { 1115 wpa_printf(MSG_DEBUG, 1116 "MLD: Medium Synchronization Delay Information not expected"); 1117 goto out; 1118 } 1119 1120 if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA) 1121 common_info_len += 2; 1122 1123 if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA) 1124 common_info_len += 2; 1125 1126 if (sizeof(*ml) + common_info_len > ml_len) { 1127 wpa_printf(MSG_DEBUG, "MLD: Not enough bytes for common info"); 1128 goto out; 1129 } 1130 1131 common_info = (struct eht_ml_basic_common_info *) ml->variable; 1132 1133 /* Common information length includes the length octet */ 1134 if (common_info->len != common_info_len) { 1135 wpa_printf(MSG_DEBUG, 1136 "MLD: Invalid common info len=%u", common_info->len); 1137 goto out; 1138 } 1139 1140 /* Get the MLD MAC Address */ 1141 os_memcpy(mld_addr, common_info->mld_addr, ETH_ALEN); 1142 ret = 0; 1143 1144 out: 1145 wpabuf_free(mlbuf); 1146 return ret; 1147 } 1148 1149 1150 u16 hostapd_process_ml_assoc_req(struct hostapd_data *hapd, 1151 struct ieee802_11_elems *elems, 1152 struct sta_info *sta) 1153 { 1154 struct wpabuf *mlbuf; 1155 const struct ieee80211_eht_ml *ml; 1156 const struct eht_ml_basic_common_info *common_info; 1157 size_t ml_len, common_info_len; 1158 struct mld_link_info *link_info; 1159 struct mld_info *info = &sta->mld_info; 1160 const u8 *pos; 1161 int ret = -1; 1162 u16 ml_control; 1163 1164 mlbuf = ieee802_11_defrag(elems->basic_mle, elems->basic_mle_len, true); 1165 if (!mlbuf) 1166 return WLAN_STATUS_SUCCESS; 1167 1168 ml = wpabuf_head(mlbuf); 1169 ml_len = wpabuf_len(mlbuf); 1170 1171 ml_control = le_to_host16(ml->ml_control); 1172 if ((ml_control & MULTI_LINK_CONTROL_TYPE_MASK) != 1173 MULTI_LINK_CONTROL_TYPE_BASIC) { 1174 wpa_printf(MSG_DEBUG, "MLD: Invalid ML type=%u", 1175 ml_control & MULTI_LINK_CONTROL_TYPE_MASK); 1176 goto out; 1177 } 1178 1179 /* Common Info length and MLD MAC address must always be present */ 1180 common_info_len = 1 + ETH_ALEN; 1181 1182 if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_LINK_ID) { 1183 wpa_printf(MSG_DEBUG, "MLD: Link ID info not expected"); 1184 goto out; 1185 } 1186 1187 if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT) { 1188 wpa_printf(MSG_DEBUG, "MLD: BSS params change not expected"); 1189 goto out; 1190 } 1191 1192 if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MSD_INFO) { 1193 wpa_printf(MSG_DEBUG, "MLD: Sync delay not expected"); 1194 goto out; 1195 } 1196 1197 if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA) { 1198 common_info_len += 2; 1199 } else { 1200 wpa_printf(MSG_DEBUG, "MLD: EML capabilities not present"); 1201 } 1202 1203 if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA) { 1204 common_info_len += 2; 1205 1206 } else { 1207 wpa_printf(MSG_DEBUG, "MLD: MLD capabilities not present"); 1208 goto out; 1209 } 1210 1211 wpa_printf(MSG_DEBUG, "MLD: expected_common_info_len=%lu", 1212 common_info_len); 1213 1214 if (sizeof(*ml) + common_info_len > ml_len) { 1215 wpa_printf(MSG_DEBUG, "MLD: Not enough bytes for common info"); 1216 goto out; 1217 } 1218 1219 common_info = (const struct eht_ml_basic_common_info *) ml->variable; 1220 1221 /* Common information length includes the length octet */ 1222 if (common_info->len != common_info_len) { 1223 wpa_printf(MSG_DEBUG, 1224 "MLD: Invalid common info len=%u (expected %zu)", 1225 common_info->len, common_info_len); 1226 goto out; 1227 } 1228 1229 pos = common_info->variable; 1230 1231 if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA) { 1232 info->common_info.eml_capa = WPA_GET_LE16(pos); 1233 pos += 2; 1234 } else { 1235 info->common_info.eml_capa = 0; 1236 } 1237 1238 info->common_info.mld_capa = WPA_GET_LE16(pos); 1239 pos += 2; 1240 1241 wpa_printf(MSG_DEBUG, "MLD: addr=" MACSTR ", eml=0x%x, mld=0x%x", 1242 MAC2STR(info->common_info.mld_addr), 1243 info->common_info.eml_capa, info->common_info.mld_capa); 1244 1245 /* Check the MLD MAC Address */ 1246 if (!ether_addr_equal(info->common_info.mld_addr, 1247 common_info->mld_addr)) { 1248 wpa_printf(MSG_DEBUG, 1249 "MLD: MLD address mismatch between authentication (" 1250 MACSTR ") and association (" MACSTR ")", 1251 MAC2STR(info->common_info.mld_addr), 1252 MAC2STR(common_info->mld_addr)); 1253 goto out; 1254 } 1255 1256 info->links[hapd->mld_link_id].valid = 1; 1257 1258 /* Parse the link info field */ 1259 ml_len -= sizeof(*ml) + common_info_len; 1260 1261 while (ml_len > 2) { 1262 size_t sub_elem_len = *(pos + 1); 1263 size_t sta_info_len; 1264 u16 control; 1265 1266 wpa_printf(MSG_DEBUG, "MLD: sub element len=%zu", 1267 sub_elem_len); 1268 1269 if (2 + sub_elem_len > ml_len) { 1270 wpa_printf(MSG_DEBUG, 1271 "MLD: Invalid link info len: %zu %zu", 1272 2 + sub_elem_len, ml_len); 1273 goto out; 1274 } 1275 1276 if (*pos == MULTI_LINK_SUB_ELEM_ID_VENDOR) { 1277 wpa_printf(MSG_DEBUG, 1278 "MLD: Skip vendor specific subelement"); 1279 1280 pos += 2 + sub_elem_len; 1281 ml_len -= 2 + sub_elem_len; 1282 continue; 1283 } 1284 1285 if (*pos != MULTI_LINK_SUB_ELEM_ID_PER_STA_PROFILE) { 1286 wpa_printf(MSG_DEBUG, 1287 "MLD: Skip unknown Multi-Link element subelement ID=%u", 1288 *pos); 1289 pos += 2 + sub_elem_len; 1290 ml_len -= 2 + sub_elem_len; 1291 continue; 1292 } 1293 1294 /* Skip the subelement ID and the length */ 1295 pos += 2; 1296 ml_len -= 2; 1297 1298 /* Get the station control field */ 1299 if (sub_elem_len < 2) { 1300 wpa_printf(MSG_DEBUG, 1301 "MLD: Too short Per-STA Profile subelement"); 1302 goto out; 1303 } 1304 control = WPA_GET_LE16(pos); 1305 link_info = &info->links[control & 1306 EHT_PER_STA_CTRL_LINK_ID_MSK]; 1307 pos += 2; 1308 ml_len -= 2; 1309 sub_elem_len -= 2; 1310 1311 if (!(control & EHT_PER_STA_CTRL_COMPLETE_PROFILE_MSK)) { 1312 wpa_printf(MSG_DEBUG, 1313 "MLD: Per-STA complete profile expected"); 1314 goto out; 1315 } 1316 1317 if (!(control & EHT_PER_STA_CTRL_MAC_ADDR_PRESENT_MSK)) { 1318 wpa_printf(MSG_DEBUG, 1319 "MLD: Per-STA MAC address not present"); 1320 goto out; 1321 } 1322 1323 if ((control & (EHT_PER_STA_CTRL_BEACON_INTERVAL_PRESENT_MSK | 1324 EHT_PER_STA_CTRL_DTIM_INFO_PRESENT_MSK))) { 1325 wpa_printf(MSG_DEBUG, 1326 "MLD: Beacon/DTIM interval not expected"); 1327 goto out; 1328 } 1329 1330 /* The length octet and the MAC address must be present */ 1331 sta_info_len = 1 + ETH_ALEN; 1332 1333 if (control & EHT_PER_STA_CTRL_NSTR_LINK_PAIR_PRESENT_MSK) { 1334 if (control & EHT_PER_STA_CTRL_NSTR_BM_SIZE_MSK) 1335 link_info->nstr_bitmap_len = 2; 1336 else 1337 link_info->nstr_bitmap_len = 1; 1338 } 1339 1340 sta_info_len += link_info->nstr_bitmap_len; 1341 1342 if (sta_info_len > ml_len || sta_info_len != *pos || 1343 sta_info_len > sub_elem_len) { 1344 wpa_printf(MSG_DEBUG, "MLD: Invalid STA Info length"); 1345 goto out; 1346 } 1347 1348 /* skip the length */ 1349 pos++; 1350 ml_len--; 1351 1352 /* get the link address */ 1353 os_memcpy(link_info->peer_addr, pos, ETH_ALEN); 1354 wpa_printf(MSG_DEBUG, 1355 "MLD: assoc: link id=%u, addr=" MACSTR, 1356 control & EHT_PER_STA_CTRL_LINK_ID_MSK, 1357 MAC2STR(link_info->peer_addr)); 1358 1359 pos += ETH_ALEN; 1360 ml_len -= ETH_ALEN; 1361 1362 /* Get the NSTR bitmap */ 1363 if (link_info->nstr_bitmap_len) { 1364 os_memcpy(link_info->nstr_bitmap, pos, 1365 link_info->nstr_bitmap_len); 1366 pos += link_info->nstr_bitmap_len; 1367 ml_len -= link_info->nstr_bitmap_len; 1368 } 1369 1370 sub_elem_len -= sta_info_len; 1371 1372 wpa_printf(MSG_DEBUG, "MLD: STA Profile len=%zu", sub_elem_len); 1373 if (sub_elem_len > ml_len) 1374 goto out; 1375 1376 if (sub_elem_len > 2) 1377 link_info->capability = WPA_GET_LE16(pos); 1378 1379 pos += sub_elem_len; 1380 ml_len -= sub_elem_len; 1381 1382 wpa_printf(MSG_DEBUG, "MLD: link ctrl=0x%x, " MACSTR 1383 ", nstr bitmap len=%u", 1384 control, MAC2STR(link_info->peer_addr), 1385 link_info->nstr_bitmap_len); 1386 1387 link_info->valid = true; 1388 } 1389 1390 if (ml_len) { 1391 wpa_printf(MSG_DEBUG, "MLD: %zu bytes left after parsing. fail", 1392 ml_len); 1393 goto out; 1394 } 1395 1396 ret = hostapd_mld_validate_assoc_info(hapd, sta); 1397 out: 1398 wpabuf_free(mlbuf); 1399 if (ret) { 1400 os_memset(info, 0, sizeof(*info)); 1401 return WLAN_STATUS_UNSPECIFIED_FAILURE; 1402 } 1403 1404 return WLAN_STATUS_SUCCESS; 1405 } 1406