From 96ab7529c10c5b896d802f5889b57a179e860ecf Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Wed, 30 Nov 2022 19:18:44 -0800 Subject: [PATCH] tests: MBSSID and EMA Add test cases for MBSSID functionality with EMA. Add helper functions to create the configuration file, start hostapd instance and client association with the transmitting interface. he_ap_mbssid_open: 4 VAPs with open security in multiple BSSID configuration. The first interface transmits beacons and probe responses which include the multiple BSSID element(s) with remaining profiles. he_ap_mbssid_same_security: 2 VAPs, all with SAE. In such a case the Multiple BSSID elements in management frames do not include RSN and RSNE elements as all non-transmitting profiles have exact same security configuration as the transmitting interface. he_ap_mbssid_mixed_security{1,2}: 8 VAPs with mixed security configurations (SAE, OWE, WPA2-PSK, open). he_ap_mbssid_mixed_security1: Transmitting interface uses SAE. In this case the non-transmitting profiles will include non inheritance element (IEEE Std 802.11-2020, 9.4.2.240) wherever the security differs from the transmitting profile. he_ap_mbssid_mixed_security2: Transmitting profile is open hence no need for the non inheritance elements. Instead each non-transmitting profile includes RSN, RSNE if applicable. he_ap_ema: Enhanced multi-BSS advertisements (EMA) with 8 VAPs all with SAE configuration. Signed-off-by: Aloka Dixit --- tests/hwsim/test_he_mbssid.py | 244 ++++++++++++++++++++++++++++++++++ 1 file changed, 244 insertions(+) create mode 100644 tests/hwsim/test_he_mbssid.py diff --git a/tests/hwsim/test_he_mbssid.py b/tests/hwsim/test_he_mbssid.py new file mode 100644 index 000000000..8474f70a0 --- /dev/null +++ b/tests/hwsim/test_he_mbssid.py @@ -0,0 +1,244 @@ +# Multiple BSSID and enhanced multi-BSS advertisements (EMA) +# Copyright (c) 2019, The Linux Foundation +# Copyright (c) 2022, Qualcomm Innovation Center, Inc +# +# This software may be distributed under the terms of the BSD license. +# See README for more details. + +import os, subprocess, time, logging, tempfile +logger = logging.getLogger() + +import hwsim_utils, hostapd +from wpasupplicant import WpaSupplicant +from utils import * + +def mbssid_create_cfg_file(apdev, params, mbssid=1): + hapd = hostapd.add_ap(apdev[0], {"ssid": "open"}) + status = hapd.get_driver_status() + if "capa.mbssid_max_interfaces" not in status or \ + int(status["capa.mbssid_max_interfaces"]) < 8: + raise HwsimSkip("MBSSID not supported") + if mbssid == 2 and \ + ("capa.ema_max_periodicity" not in status or \ + int(status["capa.ema_max_periodicity"]) < 3): + raise HwsimSkip("EMA not supported") + hapd.disable() + hglobal = hostapd.HostapdGlobal() + hglobal.remove(apdev[0]['ifname']) + + # Create configuration file and add phy characteristics + fd, fname = tempfile.mkstemp(dir='/tmp', + prefix='hostapd-' + get_phy(apdev[0])) + f = os.fdopen(fd, 'w') + f.write("driver=nl80211\n") + f.write("hw_mode=g\n") + f.write("channel=1\n") + f.write("ieee80211n=1\n") + f.write("vht_oper_chwidth=0\n") + f.write("ieee80211ac=1\n") + f.write("he_oper_chwidth=0\n") + f.write("ieee80211ax=1\n") + f.write("mbssid=%d\n\n" % mbssid) + + if isinstance(apdev[0], dict): + ifname = apdev[0]['ifname'] + else: + ifname = apdev + + return (f, fname, ifname) + +def mbssid_write_bss_params(f, ifname, idx, params=None): + # Add BSS specific characteristics + fields = ["wpa", "wpa_pairwise", "rsn_pairwise", "wpa_passphrase", + "wpa_key_mgmt", "ieee80211w", "sae_pwe" ] + + if idx == 0: + f.write("interface=%s\n" % ifname) + else: + f.write("\nbss=%s\n" % (ifname + '-' + str(idx))) + + f.write("ctrl_interface=/var/run/hostapd\n") + f.write("ssid=bss-%s\n" % idx) + f.write("bridge=br-lan\n") + f.write("bssid=00:03:7f:12:2a:%02x\n" % idx) + f.write("preamble=1\n") + f.write("auth_algs=1\n") + + if params is None: + return + + for field in fields: + if field in params: + f.write("%s=%s\n" % (field, params[field])) + +def mbssid_start_ap(dev, apdev, params, fname, ifname, sta_params): + pid = params['prefix'] + ".hostapd.pid" + cmd = ['../../hostapd/hostapd', '-dtSB', '-dt', '-P', pid, '-f', + params['prefix'] + ".hostapd-log", fname] + + logger.info("Starting APs for " + ifname) + res = subprocess.check_call(cmd) + if res != 0: + raise Exception("Could not start hostapd: %s" % str(res)) + + # Wait for hostapd to complete initialization and daemonize. + for i in range(10): + if os.path.exists(pid): + break + time.sleep(0.2) + if not os.path.exists(pid): + # For now, assume MBSSID is not supported in the kernel. + raise Exception("hostapd did not create PID file") + + hapd = hostapd.Hostapd(apdev[0]['ifname']) + hapd.ping() + os.remove(fname); + + # Allow enough time to pass for a Beacon frame to be captured. + time.sleep(0.1) + + dev[0].connect("bss-0", **sta_params) + sta = hapd.get_sta(dev[0].own_addr()) + if "[HE]" not in sta['flags']: + raise Exception("Missing STA flag: HE") + dev[0].request("DISCONNECT") + + if "OK" not in hapd.request("TERMINATE"): + raise Exception("Failed to terminate hostapd process") + ev = hapd.wait_event(["CTRL-EVENT-TERMINATING"], timeout=15) + if ev is None: + raise Exception("CTRL-EVENT-TERMINATING not seen") + for i in range(30): + time.sleep(0.1) + if not os.path.exists(pid): + break + if os.path.exists(pid): + raise Exception("PID file exits after process termination") + +def test_he_ap_mbssid_open(dev, apdev, params): + """HE AP MBSSID all open""" + f, fname, ifname = mbssid_create_cfg_file(apdev, params) + for idx in range(0, 4): + mbssid_write_bss_params(f, ifname, idx) + f.close() + + try: + sta_params = {"key_mgmt": "NONE", "scan_freq": "2412"} + mbssid_start_ap(dev, apdev, params, fname, ifname, sta_params) + finally: + subprocess.call(['ip', 'link', 'set', 'dev', apdev[0]['ifname'], + 'address', apdev[0]['bssid']]) + +def test_he_ap_mbssid_same_security(dev, apdev, params): + """HE AP MBSSID all SAE""" + f, fname, ifname = mbssid_create_cfg_file(apdev, params) + + sae_params = {"wpa": "2", "wpa_passphrase": "12345678", + "wpa_pairwise": "CCMP", "wpa_key_mgmt": "SAE", + "sae_pwe": "1", "ieee80211w": "2"} + + for idx in range(0, 2): + mbssid_write_bss_params(f, ifname, idx, sae_params) + + f.close() + + try: + dev[0].set("sae_pwe", "1") + dev[0].set("sae_groups", "") + sta_params = {"psk": "12345678", "key_mgmt": "SAE", "ieee80211w": "2", + "pairwise": "CCMP", "group": "CCMP", "scan_freq": "2412"} + mbssid_start_ap(dev, apdev, params, fname, ifname, sta_params) + finally: + dev[0].set("sae_pwe", "0") + subprocess.call(['ip', 'link', 'set', 'dev', apdev[0]['ifname'], + 'address', apdev[0]['bssid']]) + +def test_he_ap_mbssid_mixed_security1(dev, apdev, params): + """HE AP MBSSID with mixed security (STA SAE)""" + f, fname, ifname = mbssid_create_cfg_file(apdev, params) + + psk_params = {"wpa": "2", "wpa_passphrase": "12345678", + "wpa_pairwise": "CCMP", "wpa_key_mgmt": "WPA-PSK"} + + owe_params = {"wpa": "2", "wpa_pairwise": "CCMP", "wpa_key_mgmt": "OWE"} + + sae_params = {"wpa": "2", "wpa_passphrase": "12345678", + "wpa_pairwise": "CCMP", "wpa_key_mgmt": "SAE", + "sae_pwe": "1", "ieee80211w": "2"} + + mbssid_write_bss_params(f, ifname, 0, sae_params) + mbssid_write_bss_params(f, ifname, 1, psk_params) + mbssid_write_bss_params(f, ifname, 2, owe_params) + mbssid_write_bss_params(f, ifname, 3) + mbssid_write_bss_params(f, ifname, 4, psk_params) + mbssid_write_bss_params(f, ifname, 5, sae_params) + mbssid_write_bss_params(f, ifname, 6, owe_params) + mbssid_write_bss_params(f, ifname, 7) + + f.close() + + try: + dev[0].set("sae_pwe", "1") + dev[0].set("sae_groups", "") + sta_params = {"psk": "12345678", "key_mgmt": "SAE", "ieee80211w": "2", + "pairwise": "CCMP", "group": "CCMP", "scan_freq": "2412"} + mbssid_start_ap(dev, apdev, params, fname, ifname, sta_params) + finally: + dev[0].set("sae_pwe", "0") + subprocess.call(['ip', 'link', 'set', 'dev', apdev[0]['ifname'], + 'address', apdev[0]['bssid']]) + +def test_he_ap_mbssid_mixed_security2(dev, apdev, params): + """HE AP MBSSID with mixed security (STA open)""" + f, fname, ifname = mbssid_create_cfg_file(apdev, params) + + psk_params = {"wpa": "2", "wpa_passphrase": "12345678", + "wpa_pairwise": "CCMP", "wpa_key_mgmt": "WPA-PSK"} + + owe_params = {"wpa": "2", "wpa_pairwise": "CCMP", "wpa_key_mgmt": "OWE"} + + sae_params = {"wpa": "2", "wpa_passphrase": "12345678", + "wpa_pairwise": "CCMP", "wpa_key_mgmt": "SAE", + "sae_pwe": "1", "ieee80211w": "2"} + + mbssid_write_bss_params(f, ifname, 0) + mbssid_write_bss_params(f, ifname, 1, psk_params) + mbssid_write_bss_params(f, ifname, 2, owe_params) + mbssid_write_bss_params(f, ifname, 3, sae_params) + mbssid_write_bss_params(f, ifname, 4) + mbssid_write_bss_params(f, ifname, 5, psk_params) + mbssid_write_bss_params(f, ifname, 6, sae_params) + mbssid_write_bss_params(f, ifname, 7, owe_params) + + f.close() + + try: + sta_params = {"key_mgmt": "NONE", "scan_freq": "2412"} + mbssid_start_ap(dev, apdev, params, fname, ifname, sta_params) + finally: + subprocess.call(['ip', 'link', 'set', 'dev', apdev[0]['ifname'], + 'address', apdev[0]['bssid']]) + +def test_he_ap_ema(dev, apdev, params): + """HE EMA AP""" + f, fname, ifname = mbssid_create_cfg_file(apdev, params, 2) + + sae_params = {"wpa": "2", "wpa_passphrase": "12345678", + "wpa_pairwise": "CCMP", "wpa_key_mgmt": "SAE", + "sae_pwe": "1", "ieee80211w": "2"} + + for idx in range(0, 8): + mbssid_write_bss_params(f, ifname, idx, sae_params) + + f.close() + + try: + dev[0].set("sae_pwe", "1") + dev[0].set("sae_groups", "") + sta_params = {"psk": "12345678", "key_mgmt": "SAE", "ieee80211w": "2", + "pairwise": "CCMP", "group": "CCMP", "scan_freq": "2412"} + mbssid_start_ap(dev, apdev, params, fname, ifname, sta_params) + finally: + dev[0].set("sae_pwe", "0") + subprocess.call(['ip', 'link', 'set', 'dev', apdev[0]['ifname'], + 'address', apdev[0]['bssid']])