Wired + wireless client matrix: rxg_sdan 1.16 vs 1.18

Two WF‑188n, identical model / firmware / VLAN / configuration. Each AP has one wireless client and one wired client behind MAC‑auth on its LAN port, giving four client interfaces. The only variable between the two APs is the kernel module version. This extends the earlier cross‑radio east‑west result to the wired dimension.

Group 1 — north/south

Every client interface against the infrastructure it depends on: first‑hop gateway, DNS, HTTP. Both media, both APs.

TestResult
ICMP to VLAN gateway and to the rXg8/8
DNS (recursive A query)8/8
HTTP GET8/8

24/24. North/south is unaffected by the module version, on wired and wireless alike. Both wired clients complete MAC‑auth onto VLAN 301 untunneled and lease by DHCP.

Group 2 — east/west

All 12 ordered client‑to‑client pairs, under two placements (one STA per AP, then both STAs converged on one AP), each measured with ICMP, a 1 MB bidirectional TCP transfer, and 200 UDP datagrams. 72 measurements. Ordered, because a client that can send but not receive is a common failure that a single direction hides.

RelationshipResult
cross‑AP, same medium18/18
cross‑AP, cross medium24/24
same‑AP, same medium (two STAs on one radio)6/6
same‑AP, cross medium (wired ↔ wireless on one AP)6/24

That last row is the whole story, and it splits cleanly by AP:

Same‑AP wired ↔ wirelessResult
188n-96 — sdan 1.16 (abi 3)0/18 · EHOSTUNREACH, both directions
188n-99 — sdan 1.18 (abi 4)6/6 · 0% UDP loss

Every same‑AP wired‑to‑wireless pair on 1.16 fails in both directions; every one on 1.18 passes. Everything that leaves the AP works on both versions — cross‑AP is 42/42, including wired‑to‑wireless between APs, at 83‑781 Mbps up / 44‑431 Mbps down. The failure is confined to traffic that must be switched within one AP between its wired port and its wireless VIF.

Mechanism, in the counters

APrxg_sdanctl tunnels
188n-99 (1.18)vlan=301 type=vlan local-switch=true (inherited) local-sw=3776 pkts/4719844 bytes, 439 flooded
188n-96 (1.16)vlan=301 type=vlan — no local-switch capability at all

Same reason as the cross‑radio case. The wired port and the wireless client sit on separate sdan ports (eth1 and wlan0-v301) with nothing bridging them, because hostapd runs vlan_no_bridge=1 and the client VLAN is absent from the Linux bridge. Local switching is the only available path between them, and it is what 1.18 adds. Traffic that exits to the uplink never needs it, which is why cross‑AP is unaffected.

Method

Two WF‑189 sensors, each presenting two clients. The wireless client is a STA placed on an exact BSSID with verification. The wired client is the sensor’s LAN port, cabled to the AP’s LAN port, authorised by RADIUS MAC‑auth onto VLAN 301 and leased by DHCP — a real wired station, not a synthetic source. Both clients are L3‑isolated in their own Linux VRF via the production VrfDomain. Every probe is bound to its interface with SO_BINDTODEVICE rather than relying on routing, and ICMP is sent from a raw socket rather than ping -I, because BusyBox applets bind loosely and can fall back to the management default route — which would prove the AP’s uplink works rather than the path under test. Bulk transfer times the handshake separately from the transfer, since an MTU‑broken path completes the handshake and stalls on the first full‑size segment. UDP loss is counted by the receiver, not the sender. Both scenarios are declarative files that enumerate their own links, and sensors self‑reset between cases.

Cabling was verified by link‑down rather than assumed: dropping one AP’s LAN port dropped exactly one sensor’s carrier.

What this run does not show

n=1 per link per placement, and the two APs are not sampled equally. 72 measurements, one trial each. The failing side has 18 same‑AP cross‑medium measurements and the passing side has 6, because of how the placements are built: one sensor’s STA stays on 188n‑96 in both placements while the other’s is only on 188n‑99 in one. The asymmetry is in the sampling, not in the result — 0/18 and 6/6 are each internally consistent across three test types and both directions, and the earlier cross‑radio run was 0/5 vs 5/5 over five trials — but a symmetric placement set is needed before treating 6/6 as equally weighted evidence.

One uncontrolled difference. 188n‑99 also runs a patched rg_wss_client that stops a wired MAC‑auth client inheriting a WLAN’s tunnel. Both APs are untunneled plain‑VLAN in this run, so that patch should not bear on local switching, but it is not identical software end to end.

Two things this run got wrong first

Recorded because both produced confident wrong readings, and both are easy to repeat.

A VRF does not give a LAN port a path to the CPU. With the sensor’s LAN port enslaved directly to a VRF, DHCP DISCOVERs went out, the AP genuinely sent the OFFER back, and the client never saw it. The port MIB counted every frame (rx +18) while tcpdump on that same interface saw zero inbound, because on QCA nss‑dp/PPE a port only gets its frames punted to the CPU when the hardware has a forwarding instance that includes the CPU port — and a VRF is purely L3. It read exactly like a one‑way link, until interface counters at both ends were compared and matched exactly. Putting the port in a Linux bridge, and enslaving the bridge to the VRF, fixed it; rg_wss_client bridges its own downstream ports for the same reason.

A station that roams away is not removed from the old AP. Cross‑AP wireless‑to‑wireless appeared to fail in both directions while every other cross‑AP combination passed. The cause was a stale hostapd association: with no 802.11r here, a STA that reassociates elsewhere stays on the old AP until ap_max_inactivity, and that AP then answers for it locally — delivering to a phantom station instead of the uplink, which also kills the reverse direction when replies hit the same lookup. Flushing sdan’s MAC table did nothing, because the phantom is a layer above it; del_client turned 0/3 into 3/3 immediately. Real clients also roam without deauthing, so the same black‑hole window exists outside the harness. The scenario runner now evicts stale associations after every placement.