One sensor joined every BSSID of the test SSIDs on the five lab APs in turn — 2.4, 5 and 6 GHz — took a DHCP lease, and pinged 1.1.1.1 once a second for 15 s through that association. Run sweep-20261005-160037, 2026‑10‑05.
| Component | Version |
|---|---|
| rXg | 16.787-5-hbhowksdan51update · branch hbh/ow-ksdan-5-1-update @ 74ca4c00e |
| rxg_sdan bundle served by the rXg | 1.18-alpha-de62a9f |
| AP firmware (all five APs) | ApNos-92cbcec63 · wlan-ap rgnets-5.1.0-0.006 · OpenWrt 25.12.3 r32912-6639b15f62 |
| rg_wss_client (all five APs) | 1.0.40 |
| AP | Model | Address | Firmware | rg_wss_client |
|---|---|---|---|---|
| 189 | CIG WF189 | 172.16.11.100 | ApNos-92cbcec63 | 1.0.40 |
| 660a | Cigtech WF-660a | 172.16.11.102 | ApNos-92cbcec63 | 1.0.40 |
| 186h | CIG WF186h | 172.16.11.103 | ApNos-92cbcec63 | 1.0.40 |
| 188n | Cigtech WF-188n | 172.16.11.104 | ApNos-92cbcec63 | 1.0.40 |
| eap111 | Edgecore EAP111 | 172.16.11.105 | ApNos-92cbcec63 | 1.0.40 |
Read from each AP (/etc/openwrt_version, the running client’s version.py) and from the rXg’s generated build initializer shortly after the run. No AP had rebooted since before the sweep (all uptimes over an hour), so these are the versions the sweep ran against.
| AP | 5 GHz | 2.4 GHz | 6 GHz |
|---|---|---|---|
| 189 | pass · ch 44 · 15/15 | pass · ch 6 · 15/15 | pass · ch 65 · 15/15 |
| 660a | pass · ch 149 · 15/15 | pass · ch 6 · 15/15 | no 6 GHz radio |
| 186h | pass · ch 157 · 15/15 | ping‑loss · ch 11 · 14/15 | no 6 GHz radio |
| 188n | pass · ch 157 · 15/15 | pass · ch 6 · 15/15 | no 6 GHz radio |
| eap111 | pass · ch 149 · 15/15 | pass · ch 11 · 15/15 | no 6 GHz radio |
Every BSSID associated and leased on the first attempt; DHCP took 0.4–0.5 s each, all on VLAN 301 (10.20.2.0/24, server 10.20.2.1). The single miss is one dropped echo: the 186h’s 2.4 GHz BSSID answered every second except the fifth. The same BSSID was 15/15 on the previous sweep an hour earlier, so this reads as one lost frame on a busy 2.4 GHz channel, but under the strict 15/15 rule it is recorded as a fail.
| AP | Band | MHz | BSSID | SSID / auth | Lease | Ping |
|---|---|---|---|---|---|---|
| 189 | 5 | 5220 | d4:ba:ba:a3:15:ab | OW mPSK WPA2 · WPA2‑PSK | 10.20.2.2 | 15/15 |
| 660a | 5 | 5745 | d4:ba:ba:a1:8c:01 | OW mPSK WPA2 · WPA2‑PSK | 10.20.2.2 | 15/15 |
| 186h | 5 | 5785 | d4:ba:ba:a4:05:cb | OW mPSK WPA2 · WPA2‑PSK | 10.20.2.2 | 15/15 |
| 188n | 5 | 5785 | d4:ba:ba:ab:ba:aa | OW mPSK WPA2 · WPA2‑PSK | 10.20.2.2 | 15/15 |
| eap111 | 5 | 5745 | 22:1a:e3:db:53:68 | OW mPSK WPA2 · WPA2‑PSK | 10.20.2.2 | 15/15 |
| 189 | 2.4 | 2437 | d4:ba:ba:a3:15:aa | OW mPSK WPA2 · WPA2‑PSK | 10.20.2.3 | 15/15 |
| 660a | 2.4 | 2437 | d4:ba:ba:a1:8c:02 | OW mPSK WPA2 · WPA2‑PSK | 10.20.2.3 | 15/15 |
| 186h | 2.4 | 2462 | d4:ba:ba:a4:05:ca | OW mPSK WPA2 · WPA2‑PSK | 10.20.2.3 | 14/15 |
| 188n | 2.4 | 2437 | d4:ba:ba:ab:ba:ab | OW mPSK WPA2 · WPA2‑PSK | 10.20.2.3 | 15/15 |
| eap111 | 2.4 | 2462 | a0:1a:e3:db:53:68 | OW mPSK WPA2 · WPA2‑PSK | 10.20.2.3 | 15/15 |
| 189 | 6 | 6275 | d6:ba:ba:a3:15:ac | OW mPSK WPA3 6GHz · WPA3‑SAE (H2E, PMF) | 10.20.2.4 | 15/15 |
The sensor is a sixth AP — a CIG WF189 on the same ApNos-92cbcec63 firmware, with rgminiloader and rg_wss_client stopped so the rXg cannot reconfigure it mid‑run. Its tri‑band MLO radio is split into per‑band radios (ath12k mlo_capable=0) so one client interface can be placed on one band at a time. Targets are read live from each AP’s radios (iw dev), not from config, and include Wi‑Fi 7 MLO links. For each BSSID the sensor pins its supplicant to that exact BSSID and frequency, leases by DHCP, and sends one ICMP echo per second from a raw socket bound to the client interface (SO_BINDTODEVICE). The client sits in its own Linux VRF via rg_wss_client’s production VrfDomain, so its default route never touches the sensor’s own uplink and a reply proves the path through that association. The 6 GHz client uses the radio’s driver MAC 00:03:7f:12:5c:5b, registered on the mPSK account, since WPA3‑SAE binds the key to the station MAC. Harness: ~/lab/sensor/sweep.py driving sensord.py; raw results in runs/sweep-20261005-160037/results.jsonl.