diff --git a/tests/hwsim/hostapd.py b/tests/hwsim/hostapd.py index 83defb08e..9d3ca87b3 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[%d]' % 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 000000000..6b6167f51 --- /dev/null +++ b/tests/hwsim/multi-bss-iface.conf @@ -0,0 +1,40 @@ +driver=nl80211 + +hw_mode=g +channel=1 +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 5a8af739d..822bf99ed 100644 --- a/tests/hwsim/test_ap_vlan.py +++ b/tests/hwsim/test_ap_vlan.py @@ -11,8 +11,15 @@ import subprocess import logging logger = logging.getLogger(__name__) +try: + import netifaces + netifaces_imported = True +except ImportError: + netifaces_imported = False + import hwsim_utils import hostapd +from utils import iface_is_in_bridge, HwsimSkip def test_ap_vlan_open(dev, apdev): """AP VLAN with open network""" @@ -195,3 +202,183 @@ 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 ap_vlan_iface_cleanup_multibss_cleanup(): + subprocess.call(['ifconfig', 'dummy0', 'down'], + stderr=open('/dev/null', 'w')) + ifnames = [ 'wlan3.1', 'wlan3.2', 'wlan3-2.1', 'wlan3-2.2', 'dummy0.2', + 'dummy0.1', 'dummy0', 'brvlan1', 'brvlan2' ] + for ifname in ifnames: + subprocess.call(['ip', 'link', 'del', ifname], + stderr=open('/dev/null', 'w')) + +def ap_vlan_iface_test_and_prepare_environ(): + ifaces = netifaces.interfaces() + if "dummy0" in ifaces: + raise Exception("dummy0 already exists before") + ifaces = netifaces.interfaces() + if "dummy0.1" in ifaces: + raise Exception("dummy0.1 already exists before") + + subprocess.call(['ip', 'link', 'add', 'dummy0', 'type', 'dummy']) + subprocess.call(['ifconfig', 'dummy0', 'up']) + + ifaces = netifaces.interfaces() + if not("dummy0" in ifaces): + raise HwsimSkip("failed to add dummy0 - missing kernel config DUMMY ?") + + subprocess.call(['ip', 'link', 'add', 'link', 'dummy0', 'name', 'dummy0.1', + 'type', 'vlan', 'id', '1']) + + ifaces = netifaces.interfaces() + if not("dummy0.1" in ifaces): + raise HwsimSkip("failed to add dummy0.1 - missing kernel config VLAN_8021Q ?") + + subprocess.call(['ip', 'link', 'del', 'dummy0.1']) + + ifaces = netifaces.interfaces() + if "dummy0.1" in ifaces: + raise Exception("dummy0.1 was not removed before testing") + +def test_ap_vlan_iface_cleanup_multibss(dev, apdev): + """AP VLAN operation in multi-BSS multi-VLAN case""" + + # 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. + + if not netifaces_imported: + raise HwsimSkip("python module netifaces not available") + + try: + ap_vlan_iface_cleanup_multibss_cleanup() + ap_vlan_iface_test_and_prepare_environ() + + 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() + + 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="2412") + + 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="2412") + + 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", + max_tries=5) + + 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) + + # it can take some time for data connectivity to be updated + hwsim_utils.test_connectivity_iface(dev[1], hapd1, "brvlan2", + max_tries=5) + 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() + + # station removal needs some time + for i in range(5): + time.sleep(1) + ifaces = netifaces.interfaces() + if "brvlan2" not in ifaces: + break + + ifaces = netifaces.interfaces() + if "brvlan2" in ifaces: + raise Exception("bridge brvlan2 has not been cleaned up") + + hapd.request("DISABLE") + finally: + ap_vlan_iface_cleanup_multibss_cleanup() diff --git a/tests/hwsim/utils.py b/tests/hwsim/utils.py index 43dd33177..2769e192c 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 diff --git a/tests/hwsim/vm/kernel-config b/tests/hwsim/vm/kernel-config index 487c4fd0a..08fc7a9df 100644 --- a/tests/hwsim/vm/kernel-config +++ b/tests/hwsim/vm/kernel-config @@ -552,7 +552,7 @@ CONFIG_STP=y CONFIG_BRIDGE=y CONFIG_BRIDGE_IGMP_SNOOPING=y CONFIG_HAVE_NET_DSA=y -# CONFIG_VLAN_8021Q is not set +CONFIG_VLAN_8021Q=y # CONFIG_DECNET is not set CONFIG_LLC=y # CONFIG_LLC2 is not set @@ -726,7 +726,8 @@ CONFIG_SCSI_MOD=y # CONFIG_I2O is not set # CONFIG_MACINTOSH_DRIVERS is not set CONFIG_NETDEVICES=y -# CONFIG_NET_CORE is not set +CONFIG_NET_CORE=y +CONFIG_DUMMY=y # CONFIG_ARCNET is not set #