From 8abb472c3acd5a1b36188709656bdd9d4592cda1 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 13 Feb 2026 20:04:51 -0700 Subject: [PATCH] [wifi] Also require netif_is_link_up for dhcp_renew guard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DHCP_STATE_BOUND alone is insufficient — during reconnection, DHCP can remain BOUND from a previous connection while the link is down (wifi_disconnect_() doesn't stop DHCP). Both conditions are needed: DHCP must be BOUND and the interface must have link. Co-Authored-By: Claude Opus 4.6 --- esphome/components/wifi/wifi_component_esp8266.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/esphome/components/wifi/wifi_component_esp8266.cpp b/esphome/components/wifi/wifi_component_esp8266.cpp index caf362756d..4e94f86ef5 100644 --- a/esphome/components/wifi/wifi_component_esp8266.cpp +++ b/esphome/components/wifi/wifi_component_esp8266.cpp @@ -226,12 +226,16 @@ bool WiFiComponent::wifi_apply_hostname_() { intf->hostname = wifi_station_get_hostname(); #endif struct dhcp *dhcp_data = netif_dhcp_data(intf); - if (dhcp_data != nullptr && dhcp_data->state == DHCP_STATE_BOUND) { + if (dhcp_data != nullptr && dhcp_data->state == DHCP_STATE_BOUND && netif_is_link_up(intf)) { // 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 + // Both conditions are required: + // - DHCP must be BOUND (have an active lease to renew) + // - Interface must have link (able to send packets) + // During reconnection, DHCP can remain BOUND from a previous connection + // while the link is down. Calling dhcp_renew() without link 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);