[PATCH 07/13] SME: Add support for handling authentication with MLD

Andrei Otcheretianski andrei.otcheretianski at intel.com
Thu Nov 24 04:45:27 PST 2022


In case that the AP supports MLD, request an MLD authentication
from the driver.
When processing the authentication event from the driver verify
that the MLD address in the authentication data matches that of
the requested AP.

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
 src/common/ieee802_11_common.h    |   1 +
 src/drivers/driver.h              |   2 +
 wpa_supplicant/bss.c              |  18 +++
 wpa_supplicant/bss.h              |   1 +
 wpa_supplicant/events.c           |   2 +-
 wpa_supplicant/sme.c              | 191 ++++++++++++++++++++++++++++++
 wpa_supplicant/wpa_supplicant_i.h |   1 +
 7 files changed, 215 insertions(+), 1 deletion(-)

diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 0d258dfb87..178f33cf0c 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -344,5 +344,6 @@ struct wpabuf * ieee802_11_defrag(struct ieee802_11_elems *elems,
 struct wpabuf * ieee802_11_defrag_mle(struct ieee802_11_elems *elems, u8 type);
 const u8 * get_ml_ie(const u8 *ies, size_t len, u8 type);
 const u8 * get_basic_mle_mld_addr(const u8 *buf, size_t len);
+const u8 *parse_ml_auth(struct ieee80211_eht_ml *ml, size_t ml_len);
 
 #endif /* IEEE802_11_COMMON_H */
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 3d7e0356d4..437bc3b38a 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -2153,6 +2153,8 @@ struct wpa_driver_capa {
  * frames in STA mode
  */
 #define WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_STA	0x0000000000002000ULL
+/** Driver supports MLO in station/AP mode */
+#define WPA_DRIVER_FLAGS2_MLO			0x0000000000004000ULL
 	u64 flags2;
 
 #define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 401c5342ee..265082b2f0 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -1445,3 +1445,21 @@ int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab)
 	return ieee802_11_ext_capab(wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB),
 				    capab);
 }
+
+
+/**
+ * wpa_bss_defrag_mle - Get a buffer holding a de-fragmented ML element
+ * @bss: BSS table entry
+ * @type: ML control type
+ */
+struct wpabuf *wpa_bss_defrag_mle(const struct wpa_bss *bss, u8 type)
+{
+	struct ieee802_11_elems elems;
+	const u8 *pos = wpa_bss_ie_ptr(bss);
+	size_t len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
+
+	if (ieee802_11_parse_elems(pos, len, &elems, 1) == ParseFailed)
+		return NULL;
+
+	return ieee802_11_defrag_mle(&elems, type);
+}
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index b68fc879d0..b7ea211cbd 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -201,4 +201,5 @@ void calculate_update_time(const struct os_reltime *fetch_time,
 			   unsigned int age_ms,
 			   struct os_reltime *update_time);
 
+struct wpabuf *wpa_bss_defrag_mle(const struct wpa_bss *bss, u8 type);
 #endif /* BSS_H */
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 91c0e7eb2d..5cad35514b 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -308,7 +308,7 @@ void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx)
 }
 
 
-static void wpas_reset_mlo_info(struct wpa_supplicant *wpa_s)
+void wpas_reset_mlo_info(struct wpa_supplicant *wpa_s)
 {
 	if (!wpa_s->valid_links)
 		return;
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index e1abb8b1bb..1346a409e9 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -364,6 +364,186 @@ static void sme_auth_handle_rrm(struct wpa_supplicant *wpa_s,
 }
 
 
+static bool wpas_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+	struct wpabuf *mlbuf;
+	const u8 *rnr_ie, *pos;
+	u8 ml_ie_len, rnr_ie_len;
+	struct ieee80211_eht_ml *eht_ml;
+	struct eht_ml_basic_common_info *ml_basic_common_info;
+	u8 i;
+	const u16 control =
+		host_to_le16(MULTI_LINK_CONTROL_TYPE_BASIC |
+			     BASIC_MULTI_LINK_CTRL_PRES_LINK_ID |
+			     BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT |
+			     BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA);
+	bool ret = false;
+
+	if (!(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "MLD: not supported by driver");
+		return false;
+	}
+
+	mlbuf = wpa_bss_defrag_mle(bss, MULTI_LINK_CONTROL_TYPE_BASIC);
+	if (!mlbuf) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "MLD: no ML element");
+		return false;
+	}
+
+	ml_ie_len = wpabuf_len(mlbuf);
+
+	/* control + common info len + MLD address + MLD link information */
+	if (ml_ie_len < 2 + 1 + ETH_ALEN + 1)
+		goto out;
+
+	eht_ml = (struct ieee80211_eht_ml *)wpabuf_head(mlbuf);
+	if ((eht_ml->ml_control & control) != control) {
+		wpa_printf(MSG_DEBUG, "MLD: unexpected ML element control=0x%x",
+			   eht_ml->ml_control);
+		goto out;
+	}
+
+	ml_basic_common_info =
+		(struct eht_ml_basic_common_info *)eht_ml->variable;
+
+	/* common info length should be valid (self, mld_addr, link_id) */
+	if (ml_basic_common_info->len < 1 + ETH_ALEN + 1)
+		goto out;
+
+	/* get the MLD address and MLD link ID */
+	os_memcpy(wpa_s->ap_mld_addr, ml_basic_common_info->mld_addr,
+		  ETH_ALEN);
+	wpa_s->mlo_assoc_link_id = ml_basic_common_info->variable[0] &
+				   EHT_ML_LINK_ID_MSK;
+
+	os_memcpy(wpa_s->links[wpa_s->mlo_assoc_link_id].bssid, bss->bssid,
+		  ETH_ALEN);
+	wpa_s->links[wpa_s->mlo_assoc_link_id].freq = bss->freq;
+
+	wpa_printf(MSG_DEBUG, "MLD: address=" MACSTR ", link ID=%u",
+		   MAC2STR(wpa_s->ap_mld_addr),
+		   wpa_s->mlo_assoc_link_id);
+
+	wpa_s->mld = 1;
+	wpa_s->valid_links = BIT(wpa_s->mlo_assoc_link_id);
+
+	rnr_ie = wpa_bss_get_ie(bss, WLAN_EID_REDUCED_NEIGHBOR_REPORT);
+	if (!rnr_ie) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "MLD: no RNR element");
+		ret = true;
+		goto out;
+	}
+
+	rnr_ie_len = rnr_ie[1];
+	pos = rnr_ie + 2;
+
+	while (rnr_ie_len > sizeof(struct ieee80211_neighbor_ap_info)) {
+		struct ieee80211_neighbor_ap_info *ap_info =
+			(struct ieee80211_neighbor_ap_info *)pos;
+		const u8 *data = ap_info->data;
+
+		wpa_printf(MSG_DEBUG, "MLD: op_class=%u, channel=%u",
+			   ap_info->op_class, ap_info->channel);
+
+		if (ap_info->tbtt_info_len < 16) {
+			rnr_ie_len -=
+				sizeof(struct ieee80211_neighbor_ap_info) +
+				ap_info->tbtt_info_len;
+
+			pos += sizeof(struct ieee80211_neighbor_ap_info) +
+				ap_info->tbtt_info_len;
+			continue;
+		}
+
+		data += 13;
+
+		wpa_printf(MSG_DEBUG, "MLD: mld ID=%u, link ID=%u",
+			   *data, *(data + 1) & 0xF);
+
+		if (*data) {
+			wpa_printf(MSG_DEBUG,
+				   "MLD: reported link not part of MLD");
+		} else {
+			struct wpa_bss *neigh_bss =
+				wpa_bss_get_bssid(wpa_s, ap_info->data + 1);
+			u8 link_id = *(data + 1) & 0xF;
+
+			if (neigh_bss) {
+				wpa_s->valid_links |= BIT(link_id);
+				os_memcpy(wpa_s->links[link_id].bssid,
+					  ap_info->data + 1, ETH_ALEN);
+				wpa_s->links[link_id].freq =
+					neigh_bss->freq;
+			} else {
+				wpa_printf(MSG_DEBUG,
+					   "MLD: neighbor not found in scan");
+			}
+		}
+
+		rnr_ie_len -= sizeof(struct ieee80211_neighbor_ap_info) +
+			ap_info->tbtt_info_len;
+
+		pos += sizeof(struct ieee80211_neighbor_ap_info) +
+			ap_info->tbtt_info_len;
+	}
+
+	wpa_printf(MSG_DEBUG, "MLD: valid_links=0x%x", wpa_s->valid_links);
+
+	for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+		if (!(wpa_s->valid_links & BIT(i)))
+			continue;
+
+		wpa_printf(MSG_DEBUG, "MLD: link=%u, bssid=" MACSTR,
+			   i,
+			   MAC2STR(wpa_s->links[i].bssid));
+	}
+
+	ret = true;
+out:
+	wpabuf_free(mlbuf);
+	return ret;
+}
+
+
+static void wpas_sme_ml_auth(struct wpa_supplicant *wpa_s,
+			     union wpa_event_data *data)
+{
+	struct ieee802_11_elems elems;
+	const u8 *mld_addr;
+
+	if (!wpa_s->mld)
+		return;
+
+	if (ieee802_11_parse_elems(data->auth.ies, data->auth.ies_len,
+				   &elems, 0) != ParseOK) {
+		wpa_printf(MSG_DEBUG, "MLD: failed parsing elements");
+		goto out;
+	}
+
+	if (!elems.basic_mle || !elems.basic_mle_len) {
+		wpa_printf(MSG_DEBUG, "MLD: no ML element in auth");
+		goto out;
+	}
+
+	mld_addr = get_basic_mle_mld_addr(elems.basic_mle, elems.basic_mle_len);
+	if (!mld_addr)
+		goto out;
+
+	wpa_printf(MSG_DEBUG, "MLD: mld_address=" MACSTR,
+		   MAC2STR(mld_addr));
+
+	if (os_memcmp(wpa_s->ap_mld_addr, mld_addr, ETH_ALEN)) {
+		wpa_printf(MSG_DEBUG, "MLD: invalid MLD address");
+		goto out;
+	}
+
+	return;
+out:
+	wpa_printf(MSG_DEBUG, "MLD: auth: clearing MLD state");
+	wpas_reset_mlo_info(wpa_s);
+}
+
+
 static void sme_send_authentication(struct wpa_supplicant *wpa_s,
 				    struct wpa_bss *bss, struct wpa_ssid *ssid,
 				    int start)
@@ -793,6 +973,13 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
 	}
 #endif /* CONFIG_MBO */
 
+	if (wpas_ml_element(wpa_s, bss)) {
+		wpa_printf(MSG_DEBUG, "MLD: in authentication");
+		params.mld = true;
+		params.mld_link_id = wpa_s->mlo_assoc_link_id;
+		params.ap_mld_addr = wpa_s->ap_mld_addr;
+	}
+
 #ifdef CONFIG_SAE
 	if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE &&
 	    pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, 0,
@@ -1785,6 +1972,10 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
 	}
 #endif /* CONFIG_FILS */
 
+	/* TODO: Support for other auth_type as well */
+	if (data->auth.auth_type == WLAN_AUTH_OPEN)
+		wpas_sme_ml_auth(wpa_s, data);
+
 	sme_associate(wpa_s, ssid->mode, data->auth.peer,
 		      data->auth.auth_type);
 }
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 9e1ee269c8..ee4749ad27 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1754,6 +1754,7 @@ void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s,
 int wpa_supplicant_need_to_roam_within_ess(struct wpa_supplicant *wpa_s,
 					   struct wpa_bss *current_bss,
 					   struct wpa_bss *seleceted);
+void wpas_reset_mlo_info(struct wpa_supplicant *wpa_s);
 
 /* eap_register.c */
 int eap_register_methods(void);
-- 
2.25.1




More information about the Hostap mailing list