[PATCH 11/12] MLD STA: Add support for SAE external auth support

Veerendranath Jakkam quic_vjakkam at quicinc.com
Wed Aug 24 22:53:10 PDT 2022


- Add basic ML IE in SAE auth frames
- Use TA address provided by driver for sending SAE auth frames
- Use MLD address for SAE PWE derivation
- Allow auth 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 | 20 ++++++-
 wpa_supplicant/sme.c               | 96 ++++++++++++++++++++++--------
 wpa_supplicant/wpa_supplicant_i.h  |  2 +
 5 files changed, 97 insertions(+), 25 deletions(-)

diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 9a2d9bbc2..02c6604ce 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -2595,6 +2595,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 {
@@ -2607,6 +2609,7 @@ struct external_auth {
 	unsigned int key_mgmt_suite;
 	u16 status;
 	const u8 *pmkid;
+	const u8 *tx_addr;
 };
 
 /* enum nested_attr - Used to specify if subcommand uses nested attributes */
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 44ac7ea95..773045ca4 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 f756eaa1b..abe944876 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -1206,15 +1206,22 @@ static void mlme_event(struct i802_bss *bss,
 		   nl80211_command_to_string(cmd), bss->ifname,
 		   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;
+
 	if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) &&
 	    os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
 	    (is_zero_ether_addr(bss->rand_addr) ||
 	     os_memcmp(bss->rand_addr, data + 4, ETH_ALEN) != 0) &&
 	    os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
-		wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event "
+		wpa_printf(MSG_MSGDUMP, "nl80211: %s: skip check for Ignore MLME frame event "
 			   "for foreign address", bss->ifname);
 		return;
 	}
+
+skip_ra_check:
 	wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame",
 		    nla_data(frame), nla_len(frame));
 
@@ -2798,6 +2805,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 2dad36ddc..d5f5d1f0d 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -95,7 +95,9 @@ 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;
 
+	wpa_s->sme.ext_ml_auth = false;
 	if (ret_use_pt)
 		*ret_use_pt = 0;
 	if (ret_use_pk)
@@ -124,19 +126,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 +139,27 @@ 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 && !is_zero_ether_addr(bss->mld_addr)) {
+			wpa_printf(MSG_DEBUG, "SAE: AP MLD Addr: " MACSTR,
+				   MAC2STR(bss->mld_addr));
+
+			wpa_s->sme.ext_ml_auth = true;
+			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 +200,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 +1051,26 @@ 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);
+	wpabuf_put_u8(buf, 0x0);
+	wpabuf_put_u8(buf, 0x0);
+	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 +1089,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 +1117,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 +1132,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);
@@ -1160,16 +1196,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);
@@ -1183,11 +1223,19 @@ void sme_external_auth_trigger(struct wpa_supplicant *wpa_s,
 	    RSN_AUTH_KEY_MGMT_SAE)
 		return;
 
+	if (!data->external_auth.tx_addr)
+		data->external_auth.tx_addr = wpa_s->own_addr;
+
+	wpa_printf(MSG_DEBUG, "SAE: External auth transmit address " MACSTR,
+		   MAC2STR(data->external_auth.tx_addr));
+
 	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 0ee4c01f9..e881ce1b5 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1024,6 +1024,8 @@ struct wpa_supplicant {
 		u8 ext_auth_bssid[ETH_ALEN];
 		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