[PATCH 03/12] MLD STA: Add support to fetch per-link beacon WPA/RSN/RSNX IEs into wpa_sm

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


wpa_sm needs per-link beacon RSN and RSNX IEs for MLO KDE validation.
Thus, Add required APIs to parse and set AP link WPA/RSN/RSNX IEs to
wpa_sm.

Signed-off-by: Veerendranath Jakkam <quic_vjakkam at quicinc.com>
---
 src/rsn_supp/wpa.c                            | 103 +++++++++++++-----
 src/rsn_supp/wpa.h                            |  22 ++--
 src/rsn_supp/wpa_i.h                          |   8 ++
 tests/fuzzing/eapol-key-supp/eapol-key-supp.c |   2 +-
 wpa_supplicant/events.c                       |  66 ++++++++---
 wpa_supplicant/ibss_rsn.c                     |   4 +-
 wpa_supplicant/wpa_supplicant.c               |  19 ++--
 wpa_supplicant/wpas_glue.c                    | 103 +++++++++++++++---
 8 files changed, 247 insertions(+), 80 deletions(-)

diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index a28d49225..f3965ca50 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -3716,6 +3716,7 @@ int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len)
 /**
  * wpa_sm_set_ap_wpa_ie - Set AP WPA IE from Beacon/ProbeResp
  * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @link_id: MLO link ID to set specific link or -1 to set default
  * @ie: Pointer to IE data (starting from id)
  * @len: IE length
  * Returns: 0 on success, -1 on failure
@@ -3723,24 +3724,40 @@ int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len)
  * Inform WPA state machine about the WPA IE used in Beacon / Probe Response
  * frame.
  */
-int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
+int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, int link_id, const u8 *ie,
+			 size_t len)
 {
-	if (sm == NULL)
+	u8 **ap_wpa_ie;
+	size_t *ap_wpa_ie_len;
+
+	if (!sm)
 		return -1;
 
-	os_free(sm->ap_wpa_ie);
-	if (ie == NULL || len == 0) {
+	if (link_id == -1) {
+		ap_wpa_ie = &sm->ap_wpa_ie;
+		ap_wpa_ie_len = &sm->ap_wpa_ie_len;
+	} else {
+		if (link_id < 0 || link_id >= MAX_NUM_MLD_LINKS)
+			return -1;
+
 		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
-			"WPA: clearing AP WPA IE");
-		sm->ap_wpa_ie = NULL;
-		sm->ap_wpa_ie_len = 0;
+			"WPA: set AP WPA IE for link ID %d", link_id);
+		ap_wpa_ie = &sm->links[link_id].ap_wpa_ie;
+		ap_wpa_ie_len = &sm->links[link_id].ap_wpa_ie_len;
+	}
+
+	os_free(*ap_wpa_ie);
+	if (ie == NULL || len == 0) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: clearing AP WPA IE");
+		*ap_wpa_ie = NULL;
+		*ap_wpa_ie_len = 0;
 	} else {
 		wpa_hexdump(MSG_DEBUG, "WPA: set AP WPA IE", ie, len);
-		sm->ap_wpa_ie = os_memdup(ie, len);
-		if (sm->ap_wpa_ie == NULL)
+		*ap_wpa_ie = os_memdup(ie, len);
+		if (*ap_wpa_ie == NULL)
 			return -1;
 
-		sm->ap_wpa_ie_len = len;
+		*ap_wpa_ie_len = len;
 	}
 
 	return 0;
@@ -3750,6 +3767,7 @@ int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
 /**
  * wpa_sm_set_ap_rsn_ie - Set AP RSN IE from Beacon/ProbeResp
  * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @link_id: MLO link ID to set specific link or -1 to set default
  * @ie: Pointer to IE data (starting from id)
  * @len: IE length
  * Returns: 0 on success, -1 on failure
@@ -3757,24 +3775,41 @@ int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
  * Inform WPA state machine about the RSN IE used in Beacon / Probe Response
  * frame.
  */
-int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
+int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, int link_id, const u8 *ie,
+			 size_t len)
 {
-	if (sm == NULL)
+	u8 **ap_rsn_ie;
+	size_t *ap_rsn_ie_len;
+
+	if (!sm)
 		return -1;
 
-	os_free(sm->ap_rsn_ie);
+	if (link_id == -1) {
+		ap_rsn_ie = &sm->ap_rsn_ie;
+		ap_rsn_ie_len = &sm->ap_rsn_ie_len;
+	} else {
+		if (link_id < 0 || link_id >= MAX_NUM_MLD_LINKS)
+			return -1;
+
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: set AP RSN IE for link ID %d", link_id);
+		ap_rsn_ie = &sm->links[link_id].ap_rsn_ie;
+		ap_rsn_ie_len = &sm->links[link_id].ap_rsn_ie_len;
+	}
+
+	os_free(*ap_rsn_ie);
 	if (ie == NULL || len == 0) {
 		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
 			"WPA: clearing AP RSN IE");
-		sm->ap_rsn_ie = NULL;
-		sm->ap_rsn_ie_len = 0;
+		*ap_rsn_ie = NULL;
+		*ap_rsn_ie_len = 0;
 	} else {
 		wpa_hexdump(MSG_DEBUG, "WPA: set AP RSN IE", ie, len);
-		sm->ap_rsn_ie = os_memdup(ie, len);
-		if (sm->ap_rsn_ie == NULL)
+		*ap_rsn_ie = os_memdup(ie, len);
+		if (*ap_rsn_ie == NULL)
 			return -1;
 
-		sm->ap_rsn_ie_len = len;
+		*ap_rsn_ie_len = len;
 	}
 
 	return 0;
@@ -3784,6 +3819,7 @@ int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
 /**
  * wpa_sm_set_ap_rsnxe - Set AP RSNXE from Beacon/ProbeResp
  * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @link_id: MLO link ID to set specific link or -1 to set default
  * @ie: Pointer to IE data (starting from id)
  * @len: IE length
  * Returns: 0 on success, -1 on failure
@@ -3791,23 +3827,40 @@ int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
  * Inform WPA state machine about the RSNXE used in Beacon / Probe Response
  * frame.
  */
-int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len)
+int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, int link_id, const u8 *ie,
+			size_t len)
 {
+	u8 **ap_rsnxe;
+	size_t *ap_rsnxe_len;
+
 	if (!sm)
 		return -1;
 
-	os_free(sm->ap_rsnxe);
+	if (link_id == -1) {
+		ap_rsnxe = &sm->ap_rsnxe;
+		ap_rsnxe_len = &sm->ap_rsnxe_len;
+	} else {
+		if (link_id < 0 || link_id >= MAX_NUM_MLD_LINKS)
+			return -1;
+
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: set AP RSNXE IE for link ID %d", link_id);
+		ap_rsnxe = &sm->links[link_id].ap_rsnxe;
+		ap_rsnxe_len = &sm->links[link_id].ap_rsnxe_len;
+	}
+
+	os_free(*ap_rsnxe);
 	if (!ie || len == 0) {
 		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: clearing AP RSNXE");
-		sm->ap_rsnxe = NULL;
-		sm->ap_rsnxe_len = 0;
+		*ap_rsnxe = NULL;
+		*ap_rsnxe_len = 0;
 	} else {
 		wpa_hexdump(MSG_DEBUG, "WPA: set AP RSNXE", ie, len);
-		sm->ap_rsnxe = os_memdup(ie, len);
-		if (!sm->ap_rsnxe)
+		*ap_rsnxe = os_memdup(ie, len);
+		if (*ap_rsnxe == NULL)
 			return -1;
 
-		sm->ap_rsnxe_len = len;
+		*ap_rsnxe_len = len;
 	}
 
 	return 0;
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index e6eef0c99..a56802b0a 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -93,6 +93,7 @@ struct wpa_sm_ctx {
 	void (*transition_disable)(void *ctx, u8 bitmap);
 	void (*store_ptk)(void *ctx, u8 *addr, int cipher,
 			  u32 life_time, const struct wpa_ptk *ptk);
+	int (*get_link_beacon_ie)(void *ctx, u8 link_id);
 };
 
 
@@ -165,9 +166,12 @@ int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
 int wpa_sm_set_assoc_rsnxe_default(struct wpa_sm *sm, u8 *rsnxe,
 				   size_t *rsnxe_len);
 int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len);
-int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
-int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
-int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len);
+int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, int link_id, const u8 *ie,
+			 size_t len);
+int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, int link_id, const u8 *ie,
+			 size_t len);
+int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, int link_id, const u8 *ie,
+			size_t len);
 int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen);
 
 int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
@@ -299,20 +303,20 @@ static inline int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm,
 	return -1;
 }
 
-static inline int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie,
-				       size_t len)
+static inline int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, int link_id,
+				       const u8 *ie, size_t len)
 {
 	return -1;
 }
 
-static inline int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie,
-				       size_t len)
+static inline int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, int link_id,
+				       const u8 *ie, size_t len)
 {
 	return -1;
 }
 
-static inline int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie,
-				      size_t len)
+static inline int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, int link_id,
+				      const u8 *ie, size_t len)
 {
 	return -1;
 }
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 62b85cb2e..8bf0f28d8 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -224,6 +224,8 @@ struct wpa_sm {
 	struct {
 		u8 addr[ETH_ALEN];
 		u8 bssid[ETH_ALEN];
+		u8 *ap_wpa_ie, *ap_rsn_ie, *ap_rsnxe;
+		size_t ap_wpa_ie_len, ap_rsn_ie_len, ap_rsnxe_len;
 	} links[MAX_NUM_MLD_LINKS];
 };
 
@@ -288,6 +290,12 @@ static inline int wpa_sm_get_beacon_ie(struct wpa_sm *sm)
 	return sm->ctx->get_beacon_ie(sm->ctx->ctx);
 }
 
+static inline int wpa_sm_get_link_beacon_ie(struct wpa_sm *sm, u8 link_id)
+{
+	WPA_ASSERT(sm->ctx->get_link_beacon_ie);
+	return sm->ctx->get_link_beacon_ie(sm->ctx->ctx, link_id);
+}
+
 static inline void wpa_sm_cancel_auth_timeout(struct wpa_sm *sm)
 {
 	WPA_ASSERT(sm->ctx->cancel_auth_timeout);
diff --git a/tests/fuzzing/eapol-key-supp/eapol-key-supp.c b/tests/fuzzing/eapol-key-supp/eapol-key-supp.c
index 0c7189571..a86efd376 100644
--- a/tests/fuzzing/eapol-key-supp/eapol-key-supp.c
+++ b/tests/fuzzing/eapol-key-supp/eapol-key-supp.c
@@ -168,7 +168,7 @@ static int supp_get_beacon_ie(void *ctx)
 	ie = wpa->wpa1 ? wpaie : rsne;
 	if (ie[0] == WLAN_EID_RSN)
 		return wpa_sm_set_ap_rsn_ie(wpa->supp, ie, 2 + ie[1]);
-	return wpa_sm_set_ap_wpa_ie(wpa->supp, ie, 2 + ie[1]);
+	return wpa_sm_set_ap_wpa_ie(wpa->supp, -1, ie, 2 + ie[1]);
 }
 
 
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index db4de316f..5f13d4674 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -3223,27 +3223,27 @@ no_pfs:
 		    p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
 		    os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0) {
 			wpa_found = 1;
-			wpa_sm_set_ap_wpa_ie(wpa_s->wpa, p, len);
+			wpa_sm_set_ap_wpa_ie(wpa_s->wpa, -1, p, len);
 		}
 
 		if (!rsn_found &&
 		    p[0] == WLAN_EID_RSN && p[1] >= 2) {
 			rsn_found = 1;
-			wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len);
+			wpa_sm_set_ap_rsn_ie(wpa_s->wpa, -1, p, len);
 		}
 
 		if (p[0] == WLAN_EID_RSNX && p[1] >= 1)
-			wpa_sm_set_ap_rsnxe(wpa_s->wpa, p, len);
+			wpa_sm_set_ap_rsnxe(wpa_s->wpa, -1, p, len);
 
 		l -= len;
 		p += len;
 	}
 
 	if (!wpa_found && data->assoc_info.beacon_ies)
-		wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
+		wpa_sm_set_ap_wpa_ie(wpa_s->wpa, -1, NULL, 0);
 	if (!rsn_found && data->assoc_info.beacon_ies) {
-		wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
-		wpa_sm_set_ap_rsnxe(wpa_s->wpa, NULL, 0);
+		wpa_sm_set_ap_rsn_ie(wpa_s->wpa, -1, NULL, 0);
+		wpa_sm_set_ap_rsnxe(wpa_s->wpa, -1, NULL, 0);
 	}
 	if (wpa_found || rsn_found)
 		wpa_s->ap_ies_from_associnfo = 1;
@@ -3265,26 +3265,23 @@ no_pfs:
 }
 
 
-static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
+static int wpa_supplicant_update_link_ie(struct wpa_supplicant *wpa_s,
+					 int link_id, const struct wpa_bss *bss)
 {
 	const u8 *bss_wpa = NULL, *bss_rsn = NULL, *bss_rsnx = NULL;
 
-	if (!wpa_s->current_bss || !wpa_s->current_ssid)
+	if (!bss)
 		return -1;
 
-	if (!wpa_key_mgmt_wpa_any(wpa_s->current_ssid->key_mgmt))
-		return 0;
-
-	bss_wpa = wpa_bss_get_vendor_ie(wpa_s->current_bss,
-					WPA_IE_VENDOR_TYPE);
-	bss_rsn = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_RSN);
-	bss_rsnx = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_RSNX);
+	bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+	bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+	bss_rsnx = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
 
-	if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
+	if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, link_id, bss_wpa,
 				 bss_wpa ? 2 + bss_wpa[1] : 0) ||
-	    wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
+	    wpa_sm_set_ap_rsn_ie(wpa_s->wpa, link_id, bss_rsn,
 				 bss_rsn ? 2 + bss_rsn[1] : 0) ||
-	    wpa_sm_set_ap_rsnxe(wpa_s->wpa, bss_rsnx,
+	    wpa_sm_set_ap_rsnxe(wpa_s->wpa, link_id, bss_rsnx,
 				 bss_rsnx ? 2 + bss_rsnx[1] : 0))
 		return -1;
 
@@ -3292,6 +3289,39 @@ static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
 }
 
 
+static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
+{
+	int i;
+
+	if (!wpa_s->current_bss || !wpa_s->current_ssid)
+		return -1;
+
+	if (!wpa_key_mgmt_wpa_any(wpa_s->current_ssid->key_mgmt))
+		return 0;
+
+	if (wpa_supplicant_update_link_ie(wpa_s, -1, wpa_s->current_bss))
+		return -1;
+
+	if (!wpa_s->valid_links)
+		return 0;
+
+	for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+		if (!(wpa_s->valid_links & BIT(i))) {
+			wpa_sm_set_ap_wpa_ie(wpa_s->wpa, i, NULL, 0);
+			wpa_sm_set_ap_rsn_ie(wpa_s->wpa, i, NULL, 0);
+			wpa_sm_set_ap_rsnxe(wpa_s->wpa, i, NULL, 0);
+			continue;
+		}
+
+		if (wpa_supplicant_update_link_ie(wpa_s, i,
+						  wpa_s->links[i].bss))
+			return -1;
+	}
+
+	return 0;
+}
+
+
 static void wpas_fst_update_mb_assoc(struct wpa_supplicant *wpa_s,
 				     union wpa_event_data *data)
 {
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 874c2bf1d..459d7bd2d 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -117,8 +117,8 @@ static int supp_get_beacon_ie(void *ctx)
 
 	wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
 	/* TODO: get correct RSN IE */
-	wpa_sm_set_ap_rsnxe(peer->supp, NULL, 0);
-	return wpa_sm_set_ap_rsn_ie(peer->supp,
+	wpa_sm_set_ap_rsnxe(peer->supp, -1, NULL, 0);
+	return wpa_sm_set_ap_rsn_ie(peer->supp, -1,
 				    (u8 *) "\x30\x14\x01\x00"
 				    "\x00\x0f\xac\x04"
 				    "\x01\x00\x00\x0f\xac\x04"
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index ba364324d..b0087328c 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -400,9 +400,7 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
 void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
 				       struct wpa_ssid *ssid)
 {
-#ifdef CONFIG_WEP
 	int i;
-#endif /* CONFIG_WEP */
 
 	if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
 		wpa_s->key_mgmt = WPA_KEY_MGMT_WPS;
@@ -410,9 +408,14 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
 		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
 	else
 		wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
-	wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
-	wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
-	wpa_sm_set_ap_rsnxe(wpa_s->wpa, NULL, 0);
+	wpa_sm_set_ap_wpa_ie(wpa_s->wpa, -1, NULL, 0);
+	wpa_sm_set_ap_rsn_ie(wpa_s->wpa, -1, NULL, 0);
+	wpa_sm_set_ap_rsnxe(wpa_s->wpa, -1, NULL, 0);
+	for (int i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+		wpa_sm_set_ap_wpa_ie(wpa_s->wpa, i, NULL, 0);
+		wpa_sm_set_ap_rsn_ie(wpa_s->wpa, i, NULL, 0);
+		wpa_sm_set_ap_rsnxe(wpa_s->wpa, i, NULL, 0);
+	}
 	wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
 	wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
 	wpa_s->rsnxe_len = 0;
@@ -1505,11 +1508,11 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 			 !!(ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)));
 
 	if (bss || !wpa_s->ap_ies_from_associnfo) {
-		if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
+		if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, -1, bss_wpa,
 					 bss_wpa ? 2 + bss_wpa[1] : 0) ||
-		    wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
+		    wpa_sm_set_ap_rsn_ie(wpa_s->wpa, -1, bss_rsn,
 					 bss_rsn ? 2 + bss_rsn[1] : 0) ||
-		    wpa_sm_set_ap_rsnxe(wpa_s->wpa, bss_rsnx,
+		    wpa_sm_set_ap_rsnxe(wpa_s->wpa, -1, bss_rsnx,
 					bss_rsnx ? 2 + bss_rsnx[1] : 0))
 			return -1;
 	}
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index ccc72c4d6..2784fb096 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -390,15 +390,21 @@ static void wpa_supplicant_notify_eapol_done(void *ctx)
 
 #ifndef CONFIG_NO_WPA
 
-static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s)
+struct beacon_ies {
+	const u8 *wpa_ie, *rsn_ie, *rsnxe;
+	size_t wpa_ie_len, rsn_ie_len, rsnxe_len;
+};
+
+
+static int wpa_get_bssid_beacon_ie(struct wpa_supplicant *wpa_s,
+				   const u8 *bssid, struct beacon_ies *ies)
 {
-	int ret = 0;
 	struct wpa_bss *curr = NULL, *bss;
 	struct wpa_ssid *ssid = wpa_s->current_ssid;
 	const u8 *ie;
 
 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
-		if (os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) != 0)
+		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) != 0)
 			continue;
 		if (ssid == NULL ||
 		    ((bss->ssid_len == ssid->ssid_len &&
@@ -416,23 +422,42 @@ static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s)
 #endif /* CONFIG_OWE */
 	}
 
-	if (curr) {
-		ie = wpa_bss_get_vendor_ie(curr, WPA_IE_VENDOR_TYPE);
-		if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
-			ret = -1;
+	if (!curr)
+		return -1;
 
-		ie = wpa_bss_get_ie(curr, WLAN_EID_RSN);
-		if (wpa_sm_set_ap_rsn_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
-			ret = -1;
+	ie = wpa_bss_get_vendor_ie(curr, WPA_IE_VENDOR_TYPE);
+	ies->wpa_ie = ie;
+	ies->wpa_ie_len = ie ? 2 + ie[1] : 0;
 
-		ie = wpa_bss_get_ie(curr, WLAN_EID_RSNX);
-		if (wpa_sm_set_ap_rsnxe(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
-			ret = -1;
-	} else {
-		ret = -1;
-	}
+	ie = wpa_bss_get_ie(curr, WLAN_EID_RSN);
+	ies->rsn_ie = ie;
+	ies->rsn_ie_len = ie ? 2 + ie[1] : 0;
 
-	return ret;
+	ie = wpa_bss_get_ie(curr, WLAN_EID_RSNX);
+	ies->rsnxe = ie;
+	ies->rsnxe_len = ie ? 2 + ie[1] : 0;
+
+	return 0;
+}
+
+
+static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s)
+{
+	struct beacon_ies ies;
+
+	if (wpa_get_bssid_beacon_ie(wpa_s, wpa_s->bssid, &ies))
+		return -1;
+
+	if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, -1, ies.wpa_ie, ies.wpa_ie_len))
+		return -1;
+
+	if (wpa_sm_set_ap_rsn_ie(wpa_s->wpa, -1, ies.rsn_ie, ies.rsn_ie_len))
+		return -1;
+
+	if (wpa_sm_set_ap_rsnxe(wpa_s->wpa, -1, ies.rsnxe, ies.rsnxe_len))
+		return -1;
+
+	return 0;
 }
 
 
@@ -452,6 +477,49 @@ static int wpa_supplicant_get_beacon_ie(void *ctx)
 }
 
 
+static int wpa_get_link_beacon_ie(struct wpa_supplicant *wpa_s, u8 link_id)
+{
+	struct beacon_ies ies;
+
+	if (!(wpa_s->valid_links & BIT(link_id)))
+		return -1;
+
+
+	if (wpa_get_bssid_beacon_ie(wpa_s, wpa_s->links[link_id].bssid, &ies))
+		return -1;
+
+	if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, link_id, ies.wpa_ie,
+				 ies.wpa_ie_len))
+		return -1;
+
+	if (wpa_sm_set_ap_rsn_ie(wpa_s->wpa, link_id, ies.rsn_ie,
+				 ies.rsn_ie_len))
+		return -1;
+
+	if (wpa_sm_set_ap_rsnxe(wpa_s->wpa, link_id, ies.rsnxe, ies.rsnxe_len))
+		return -1;
+
+	return 0;
+}
+
+
+static int wpa_supplicant_get_link_beacon_ie(void *ctx, u8 link_id)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	if (wpa_get_link_beacon_ie(wpa_s, link_id) == 0) {
+		return 0;
+	}
+
+	/* No WPA/RSN IE found in the cached scan results. Try to get updated
+	 * scan results from the driver. */
+	if (wpa_supplicant_update_scan_results(wpa_s) < 0)
+		return -1;
+
+	return wpa_get_link_beacon_ie(wpa_s, link_id);
+}
+
+
+
 static u8 * _wpa_alloc_eapol(void *wpa_s, u8 type,
 			     const void *data, u16 data_len,
 			     size_t *msg_len, void **data_pos)
@@ -1412,6 +1480,7 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
 	ctx->get_bssid = wpa_supplicant_get_bssid;
 	ctx->ether_send = _wpa_ether_send;
 	ctx->get_beacon_ie = wpa_supplicant_get_beacon_ie;
+	ctx->get_link_beacon_ie = wpa_supplicant_get_link_beacon_ie;
 	ctx->alloc_eapol = _wpa_alloc_eapol;
 	ctx->cancel_auth_timeout = _wpa_supplicant_cancel_auth_timeout;
 	ctx->add_pmkid = wpa_supplicant_add_pmkid;
-- 
2.25.1




More information about the Hostap mailing list