diff mbox series

[6/6] tests: add S1G association coverage

Message ID 4c64e424fc741fd954076681ca08a0a73b5df737.1759334464.git.james@teledatics.com
State New
Headers show
Series S1G bootstrap and scan plumbing | expand

Commit Message

James Ewing Oct. 1, 2025, 4:50 p.m. UTC
---
 tests/hwsim/test_s1g_assoc.py | 101 ++++++++++++++++++++++++++++++++++
 1 file changed, 101 insertions(+)
 create mode 100644 tests/hwsim/test_s1g_assoc.py

Comments

Lachlan Hodges Oct. 2, 2025, 2:05 a.m. UTC | #1
On Wed, Oct 01, 2025 at 12:50:01PM -0400, James Ewing wrote:
> ---
>  tests/hwsim/test_s1g_assoc.py | 101 ++++++++++++++++++++++++++++++++++
>  1 file changed, 101 insertions(+)
>  create mode 100644 tests/hwsim/test_s1g_assoc.py

Maybe a bit more information in the commit message would be good.

> diff --git a/tests/hwsim/test_s1g_assoc.py b/tests/hwsim/test_s1g_assoc.py
> new file mode 100644
> index 000000000..80ca3be31
> --- /dev/null
> +++ b/tests/hwsim/test_s1g_assoc.py
> @@ -0,0 +1,101 @@
> +# S1G association path coverage
> +#
> +# Validates that the supplicant can associate with an S1G-capable AP while
> +# preserving kHz-level channel metadata inside the BSS cache.

I am unable to run the test on the tip of wireless-next:

94aced6ed9e2 (origin/main, origin/HEAD) Merge tag 'wireless-next-2025-09-25'

Test output:
============

./vm-run.sh sta_assoc_s1g_channel
Starting test run in a virtual machine
./run-all.sh: running inside a VM
./run-all.sh: passing the following args to run-tests.py: --long sta_assoc_s1g_channel
START sta_assoc_s1g_channel 1/1
Exception during test execution: Failed to set hostapd parameter hw_mode
Traceback (most recent call last):
  File "/home/osp-nuc/hostap/tests/hwsim/./run-tests.py", line 587, in main
    t(dev, apdev)
    ~^^^^^^^^^^^^
  File "/home/osp-nuc/hostap/tests/hwsim/test_s1g_assoc.py", line 58, in test_sta_assoc_s1g_channel
    hapd = hostapd.add_ap(apdev[0], params, set_channel=False)
  File "/home/osp-nuc/hostap/tests/hwsim/hostapd.py", line 710, in add_ap
    hapd.set(f, v)
    ~~~~~~~~^^^^^^
  File "/home/osp-nuc/hostap/tests/hwsim/hostapd.py", line 243, in set
    raise Exception("Failed to set hostapd parameter " + field)
Exception: Failed to set hostapd parameter hw_mode
FAIL sta_assoc_s1g_channel 0.000659 2025-10-02 01:59:37.446980
failed tests: sta_assoc_s1g_channel

sta_assoc_s1g_channel.hostapd:
==============================

1759370600.884002: Using existing control interface directory.
1759370600.884800: Global ctrl_iface command: PING
1759370600.886400: Global ctrl_iface command: ATTACH
1759370600.886400: CTRL_IFACE monitor attached /tmp/wpa_ctrl_455-14\x00
1759370600.886404: Global ctrl_iface command: FLUSH
1759370600.886407: Global ctrl_iface command: INTERFACES
1759370600.886411: Global ctrl_iface command: REMOVE as-erp
1759370600.886411: Removing interface as-erp failed
1759370600.886414: Global ctrl_iface command: DETACH
1759370600.886414: CTRL_IFACE monitor detached /tmp/wpa_ctrl_455-14\x00
1759370600.886605: Global ctrl_iface command: ATTACH
1759370600.886605: CTRL_IFACE monitor attached /tmp/wpa_ctrl_455-16\x00
1759370600.886609: Global ctrl_iface command: REMOVE wlan3
1759370600.886609: Removing interface wlan3 failed
1759370600.886613: Global ctrl_iface command: ADD wlan3 /var/run/hostapd
1759370600.886614: Using existing control interface directory.
1759370600.886614: Add interface 'wlan3'
1759370600.886617: RX ctrl_iface - hexdump_ascii(len=6):
     41 54 54 41 43 48                                 ATTACH
1759370600.886617: CTRL_IFACE monitor attached /tmp/wpa_ctrl_455-18\x00
1759370600.886624: RX ctrl_iface - hexdump_ascii(len=18):
     53 45 54 20 64 72 69 76 65 72 20 6e 6c 38 30 32   SET driver nl802
     31 31                                             11
1759370600.886624: CTRL_IFACE SET 'driver'='nl80211'
1759370600.886628: RX ctrl_iface - hexdump_ascii(len=20):
     53 45 54 20 6c 6f 67 67 65 72 5f 73 74 64 6f 75   SET logger_stdou
     74 20 2d 31                                       t -1
1759370600.886628: CTRL_IFACE SET 'logger_stdout'='-1'
1759370600.886632: RX ctrl_iface - hexdump_ascii(len=25):
     53 45 54 20 6c 6f 67 67 65 72 5f 73 74 64 6f 75   SET logger_stdou
     74 5f 6c 65 76 65 6c 20 30                        t_level 0
1759370600.886632: CTRL_IFACE SET 'logger_stdout_level'='0'
1759370600.886635: RX ctrl_iface - hexdump_ascii(len=18):
     53 45 54 20 73 73 69 64 20 73 31 67 2d 61 73 73   SET ssid s1g-ass
     6f 63                                             oc
1759370600.886636: CTRL_IFACE SET 'ssid'='s1g-assoc'
1759370600.886639: RX ctrl_iface - hexdump_ascii(len=14):
     53 45 54 20 68 77 5f 6d 6f 64 65 20 61 68         SET hw_mode ah
1759370600.886640: CTRL_IFACE SET 'hw_mode'='ah'
1759370600.886640: Line 0: unknown hw_mode 'ah'
1759370600.886640: Failed to set configuration field 'hw_mode' to value 'ah'
1759370600.886655: Global ctrl_iface command: DETACH
1759370600.886655: CTRL_IFACE monitor detached /tmp/wpa_ctrl_455-16\x00
1759370600.886658: RX ctrl_iface - hexdump_ascii(len=6):
     44 45 54 41 43 48                                 DETACH
1759370600.886658: CTRL_IFACE monitor detached /tmp/wpa_ctrl_455-18\x00
1759370600.886867: Global ctrl_iface command: ATTACH
1759370600.886867: CTRL_IFACE monitor attached /tmp/wpa_ctrl_455-21\x00
1759370600.886871: Global ctrl_iface command: FLUSH
1759370600.886875: Global ctrl_iface command: INTERFACES
1759370600.886878: Global ctrl_iface command: REMOVE wlan3
1759370600.886878: Remove interface 'wlan3'
1759370600.886879: hostapd_interface_deinit_free(0x5500002b7ef0)
1759370600.886879: hostapd_interface_deinit_free: num_bss=1 conf->num_bss=1
1759370600.886879: hostapd_interface_deinit(0x5500002b7ef0)
1759370600.886879: wlan3: interface state UNINITIALIZED->DISABLED
1759370600.886880: hostapd_bss_deinit: deinit bss wlan3
1759370600.886880: wlan3: AP-DISABLED
1759370600.886880: CTRL_IFACE monitor send /tmp/wpa_ctrl_455-21\x00
1759370600.886880: hostapd_cleanup(hapd=0x5500002b9c40 (wlan3))
1759370600.886881: wlan3: CTRL-EVENT-TERMINATING
1759370600.886881: CTRL_IFACE monitor send /tmp/wpa_ctrl_455-21\x00
1759370600.886882: Control interface directory not empty - leaving it behind
1759370600.886882: hostapd_free_hapd_data: Interface wlan3 wasn't started
1759370600.886883: hostapd_interface_deinit_free: driver=0x5500002ab2c0 drv_priv=(nil) -> hapd_deinit
1759370600.886883: hostapd_interface_free(0x5500002b7ef0)
1759370600.886883: hostapd_interface_free: free hapd 0x5500002b9c40
1759370600.886883: hostapd_cleanup_iface(0x5500002b7ef0)
1759370600.886884: hostapd_cleanup_iface_partial(0x5500002b7ef0)
1759370600.886884: hostapd_cleanup_iface: free iface=0x5500002b7ef0
1759370600.886888: Global ctrl_iface command: REMOVE as-erp
1759370600.886888: Removing interface as-erp failed
1759370600.886891: Global ctrl_iface command: DETACH
1759370600.886891: CTRL_IFACE monitor detached /tmp/wpa_ctrl_455-21\x00
1759370600.887000: Global ctrl_iface command: ATTACH
1759370600.887000: CTRL_IFACE monitor attached /tmp/wpa_ctrl_455-24\x00
1759370600.887005: Global ctrl_iface command: RELOG

Seems to be some issue setting the hardware mode to ah.

lachlan
James Ewing Oct. 2, 2025, 3:21 a.m. UTC | #2
This series updates wpa_supplicant. Test fails at hapd = 
hostapd.add_ap(...) because hostapd rejects hw_mode=ah. I can bundle 
hostapd S1G support into the same patchset with larger code changes, if 
preferred.

james
Lachlan Hodges Oct. 2, 2025, 4:15 a.m. UTC | #3
On Wed, Oct 01, 2025 at 11:21:14PM -0400, James Ewing wrote:
> This series updates wpa_supplicant. Test fails at hapd = hostapd.add_ap(...)
> because hostapd rejects hw_mode=ah. I can bundle hostapd S1G support into
> the same patchset with larger code changes, if preferred.

Ah OK. Its not up to me but my preference would probably be a patchset that
introduces the absolute minimum to get an AP and STA associated. However if
we just did supplicant only maybe a scan based test? Im not sure.

Either way Jouni or others may have a better idea on how to start integrating
S1G. So I guess we can wait to see what others think :).

lachlan
diff mbox series

Patch

diff --git a/tests/hwsim/test_s1g_assoc.py b/tests/hwsim/test_s1g_assoc.py
new file mode 100644
index 000000000..80ca3be31
--- /dev/null
+++ b/tests/hwsim/test_s1g_assoc.py
@@ -0,0 +1,101 @@ 
+# S1G association path coverage
+#
+# Validates that the supplicant can associate with an S1G-capable AP while
+# preserving kHz-level channel metadata inside the BSS cache.
+
+import logging
+
+import hostapd
+
+from utils import HwsimSkip, list_s1g_capable_channels
+
+
+logger = logging.getLogger()
+
+
+def _pick_s1g_channel():
+    channels = list_s1g_capable_channels()
+    if not channels:
+        raise HwsimSkip("mac80211_hwsim does not expose any S1G channels")
+
+    for entry in channels:
+        if entry.get("channel"):
+            return entry
+
+    # Fall back to the first entry even if iw does not report a channel number.
+    return channels[0]
+
+
+def test_sta_assoc_s1g_channel(dev, apdev):
+    """Exercise STA association on an S1G channel and observe freq_khz plumbing"""
+
+    channel_info = _pick_s1g_channel()
+    channel = channel_info.get("channel")
+    if channel is None:
+        raise HwsimSkip("iw phy did not report an S1G channel index")
+
+    freq_khz = int(round(channel_info["freq_mhz"] * 1000))
+    primary_freq_mhz = freq_khz // 1000
+    freq_offset = freq_khz - primary_freq_mhz * 1000
+
+    logger.info(
+        "Using S1G channel %d at %.3f MHz (primary %d MHz, offset %d kHz)",
+        channel,
+        channel_info["freq_mhz"],
+        primary_freq_mhz,
+        freq_offset,
+    )
+
+    params = {
+        "ssid": "s1g-assoc",
+        "hw_mode": "ah",
+        "channel": str(channel),
+        "ieee80211n": "0",
+        "ieee80211ac": "0",
+        "ieee80211ax": "0",
+    }
+
+    hapd = hostapd.add_ap(apdev[0], params, set_channel=False)
+
+    dev[0].connect(
+        ssid="s1g-assoc",
+        key_mgmt="NONE",
+        scan_freq=str(primary_freq_mhz),
+    )
+
+    status = dev[0].get_status()
+    if status.get("freq") != str(primary_freq_mhz):
+        raise Exception(
+            "Supplicant reported freq %s, expected %d MHz" %
+            (status.get("freq"), primary_freq_mhz))
+
+    bss = dev[0].get_bss(hapd.own_addr())
+    if not bss:
+        raise Exception("Failed to fetch BSS entry for associated S1G AP")
+
+    if bss.get("freq") != str(primary_freq_mhz):
+        raise Exception(
+            "BSS table freq %s does not match primary %d MHz" %
+            (bss.get("freq"), primary_freq_mhz))
+
+    freq_khz_str = bss.get("freq_khz")
+    if freq_khz_str is None:
+        raise Exception("freq_khz missing from BSS table entry")
+    if int(freq_khz_str) != freq_khz:
+        raise Exception(
+            "freq_khz %s did not match expected %d" %
+            (freq_khz_str, freq_khz))
+
+    freq_offset_str = bss.get("freq_offset")
+    if freq_offset:
+        if freq_offset_str is None:
+            raise Exception("freq_offset missing from BSS table entry")
+        if int(freq_offset_str) != freq_offset:
+            raise Exception(
+                "freq_offset %s did not match expected %d" %
+                (freq_offset_str, freq_offset))
+    elif freq_offset_str is not None and int(freq_offset_str) != 0:
+        raise Exception("Expected zero freq_offset, saw %s" % freq_offset_str)
+
+    dev[0].request("DISCONNECT")
+