[PATCH 4/4] tests: AP+STA on same radio

Raphaël Mélotte raphael.melotte at mind.be
Wed Mar 29 06:44:55 PDT 2023


From: "Arnout Vandecappelle (Essensium/Mind)" <arnout at mind.be>

Add a test for the support of an AP (hostapd) and a STA (wpa_supplicant)
running simultaneously on the same radio.

The test creates a new radio, with a managed and a station interface on
that radio. On the managed interface, hostapd is started in the usual
way. On the station interface, wpa_supplicant is started manually so we
can pass the -H argument. The station is connected to apdev[0]; dev[0]
is connected to the AP. Finally, a channel switch is started on
apdev[0]. This channel switch must propagate all the way down to dev[0].

Without the AP+STA functionality, the test fails in the following ways.

- Once AP2 is started on channel 11, it's not possible for wpas to
  connect to channel 1. For that, the AP has to be stopped first.
- When AP2 is started on channel 1, it's possible for wpas to connect.
  However, it cannot follow the CSA from AP1.

Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout at mind.be>
---
 tests/hwsim/test_ap_csa.py | 115 +++++++++++++++++++++++++++++++++++++
 1 file changed, 115 insertions(+)

diff --git a/tests/hwsim/test_ap_csa.py b/tests/hwsim/test_ap_csa.py
index 744d1e1f2..93bf6a892 100644
--- a/tests/hwsim/test_ap_csa.py
+++ b/tests/hwsim/test_ap_csa.py
@@ -9,9 +9,11 @@ import time
 import logging
 logger = logging.getLogger()
 
+from hwsim import HWSimRadio
 import hwsim_utils
 import hostapd
 from utils import *
+from wpasupplicant import WpaSupplicant
 
 def connect(dev, apdev, scan_freq="2412", **kwargs):
     params = {"ssid": "ap-csa",
@@ -187,3 +189,116 @@ def test_ap_csa_disable(dev, apdev):
     ap.enable()
     dev[0].wait_disconnected()
     dev[0].wait_connected()
+
+def write_hostapd_config(conffile, ifname, ssid):
+    with open(conffile, "w") as f:
+        f.write("driver=nl80211\n")
+        f.write("hw_mode=g\n")
+        f.write("channel=11\n")
+        f.write("ieee80211n=1\n")
+        f.write("ctrl_interface=/var/run/hostapd\n")
+        f.write("interface=" + ifname + "\n")
+        f.write("ssid=" + ssid + "\n")
+
+def test_ap_csa_1_switch_backhaul(dev, apdev, test_params):
+    """AP Channel Switch of backhaul with AP on same radio, one switch"""
+    csa_supported(dev[0])
+
+    params1 = {"ssid": "ap-csa-back",
+               "channel": "1"}
+    ap1 = hostapd.add_ap(apdev[0], params1)
+
+    with HWSimRadio() as (radio, ifname):
+        apifname2 = ifname + "_ap"
+        apdev2 = {"ifname": apifname2}
+
+        subprocess.call(['iw', 'dev', ifname, 'interface', 'add', apifname2,
+                         'type', 'managed'])
+
+        ap2 = None
+        try:
+            prefix = "ap_csa_1_switch_backhaul-ap"
+            conffile = os.path.join(test_params["logdir"], prefix + ".conf")
+            logfile = os.path.join(test_params["logdir"], prefix + ".log")
+            pidfile = os.path.join(test_params["logdir"], prefix + ".pid")
+            prg = os.path.join(test_params['logdir'], 'alt-hostapd/hostapd/hostapd')
+            if not os.path.exists(prg):
+                prg = '../../hostapd/hostapd'
+            write_hostapd_config(conffile, apifname2, "ap-csa-front")
+            arg = [prg, '-B', '-dddt', '-P', pidfile, '-f', logfile, conffile]
+            logger.info("Start hostapd: " + str(arg))
+            res = subprocess.check_call(arg)
+            if res != 0:
+                raise Exception("Could not start hostapd: %s" % str(res))
+            ap2 = hostapd.Hostapd(apifname2)
+            ap2.ping()
+
+            freq = int(ap2.get_status_field("freq"))
+            if freq != 2462:
+                raise Exception("Unexpected AP2 freq=%d before association" % freq)
+
+            prefix = "ap_csa_1_switch_backhaul-sta"
+            conffile = os.path.join(test_params["logdir"], prefix + ".conf")
+            logfile = os.path.join(test_params["logdir"], prefix + ".log")
+            pidfile2 = os.path.join(test_params["logdir"], prefix + ".pid")
+
+            with open(conffile, 'w') as f:
+                f.write("ctrl_interface=DIR=/var/run/wpa_supplicant\n")
+
+            prg = os.path.join(test_params['logdir'],
+                            'alt-wpa_supplicant/wpa_supplicant/wpa_supplicant')
+            if not os.path.exists(prg):
+                prg = '../../wpa_supplicant/wpa_supplicant'
+
+            arg = [prg, '-BddtK', '-P', pidfile2, '-f', logfile,
+                '-Dnl80211', '-c', conffile, '-i', ifname,
+                '-H', '/var/run/hostapd/' + apifname2]
+            logger.info("Start wpa_supplicant: " + str(arg))
+            subprocess.call(arg)
+            wpas = WpaSupplicant(ifname=ifname)
+            try:
+                csa_supported(wpas)
+
+                wpas.connect("ap-csa-back", key_mgmt="NONE", scan_freq="2412")
+                freq = int(wpas.get_driver_status_field("freq"))
+                if freq != 2412:
+                    raise Exception("Unexpected freq=%d after association" % freq)
+                hwsim_utils.test_connectivity(wpas, ap1)
+
+                freq = int(ap2.get_status_field("freq"))
+                if freq != 2412:
+                    raise Exception("Unexpected AP2 freq=%d after association" % freq)
+
+                dev[0].connect("ap-csa-front", key_mgmt="NONE", scan_freq="2412 2462")
+                freq = int(dev[0].get_status_field("freq"))
+                if freq != 2412:
+                    raise Exception("Unexpected freq=%d after association" % freq)
+                hwsim_utils.test_connectivity(dev[0], ap2)
+
+                switch_channel(ap1, 10, 2437)
+                wait_channel_switch(wpas, 2437)
+                wait_channel_switch(dev[0], 2437)
+
+                hwsim_utils.test_connectivity(wpas, ap1)
+                hwsim_utils.test_connectivity(dev[0], ap2)
+
+                for f in (ap1, wpas, ap2, dev[0]):
+                    freq = int(f.get_status_field("freq"))
+                    if freq != 2437:
+                        raise Exception("Unexpected driver freq=%d after channel switch" % freq)
+            finally:
+                wpas.close_monitor()
+                wpas.request("TERMINATE")
+        finally:
+            if ap2:
+                if "OK" not in ap2.request("TERMINATE"):
+                    raise Exception("Failed to terminate hostapd process")
+                ev = ap2.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(pidfile):
+                    break
+            if os.path.exists(pidfile):
+                raise Exception("PID file exits after process termination")
-- 
2.37.3




More information about the Hostap mailing list