From 69e8c0a92fed0c497a68e1d639ed661088f8b20c Mon Sep 17 00:00:00 2001 From: cpq Date: Fri, 30 Oct 2026 09:33:54 +0000 Subject: [PATCH] Fix: DHCP client stuck in REQUESTING state forever if the REQUEST or ACK is lost --- mongoose.c | 4 ++++ src/net_builtin.c | 4 ++++ test/mip_test.c | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/mongoose.c b/mongoose.c index e06b827f..615fd9a7 100644 --- a/mongoose.c +++ b/mongoose.c @@ -9399,6 +9399,7 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { : pkt->dhcp->siaddr ? pkt->dhcp->siaddr : pkt->ip->src); ifp->state = MG_TCPIP_STATE_REQ; // REQUESTING state + ifp->lease_expire = ifp->now + 5000; // No ACK by then: start over } else if (msgtype == 5) { // DHCPACK if (ifp->state == MG_TCPIP_STATE_REQ && ip && gw && lease) { // got an IP uint64_t rand; @@ -10706,6 +10707,9 @@ static void mg_ip_poll(struct mg_tcpip_if *ifp, bool s1) { if (ifp->enable_dhcp_client && s1) { if (ifp->state == MG_TCPIP_STATE_UP) { tx_dhcp_discover(ifp); // INIT (4.4.1) + } else if (ifp->state == MG_TCPIP_STATE_REQ && + ifp->now >= ifp->lease_expire) { + ifp->state = MG_TCPIP_STATE_UP; // REQUEST or ACK lost: DISCOVER again } else if (ifp->state == MG_TCPIP_STATE_READY && ifp->lease_expire > 0) { // BOUND / RENEWING / REBINDING if (ifp->now >= ifp->lease_expire) { diff --git a/src/net_builtin.c b/src/net_builtin.c index 95f29e93..ec9882f0 100644 --- a/src/net_builtin.c +++ b/src/net_builtin.c @@ -734,6 +734,7 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { : pkt->dhcp->siaddr ? pkt->dhcp->siaddr : pkt->ip->src); ifp->state = MG_TCPIP_STATE_REQ; // REQUESTING state + ifp->lease_expire = ifp->now + 5000; // No ACK by then: start over } else if (msgtype == 5) { // DHCPACK if (ifp->state == MG_TCPIP_STATE_REQ && ip && gw && lease) { // got an IP uint64_t rand; @@ -2041,6 +2042,9 @@ static void mg_ip_poll(struct mg_tcpip_if *ifp, bool s1) { if (ifp->enable_dhcp_client && s1) { if (ifp->state == MG_TCPIP_STATE_UP) { tx_dhcp_discover(ifp); // INIT (4.4.1) + } else if (ifp->state == MG_TCPIP_STATE_REQ && + ifp->now >= ifp->lease_expire) { + ifp->state = MG_TCPIP_STATE_UP; // REQUEST or ACK lost: DISCOVER again } else if (ifp->state == MG_TCPIP_STATE_READY && ifp->lease_expire > 0) { // BOUND / RENEWING / REBINDING if (ifp->now >= ifp->lease_expire) { diff --git a/test/mip_test.c b/test/mip_test.c index 365650f1..75656867 100644 --- a/test/mip_test.c +++ b/test/mip_test.c @@ -80,6 +80,10 @@ static void test_statechange(void) { onstatechange(&iface); ASSERT(executed == true); executed = false; + iface.enable_dhcp_client = true; // DHCP REQUEST unanswered: start over + iface.state = MG_TCPIP_STATE_REQ, iface.lease_expire = 0; + mg_ip_poll(&iface, true); + ASSERT(iface.state == MG_TCPIP_STATE_UP); } #if MG_ENABLE_IPV6 static void mif6_fn(struct mg_tcpip_if *ifp, int ev, void *ev_data) {