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

James Ewing james at teledatics.com
Tue Sep 30 12:11:38 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 | 55 ++++++++++++++++++++++++++++++++++++++++++++
  1 file changed, 55 insertions(+)

diff --git a/tests/hwsim/utils.py b/tests/hwsim/utils.py
index 5c2af5635..26db40b8d 100644
--- a/tests/hwsim/utils.py
+++ b/tests/hwsim/utils.py
@@ -185,6 +185,61 @@ 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:
+        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
+
+            channels.append({
+                "phy": phy,
+                "freq_mhz": freq_mhz,
+                "channel": int(match.group(2)) if match.group(2) else None,
+            })
+
+    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