Embed the IEEE OUI registry (~1MB pre-processed text file) and resolve
the vendor for every station MAC. Locally administered MACs (U/L bit
set, used by iOS/Android private addresses and virtual interfaces) are
skipped so we don't return spurious matches against randomized prefixes.
The vendor name shows up in the device card as a secondary line, and
falls back to the title position when no DHCP hostname is available —
"Apple" with the IP and MAC is far more useful than "Sans nom".
The lookup table loads lazily (sync.Once) on the first call so the
~40k-entry parse only runs when the station discovery code is exercised.
Hostapd already parsed signal strength and rx/tx counters but the
station -> ConnectedDevice conversion threw them away. Add signalDbm,
rxBytes, txBytes and connectedAt to the OpenAPI schema and the
ConnectedDevice model, and centralise the conversion in
station.ToConnectedDevice so handlers, the periodic refresh and the
event callbacks all serialise the same shape.
Two follow-on bugs surfaced while wiring this up:
- The hostapd backend only stored station entries on first contact.
Subsequent polls were dropped, so signal and byte counters never
refreshed. Reconcile updates in checkStationChanges.
- ConnectedAt was reset to time.Now() on every conversion. Track
FirstSeen on HostapdStation when the station joins, and preserve
the timestamp across periodic refreshes in app.go so the UI's
"connected since" badge is stable.
Frontend gains a metrics row on each device card with signal bars,
total traffic and a live duration. Falls back gracefully when a
backend (DHCP, ARP) doesn't expose these fields.