xref: /freebsd/contrib/wpa/src/ap/ieee802_11_eht.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
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 
ieee80211_eht_ppet_size(u16 ppe_thres_hdr,const u8 * phy_cap_info)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 
ieee80211_eht_mcs_set_size(enum hostapd_hw_mode mode,u8 opclass,int he_oper_chwidth,const u8 * he_phy_cap,const u8 * eht_phy_cap)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 
hostapd_eid_eht_capab_len(struct hostapd_data * hapd,enum ieee80211_op_mode opmode)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 
hostapd_eid_eht_capab(struct hostapd_data * hapd,u8 * eid,enum ieee80211_op_mode opmode)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 
hostapd_eid_eht_operation(struct hostapd_data * hapd,u8 * eid)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 
check_valid_eht_mcs_nss(struct hostapd_data * hapd,const u8 * ap_mcs,const u8 * sta_mcs,u8 mcs_count,u8 map_len)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 
check_valid_eht_mcs(struct hostapd_data * hapd,const u8 * sta_eht_capab,enum ieee80211_op_mode opmode)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 
ieee80211_invalid_eht_cap_size(enum hostapd_hw_mode mode,u8 opclass,const u8 * he_cap,const u8 * eht_cap,size_t len)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 
copy_sta_eht_capab(struct hostapd_data * hapd,struct sta_info * sta,enum ieee80211_op_mode opmode,const u8 * he_capab,size_t he_capab_len,const u8 * eht_capab,size_t eht_capab_len)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 
hostapd_get_eht_capab(struct hostapd_data * hapd,const struct ieee80211_eht_capabilities * src,struct ieee80211_eht_capabilities * dest,size_t len)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 
hostapd_eid_eht_basic_ml_common(struct hostapd_data * hapd,u8 * eid,struct mld_info * mld_info,bool include_mld_id)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 
hostapd_eid_eht_reconf_ml(struct hostapd_data * hapd,u8 * eid)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 
hostapd_eid_eht_ml_len(struct mld_info * info,bool include_mld_id)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 
hostapd_eid_eht_ml_beacon(struct hostapd_data * hapd,struct mld_info * info,u8 * eid,bool include_mld_id)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 
hostapd_eid_eht_ml_assoc(struct hostapd_data * hapd,struct sta_info * info,u8 * eid)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 
hostapd_eid_eht_ml_beacon_len(struct hostapd_data * hapd,struct mld_info * info,bool include_mld_id)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 
hostapd_ml_auth_resp(struct hostapd_data * hapd)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 *
sae_commit_skip_fixed_fields(const struct ieee80211_mgmt * mgmt,size_t len,const u8 * pos,u16 status_code)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 *
sae_confirm_skip_fixed_fields(struct hostapd_data * hapd,const struct ieee80211_mgmt * mgmt,size_t len,const u8 * pos,u16 status_code)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 
auth_skip_fixed_fields(struct hostapd_data * hapd,const struct ieee80211_mgmt * mgmt,size_t len)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 
hostapd_process_ml_auth(struct hostapd_data * hapd,const struct ieee80211_mgmt * mgmt,size_t len)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 
hostapd_mld_validate_assoc_info(struct hostapd_data * hapd,struct sta_info * sta)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 
hostapd_process_ml_assoc_req_addr(struct hostapd_data * hapd,const u8 * basic_mle,size_t basic_mle_len,u8 * mld_addr)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 
hostapd_process_ml_assoc_req(struct hostapd_data * hapd,struct ieee802_11_elems * elems,struct sta_info * sta)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