diff --git a/core/openwrt/src/tollgate/mod.rs b/core/openwrt/src/tollgate/mod.rs index c05d96a4..8017f8f0 100644 --- a/core/openwrt/src/tollgate/mod.rs +++ b/core/openwrt/src/tollgate/mod.rs @@ -86,12 +86,27 @@ fn restart_services(router: &Router, enabled: bool) -> Result<()> { // Reload wireless so wireless.tollgate.disabled takes effect on the radio — // `network restart` alone doesn't reliably reconfigure wifi interfaces. router.run_ok("wifi down 2>&1; wifi up 2>&1")?; - // Observed live: netifd can lose the race to claim br-tollgate as the - // wifi vif attaches to it during the restart above, leaving the - // interface reported "up: false, DEVICE_CLAIM_FAILED" even though the - // bridge device and its member both exist. An explicit down/up of just - // this logical interface resolves it — needed before NoDogSplash starts, - // since it refuses to start against an interface netifd hasn't brought up. - router.run_ok("sleep 2; ifdown tollgate 2>&1; sleep 1; ifup tollgate 2>&1; sleep 2")?; + // Observed live, twice, in two different ways: netifd can lose the race + // to claim br-tollgate as the wifi vif attaches to it during the restart + // above. The first time it showed up as netifd reporting + // "up: false, DEVICE_CLAIM_FAILED"; the second time netifd reported the + // interface up with its address assigned while the kernel-level device + // genuinely had none (`ip -4 addr show br-tollgate` empty) — dnsmasq + // logged "DHCP packet received on br-tollgate which has no address" and + // silently dropped every DISCOVER. A single blind ifdown/ifup isn't + // trustworthy here — verify the address actually landed at the kernel + // level (not just what netifd claims) and retry the cycle if not, since + // NoDogSplash refuses to start against an interface that isn't really up + // and dnsmasq will silently refuse to answer DHCP without erroring loudly. + router.run_ok( + "sleep 2; \ + for i in 1 2 3 4 5; do \ + ifdown tollgate 2>&1; sleep 1; ifup tollgate 2>&1; sleep 2; \ + ip -4 addr show br-tollgate 2>/dev/null | grep -q 'inet ' && break; \ + echo \"br-tollgate has no kernel-level IPv4 address after cycle $i, retrying\"; \ + done; \ + ip -4 addr show br-tollgate 2>/dev/null | grep -q 'inet ' || \ + { echo 'br-tollgate never got a kernel-level IPv4 address after 5 cycles'; exit 1; }" + )?; Ok(()) }