From c53d50b6cf2424f160bf5d7a6fdad9cb3b76bdf7 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 13 Feb 2026 14:36:51 -0600 Subject: [PATCH] [wifi] Use DHCP_STATE_BOUND check instead of netif_is_link_up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit netif_is_link_up() is insufficient — if wifi_station_connect() completes quickly (e.g. fast_connect), the setup() call at line 710 could reach dhcp_renew() with link up but DHCP still in SELECTING or REQUESTING state, causing the same state corruption. Check dhcp->state == DHCP_STATE_BOUND directly to ensure dhcp_renew() is only called when there is an actual lease to renew. Co-Authored-By: Claude Opus 4.6 --- .../components/wifi/wifi_component_esp8266.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/esphome/components/wifi/wifi_component_esp8266.cpp b/esphome/components/wifi/wifi_component_esp8266.cpp index b913ca5f70..caf362756d 100644 --- a/esphome/components/wifi/wifi_component_esp8266.cpp +++ b/esphome/components/wifi/wifi_component_esp8266.cpp @@ -16,7 +16,8 @@ extern "C" { #include "lwip/err.h" #include "lwip/dns.h" #include "lwip/dhcp.h" -#include "lwip/init.h" // LWIP_VERSION_ +#include "lwip/prot/dhcp.h" // DHCP_STATE_BOUND +#include "lwip/init.h" // LWIP_VERSION_ #include "lwip/apps/sntp.h" #include "lwip/netif.h" // struct netif #include @@ -224,13 +225,14 @@ bool WiFiComponent::wifi_apply_hostname_() { #else intf->hostname = wifi_station_get_hostname(); #endif - if (netif_dhcp_data(intf) != nullptr && netif_is_link_up(intf)) { - // Renew already started DHCP leases to inform server of hostname change. - // Only attempt when the interface has link — calling dhcp_renew() without - // an active connection corrupts lwIP's DHCP state machine (it unconditionally - // sets state to RENEWING before attempting to send, and never rolls back on - // failure). This causes dhcp_network_changed() to call dhcp_reboot() instead - // of dhcp_discover() when WiFi later connects, sending a bogus DHCP REQUEST + struct dhcp *dhcp_data = netif_dhcp_data(intf); + if (dhcp_data != nullptr && dhcp_data->state == DHCP_STATE_BOUND) { + // Renew already-bound DHCP leases to inform server of hostname change. + // Only attempt when DHCP is BOUND — calling dhcp_renew() in any other + // state corrupts lwIP's DHCP state machine (it unconditionally sets state + // to RENEWING before attempting to send, and never rolls back on failure). + // This causes dhcp_network_changed() to call dhcp_reboot() instead of + // dhcp_discover() when WiFi later connects, sending a bogus DHCP REQUEST // for IP 0.0.0.0 that can put some routers into a persistent bad state. err_t lwipret = dhcp_renew(intf); if (lwipret != ERR_OK) {