[PATCH 1/6] tests: add S1G channel helpers

James Ewing james at teledatics.com
Wed Oct 1 09:49:56 PDT 2025


Extend the hwsim utilities with `list_s1g_capable_channels()` and
`s1g_supported()` so tests can detect IEEE 802.11ah capability directly
from `iw phy` output. The parser copes with output variants where S1G
channels omit the `[idx]` token and normalises the reported MHz into a
structured dictionary.

This is required by the upcoming S1G smoke and association scenarios to
choose an operable channel without hardcoding numbers.

Tested: python3 - <<'PY'
from utils import list_s1g_capable_channels
list_s1g_capable_channels()
PY

Signed-off-by: James Ewing <james at teledatics.com>
---
 tests/hwsim/utils.py | 63 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 63 insertions(+)

diff --git a/tests/hwsim/utils.py b/tests/hwsim/utils.py
index 5c2af5635..dd9d43262 100644
--- a/tests/hwsim/utils.py
+++ b/tests/hwsim/utils.py
@@ -185,6 +185,69 @@ def he_6ghz_supported(freq=5975):
 
     return False
 
+
+def _list_phys():
+    base = "/sys/class/ieee80211"
+    try:
+        return sorted(os.listdir(base))
+    except FileNotFoundError:
+        return []
+
+
+def list_s1g_capable_channels():
+    """Return S1G channel metadata exposed by available phys.
+
+    Each entry contains ``phy`` (string), ``freq_mhz`` (float), and
+    ``channel`` (int). The list is empty if the running kernel/mac80211
+    stack does not advertise any S1G channels.
+    """
+
+    channels = []
+    phys = _list_phys()
+    for phy in phys:
+        auto_channel = 1
+        try:
+            out = subprocess.check_output(["iw", "phy", phy, "info"],
+                                          stderr=subprocess.DEVNULL,
+                                          universal_newlines=True)
+        except Exception:
+            continue
+
+        for line in out.splitlines():
+            stripped = line.strip()
+            if not stripped.startswith('* '):
+                continue
+
+            match = re.match(r"\*\s+([0-9]+(?:\.[0-9]+)?)\s+MHz(?:\s+\[(\d+)\])?",
+                             stripped)
+            if not match:
+                continue
+
+            freq_mhz = float(match.group(1))
+            if freq_mhz < 700 or freq_mhz > 1000:
+                continue
+
+            if match.group(2):
+                channel = int(match.group(2))
+                auto_channel = channel + 1
+            else:
+                channel = auto_channel
+                auto_channel += 1
+
+            channels.append({
+                "phy": phy,
+                "freq_mhz": freq_mhz,
+                "channel": channel,
+            })
+
+    return channels
+
+
+def s1g_supported():
+    """Check whether any local mac80211 wiphy advertises S1G channels."""
+
+    return len(list_s1g_capable_channels()) > 0
+
 # This function checks whether the provided dev, which may be either
 # WpaSupplicant or Hostapd supports CSA.
 def csa_supported(dev):
-- 
2.43.0




More information about the Hostap mailing list