[PATCH v3 3/3] tests: FT RSNXE Used without RSNXE in Beacon or request
Koral Ilgun
koralilgun at gmail.com
Fri Oct 30 07:58:19 PDT 2026
From: Koral Ilgun <koral.ilgun at adtran.com>
Cover an FT-PSK roam of a STA without RSN Overriding in WPA3-Personal
Compatibility Mode, with and without rsn_override_omit_rsnxe, and RSNXE
Used toward a STA that sends no RSNXE, with and without
ft_rsnxe_used_only_with_rsnxe.
Signed-off-by: Koral Ilgun <koral.ilgun at adtran.com>
---
tests/hwsim/test_ap_ft.py | 80 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 79 insertions(+), 1 deletion(-)
diff --git a/tests/hwsim/test_ap_ft.py b/tests/hwsim/test_ap_ft.py
index 29bec3de9..9bdf45a43 100644
--- a/tests/hwsim/test_ap_ft.py
+++ b/tests/hwsim/test_ap_ft.py
@@ -1140,7 +1140,7 @@ def start_ft_sae(dev, apdev, wpa_ptk_rekey=None, sae_pwe=None,
no_beacon_rsnxe2=False, ext_key_id=False,
skip_prune_assoc=False, ft_rsnxe_used=False,
sae_transition=False, ext_key=False, sae_groups=None,
- wpa_gtk_rekey=None):
+ wpa_gtk_rekey=None, ft_rsnxe_used_only_with_rsnxe=False):
check_sae_capab(dev)
ssid = "test-ft"
passphrase = "12345678"
@@ -1167,6 +1167,8 @@ def start_ft_sae(dev, apdev, wpa_ptk_rekey=None, sae_pwe=None,
params['ft_rsnxe_used'] = '1'
if sae_groups:
params['sae_groups'] = sae_groups
+ if ft_rsnxe_used_only_with_rsnxe:
+ params['ft_rsnxe_used_only_with_rsnxe'] = '1'
hapd0 = hostapd.add_ap(apdev[0], params)
params = ft_params2(ssid=ssid, passphrase=passphrase)
if not sae_transition:
@@ -1191,6 +1193,8 @@ def start_ft_sae(dev, apdev, wpa_ptk_rekey=None, sae_pwe=None,
params['ft_rsnxe_used'] = '1'
if sae_groups:
params['sae_groups'] = sae_groups
+ if ft_rsnxe_used_only_with_rsnxe:
+ params['ft_rsnxe_used_only_with_rsnxe'] = '1'
hapd1 = hostapd.add_ap(apdev[1], params)
key_mgmt = hapd1.get_config()['key_mgmt']
if key_mgmt.split(' ')[0] != key_mgmt and not sae_transition:
@@ -1476,6 +1480,80 @@ def test_ap_ft_sae_rsnxe_used_mismatch2(dev, apdev):
finally:
dev[0].set("sae_pwe", "0")
+def ft_compat_params(params, omit_rsnxe):
+ # WPA3-Personal Compatibility Mode: FT-PSK in the base RSNE, FT-SAE with
+ # H2E in the RSN Override elements, so the base RSNE has no RSNXE.
+ params['wpa_key_mgmt'] = 'WPA-PSK FT-PSK'
+ params['ieee80211w'] = '0'
+ params['rsn_override_key_mgmt'] = 'SAE FT-SAE'
+ params['rsn_override_pairwise'] = 'CCMP'
+ params['rsn_override_mfp'] = '2'
+ params['sae_pwe'] = '2'
+ if omit_rsnxe:
+ params['rsn_override_omit_rsnxe'] = '1'
+ return params
+
+def run_ft_psk_rsn_override_no_rsno_sta(dev, apdev, omit_rsnxe):
+ # A STA without RSN Overriding uses FT-PSK and gets no RSNXE Used.
+ check_sae_capab(dev[0])
+ ssid = "test-ft"
+ passphrase = "12345678"
+ params = ft_params1(ssid=ssid, passphrase=passphrase)
+ hapd0 = hostapd.add_ap(apdev[0], ft_compat_params(params, omit_rsnxe))
+ params = ft_params2(ssid=ssid, passphrase=passphrase)
+ hapd1 = hostapd.add_ap(apdev[1], ft_compat_params(params, omit_rsnxe))
+ dev[0].set("rsn_overriding", "0")
+ run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, ieee80211w="0")
+
+def test_ap_ft_psk_rsn_override_no_rsno_sta(dev, apdev):
+ """FT-PSK roam of a STA without RSN Overriding in Compatibility Mode"""
+ try:
+ run_ft_psk_rsn_override_no_rsno_sta(dev, apdev, False)
+ finally:
+ dev[0].set("rsn_overriding", "0")
+
+def test_ap_ft_psk_rsn_override_no_rsno_sta_omit_rsnxe(dev, apdev):
+ """FT-PSK roam of a STA without RSN Overriding, RSNXE omitted"""
+ try:
+ run_ft_psk_rsn_override_no_rsno_sta(dev, apdev, True)
+ finally:
+ dev[0].set("rsn_overriding", "0")
+
+def run_ft_sae_no_beacon_rsnxe_sta_loop(dev, apdev, only_with_rsnxe):
+ hapd0, hapd1 = start_ft_sae(dev[0], apdev, sae_pwe="2",
+ no_beacon_rsnxe2=True,
+ ft_rsnxe_used_only_with_rsnxe=only_with_rsnxe)
+ dev[0].set("sae_pwe", "0")
+ run_roams(dev[0], apdev, hapd0, hapd1, "test-ft", "12345678", sae=True,
+ force_initial_conn_to_first_ap=True,
+ return_after_initial=True)
+ dev[0].scan_for_bss(hapd1.own_addr(), freq="2412")
+ if "OK" not in dev[0].request("ROAM " + hapd1.own_addr()):
+ raise Exception("ROAM command failed")
+ ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=10)
+ return ev is not None and hapd1.own_addr() in ev
+
+def test_ap_ft_sae_rsnxe_used_no_rsnxe(dev, apdev):
+ """FT-SAE AP sets RSNXE Used for a STA without RSNXE by default"""
+ try:
+ # The STA sends no RSNXE and the target AP has no RSNXE in its
+ # Beacon frames. By default, the response still has RSNXE Used set,
+ # and the STA rejects it.
+ if run_ft_sae_no_beacon_rsnxe_sta_loop(dev, apdev, False):
+ raise Exception("Roaming succeeded unexpectedly")
+ finally:
+ dev[0].set("sae_pwe", "0")
+
+def test_ap_ft_sae_rsnxe_used_only_with_rsnxe(dev, apdev):
+ """FT-SAE AP with ft_rsnxe_used_only_with_rsnxe"""
+ try:
+ # With the option, the response to a STA without RSNXE has RSNXE Used
+ # cleared, so the STA accepts it even without RSNXE in the Beacon.
+ if not run_ft_sae_no_beacon_rsnxe_sta_loop(dev, apdev, True):
+ raise Exception("Roaming failed")
+ finally:
+ dev[0].set("sae_pwe", "0")
+
def test_ap_ft_sae_pw_id(dev, apdev):
"""FT-SAE with Password Identifier"""
check_sae_capab(dev[0])
--
2.43.0
More information about the Hostap
mailing list