[PATCH 2/2] test: verify correct vlan operation in multi-bss multi-vlan case

Michael Braun michael-dev at fami-braun.de
Mon Apr 27 03:08:04 EDT 2015


This adds hwsim test ap_vlan_iface_cleanup_multibss. It connects two stations
in different BSS but the same hostapd process. First both stations are in
VLAN 1, then they get reauthenticated into VLAN 2. Due to the ordering of the
stations moving around, this patch checks that bridge and tagged interface
referencing counting is done globally, such that the tagged interface is not
removed too early and not bridge is left over.

Signed-off-by: Michael Braun <michael-dev at fami-braun.de>
---
 tests/hwsim/hostapd.py           |   5 +-
 tests/hwsim/multi-bss-iface.conf |  41 ++++++++++
 tests/hwsim/test_ap_vlan.py      | 156 +++++++++++++++++++++++++++++++++++++++
 tests/hwsim/utils.py             |  13 ++++
 4 files changed, 213 insertions(+), 2 deletions(-)
 create mode 100644 tests/hwsim/multi-bss-iface.conf

diff --git a/tests/hwsim/hostapd.py b/tests/hwsim/hostapd.py
index 83defb0..d726ca1 100644
--- a/tests/hwsim/hostapd.py
+++ b/tests/hwsim/hostapd.py
@@ -49,16 +49,17 @@ class HostapdGlobal:
 
 
 class Hostapd:
-    def __init__(self, ifname):
+    def __init__(self, ifname, bssidx=0):
         self.ifname = ifname
         self.ctrl = wpaspy.Ctrl(os.path.join(hapd_ctrl, ifname))
         self.mon = wpaspy.Ctrl(os.path.join(hapd_ctrl, ifname))
         self.mon.attach()
         self.bssid = None
+        self.bssidx = bssidx
 
     def own_addr(self):
         if self.bssid is None:
-            self.bssid = self.get_status_field('bssid[0]')
+            self.bssid = self.get_status_field('bssid['+str(self.bssidx)+']')
         return self.bssid
 
     def request(self, cmd):
diff --git a/tests/hwsim/multi-bss-iface.conf b/tests/hwsim/multi-bss-iface.conf
new file mode 100644
index 0000000..115358a
--- /dev/null
+++ b/tests/hwsim/multi-bss-iface.conf
@@ -0,0 +1,41 @@
+driver=nl80211
+
+hw_mode=g
+channel=0
+ieee80211n=1
+
+interface=wlan3
+ctrl_interface=/var/run/hostapd
+
+ssid=bss-1
+dynamic_vlan=1
+vlan_tagged_interface=dummy0
+vlan_bridge=brvlan
+wpa=2
+wpa_key_mgmt=WPA-EAP
+rsn_pairwise=CCMP
+ieee8021x=1
+auth_server_addr=127.0.0.1
+auth_server_port=18128
+auth_server_shared_secret=radius
+nas_identifier=nas.w1.fi
+vlan_naming=1
+
+bss=wlan3-2
+bssid=02:00:00:00:03:01
+ctrl_interface=/var/run/hostapd
+ssid=bss-2
+
+dynamic_vlan=1
+vlan_tagged_interface=dummy0
+vlan_bridge=brvlan
+wpa=2
+wpa_key_mgmt=WPA-EAP
+rsn_pairwise=CCMP
+ieee8021x=1
+auth_server_addr=127.0.0.1
+auth_server_port=18128
+auth_server_shared_secret=radius
+nas_identifier=nas.w1.fi
+vlan_naming=1
+
diff --git a/tests/hwsim/test_ap_vlan.py b/tests/hwsim/test_ap_vlan.py
index 5a8af73..f5348a5 100644
--- a/tests/hwsim/test_ap_vlan.py
+++ b/tests/hwsim/test_ap_vlan.py
@@ -13,6 +13,8 @@ logger = logging.getLogger(__name__)
 
 import hwsim_utils
 import hostapd
+import netifaces
+from utils import iface_is_in_bridge
 
 def test_ap_vlan_open(dev, apdev):
     """AP VLAN with open network"""
@@ -195,3 +197,157 @@ def test_ap_vlan_tagged(dev, apdev):
     hwsim_utils.test_connectivity_iface(dev[0], hapd, "brlo.1")
     hwsim_utils.test_connectivity_iface(dev[1], hapd, "brlo.2")
     hwsim_utils.test_connectivity(dev[2], hapd)
+
+def helper_ap_vlan_iface_cleanup_multibss_cleanup():
+    subprocess.call(['ifconfig','dummy0','down'],
+                    stderr=open('/dev/null', 'w'))
+    subprocess.call(['ip','link','del','wlan3.1'],
+                    stderr=open('/dev/null', 'w'))
+    subprocess.call(['ip','link','del','wlan3.2'],
+                    stderr=open('/dev/null', 'w'))
+    subprocess.call(['ip','link','del','wlan3-2.1'],
+                    stderr=open('/dev/null', 'w'))
+    subprocess.call(['ip','link','del','wlan3-2.2'],
+                    stderr=open('/dev/null', 'w'))
+    subprocess.call(['ip','link','del','dummy0.2'],
+                    stderr=open('/dev/null', 'w'))
+    subprocess.call(['ip','link','del','dummy0.1'],
+                    stderr=open('/dev/null', 'w'))
+    subprocess.call(['ip','link','del','dummy0'],
+                    stderr=open('/dev/null', 'w'))
+    subprocess.call(['ip','link','del','brvlan1'],
+                    stderr=open('/dev/null', 'w'))
+    subprocess.call(['ip','link','del','brvlan2'],
+                    stderr=open('/dev/null', 'w'))
+
+def test_ap_vlan_iface_cleanup_multibss(dev, apdev):
+    """AP VLAN with WPA2-Enterprise and RADIUS attributes changing VLANID
+       check that multiple bss do not interfere with each other with respect
+       to deletion of bridge and tagged interface
+    """
+    try:
+        helper_ap_vlan_iface_cleanup_multibss_cleanup()
+        subprocess.call(['ip','link','add','dummy0','type','dummy'])
+        subprocess.call(['ifconfig','dummy0','up'])
+
+        as_params = { "ssid": "as",
+                      "beacon_int": "2000",
+                      "radius_server_clients": "auth_serv/radius_clients.conf",
+                      "radius_server_auth_port": '18128',
+                      "eap_server": "1",
+                      "eap_user_file": "auth_serv/eap_user.conf",
+                      "ca_cert": "auth_serv/ca.pem",
+                      "server_cert": "auth_serv/server.pem",
+                      "private_key": "auth_serv/server.key",
+                      "vlan_naming": "1" }
+        authserv = hostapd.add_ap(apdev[1]['ifname'], as_params)
+
+        ifname = apdev[0]['ifname']
+
+        # start the actual test
+        hostapd.add_iface(ifname, 'multi-bss-iface.conf')
+        hapd = hostapd.Hostapd(ifname)
+        hapd1 = hostapd.Hostapd("wlan3-2",1)
+        hapd1.enable()
+
+        freq = hapd.get_status_field("freq")
+
+        ifaces = netifaces.interfaces()
+        if "brvlan1" in ifaces:
+            raise Exception("bridge brvlan1 already exists before")
+        if "brvlan2" in ifaces:
+            raise Exception("bridge brvlan2 already exists before")
+
+        dev[0].connect("bss-1", key_mgmt="WPA-EAP", eap="PAX",
+                       identity="vlan1",
+                       password_hex="0123456789abcdef0123456789abcdef",
+                       scan_freq=freq)
+
+        ifaces = netifaces.interfaces()
+        if not("brvlan1" in ifaces):
+            raise Exception("bridge brvlan1 was not created")
+
+        hwsim_utils.test_connectivity_iface(dev[0], hapd, "brvlan1")
+        if not iface_is_in_bridge("brvlan1", "dummy0.1"):
+            raise Exception("dummy0.1 not in brvlan1")
+
+        dev[1].connect("bss-2", key_mgmt="WPA-EAP", eap="PAX",
+                       identity="vlan1",
+                       password_hex="0123456789abcdef0123456789abcdef",
+                       scan_freq=freq)
+
+        hwsim_utils.test_connectivity_iface(dev[1], hapd1, "brvlan1")
+        if not iface_is_in_bridge("brvlan1", "dummy0.1"):
+            raise Exception("dummy0.1 not in brvlan1")
+
+        authserv.disable()
+        authserv.set('eap_user_file', "auth_serv/eap_user_vlan.conf")
+        authserv.enable()
+
+        logger.info("wlan0 -> VLAN 2")
+
+        dev[0].dump_monitor()
+        dev[0].request("REAUTHENTICATE")
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
+        if ev is None:
+            raise Exception("EAP reauthentication timed out")
+        ev = dev[0].wait_event(["WPA: Key negotiation completed"], timeout=5)
+        if ev is None:
+            raise Exception("4-way handshake after reauthentication timed out")
+        state = dev[0].get_status_field('wpa_state')
+        if state != "COMPLETED":
+            raise Exception("Unexpected state after reauth: " + state)
+
+        ifaces = netifaces.interfaces()
+        if not ("brvlan1" in ifaces):
+            raise Exception("bridge brvlan1 has been removed too early")
+
+        hwsim_utils.test_connectivity_iface(dev[0], hapd, "brvlan2")
+
+        if not iface_is_in_bridge("brvlan2", "dummy0.2"):
+            raise Exception("dummy0.2 not in brvlan2")
+
+        logger.info("test wlan1 == VLAN 1")
+        hwsim_utils.test_connectivity_iface(dev[1], hapd1, "brvlan1")
+        if not iface_is_in_bridge("brvlan1", "dummy0.1"):
+            raise Exception("dummy0.1 not in brvlan1")
+
+        logger.info("wlan1 -> VLAN 2")
+
+        dev[1].dump_monitor()
+        dev[1].request("REAUTHENTICATE")
+        ev = dev[1].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
+        if ev is None:
+            raise Exception("EAP reauthentication timed out")
+        ev = dev[1].wait_event(["WPA: Key negotiation completed"], timeout=5)
+        if ev is None:
+            raise Exception("4-way handshake after reauthentication timed out")
+        state = dev[1].get_status_field('wpa_state')
+        if state != "COMPLETED":
+            raise Exception("Unexpected state after reauth: " + state)
+
+        hwsim_utils.test_connectivity_iface(dev[1], hapd1, "brvlan2")
+        logger.info("test wlan0 == VLAN 2")
+        hwsim_utils.test_connectivity_iface(dev[0], hapd, "brvlan2")
+
+        if not iface_is_in_bridge("brvlan2", "dummy0.2"):
+            raise Exception("dummy0.2 not in brvlan2")
+
+        ifaces = netifaces.interfaces()
+        if "brvlan1" in ifaces:
+            raise Exception("bridge brvlan1 has not been cleaned up")
+
+        # disconnect dev0 first to test a corner case
+        dev[0].request("DISCONNECT")
+        dev[0].wait_disconnected()
+        dev[1].request("DISCONNECT")
+        dev[1].wait_disconnected()
+        time.sleep(5) # station removal needs some time
+
+        ifaces = netifaces.interfaces()
+        if "brvlan2" in ifaces:
+            raise Exception("bridge brvlan2 has not been cleaned up")
+
+        hapd.request("DISABLE")
+    finally:
+        helper_ap_vlan_iface_cleanup_multibss_cleanup()
diff --git a/tests/hwsim/utils.py b/tests/hwsim/utils.py
index 43dd331..2769e19 100644
--- a/tests/hwsim/utils.py
+++ b/tests/hwsim/utils.py
@@ -4,6 +4,8 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+import os
+
 def get_ifnames():
     ifnames = []
     with open("/proc/net/dev", "r") as f:
@@ -39,3 +41,14 @@ def require_under_vm():
         cmd = f.read()
         if "inside.sh" not in cmd:
             raise HwsimSkip("Not running under VM")
+
+def iface_is_in_bridge(bridge, ifname):
+    fname = "/sys/class/net/"+ifname+"/brport/bridge"
+    if not os.path.exists(fname):
+        return False
+    if not os.path.islink(fname):
+        return False
+    truebridge = os.path.basename(os.readlink(fname))
+    if bridge == truebridge:
+        return True
+    return False
-- 
1.9.1



More information about the HostAP mailing list