]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
tests: Avoid race condition in DPP GAS protocol testing
authorJouni Malinen <j@w1.fi>
Sat, 4 Nov 2023 09:33:15 +0000 (11:33 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 4 Nov 2023 09:33:15 +0000 (11:33 +0200)
Responder receives Authentication Request and Config Request in a
sequence and it is possible for the Config Request to be received before
MGMT_RX_PROCESS has been processed for Authentication Request in the
cases where the test script is in the middle of RX processing. This can
result in DPP-AUTH-SUCCESS being delivered only after the MGMT-RX event
for Config Reques which means that wait_auth_success() would lose that
MGMT-RX event.

Avoid this issue by caching the "extra" MGMT-RX event within
wait_auth_success() and having the caller verify if the Config Request
(GAS Initial Request) has already been received before waiting to
receive it.

This makes dpp_gas, dpp_gas_comeback_after_failure, and
dpp_gas_timeout_handling more robust.

Signed-off-by: Jouni Malinen <j@w1.fi>
tests/hwsim/test_dpp.py
tests/hwsim/wpasupplicant.py

index a490f67ee6cf6b3b321dd9754553a6fe48e5aad9..95fcf67d7a97d1ae1d69c1522d5dfd79d7b01085 100644 (file)
@@ -4858,8 +4858,9 @@ def test_dpp_keygen_configurator_error(dev, apdev):
     if "FAIL" not in dev[0].request("DPP_CONFIGURATOR_ADD curve=unknown"):
         raise Exception("Unexpected success of invalid DPP_CONFIGURATOR_ADD")
 
-def rx_process_frame(dev):
-    msg = dev.mgmt_rx()
+def rx_process_frame(dev, msg=None):
+    if msg is None:
+        msg = dev.mgmt_rx()
     if msg is None:
         raise Exception("No management frame RX reported")
     if "OK" not in dev.request("MGMT_RX_PROCESS freq={} datarate={} ssi_signal={} frame={}".format(
@@ -4873,7 +4874,12 @@ def wait_auth_success(responder, initiator, configurator=None, enrollee=None,
                       require_configurator_failure=False,
                       timeout=5, stop_responder=False, stop_initiator=False):
     res = {}
-    ev = responder.wait_event(["DPP-AUTH-SUCCESS", "DPP-FAIL"], timeout=timeout)
+    ev = responder.wait_event(["DPP-AUTH-SUCCESS", "DPP-FAIL",
+                               "MGMT-RX"], timeout=timeout)
+    if ev and "MGMT-RX" in ev:
+        res['responder-mgmt-rx'] = ev
+        ev = responder.wait_event(["DPP-AUTH-SUCCESS", "DPP-FAIL"],
+                                  timeout=timeout)
     if ev is None or "DPP-AUTH-SUCCESS" not in ev:
         raise Exception("DPP authentication did not succeed (Responder)")
     for i in ev.split(' '):
@@ -4945,10 +4951,14 @@ def test_dpp_gas_timeout_handling(dev, apdev):
     # DPP Authentication Confirmation
     rx_process_frame(dev[0])
 
-    wait_auth_success(dev[0], dev[1])
+    res = wait_auth_success(dev[0], dev[1])
+    if 'responder-mgmt-rx' in res:
+        msg = dev[0].mgmt_rx_parse(res['responder-mgmt-rx'])
+    else:
+        msg = None
 
     # DPP Configuration Request (GAS Initial Request frame)
-    rx_process_frame(dev[0])
+    rx_process_frame(dev[0], msg)
 
     # DPP Configuration Request (GAS Comeback Request frame)
     rx_process_frame(dev[0])
@@ -4970,10 +4980,14 @@ def test_dpp_gas_comeback_after_failure(dev, apdev):
     # DPP Authentication Confirmation
     rx_process_frame(dev[0])
 
-    wait_auth_success(dev[0], dev[1])
+    res = wait_auth_success(dev[0], dev[1])
+    if 'responder-mgmt-rx' in res:
+        msg = dev[0].mgmt_rx_parse(res['responder-mgmt-rx'])
+    else:
+        msg = None
 
     # DPP Configuration Request (GAS Initial Request frame)
-    rx_process_frame(dev[0])
+    rx_process_frame(dev[0], msg)
 
     # DPP Configuration Request (GAS Comeback Request frame)
     msg = dev[0].mgmt_rx()
@@ -5002,14 +5016,17 @@ def test_dpp_gas(dev, apdev):
     # DPP Authentication Confirmation
     rx_process_frame(dev[0])
 
-    wait_auth_success(dev[0], dev[1])
+    res = wait_auth_success(dev[0], dev[1])
 
     # DPP Configuration Request (GAS Initial Request frame)
-    msg = dev[0].mgmt_rx()
+    if 'responder-mgmt-rx' in res:
+        msg = dev[0].mgmt_rx_parse(res['responder-mgmt-rx'])
+    else:
+        msg = dev[0].mgmt_rx()
 
     # Protected Dual of GAS Initial Request frame (dropped by GAS server)
     if msg == None:
-        raise Exception("MGMT_RX_PROCESS failed. <Please retry>")
+        raise Exception("GAS Initial Request frame not received")
     frame = binascii.hexlify(msg['frame'])
     frame = frame[0:48] + b"09" + frame[50:]
     frame = frame.decode()
index d525369806745dc0253768eca3971d9b009e699b..a9ca6c1b64a273a46b347e0e9f8abde5c4bd2ce8 100644 (file)
@@ -1382,6 +1382,9 @@ class WpaSupplicant:
         ev = self.wait_event(["MGMT-RX"], timeout=timeout)
         if ev is None:
             return None
+        return self.mgmt_rx_parse(ev)
+
+    def mgmt_rx_parse(self, ev):
         msg = {}
         items = ev.split(' ')
         field, val = items[1].split('=')