]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
tests: Association comeback mechanism in wpa_supplicant
authorJouni Malinen <j@w1.fi>
Sun, 21 Jan 2024 10:17:07 +0000 (12:17 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 21 Jan 2024 10:17:23 +0000 (12:17 +0200)
Allow the Timeout Interval Type field in the Timeout Interval element to
be overridden with a different value for testing purposes to be able to
bypass the association comeback processing in mac80211. This allows the
wpa_supplicant internal functionality to be tested.

Signed-off-by: Jouni Malinen <j@w1.fi>
hostapd/config_file.c
src/ap/ap_config.c
src/ap/ap_config.h
src/ap/ieee802_11_shared.c
tests/hwsim/test_ap_pmf.py
wpa_supplicant/ctrl_iface.c
wpa_supplicant/sme.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index c96aa37c2d8ccdaa6598f79edd16ded2632f2471..8933908b262ca42e7de04301971938df45289e4c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / Configuration file parser
- * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2024, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -4450,6 +4450,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                        return 1;
        } else if (os_strcmp(buf, "eapol_m3_no_encrypt") == 0) {
                bss->eapol_m3_no_encrypt = atoi(pos);
+       } else if (os_strcmp(buf, "test_assoc_comeback_type") == 0) {
+               bss->test_assoc_comeback_type = atoi(pos);
 #endif /* CONFIG_TESTING_OPTIONS */
 #ifdef CONFIG_SAE
        } else if (os_strcmp(buf, "sae_password") == 0) {
index 1ff67737191a73b9ea8d5b03fb1c8c83822bf111..ebf6828d8cbf039012bb44348bcfd24b7eb5ad70 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / Configuration helper functions
- * Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2024, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -165,6 +165,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
 
 #ifdef CONFIG_TESTING_OPTIONS
        bss->sae_commit_status = -1;
+       bss->test_assoc_comeback_type = -1;
 #endif /* CONFIG_TESTING_OPTIONS */
 
 #ifdef CONFIG_PASN
index 46a88394a9df6768b73df5c978c3774138975944..8c459bd59ae34518b16846668f35a2db07ff55bf 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / Configuration definitions and helpers functions
- * Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2024, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -708,6 +708,7 @@ struct hostapd_bss_config {
        struct wpabuf *eapol_m1_elements;
        struct wpabuf *eapol_m3_elements;
        bool eapol_m3_no_encrypt;
+       int test_assoc_comeback_type;
 
 #ifdef CONFIG_IEEE80211BE
        u16 eht_oper_puncturing_override;
index c2d38e7151cc5af9630fb31c0d2a86a0691fba0b..0cd6f9503aa83dcca850eb6ea27221eed1adb0ac 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / IEEE 802.11 Management
- * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2024, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
 #include "ieee802_11.h"
 
 
+static u8 * hostapd_eid_timeout_interval(u8 *pos, u8 type, u32 value)
+{
+       *pos++ = WLAN_EID_TIMEOUT_INTERVAL;
+       *pos++ = 5;
+       *pos++ = type;
+       WPA_PUT_LE32(pos, value);
+       pos += 4;
+
+       return pos;
+}
+
+
 u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
                                     struct sta_info *sta, u8 *eid)
 {
-       u8 *pos = eid;
        u32 timeout, tu;
        struct os_reltime now, passed;
+       u8 type = WLAN_TIMEOUT_ASSOC_COMEBACK;
 
-       *pos++ = WLAN_EID_TIMEOUT_INTERVAL;
-       *pos++ = 5;
-       *pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
        os_get_reltime(&now);
        os_reltime_sub(&now, &sta->sa_query_start, &passed);
        tu = (passed.sec * 1000000 + passed.usec) / 1024;
@@ -40,10 +49,12 @@ u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
                timeout = 0;
        if (timeout < hapd->conf->assoc_sa_query_max_timeout)
                timeout++; /* add some extra time for local timers */
-       WPA_PUT_LE32(pos, timeout);
-       pos += 4;
 
-       return pos;
+#ifdef CONFIG_TESTING_OPTIONS
+       if (hapd->conf->test_assoc_comeback_type != -1)
+               type = hapd->conf->test_assoc_comeback_type;
+#endif /* CONFIG_TESTING_OPTIONS */
+       return hostapd_eid_timeout_interval(eid, type, timeout);
 }
 
 
index 20ad4ce06c1e30b9baf4deeadc408f6566676283..194cb7e289176717a1af1d9211c78f81cb63a913 100644 (file)
@@ -1,5 +1,5 @@
 # Protected management frames tests
-# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2013-2024, Jouni Malinen <j@w1.fi>
 #
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
@@ -272,6 +272,61 @@ def run_ap_pmf_assoc_comeback(dev, apdev, comeback=None):
                           dev[0].p2p_interface_addr()) < 1:
         raise Exception("AP did not use association comeback request")
 
+def test_ap_pmf_assoc_comeback_in_wpas(dev, apdev):
+    """WPA2-PSK AP with PMF association comeback in wpa_supplicant"""
+    ssid = "assoc-comeback"
+    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+    params["wpa_key_mgmt"] = "WPA-PSK-SHA256"
+    params["ieee80211w"] = "2"
+    params["test_assoc_comeback_type"] = "255"
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].set("test_assoc_comeback_type", "255")
+    dev[0].connect(ssid, psk="12345678", ieee80211w="1",
+                   key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2",
+                   scan_freq="2412")
+    hapd.wait_sta(wait_4way_hs=True)
+    hapd.set("ext_mgmt_frame_handling", "1")
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected(timeout=10)
+    ev = hapd.wait_event(["MGMT-RX"], timeout=1)
+    if ev is None:
+        raise Exception("Deauthentication frame RX not reported")
+    hapd.set("ext_mgmt_frame_handling", "0")
+    dev[0].request("REASSOCIATE")
+    ev = dev[0].wait_event(["CTRL-EVENT-ASSOC-REJECT"], timeout=10)
+    if ev is None or "status_code=30" not in ev:
+        raise Exception("Association comeback not requested")
+    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
+                            "CTRL-EVENT-ASSOC-REJECT"], timeout=10)
+    if ev is None:
+        raise Exception("Association not reported")
+    if "CTRL-EVENT-ASSOC-REJECT" in ev:
+        raise Exception("Unexpected association rejection: " + ev)
+    hapd.wait_4way_hs()
+
+    hapd.set("ext_mgmt_frame_handling", "1")
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected(timeout=10)
+    ev = hapd.wait_event(["MGMT-RX"], timeout=1)
+    if ev is None:
+        raise Exception("Deauthentication frame RX not reported")
+    hapd.set("ext_mgmt_frame_handling", "0")
+    dev[0].set("test_assoc_comeback_type", "254")
+    dev[0].request("REASSOCIATE")
+    ev = dev[0].wait_event(["CTRL-EVENT-ASSOC-REJECT"], timeout=10)
+    if ev is None or "status_code=30" not in ev:
+        raise Exception("Association comeback not requested")
+    ev = dev[0].wait_event(["SME: Temporary assoc reject: missing association comeback time",
+                            "CTRL-EVENT-CONNECTED",
+                            "CTRL-EVENT-ASSOC-REJECT"], timeout=10)
+    if ev is None:
+        raise Exception("Association not reported")
+    if "SME: Temporary assoc reject: missing association comeback time" not in ev:
+        raise Exception("Unexpected result: " + ev)
+    dev[0].wait_connected(timeout=20, error="Timeout on re-connection with misbehaving AP")
+    hapd.wait_4way_hs()
+
 @remote_compatible
 def test_ap_pmf_assoc_comeback2(dev, apdev):
     """WPA2-PSK AP with PMF association comeback (using DROP_SA)"""
index 99a8475f0bd07e80b11ab44b2c9113388c5458b0..92b46a89749aea1a233a41567aaa2f5eb3ebdcc5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / Control interface (shared code for all backends)
- * Copyright (c) 2004-2020, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2024, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -850,6 +850,8 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
                /* Populate value to wpa_sm if already associated. */
                wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DISABLE_EAPOL_G2_TX,
                                 wpa_s->disable_eapol_g2_tx);
+       } else if (os_strcasecmp(cmd, "test_assoc_comeback_type") == 0) {
+               wpa_s->test_assoc_comeback_type = atoi(value);
 #ifdef CONFIG_DPP
        } else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) {
                os_free(wpa_s->dpp_config_obj_override);
@@ -8888,6 +8890,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
        wpa_s->oci_freq_override_fils_assoc = 0;
        wpa_s->oci_freq_override_wnm_sleep = 0;
        wpa_s->disable_eapol_g2_tx = 0;
+       wpa_s->test_assoc_comeback_type = -1;
 #ifdef CONFIG_DPP
        os_free(wpa_s->dpp_config_obj_override);
        wpa_s->dpp_config_obj_override = NULL;
index eff7430ef1f5bd96a2824babd86b28ebf407d70d..706310b6129edbce145be28f7fbca49a09b01072 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant - SME
- * Copyright (c) 2009-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2024, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -2745,6 +2745,12 @@ static bool sme_try_assoc_comeback(struct wpa_supplicant *wpa_s,
        struct ieee802_11_elems elems;
        u32 timeout_interval;
        unsigned long comeback_usec;
+       u8 type = WLAN_TIMEOUT_ASSOC_COMEBACK;
+
+#ifdef CONFIG_TESTING_OPTIONS
+       if (wpa_s->test_assoc_comeback_type != -1)
+               type = wpa_s->test_assoc_comeback_type;
+#endif /* CONFIG_TESTING_OPTIONS */
 
        if (ieee802_11_parse_elems(data->assoc_reject.resp_ies,
                                   data->assoc_reject.resp_ies_len,
@@ -2760,7 +2766,7 @@ static bool sme_try_assoc_comeback(struct wpa_supplicant *wpa_s,
                return false;
        }
 
-       if (elems.timeout_int[0] != WLAN_TIMEOUT_ASSOC_COMEBACK) {
+       if (elems.timeout_int[0] != type) {
                wpa_msg(wpa_s, MSG_INFO,
                        "SME: Temporary assoc reject: missing association comeback time");
                return false;
index b8d15e409e1ba2a385810a55c444023ca29d9c3a..ecfc3b3ef80f04ceaf75c94aeda77036170fb3f0 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant
- * Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2024, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -5857,6 +5857,7 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent)
        dl_list_init(&wpa_s->fils_hlp_req);
 #ifdef CONFIG_TESTING_OPTIONS
        dl_list_init(&wpa_s->drv_signal_override);
+       wpa_s->test_assoc_comeback_type = -1;
 #endif /* CONFIG_TESTING_OPTIONS */
 #ifndef CONFIG_NO_ROBUST_AV
        dl_list_init(&wpa_s->active_scs_ids);
index 301be20519878cecd987845e49ab153a64cbde97..933fc36268a00e553c509d1d0262eda3efd10b45 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant - Internal definitions
- * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2024, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -1366,6 +1366,7 @@ struct wpa_supplicant {
        unsigned int oci_freq_override_fils_assoc;
        unsigned int oci_freq_override_wnm_sleep;
        unsigned int disable_eapol_g2_tx;
+       int test_assoc_comeback_type;
 #endif /* CONFIG_TESTING_OPTIONS */
 
        struct wmm_ac_assoc_data *wmm_ac_assoc_info;