tests: Avoid race condition in DPP GAS protocol testing

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>
This commit is contained in:
Jouni Malinen 2023-11-04 11:33:15 +02:00
parent 5c5f86900b
commit 8dd272fded
2 changed files with 30 additions and 10 deletions

View 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"): if "FAIL" not in dev[0].request("DPP_CONFIGURATOR_ADD curve=unknown"):
raise Exception("Unexpected success of invalid DPP_CONFIGURATOR_ADD") raise Exception("Unexpected success of invalid DPP_CONFIGURATOR_ADD")
def rx_process_frame(dev): def rx_process_frame(dev, msg=None):
msg = dev.mgmt_rx() if msg is None:
msg = dev.mgmt_rx()
if msg is None: if msg is None:
raise Exception("No management frame RX reported") raise Exception("No management frame RX reported")
if "OK" not in dev.request("MGMT_RX_PROCESS freq={} datarate={} ssi_signal={} frame={}".format( 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, require_configurator_failure=False,
timeout=5, stop_responder=False, stop_initiator=False): timeout=5, stop_responder=False, stop_initiator=False):
res = {} 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: if ev is None or "DPP-AUTH-SUCCESS" not in ev:
raise Exception("DPP authentication did not succeed (Responder)") raise Exception("DPP authentication did not succeed (Responder)")
for i in ev.split(' '): for i in ev.split(' '):
@ -4945,10 +4951,14 @@ def test_dpp_gas_timeout_handling(dev, apdev):
# DPP Authentication Confirmation # DPP Authentication Confirmation
rx_process_frame(dev[0]) 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) # 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) # DPP Configuration Request (GAS Comeback Request frame)
rx_process_frame(dev[0]) rx_process_frame(dev[0])
@ -4970,10 +4980,14 @@ def test_dpp_gas_comeback_after_failure(dev, apdev):
# DPP Authentication Confirmation # DPP Authentication Confirmation
rx_process_frame(dev[0]) 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) # 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) # DPP Configuration Request (GAS Comeback Request frame)
msg = dev[0].mgmt_rx() msg = dev[0].mgmt_rx()
@ -5002,14 +5016,17 @@ def test_dpp_gas(dev, apdev):
# DPP Authentication Confirmation # DPP Authentication Confirmation
rx_process_frame(dev[0]) 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) # 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) # Protected Dual of GAS Initial Request frame (dropped by GAS server)
if msg == None: 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 = binascii.hexlify(msg['frame'])
frame = frame[0:48] + b"09" + frame[50:] frame = frame[0:48] + b"09" + frame[50:]
frame = frame.decode() frame = frame.decode()

View file

@ -1382,6 +1382,9 @@ class WpaSupplicant:
ev = self.wait_event(["MGMT-RX"], timeout=timeout) ev = self.wait_event(["MGMT-RX"], timeout=timeout)
if ev is None: if ev is None:
return None return None
return self.mgmt_rx_parse(ev)
def mgmt_rx_parse(self, ev):
msg = {} msg = {}
items = ev.split(' ') items = ev.split(' ')
field, val = items[1].split('=') field, val = items[1].split('=')