[PATCH v2 2/3] FT: Add ft_rsnxe_used_only_with_rsnxe interoperability workaround

Koral Ilgun koralilgun at gmail.com
Thu Oct 29 09:34:10 PDT 2026


From: Koral Ilgun <koral.ilgun at adtran.com>

The AP sets the RSNXE Used subfield of the FTE MIC Control field in an
FT Reassociation Response frame whenever it uses the RSNXE in other
frames (sae_pwe=1 or 2). For a STA that sent no RSNXE, the response
carries no RSNXE either, but the subfield is still set.

Some STAs check the subfield against the elements of the response
itself. An iPad that uses SAE without H2E discards such a response and
sends the Reassociation Request frame again, four to five times, and
the FT protocol never completes, so it stays with the old AP.

Add a per-BSS option ft_rsnxe_used_only_with_rsnxe that does not set the
subfield in the response to a STA that sent no RSNXE. The option
defaults to 0, which keeps the current behavior. Enabling it removes an
indication that a STA without an RSNXE of its own could use to detect an
RSNXE removed from the Beacon frame; a STA that sends an RSNXE gets the
same response as before.

Signed-off-by: Koral Ilgun <koral.ilgun at adtran.com>
---
 hostapd/config_file.c  |  2 ++
 hostapd/hostapd.conf   | 12 ++++++++++++
 src/ap/ap_config.h     |  3 +++
 src/ap/wpa_auth.h      |  1 +
 src/ap/wpa_auth_ft.c   |  1 +
 src/ap/wpa_auth_glue.c |  2 ++
 6 files changed, 21 insertions(+)

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 396d145b5..b9aafa5e3 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -3300,6 +3300,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 		bss->ft_over_ds = atoi(pos);
 	} else if (os_strcmp(buf, "ft_psk_generate_local") == 0) {
 		bss->ft_psk_generate_local = atoi(pos);
+	} else if (os_strcmp(buf, "ft_rsnxe_used_only_with_rsnxe") == 0) {
+		bss->ft_rsnxe_used_only_with_rsnxe = atoi(pos);
 #endif /* CONFIG_IEEE80211R_AP */
 #ifndef CONFIG_NO_CTRL_IFACE
 	} else if (os_strcmp(buf, "ctrl_interface") == 0) {
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 639556ef4..aad49cd62 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -2787,6 +2787,18 @@ own_ip_addr=127.0.0.1
 # 1 = enabled
 #ft_psk_generate_local=0
 
+# Do not set the RSNXE Used subfield in an FT Reassociation Response frame to a
+# STA that sent no RSNXE
+# By default (0), the AP sets RSNXE Used whenever it uses the RSNXE in other
+# frames (sae_pwe=1 or 2), also in a response without the RSNXE to a STA that
+# sent none. Some STAs reject such a response and repeat the FT
+# reassociation. This option is a workaround for those STAs. Enabling it
+# removes an indication that a STA could use to detect an RSNXE removed from
+# the Beacon frame.
+# 0 = disabled (default)
+# 1 = enabled
+#ft_rsnxe_used_only_with_rsnxe=0
+
 ##### IEEE 802.11bi related configuration #####################################
 
 # IEEE Std 802.11bi introduces following Enhanced Privacy Protection (EPP)
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index bde816591..fd7bee9c9 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -422,6 +422,9 @@ struct hostapd_bss_config {
 	int pmk_r1_push;
 	int ft_over_ds;
 	int ft_psk_generate_local;
+	/* Interoperability workaround: do not set RSNXE Used in an FT
+	 * Reassociation Response to a STA that sent no RSNXE */
+	bool ft_rsnxe_used_only_with_rsnxe;
 	int r1_max_key_lifetime;
 	char *rxkh_file;
 #endif /* CONFIG_IEEE80211R_AP */
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 9e5e38459..264fdf398 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -223,6 +223,7 @@ struct wpa_auth_config {
 	int pmk_r1_push;
 	int ft_over_ds;
 	int ft_psk_generate_local;
+	bool ft_rsnxe_used_only_with_rsnxe;
 #endif /* CONFIG_IEEE80211R_AP */
 	int disable_gtk;
 	int ap_mlme;
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 3dcfefe83..fac1f15df 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -2719,6 +2719,7 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
 	 * no RSNXE, and a STA rejects the bit. */
 	rsnxe_used = (auth_alg == WLAN_AUTH_FT) &&
 		!conf->rsn_override_omit_rsnxe &&
+		!(conf->ft_rsnxe_used_only_with_rsnxe && omit_rsnxe) &&
 		(conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
 		 conf->sae_pwe == SAE_PWE_BOTH);
 #ifdef CONFIG_TESTING_OPTIONS
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 9da2e6d20..ee614248e 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -192,6 +192,8 @@ static void hostapd_wpa_auth_conf(struct hostapd_iface *iface,
 	wconf->pmk_r1_push = conf->pmk_r1_push;
 	wconf->ft_over_ds = conf->ft_over_ds;
 	wconf->ft_psk_generate_local = conf->ft_psk_generate_local;
+	wconf->ft_rsnxe_used_only_with_rsnxe =
+		conf->ft_rsnxe_used_only_with_rsnxe;
 #endif /* CONFIG_IEEE80211R_AP */
 #ifdef CONFIG_HS20
 	wconf->disable_gtk = conf->disable_dgaf;
-- 
2.43.0




More information about the Hostap mailing list