#19685·micropython

USB-NCM DHCP-Server shared with WiFi-AP DHCP-Server -> local link IP on AP

Author: SciLorCreated Sep 5, 2026Updated Sep 9, 2026
Labelsbug

Port, board and/or hardware

pico2w

MicroPython version

v1.29.0

Reproduction

Build with USB-NCM enabled and run this on a Pico W/Pico 2 W:

import network

# Brings up the SoftAP - own DHCP server on 192.168.4.0/24.
ap = network.WLAN(network.AP_IF)
ap.config(ssid="repro-ap", password="testtest", security=network.WLAN.SEC_WPA_WPA2)
ap.active(True)
print("AP up:", ap.ifconfig())  # ('192.168.4.1', '255.255.255.0', ...)

# Brings up USB-NCM - its own separate DHCP server on a MAC-derived
# 169.254.x.0/16 pool, active unconditionally regardless of WiFi mode.
nic = network.USBD_NCM()
nic.active(True)
print("USB-NCM up:", nic.ifconfig())  # ('169.254.X.1', '255.255.0.0', ...)

Then connect any WiFi client (phone/laptop) to repro-ap. Expected: the client gets a 192.168.4.x lease. Actual: the client gets a 169.254.X.y lease (confirm via the client's own reported gateway/DNS, which will read back as the USB-NCM interface's own 169.254.X.1 address) and cannot reach 192.168.4.1.

Expected behaviour

Get an IP-Address in the 192.168.0.0/16 range

Observed behaviour

Getting a local link 169.254 IP via the WiFi AP DHCP, which is identical to the one on the USB-NCM

Additional Information

Suggested fix

Scope each DHCP server's UDP PCB to its own interface with the existing udp_bind_netif() API, so lwIP's first-line netif check in udp_input_local_match() (if (pcb->netif_idx != NETIF_NO_INDEX && pcb->netif_idx != netif_get_index(current_input_netif)) return 0;) rejects it outright for any broadcast arriving on a different interface:

Add a struct netif *netif parameter to dhcp_server_init() (shared/netutils/dhcpserver.h/.c). In dhcp_server_init(), after dhcp_socket_bind()'s udp_bind() call, add udp_bind_netif(d->udp, netif);. Update both call sites to pass their own netif: extmod/network_cyw43.c's AP-mode cyw43_cb_tcpip_init() path (in lib/cyw43-driver/src/cyw43_lwip.c) — pass n (the netif it just created). extmod/network_usbd_ncm.c's ncm_init() — pass &ncm_obj.netif. This keeps both DHCP servers fully functional and correctly isolated to their own interface, rather than requiring either one to be disabled to avoid the collision.

Code of Conduct

Yes, I agree