[PATCH 15/18] tests: hwsim: Verify that the NDC channel is not evacuated

Andrei Otcheretianski andrei.otcheretianski at intel.com
Mon Oct 12 08:46:49 PDT 2026


Add a hwsim test that checks that NDC channel is not evacuated.

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
 tests/hwsim/test_nan.py | 88 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 88 insertions(+)

diff --git a/tests/hwsim/test_nan.py b/tests/hwsim/test_nan.py
index 920d5144a4..b9ef2b3516 100644
--- a/tests/hwsim/test_nan.py
+++ b/tests/hwsim/test_nan.py
@@ -10,6 +10,7 @@ logger = logging.getLogger()
 from utils import *
 import string
 import hwsim_utils
+import hostapd
 from hwsim import HWSimRadio, HWSimController
 from contextlib import contextmanager, ExitStack
 from test_p2p_channel import set_country
@@ -3205,6 +3206,9 @@ def _nan_get_ndc_freq(dev):
     m = re.search(r'^nan_ndc_freq=(\d+)$', status, re.MULTILINE)
     return int(m.group(1)) if m else None
 
+def _nan_bitmap_slots(bitmap):
+    return bin(int(bitmap, 16)).count("1")
+
 def _nan_get_advertised_ndc(dev, addr):
     """Query the NDC ID and time bitmap advertised in a peer's SDFs, if any
     (NAN_PEER_INFO schedule)."""
@@ -3393,3 +3397,87 @@ def test_nan_dp_ndc_not_reusable(dev, apdev, params):
             _nan_ndp_terminate(dev_a, dev_b, addr_a, init_ndi1, ndp_id1)
     finally:
         set_country("00")
+
+# TODO: Drop @disable_ipv6 once mac80211_hwsim is fixed - IPv6 MLD reports on the
+# NDI hit a "TX w/o channel" warning while the evacuation is in progress
+ at disable_ipv6
+def test_nan_dp_ndc_chan_not_evacuated(dev, apdev, params):
+    """NAN DP - channel evacuation skips the NDC channel"""
+    set_country("US")
+    try:
+        # The radio supports only two channels, so bringing up a BSS on a
+        # third one forces the driver to evacuate one of the NAN channels.
+        with hwsim_nan_radios(count=2, n_channels=2) as [wpas1, wpas2], \
+             NanDevice(wpas1, "nan0", "ndi0") as pub, \
+             NanDevice(wpas2, "nan1", "ndi1") as sub:
+
+            pssi = "aabbccdd001122334455667788"
+            sssi = "ddbbccaa001122334455667788"
+
+            # The NDC is expected on 2437 MHz, which has the fewest slots,
+            # i.e. it is the channel the driver would evacuate first if it
+            # were not protected.
+            chans = ((2437, "0e000000"), (5180, "f0000000"))
+            slots = {freq: _nan_bitmap_slots(bitmap) for freq, bitmap in chans}
+
+            pid, sid, paddr, saddr = _nan_discover_service(
+                pub, sub, "test_svc", pssi, sssi, data_path=True)
+
+            _nan_schedule_config(sub, *chans)
+            _nan_schedule_config(pub, *chans)
+
+            ndp_id, init_ndi = _nan_ndp_request_and_accept(
+                pub, sub, pid, sid, paddr, saddr,
+                req_ssi="aabbcc", resp_ssi="ddeeff",
+                configure_schedule=False)
+
+            if _nan_get_ndc_id(pub) is None:
+                raise Exception("NDC not established after NDP")
+
+            ndc_freq = _nan_get_ndc_freq(pub)
+            if ndc_freq not in slots:
+                raise Exception(f"NDC on unexpected freq {ndc_freq}")
+            # mac80211 evacuates the least used channel first; the test only
+            # proves anything while that assumption holds
+            if slots[ndc_freq] != min(slots.values()):
+                raise Exception(
+                    f"NDC freq {ndc_freq} is not the cheapest evacuation "
+                    "candidate, the test would not prove anything")
+
+            logger.info(f"NDC established on {ndc_freq} MHz")
+
+            # Bring up a BSS on a channel that NAN is not using, leaving the
+            # driver no choice but to evacuate one of the NAN channels.
+            params_ap = {"ssid": "test-nan-bss", "channel": "1",
+                         "country_code": "US", "ieee80211n": "1"}
+            hostapd.add_ap(apdev[0], params_ap)
+
+            # mac80211_hwsim keeps the radio on the NDC channel, so the STA
+            # misses the authentication response and the association never
+            # completes. Only the evacuation decision is verified here.
+            # TODO: Wait for the connection and verify that the NDP survived
+            # it once mac80211_hwsim is fixed.
+            pub.wpas.dump_monitor()
+            wpas1.connect("test-nan-bss", key_mgmt="NONE", scan_freq="2412",
+                          wait_connect=False)
+
+            ev = pub.wpas.wait_event(["NAN-CHAN-EVACUATION"], timeout=10)
+            if ev is None:
+                raise Exception("No NAN channel was evacuated for the BSS")
+
+            evac_freq = int(split_nan_event(ev)['freq'])
+            logger.info(f"Evacuated {evac_freq} MHz")
+
+            other_freq = next(freq for freq in slots if freq != ndc_freq)
+            if evac_freq != other_freq:
+                raise Exception(f"Expected {other_freq} MHz to be evacuated, "
+                                f"got {evac_freq} MHz")
+
+            # The NDC survived, so the NDP is still usable.
+            if _nan_get_ndc_freq(pub) != ndc_freq:
+                raise Exception("NDC moved after the evacuation")
+
+            _nan_test_connectivity(pub, sub)
+            _nan_ndp_terminate(pub, sub, paddr, init_ndi, ndp_id)
+    finally:
+        set_country("00")
-- 
2.53.0




More information about the Hostap mailing list