Verified on real hardware: the Raspberry Pi 5’s built-in WiFi (brcmfmac) can run a full-band iw dev wlan0 scan while wlan0 is hosting an AP/hotspot — so a second USB WiFi dongle is NOT required for a combined hotspot + scanner setup.
Bottom line for wifi-hunter
One radio does both jobs. Host the hotspot on
wlan0and scan on the samewlan0in AP mode. The only observed cost is a brief beacon stutter during each scan sweep. No dongle, no monitor-mode interface, no channel juggling.
What Was Tested
- Hardware: Raspberry Pi 5, model 2712, kernel 6.18, aarch64, over
ssh raspi. - Driver:
brcmfmac(built-in Broadcom WiFi). - Hotspot brought up with:
sudo nmcli device wifi hotspot ifname wlan0 ssid hunter-ap password huntme123 - Then, with the AP live, ran:
sudo iw dev wlan0 scan
Result
- The scan succeeded with no error while in AP mode.
- It returned the full band — both 2.4 GHz (e.g.
2412) and 5 GHz (e.g.5180) networks were seen. - The result set was identical to managed mode — no channel lock, no band restriction.
Why This Matters
Contradicts common assumption
The widely-repeated assumption is that scanning is impossible, errors out, or is channel-locked to the AP’s operating channel while an interface hosts an AP. On this Pi 5 /
brcmfmac/ kernel 6.18 combo, that is not the case — the firmware performs off-channel scanning transparently. This is why the combined single-radio hotspot+scanner design in wifi-hunter works without extra hardware.
The tradeoff is only the brief beacon stutter during each sweep (clients on the AP may see a momentary hiccup while the radio hops channels to scan), which is acceptable for a hunting tool where you scan every few seconds.
Gotcha: Scans Can HANG in AP Mode and Wedge the Server (field test 2026-07-15)
Single-radio scanning has a failure mode: indefinite hang
Scanning works, but on the same radio that hosts the AP,
iw dev wlan0 scancan occasionally hang indefinitely — not just return the usualDevice or resource busy. Without a subprocess timeout this hangs the whole server.
Symptoms
- Phone shows no networks after an initial burst.
journalctl -u wifi-huntershows a handful ofGET /scan 200then zero further/scancompletions — requests stop finishing entirely.
Root Cause
server.py serializes scans under a threading.Lock. A hung iw scan with no subprocess timeout holds the lock forever, so every subsequent /scan request blocks behind it (the phone polls every 2 s). The whole endpoint wedges.
Fix
- Added
SCAN_TIMEOUT = 8and wrapped the scan insubprocess.run(..., timeout=SCAN_TIMEOUT), catchingsubprocess.TimeoutExpired→ returnNone. A hung scan now times out, releases the lock, andrun_scanfalls back toiw dev wlan0 scan dump(kernel cache) or the last-good result. - Verified: 10 rapid
/scanhits all returned200with real JSON, no hangs.
Related earlier fix (same session)
To stop overlapping polls from colliding into Device or resource busy:
- Serialize scans under the lock (one live scan at a time).
- Debounce with
MIN_SCAN_INTERVAL = 2.0s between real scans. - Fall back to
iw dev wlan0 scan dump(cache) when a fresh scan can’t run. - Keep a last-good cache to always return something usable.
For Agents
Distinguish the two scan failure modes:
Device or resource busy= overlapping/too-frequent scans (fixed by serialize + debounce +scan dumpfallback), vs an indefinite hang = no completion at all (fixed bysubprocesstimeout so the lock releases). Both are handled inserver.py.