auto-t: add SA Query tests

Two autotests:

1. Tests SA Query procedure when the AP goes down. In this case the AP
   goes down ungracefully, now allowing it to send out any deauth
   frames. When the AP comes back up, IWD still thinks its connected.
   The AP will then send unprotected disassociate frames so the client
   can re-connect. This kicks off the SA Query procedure, which the AP
   will not respond to. At this point we can deauth and reconnect to
   the AP.

2. Test SA Query procedure when a disassociate frame has been spoofed.
   In this case we receive an unprotected disassociate frame and start
   SA Query. The AP should then respond to the SA query within the
   timeout. We then know the frame was spoofed and can remain
   connected.
This commit is contained in:
James Prestwood 2018-01-31 09:56:00 -08:00 committed by Denis Kenzior
parent ce0d5858da
commit 1491ebe877
6 changed files with 214 additions and 0 deletions

View File

@ -0,0 +1,96 @@
#!/usr/bin/python3
import unittest
import sys
sys.path.append('../util')
import iwd
from iwd import IWD
from iwd import PSKAgent
from iwd import NetworkType
from hwsim import Hwsim
from hostapd import HostapdCLI
from wiphy import wiphy_map
from time import sleep
class Test(unittest.TestCase):
def test_connection_success(self):
hwsim = Hwsim()
hostapd = None
radio = None
for wname in wiphy_map:
wiphy = wiphy_map[wname]
intf = list(wiphy.values())[0]
if intf.use == 'hostapd':
hostapd = HostapdCLI(intf)
for path in hwsim.radios:
if hwsim.radios[path].name == wname:
radio = hwsim.radios[path]
break
wd = IWD()
psk_agent = PSKAgent("secret123")
wd.register_psk_agent(psk_agent)
devices = wd.list_devices();
self.assertIsNotNone(devices)
device = devices[0]
condition = 'not obj.scanning'
wd.wait_for_object_condition(device, condition)
device.scan()
condition = 'not obj.scanning'
wd.wait_for_object_condition(device, condition)
ordered_networks = device.get_ordered_networks()
ordered_network = ordered_networks[0]
self.assertEqual(ordered_network.name, "ssidCCMP")
self.assertEqual(ordered_network.type, NetworkType.psk)
condition = 'not obj.connected'
wd.wait_for_object_condition(ordered_network.network_object, condition)
ordered_network.network_object.connect()
condition = 'obj.connected'
wd.wait_for_object_condition(ordered_network.network_object, condition)
# TODO: for some reason hostapd does not respond to SA query if done
# too soon after connection.
sleep(1)
# Spoof a disassociate frame. This will kick off SA Query procedure.
hwsim.spoof_disassociate(radio, hostapd.get_freq(), device.address)
# sleep to ensure hostapd responds and SA Query does not timeout
sleep(4)
# Since disassociate was spoofed we should still be connected
condition = 'obj.connected'
wd.wait_for_object_condition(ordered_network.network_object, condition)
device.disconnect()
condition = 'not obj.connected'
wd.wait_for_object_condition(ordered_network.network_object, condition)
wd.unregister_psk_agent(psk_agent)
@classmethod
def setUpClass(cls):
pass
@classmethod
def tearDownClass(cls):
IWD.clear_storage()
if __name__ == '__main__':
unittest.main(exit=True)

View File

@ -0,0 +1,5 @@
[SETUP]
num_radios=2
[HOSTAPD]
rad0=ssidCCMP.conf

View File

@ -0,0 +1,10 @@
hw_mode=g
channel=1
ssid=ssidCCMP
wpa=2
wpa_pairwise=CCMP
wpa_passphrase=secret123
ieee80211w=2
wpa_key_mgmt=WPA-PSK-SHA256

View File

@ -0,0 +1,88 @@
#!/usr/bin/python3
import unittest
import sys
sys.path.append('../util')
import iwd
from iwd import IWD
from iwd import PSKAgent
from iwd import NetworkType
from hwsim import Hwsim
from hostapd import HostapdCLI
from wiphy import wiphy_map
class Test(unittest.TestCase):
def test_connection_success(self):
hostapd = None
for wname in wiphy_map:
wiphy = wiphy_map[wname]
intf = list(wiphy.values())[0]
if intf.use == 'hostapd':
hostapd = HostapdCLI(intf)
break
hwsim = Hwsim()
wd = IWD()
psk_agent = PSKAgent("secret123")
wd.register_psk_agent(psk_agent)
devices = wd.list_devices();
self.assertIsNotNone(devices)
device = devices[0]
condition = 'not obj.scanning'
wd.wait_for_object_condition(device, condition)
device.scan()
condition = 'not obj.scanning'
wd.wait_for_object_condition(device, condition)
ordered_networks = device.get_ordered_networks()
ordered_network = ordered_networks[0]
self.assertEqual(ordered_network.name, "ssidCCMP")
self.assertEqual(ordered_network.type, NetworkType.psk)
condition = 'not obj.connected'
wd.wait_for_object_condition(ordered_network.network_object, condition)
ordered_network.network_object.connect()
condition = 'obj.connected'
wd.wait_for_object_condition(ordered_network.network_object, condition)
# Make AP go down ungracefully, when hostapd comes back up it should
# send an unprotected disassociate frame so the client will re-auth.
# This will kick off the SA Query procedure
hostapd.ungraceful_restart()
condition = 'not obj.connected'
wd.wait_for_object_condition(ordered_network.network_object, condition)
# IWD should now try and re-connect to the AP
condition = 'obj.connected'
wd.wait_for_object_condition(ordered_network.network_object, condition)
device.disconnect()
condition = 'not obj.connected'
wd.wait_for_object_condition(ordered_network.network_object, condition)
wd.unregister_psk_agent(psk_agent)
@classmethod
def setUpClass(cls):
pass
@classmethod
def tearDownClass(cls):
IWD.clear_storage()
if __name__ == '__main__':
unittest.main(exit=True)

View File

@ -0,0 +1,5 @@
[SETUP]
num_radios=2
[HOSTAPD]
rad0=ssidCCMP.conf

View File

@ -0,0 +1,10 @@
hw_mode=g
channel=1
ssid=ssidCCMP
wpa=2
wpa_pairwise=CCMP
wpa_passphrase=secret123
ieee80211w=2
wpa_key_mgmt=WPA-PSK-SHA256