[PATCH v4 11/13] MLD STA: Add support for SAE external authentication

Veerendranath Jakkam quic_vjakkam at quicinc.com
Thu Nov 3 01:08:54 PDT 2022


This commit does below:
- Enable MLO for SAE authentication when driver indicates transmit
  address(TA).
- Add basic ML IE in SAE authentication frames.
- Use TA address provided by driver for sending SAE authentication
  frames.
- Use MLD address for SAE PWE derivation.
- Allow authentication frames with RA address same as TA address
  provided by driver.

Signed-off-by: Veerendranath Jakkam <quic_vjakkam at quicinc.com>
---
 src/drivers/driver.h               |   3 +
 src/drivers/driver_nl80211.h       |   1 +
 src/drivers/driver_nl80211_event.c |  17 +++++
 wpa_supplicant/sme.c               | 107 ++++++++++++++++++++++-------
 wpa_supplicant/wpa_supplicant_i.h  |   2 +
 5 files changed, 106 insertions(+), 24 deletions(-)

diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 573dd7dd5..0fe416928 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -2623,6 +2623,8 @@ enum wpa_drv_update_connect_params_mask {
  *	the real status code for failures. Used only for the request interface
  *	from user space to the driver.
  * @pmkid: Generated PMKID as part of external auth exchange (e.g., SAE).
+ * @tx_addr: Transmit address to be used for the authentication frames. Optional
+ *	for the request interface.
  */
 struct external_auth {
 	enum {
@@ -2635,6 +2637,7 @@ struct external_auth {
 	unsigned int key_mgmt_suite;
 	u16 status;
 	const u8 *pmkid;
+	const u8 *tx_addr;
 };
 
 #define WPAS_MAX_PASN_PEERS 10
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 0b8b0ce11..40e845d78 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -80,6 +80,7 @@ struct i802_bss {
 	struct nl80211_wiphy_data *wiphy_data;
 	struct dl_list wiphy_list;
 	u8 rand_addr[ETH_ALEN];
+	u8 ext_auth_rand_addr[ETH_ALEN];
 };
 
 struct drv_nl80211_if_info {
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 2e199c49a..1777236e7 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -1425,6 +1425,10 @@ static void mlme_event(struct i802_bss *bss,
 		   MAC2STR(bss->addr), MAC2STR(data + 4),
 		   MAC2STR(data + 4 + ETH_ALEN));
 
+	if (!is_zero_ether_addr(bss->ext_auth_rand_addr) &&
+	    os_memcmp(bss->ext_auth_rand_addr, data + 4, ETH_ALEN) == 0)
+		goto skip_ra_check;
+
 	/* PASN Authentication frame can be received with a different source MAC
 	 * address. Allow NL80211_CMD_FRAME event with foreign addresses also.
 	 */
@@ -1453,6 +1457,8 @@ static void mlme_event(struct i802_bss *bss,
 			   "for foreign address", bss->ifname);
 		return;
 	}
+
+skip_ra_check:
 	wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame",
 		    nla_data(frame), nla_len(frame));
 
@@ -3131,6 +3137,17 @@ static void nl80211_external_auth(struct wpa_driver_nl80211_data *drv,
 
 	event.external_auth.bssid = nla_data(tb[NL80211_ATTR_BSSID]);
 
+	if (tb[NL80211_ATTR_MAC]) {
+		event.external_auth.tx_addr = nla_data(tb[NL80211_ATTR_MAC]);
+		wpa_printf(MSG_ERROR, "TA addr for external auth: " MACSTR,
+			   MAC2STR(event.external_auth.tx_addr));
+		os_memcpy(drv->first_bss->ext_auth_rand_addr,
+			  event.external_auth.tx_addr,
+			  ETH_ALEN);
+	} else {
+		os_memset(drv->first_bss->ext_auth_rand_addr, 0, ETH_ALEN);
+	}
+
 	wpa_printf(MSG_DEBUG,
 		   "nl80211: External auth action: %u, AKM: 0x%x",
 		   event.external_auth.action,
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 896fa9df4..e6e39c4c3 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -95,6 +95,7 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
 	int use_pt = 0;
 	bool use_pk = false;
 	u8 rsnxe_capa = 0;
+	const u8 *peer_addr = bssid;
 
 	if (ret_use_pt)
 		*ret_use_pt = 0;
@@ -124,19 +125,6 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
 		return NULL;
 	}
 
-	if (reuse && wpa_s->sme.sae.tmp &&
-	    os_memcmp(bssid, wpa_s->sme.sae.tmp->bssid, ETH_ALEN) == 0) {
-		wpa_printf(MSG_DEBUG,
-			   "SAE: Reuse previously generated PWE on a retry with the same AP");
-		use_pt = wpa_s->sme.sae.h2e;
-		use_pk = wpa_s->sme.sae.pk;
-		goto reuse_data;
-	}
-	if (sme_set_sae_group(wpa_s) < 0) {
-		wpa_printf(MSG_DEBUG, "SAE: Failed to select group");
-		return NULL;
-	}
-
 	bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
 	if (!bss) {
 		wpa_printf(MSG_DEBUG,
@@ -150,6 +138,31 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
 		rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
 		if (rsnxe && rsnxe[1] >= 1)
 			rsnxe_capa = rsnxe[2];
+
+		if (external && wpa_s->sme.ext_ml_auth) {
+			if (is_zero_ether_addr(bss->mld_addr)) {
+				wpa_printf(MSG_DEBUG,
+					   "SAE: BSS not affliated with MLD");
+				return NULL;
+			}
+
+			wpa_printf(MSG_DEBUG, "SAE: AP MLD address: " MACSTR,
+				   MAC2STR(bss->mld_addr));
+			peer_addr = bss->mld_addr;
+		}
+	}
+
+	if (reuse && wpa_s->sme.sae.tmp &&
+	    os_memcmp(peer_addr, wpa_s->sme.sae.tmp->bssid, ETH_ALEN) == 0) {
+		wpa_printf(MSG_DEBUG,
+			   "SAE: Reuse previously generated PWE on a retry with the same AP");
+		use_pt = wpa_s->sme.sae.h2e;
+		use_pk = wpa_s->sme.sae.pk;
+		goto reuse_data;
+	}
+	if (sme_set_sae_group(wpa_s) < 0) {
+		wpa_printf(MSG_DEBUG, "SAE: Failed to select group");
+		return NULL;
 	}
 
 	if (ssid->sae_password_id && wpa_s->conf->sae_pwe != 3)
@@ -190,24 +203,24 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
 
 	if (use_pt &&
 	    sae_prepare_commit_pt(&wpa_s->sme.sae, ssid->pt,
-				  wpa_s->own_addr, bssid,
+				  wpa_s->own_addr, peer_addr,
 				  wpa_s->sme.sae_rejected_groups, NULL) < 0)
 		return NULL;
 	if (!use_pt &&
-	    sae_prepare_commit(wpa_s->own_addr, bssid,
+	    sae_prepare_commit(wpa_s->own_addr, peer_addr,
 			       (u8 *) password, os_strlen(password),
 			       &wpa_s->sme.sae) < 0) {
 		wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
 		return NULL;
 	}
 	if (wpa_s->sme.sae.tmp) {
-		os_memcpy(wpa_s->sme.sae.tmp->bssid, bssid, ETH_ALEN);
+		os_memcpy(wpa_s->sme.sae.tmp->bssid, peer_addr, ETH_ALEN);
 		if (use_pt && use_pk)
 			wpa_s->sme.sae.pk = 1;
 #ifdef CONFIG_SAE_PK
 		os_memcpy(wpa_s->sme.sae.tmp->own_addr, wpa_s->own_addr,
 			  ETH_ALEN);
-		os_memcpy(wpa_s->sme.sae.tmp->peer_addr, bssid, ETH_ALEN);
+		os_memcpy(wpa_s->sme.sae.tmp->peer_addr, peer_addr, ETH_ALEN);
 		sae_pk_set_password(&wpa_s->sme.sae, password);
 #endif /* CONFIG_SAE_PK */
 	}
@@ -1041,11 +1054,30 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
 
 #ifdef CONFIG_SAE
 
+#define WPA_AUTH_FRAME_ML_IE_LEN (6 + ETH_ALEN)
+
+static void wpa_auth_ml_ie(struct wpabuf *buf, const u8 *mld_addr)
+{
+
+	wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+	wpabuf_put_u8(buf, WPA_AUTH_FRAME_ML_IE_LEN - 2);
+	wpabuf_put_u8(buf, WLAN_EID_EXT_MULTI_LINK);
+
+	/* Basic Multi-Link IE control field */
+	wpabuf_put_u8(buf, 0x0);
+	wpabuf_put_u8(buf, 0x0);
+
+	/* Common info: Common Info Length + MLD MAC LEN */
+	wpabuf_put_u8(buf, 0x7);
+	wpabuf_put_data(buf, mld_addr, ETH_ALEN);
+}
+
+
 static int sme_external_auth_build_buf(struct wpabuf *buf,
 				       struct wpabuf *params,
 				       const u8 *sa, const u8 *da,
 				       u16 auth_transaction, u16 seq_num,
-				       u16 status_code)
+				       u16 status_code, const u8 *mld_addr)
 {
 	struct ieee80211_mgmt *resp;
 
@@ -1064,10 +1096,17 @@ static int sme_external_auth_build_buf(struct wpabuf *buf,
 	if (params)
 		wpabuf_put_buf(buf, params);
 
+	if (mld_addr) {
+		wpa_auth_ml_ie(buf, mld_addr);
+		wpa_hexdump(MSG_DEBUG, "ML Auth Frame", wpabuf_head(buf),
+			    wpabuf_len(buf));
+	}
+
 	return 0;
 }
 
 
+
 static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s,
 					     const u8 *bssid,
 					     struct wpa_ssid *ssid)
@@ -1085,7 +1124,9 @@ static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s,
 	}
 
 	wpa_s->sme.sae.state = SAE_COMMITTED;
-	buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + wpabuf_len(resp));
+	buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + wpabuf_len(resp) +
+			   (wpa_s->sme.ext_ml_auth ?
+			    WPA_AUTH_FRAME_ML_IE_LEN : 0));
 	if (!buf) {
 		wpabuf_free(resp);
 		return -1;
@@ -1098,8 +1139,10 @@ static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s,
 		status = WLAN_STATUS_SAE_HASH_TO_ELEMENT;
 	else
 		status = WLAN_STATUS_SUCCESS;
-	sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
-				    bssid, 1, wpa_s->sme.seq_num, status);
+	sme_external_auth_build_buf(buf, resp, wpa_s->sme.ext_auth_tx_addr,
+				    bssid, 1, wpa_s->sme.seq_num, status,
+				    wpa_s->sme.ext_ml_auth ?
+				    wpa_s->own_addr : NULL);
 	wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0);
 	wpabuf_free(resp);
 	wpabuf_free(buf);
@@ -1166,16 +1209,20 @@ static void sme_external_auth_send_sae_confirm(struct wpa_supplicant *wpa_s,
 	}
 
 	wpa_s->sme.sae.state = SAE_CONFIRMED;
-	buf = wpabuf_alloc(4 + SAE_CONFIRM_MAX_LEN + wpabuf_len(resp));
+	buf = wpabuf_alloc(4 + SAE_CONFIRM_MAX_LEN + wpabuf_len(resp) +
+			   (wpa_s->sme.ext_ml_auth ? WPA_AUTH_FRAME_ML_IE_LEN : 0));
 	if (!buf) {
 		wpa_printf(MSG_DEBUG, "SAE: Auth Confirm buf alloc failure");
 		wpabuf_free(resp);
 		return;
 	}
 	wpa_s->sme.seq_num++;
-	sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
+	sme_external_auth_build_buf(buf, resp, wpa_s->sme.ext_auth_tx_addr,
 				    da, 2, wpa_s->sme.seq_num,
-				    WLAN_STATUS_SUCCESS);
+				    WLAN_STATUS_SUCCESS,
+				    wpa_s->sme.ext_ml_auth ?
+				    wpa_s->own_addr : NULL);
+
 	wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0);
 	wpabuf_free(resp);
 	wpabuf_free(buf);
@@ -1206,11 +1253,23 @@ void sme_external_auth_trigger(struct wpa_supplicant *wpa_s,
 	if (!is_sae_key_mgmt_suite(data->external_auth.key_mgmt_suite))
 		return;
 
+	if (data->external_auth.tx_addr) {
+		wpa_s->sme.ext_ml_auth = true;
+		wpa_printf(MSG_DEBUG,
+			   "SAE: External multi-link authentication with transmit address " MACSTR,
+			   MAC2STR(data->external_auth.tx_addr));
+	} else {
+		data->external_auth.tx_addr = wpa_s->own_addr;
+		wpa_s->sme.ext_ml_auth = false;
+	}
+
 	if (data->external_auth.action == EXT_AUTH_START) {
 		if (!data->external_auth.bssid || !data->external_auth.ssid)
 			return;
 		os_memcpy(wpa_s->sme.ext_auth_bssid, data->external_auth.bssid,
 			  ETH_ALEN);
+		os_memcpy(wpa_s->sme.ext_auth_tx_addr, data->external_auth.tx_addr,
+			  ETH_ALEN);
 		os_memcpy(wpa_s->sme.ext_auth_ssid, data->external_auth.ssid,
 			  data->external_auth.ssid_len);
 		wpa_s->sme.ext_auth_ssid_len = data->external_auth.ssid_len;
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 9db847cec..68ca5229f 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1034,6 +1034,8 @@ struct wpa_supplicant {
 		struct wpa_ssid *ext_auth_wpa_ssid;
 		u8 ext_auth_ssid[SSID_MAX_LEN];
 		size_t ext_auth_ssid_len;
+		u8 ext_auth_tx_addr[ETH_ALEN];
+		bool ext_ml_auth;
 		int *sae_rejected_groups;
 #endif /* CONFIG_SAE */
 	} sme;
-- 
2.25.1




More information about the Hostap mailing list