Home | History | Annotate | Line # | Download | only in ap
      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