Environment: OpenMV N6 (STM32N657X0), firmware banner OpenMV fe74ac2725; MicroPython 0f831e89f0 (omv.version_string() = 5.0.0). Three network interfaces active concurrently: network.WLAN(AP_IF) (192.168.4.1, built-in DHCP server), network.WLAN(STA_IF) as DHCP client on an external Wi-Fi network (192.168.88.0/24), and network.LAN() (W5500) as DHCP client on the same LAN.
Summary: While the AP interface is active, its built-in DHCP server responds to DHCP requests that arrive on other netifs of the shared lwIP stack, and its replies are transmitted as broadcasts through the default netif — i.e. out of the Ethernet/STA interface onto the external customer network. The device acts as an intermittent rogue DHCP server on any LAN it is connected to.
Observed problem 1 — self-poisoning: the device’s own STA (and previously Ethernet) DHCP DISCOVER can be answered by its own AP DHCP server, faster than the real router. The STA then holds 192.168.4.16/24 with gateway 192.168.4.1 (the device itself) — outbound black hole. Reproduced reliably at boot when the AP and STA come up together.
Observed problem 2 — poisoning third parties: tcpdump on the external LAN shows the AP DHCP server’s OFFERs leaving the device through its externally-connected interfaces as full L2/L3 broadcasts:
192.168.88.101.67 > 255.255.255.255.68: BOOTP/DHCP, Reply
Your-IP 192.168.4.16
DHCP-Message: Offer
Server-ID 192.168.4.1
Default-Gateway 192.168.4.1
Domain-Name-Server 192.168.4.1
Lease-Time 86400
(192.168.88.101 is the device’s own W5500 address on the external LAN; identical packets were also captured from its STA address .103:67.) Because these are broadcast to 255.255.255.255:68, any other client on the LAN in DISCOVER state can accept one — we had a real incident where a PC on the wired LAN ended up with default gateway 192.168.4.1 and lost connectivity.
Minimal repro:
import network, time
ap = network.WLAN(network.AP_IF); ap.active(True)
ap.config(essid=“TEST-AP”, password=“12345678”)
sta = network.WLAN(network.STA_IF); sta.active(True)
sta.connect(“”, “”)
while not sta.isconnected(): time.sleep_ms(200)
print(sta.ifconfig()) # intermittently (‘192.168.4.16’, …, ‘192.168.4.1’, ‘192.168.4.1’)
On a second machine on the same LAN: sudo tcpdump -i -n -vv port 67 or port 68 and renew a DHCP lease — OFFERs for 192.168.4.x appear from the device’s external IP, source port 67.
Suspected cause: the lwIP dhserver used for AP mode binds its UDP PCB to IP_ADDR_ANY:67, so it receives DISCOVER/REQUEST broadcasts delivered from any netif, and its reply (udp_sendto to broadcast) is routed via the default netif instead of the AP netif.
Suggested fix: serve only requests whose input netif is the AP netif (check ip_current_input_netif() or bind the PCB to the AP netif), and transmit replies explicitly via the AP netif (udp_sendto_if).
Impact: any application that runs the AP concurrently with Ethernet or Wi-Fi STA (e.g. AP for local provisioning + STA/eth uplink) intermittently poisons DHCP on the attached network. Application-level code can detect and reject a poisoned lease on the device’s own interfaces, but cannot stop the broadcasts reaching other clients.