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 = hostapd_get_active_links(hapd);
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 	if (len - 2 < prime_len * (ec ? 3 : 2))
875 		goto truncated;
876 	/* scalar */
877 	pos += prime_len;
878 
879 	if (ec) {
880 		pos += prime_len * 2;
881 		crypto_ec_deinit(ec);
882 	} else {
883 		pos += prime_len;
884 	}
885 
886 	if (pos - mgmt->u.auth.variable > (int) len) {
887 	truncated:
888 		wpa_printf(MSG_DEBUG,
889 			   "EHT: Too short SAE commit Authentication frame");
890 		return NULL;
891 	}
892 
893 	wpa_hexdump(MSG_DEBUG, "EHT: SAE: Authentication frame elements",
894 		    pos, (int) len - (pos - mgmt->u.auth.variable));
895 
896 	return pos;
897 }
898 
899 
900 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)901 sae_confirm_skip_fixed_fields(struct hostapd_data *hapd,
902 			      const struct ieee80211_mgmt *mgmt, size_t len,
903 			      const u8 *pos, u16 status_code)
904 {
905 	struct sta_info *sta;
906 
907 	if (status_code == WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION)
908 		return pos;
909 
910 	/* send confirm integer */
911 	if (len < 2)
912 		goto truncated;
913 	pos += 2;
914 
915 	/*
916 	 * At this stage we should already have an MLD station and actually SA
917 	 * will be replaced with the MLD MAC address by the driver. However,
918 	 * there is at least a theoretical race condition in a case where the
919 	 * peer sends the SAE confirm message quickly enough for the driver
920 	 * translation mechanism to not be available to update the SAE confirm
921 	 * message addresses. Work around that by searching for the STA entry
922 	 * using the link address of the non-AP MLD if no match is found based
923 	 * on the MLD MAC address.
924 	 */
925 	sta = ap_get_sta(hapd, mgmt->sa);
926 	if (!sta) {
927 		wpa_printf(MSG_DEBUG, "SAE: No MLD STA for SAE confirm");
928 		for (sta = hapd->sta_list; sta; sta = sta->next) {
929 			int link_id = hapd->mld_link_id;
930 
931 			if (!sta->mld_info.mld_sta ||
932 			    sta->mld_info.links[link_id].valid ||
933 			    !ether_addr_equal(
934 				    mgmt->sa,
935 				    sta->mld_info.links[link_id].peer_addr))
936 				continue;
937 			wpa_printf(MSG_DEBUG,
938 				   "SAE: Found MLD STA for SAE confirm based on link address");
939 			break;
940 		}
941 		if (!sta)
942 			return NULL;
943 	}
944 
945 	if (!sta->sae || sta->sae->state < SAE_COMMITTED || !sta->sae->tmp) {
946 		if (sta->sae)
947 			wpa_printf(MSG_DEBUG, "SAE: Invalid state=%u",
948 				   sta->sae->state);
949 		else
950 			wpa_printf(MSG_DEBUG, "SAE: No SAE context");
951 		return NULL;
952 	}
953 
954 	wpa_printf(MSG_DEBUG, "SAE: confirm: kck_len=%zu",
955 		   sta->sae->tmp->kck_len);
956 
957 	if (len - 2 < sta->sae->tmp->kck_len)
958 		goto truncated;
959 	pos += sta->sae->tmp->kck_len;
960 
961 	if (pos - mgmt->u.auth.variable > (int) len) {
962 	truncated:
963 		wpa_printf(MSG_DEBUG,
964 			   "EHT: Too short SAE confirm Authentication frame");
965 		return NULL;
966 	}
967 
968 	return pos;
969 }
970 
971 #endif /* CONFIG_SAE */
972 
973 
auth_skip_fixed_fields(struct hostapd_data * hapd,const struct ieee80211_mgmt * mgmt,size_t len)974 static const u8 * auth_skip_fixed_fields(struct hostapd_data *hapd,
975 					 const struct ieee80211_mgmt *mgmt,
976 					 size_t len)
977 {
978 	u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
979 #ifdef CONFIG_SAE
980 	u16 auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
981 	u16 status_code = le_to_host16(mgmt->u.auth.status_code);
982 #endif /* CONFIG_SAE */
983 	const u8 *pos = mgmt->u.auth.variable;
984 
985 	/* Skip fixed fields as based on IEE P802.11-REVme/D3.0, Table 9-69
986 	 * (Presence of fields and elements in Authentications frames) */
987 	switch (auth_alg) {
988 	case WLAN_AUTH_OPEN:
989 		return pos;
990 #ifdef CONFIG_SAE
991 	case WLAN_AUTH_SAE:
992 		if (auth_transaction == 1) {
993 			if (status_code == WLAN_STATUS_SUCCESS) {
994 				wpa_printf(MSG_DEBUG,
995 					   "EHT: SAE H2E is mandatory for MLD");
996 				goto out;
997 			}
998 
999 			return sae_commit_skip_fixed_fields(mgmt, len, pos,
1000 							    status_code);
1001 		} else if (auth_transaction == 2) {
1002 			return sae_confirm_skip_fixed_fields(hapd, mgmt, len,
1003 							     pos, status_code);
1004 		}
1005 
1006 		return pos;
1007 #endif /* CONFIG_SAE */
1008 	/* TODO: Support additional algorithms that can be used for MLO */
1009 	case WLAN_AUTH_FT:
1010 	case WLAN_AUTH_FILS_SK:
1011 	case WLAN_AUTH_FILS_SK_PFS:
1012 	case WLAN_AUTH_FILS_PK:
1013 	case WLAN_AUTH_PASN:
1014 	default:
1015 		break;
1016 	}
1017 
1018 #ifdef CONFIG_SAE
1019 out:
1020 #endif /* CONFIG_SAE */
1021 	wpa_printf(MSG_DEBUG,
1022 		   "TODO: Authentication algorithm %u not supported with MLD",
1023 		   auth_alg);
1024 	return NULL;
1025 }
1026 
1027 
hostapd_process_ml_auth(struct hostapd_data * hapd,const struct ieee80211_mgmt * mgmt,size_t len)1028 const u8 * hostapd_process_ml_auth(struct hostapd_data *hapd,
1029 				   const struct ieee80211_mgmt *mgmt,
1030 				   size_t len)
1031 {
1032 	struct ieee802_11_elems elems;
1033 	const u8 *pos;
1034 
1035 	if (!hapd->conf->mld_ap)
1036 		return NULL;
1037 
1038 	len -= offsetof(struct ieee80211_mgmt, u.auth.variable);
1039 
1040 	pos = auth_skip_fixed_fields(hapd, mgmt, len);
1041 	if (!pos)
1042 		return NULL;
1043 
1044 	if (ieee802_11_parse_elems(pos,
1045 				   (int)len - (pos - mgmt->u.auth.variable),
1046 				   &elems, 0) == ParseFailed) {
1047 		wpa_printf(MSG_DEBUG,
1048 			   "MLD: Failed parsing Authentication frame");
1049 	}
1050 
1051 	if (!elems.basic_mle || !elems.basic_mle_len)
1052 		return NULL;
1053 
1054 	return get_basic_mle_mld_addr(elems.basic_mle, elems.basic_mle_len);
1055 }
1056 
1057 
hostapd_mld_validate_assoc_info(struct hostapd_data * hapd,struct sta_info * sta)1058 static int hostapd_mld_validate_assoc_info(struct hostapd_data *hapd,
1059 					   struct sta_info *sta)
1060 {
1061 	u8 link_id;
1062 	struct mld_info *info = &sta->mld_info;
1063 
1064 	if (!ap_sta_is_mld(hapd, sta)) {
1065 		wpa_printf(MSG_DEBUG, "MLD: Not a non-AP MLD");
1066 		return 0;
1067 	}
1068 
1069 	/*
1070 	 * Iterate over the links negotiated in the (Re)Association Request
1071 	 * frame and validate that they are indeed valid links in the local AP
1072 	 * MLD.
1073 	 *
1074 	 * While at it, also update the local address for the links in the
1075 	 * mld_info, so it could be easily available for later flows, e.g., for
1076 	 * the RSN Authenticator, etc.
1077 	 */
1078 	for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
1079 		struct hostapd_data *other_hapd;
1080 
1081 		if (!info->links[link_id].valid || link_id == hapd->mld_link_id)
1082 			continue;
1083 
1084 		other_hapd = hostapd_mld_get_link_bss(hapd, link_id);
1085 		if (!other_hapd) {
1086 			wpa_printf(MSG_DEBUG, "MLD: Invalid link ID=%u",
1087 				   link_id);
1088 			return -1;
1089 		}
1090 
1091 		os_memcpy(info->links[link_id].local_addr, other_hapd->own_addr,
1092 			  ETH_ALEN);
1093 	}
1094 
1095 	return 0;
1096 }
1097 
1098 
hostapd_process_ml_assoc_req_addr(struct hostapd_data * hapd,const u8 * basic_mle,size_t basic_mle_len,u8 * mld_addr)1099 int hostapd_process_ml_assoc_req_addr(struct hostapd_data *hapd,
1100 				      const u8 *basic_mle, size_t basic_mle_len,
1101 				      u8 *mld_addr)
1102 {
1103 	struct wpabuf *mlbuf = ieee802_11_defrag(basic_mle, basic_mle_len,
1104 						 true);
1105 	struct ieee80211_eht_ml *ml;
1106 	struct eht_ml_basic_common_info *common_info;
1107 	size_t ml_len, common_info_len;
1108 	int ret = -1;
1109 	u16 ml_control;
1110 
1111 	if (!mlbuf)
1112 		return WLAN_STATUS_SUCCESS;
1113 
1114 	ml = (struct ieee80211_eht_ml *) wpabuf_head(mlbuf);
1115 	ml_len = wpabuf_len(mlbuf);
1116 
1117 	if (ml_len < sizeof(*ml))
1118 		goto out;
1119 
1120 	ml_control = le_to_host16(ml->ml_control);
1121 	if ((ml_control & MULTI_LINK_CONTROL_TYPE_MASK) !=
1122 	    MULTI_LINK_CONTROL_TYPE_BASIC) {
1123 		wpa_printf(MSG_DEBUG, "MLD: Invalid ML type=%u",
1124 			   ml_control & MULTI_LINK_CONTROL_TYPE_MASK);
1125 		goto out;
1126 	}
1127 
1128 	/* Common Info Length and MLD MAC Address must always be present */
1129 	common_info_len = 1 + ETH_ALEN;
1130 	/* Ignore optional fields */
1131 
1132 	if (sizeof(*ml) + common_info_len > ml_len) {
1133 		wpa_printf(MSG_DEBUG, "MLD: Not enough bytes for common info");
1134 		goto out;
1135 	}
1136 
1137 	common_info = (struct eht_ml_basic_common_info *) ml->variable;
1138 
1139 	/* Common information length includes the length octet */
1140 	if (common_info->len < common_info_len) {
1141 		wpa_printf(MSG_DEBUG,
1142 			   "MLD: Invalid common info len=%u", common_info->len);
1143 		goto out;
1144 	}
1145 
1146 	/* Get the MLD MAC Address */
1147 	os_memcpy(mld_addr, common_info->mld_addr, ETH_ALEN);
1148 	ret = 0;
1149 
1150 out:
1151 	wpabuf_free(mlbuf);
1152 	return ret;
1153 }
1154 
1155 
hostapd_process_ml_assoc_req(struct hostapd_data * hapd,struct ieee802_11_elems * elems,struct sta_info * sta)1156 u16 hostapd_process_ml_assoc_req(struct hostapd_data *hapd,
1157 				 struct ieee802_11_elems *elems,
1158 				 struct sta_info *sta)
1159 {
1160 	struct wpabuf *mlbuf;
1161 	const struct ieee80211_eht_ml *ml;
1162 	const struct eht_ml_basic_common_info *common_info;
1163 	size_t ml_len, common_info_len;
1164 	struct mld_link_info *link_info;
1165 	struct mld_info *info = &sta->mld_info;
1166 	const u8 *pos, *end;
1167 	int ret = -1;
1168 	u16 ml_control;
1169 	const u8 *ml_end;
1170 
1171 	mlbuf = ieee802_11_defrag(elems->basic_mle, elems->basic_mle_len, true);
1172 	if (!mlbuf)
1173 		return WLAN_STATUS_SUCCESS;
1174 
1175 	ml = wpabuf_head(mlbuf);
1176 	ml_len = wpabuf_len(mlbuf);
1177 	ml_end = ((const u8 *) ml) + ml_len;
1178 
1179 	ml_control = le_to_host16(ml->ml_control);
1180 	if ((ml_control & MULTI_LINK_CONTROL_TYPE_MASK) !=
1181 	    MULTI_LINK_CONTROL_TYPE_BASIC) {
1182 		wpa_printf(MSG_DEBUG, "MLD: Invalid ML type=%u",
1183 			   ml_control & MULTI_LINK_CONTROL_TYPE_MASK);
1184 		goto out;
1185 	}
1186 
1187 	/* Common Info length and MLD MAC address must always be present */
1188 	common_info_len = 1 + ETH_ALEN;
1189 
1190 	if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_LINK_ID) {
1191 		wpa_printf(MSG_DEBUG, "MLD: Link ID info not expected");
1192 		goto out;
1193 	}
1194 
1195 	if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT) {
1196 		wpa_printf(MSG_DEBUG, "MLD: BSS params change not expected");
1197 		goto out;
1198 	}
1199 
1200 	if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MSD_INFO) {
1201 		wpa_printf(MSG_DEBUG, "MLD: Sync delay not expected");
1202 		goto out;
1203 	}
1204 
1205 	if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA) {
1206 		common_info_len += 2;
1207 	} else {
1208 		wpa_printf(MSG_DEBUG, "MLD: EML capabilities not present");
1209 	}
1210 
1211 	if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA) {
1212 		common_info_len += 2;
1213 
1214 	} else {
1215 		wpa_printf(MSG_DEBUG, "MLD: MLD capabilities not present");
1216 		goto out;
1217 	}
1218 
1219 	if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_EXT_MLD_CAP) {
1220 		common_info_len += 2;
1221 	} else {
1222 		wpa_printf(MSG_DEBUG, "MLD: EXT ML capabilities not present");
1223 	}
1224 
1225 	wpa_printf(MSG_DEBUG, "MLD: expected_common_info_len=%lu",
1226 		   common_info_len);
1227 
1228 	if (sizeof(*ml) + common_info_len > ml_len) {
1229 		wpa_printf(MSG_DEBUG, "MLD: Not enough bytes for common info");
1230 		goto out;
1231 	}
1232 
1233 	common_info = (const struct eht_ml_basic_common_info *) ml->variable;
1234 
1235 	/* Common information length includes the length octet */
1236 	if (common_info->len < common_info_len) {
1237 		wpa_printf(MSG_DEBUG,
1238 			   "MLD: Invalid common info len=%u (expected %zu)",
1239 			   common_info->len, common_info_len);
1240 		goto out;
1241 	}
1242 
1243 	pos = common_info->variable;
1244 	end = ((const u8 *) common_info) + common_info->len;
1245 
1246 	if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA) {
1247 		info->common_info.eml_capa = WPA_GET_LE16(pos);
1248 		pos += 2;
1249 	} else {
1250 		info->common_info.eml_capa = 0;
1251 	}
1252 
1253 	info->common_info.mld_capa = WPA_GET_LE16(pos);
1254 	pos += 2;
1255 
1256 	if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_EXT_MLD_CAP) {
1257 		pos += 2;
1258 	}
1259 
1260 	wpa_printf(MSG_DEBUG, "MLD: addr=" MACSTR ", eml=0x%x, mld=0x%x",
1261 		   MAC2STR(info->common_info.mld_addr),
1262 		   info->common_info.eml_capa, info->common_info.mld_capa);
1263 
1264 	/* Check the MLD MAC Address */
1265 	if (!ether_addr_equal(info->common_info.mld_addr,
1266 			      common_info->mld_addr)) {
1267 		wpa_printf(MSG_DEBUG,
1268 			   "MLD: MLD address mismatch between authentication ("
1269 			   MACSTR ") and association (" MACSTR ")",
1270 			   MAC2STR(info->common_info.mld_addr),
1271 			   MAC2STR(common_info->mld_addr));
1272 		goto out;
1273 	}
1274 
1275 	info->links[hapd->mld_link_id].valid = 1;
1276 
1277 	/* Parse the Link Info field that starts after the end of the variable
1278 	 * length Common Info field. */
1279 	pos = end;
1280 	while (ml_end - pos > 2) {
1281 		size_t sub_elem_len = *(pos + 1);
1282 		size_t sta_info_len;
1283 		u16 control;
1284 		const u8 *sub_elem_end;
1285 
1286 		wpa_printf(MSG_DEBUG, "MLD: sub element len=%zu",
1287 			   sub_elem_len);
1288 
1289 		if (2 + sub_elem_len > (size_t) (ml_end - pos)) {
1290 			wpa_printf(MSG_DEBUG,
1291 				   "MLD: Invalid link info len: %zu %zu",
1292 				   2 + sub_elem_len, ml_end - pos);
1293 			goto out;
1294 		}
1295 
1296 		if (*pos == MULTI_LINK_SUB_ELEM_ID_VENDOR) {
1297 			wpa_printf(MSG_DEBUG,
1298 				   "MLD: Skip vendor specific subelement");
1299 
1300 			pos += 2 + sub_elem_len;
1301 			continue;
1302 		}
1303 
1304 		if (*pos != MULTI_LINK_SUB_ELEM_ID_PER_STA_PROFILE) {
1305 			wpa_printf(MSG_DEBUG,
1306 				   "MLD: Skip unknown Multi-Link element subelement ID=%u",
1307 				   *pos);
1308 			pos += 2 + sub_elem_len;
1309 			continue;
1310 		}
1311 
1312 		/* Skip the subelement ID and the length */
1313 		pos += 2;
1314 		sub_elem_end = pos + sub_elem_len;
1315 
1316 		/* Get the station control field */
1317 		if (sub_elem_end - pos < 2) {
1318 			wpa_printf(MSG_DEBUG,
1319 				   "MLD: Too short Per-STA Profile subelement");
1320 			goto out;
1321 		}
1322 		control = WPA_GET_LE16(pos);
1323 		link_info = &info->links[control &
1324 					 EHT_PER_STA_CTRL_LINK_ID_MSK];
1325 		pos += 2;
1326 
1327 		if (!(control & EHT_PER_STA_CTRL_COMPLETE_PROFILE_MSK)) {
1328 			wpa_printf(MSG_DEBUG,
1329 				   "MLD: Per-STA complete profile expected");
1330 			goto out;
1331 		}
1332 
1333 		if (!(control & EHT_PER_STA_CTRL_MAC_ADDR_PRESENT_MSK)) {
1334 			wpa_printf(MSG_DEBUG,
1335 				   "MLD: Per-STA MAC address not present");
1336 			goto out;
1337 		}
1338 
1339 		if ((control & (EHT_PER_STA_CTRL_BEACON_INTERVAL_PRESENT_MSK |
1340 				EHT_PER_STA_CTRL_DTIM_INFO_PRESENT_MSK))) {
1341 			wpa_printf(MSG_DEBUG,
1342 				   "MLD: Beacon/DTIM interval not expected");
1343 			goto out;
1344 		}
1345 
1346 		/* The length octet and the MAC address must be present */
1347 		sta_info_len = 1 + ETH_ALEN;
1348 
1349 		if (control & EHT_PER_STA_CTRL_NSTR_LINK_PAIR_PRESENT_MSK) {
1350 			if (control & EHT_PER_STA_CTRL_NSTR_BM_SIZE_MSK)
1351 				link_info->nstr_bitmap_len = 2;
1352 			else
1353 				link_info->nstr_bitmap_len = 1;
1354 		}
1355 
1356 		sta_info_len += link_info->nstr_bitmap_len;
1357 
1358 		if (sta_info_len > (size_t) (sub_elem_end - pos) ||
1359 		    sta_info_len > *pos ||
1360 		    *pos > sub_elem_end - pos ||
1361 		    sta_info_len > (size_t) (sub_elem_end - pos)) {
1362 			wpa_printf(MSG_DEBUG, "MLD: Invalid STA Info length");
1363 			goto out;
1364 		}
1365 
1366 		sta_info_len = *pos;
1367 		end = pos + sta_info_len;
1368 
1369 		/* skip the length */
1370 		pos++;
1371 
1372 		/* get the link address */
1373 		os_memcpy(link_info->peer_addr, pos, ETH_ALEN);
1374 		wpa_printf(MSG_DEBUG,
1375 			   "MLD: assoc: link id=%u, addr=" MACSTR,
1376 			   control & EHT_PER_STA_CTRL_LINK_ID_MSK,
1377 			   MAC2STR(link_info->peer_addr));
1378 
1379 		pos += ETH_ALEN;
1380 
1381 		/* Get the NSTR bitmap */
1382 		if (link_info->nstr_bitmap_len) {
1383 			os_memcpy(link_info->nstr_bitmap, pos,
1384 				  link_info->nstr_bitmap_len);
1385 			pos += link_info->nstr_bitmap_len;
1386 		}
1387 
1388 		pos = end;
1389 
1390 		if (sub_elem_end - pos >= 2)
1391 			link_info->capability = WPA_GET_LE16(pos);
1392 
1393 		pos = sub_elem_end;
1394 
1395 		wpa_printf(MSG_DEBUG, "MLD: link ctrl=0x%x, " MACSTR
1396 			   ", nstr bitmap len=%u",
1397 			   control, MAC2STR(link_info->peer_addr),
1398 			   link_info->nstr_bitmap_len);
1399 
1400 		link_info->valid = true;
1401 	}
1402 
1403 	ret = hostapd_mld_validate_assoc_info(hapd, sta);
1404 out:
1405 	wpabuf_free(mlbuf);
1406 	if (ret) {
1407 		os_memset(info, 0, sizeof(*info));
1408 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
1409 	}
1410 
1411 	return WLAN_STATUS_SUCCESS;
1412 }
1413