Skip to content

Static IP: fall back to DHCP when the gateway does not answer (phase 2 of #61) #69

Description

@Timdebruijn

Follow-up to #61, which auto-closed on the merge of #64 even though that PR shipped phase 1 only ("Closes #61 — phase 1" — the keyword does not know about phases). Filing this so the deferred half stops living in a PR description.

What is missing

A bridge configured with a static address that is wrong for its network has no way back on its own. Validation refuses everything visible from the config page — unparseable octets, non-contiguous masks, network/broadcast addresses, a gateway outside the subnet, DNS missing while something is addressed by name — but none of that can see whether the gateway actually answers. A typo'd-but-valid address, a VLAN change, or moving the bridge to another network all produce a configuration that passes validation and is unreachable.

Why the existing failure machinery does not cover this

This is the part that makes the issue worth doing rather than nice-to-have, and it is not obvious from reading wifi_manager.cpp alone.

WifiManager::connected() is WiFi.status() == WL_CONNECTED. In Arduino core 3.3.9 that status is set in exactly one place — libraries/WiFi/src/STA.cpp:183 — on the ARDUINO_EVENT_WIFI_STA_GOT_IP event.

  • On DHCP that event follows a completed lease. No DHCP server, wrong VLAN, no answer → no GOT_IPconsecutiveFailures_ climbs in loop(), decideState() reaches PortalAfterFailures, and the setup portal comes up. The user gets back in.
  • On a static address there is no lease to wait for. The address is already configured before WiFi.begin(), so GOT_IP is expected to fire on association alone.

If that holds, connected() returns true forever on a completely unusable network. consecutiveFailures_ stays 0, the portal never opens, and the retry/back-off path in loop() is dead code for this failure. Switching to a static address silently disables the recovery mechanism that DHCP users have. The only way back is the BOOT-hold factory reset, which wipes every other setting with it — so: take a config backup before setting a static address.

Step 0 of this issue is confirming that on hardware, because the whole design rests on it: static address on a network with no matching gateway, then read WiFi.status() and watch whether the portal ever appears. The core source says what should happen; the bridge has not been asked.

Why it is not a small change

The obvious implementation is the wrong one. Association succeeding tells you nothing here, so the probe has to be at layer 3:

  • What to probe. The gateway is the natural target, but plenty of gateways drop ICMP, and a bridge that falls back to DHCP because the router ignores pings is worse than the bug. ARP for the gateway is cheaper and harder to filter, since a gateway that does not answer ARP is genuinely not usable.
  • When. Only after a static association, only once per boot, with a bounded window. A probe that runs continuously turns a brief network hiccup into an address change.
  • What "fall back" means. For this boot only, or persisted? Persisting means the user's configured address quietly disappears from the config; not persisting means a bridge that reboots nightly flaps between the two. Leaning towards this-boot-only plus a visible state in the UI and REST status, so the configured value stays the source of truth and the deviation is observable.
  • How it is visible. A fallback that happens silently is its own trap — the bridge is reachable, at an address nobody expects, and the settings page still shows the static one.

Testable how

The probe policy itself belongs in the host-testable pure core, the way ipv4.{h,cpp} and the rate limiter are: a state machine over (associated, probe result, elapsed) with no WiFi.* in it. What genuinely needs hardware is the GOT_IP-on-static behaviour above and one end-to-end run on a wrong-but-valid address.

Not urgent

Every bridge in existence is on DHCP or on a static address that works. This is about the failure mode of a feature that shipped a day ago, not a fault anyone is hitting. It should not be rushed onto hardware that is currently in a metering cupboard.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions