[PATCH v2] dhcp: fix overflow causing retries to stop
James Prestwood <[email protected]> Thu, 11 Jan 2024 05:33:31 -0800
| Newsgroups | dev.linux.lists.ell |
|---|---|
| Message-ID | <[email protected]> |
If DHCP is in a SELECTING/REQUESTING state and the number of attempts
reached a value where 2 << attempts overflowed an unsigned int the
next timeout would become zero, causing DHCP to never retry without
any event notification.
Roughly 2 minutes has passed when we reach >5 attempts so it makes
little sense to retry indefinitely, at least without notifying the
upper layers (which could decided to retry themselves).
Add a new event L_DHCP_CLIENT_EVENT_MAX_RETRIES_REACHED to notify
netconfig of the situation. Netconfig will then send a failure event
and the consumer can decide how to proceed.
Fixes: f130c448 ("dhcp: Introduce timeout fuzzing")
---
ell/dhcp.c | 19 ++++++++++++++++---
ell/dhcp.h | 1 +
ell/netconfig.c | 6 ++++++
3 files changed, 23 insertions(+), 3 deletions(-)
v2:
* Added new event instead of retry forever.
diff --git a/ell/dhcp.c b/ell/dhcp.c
index ece3e23..79fc54c 100644
--- a/ell/dhcp.c
+++ b/ell/dhcp.c
@@ -557,10 +557,23 @@ static void dhcp_client_timeout_resend(struct l_timeout *timeout,
* RFC 2131 Section 4.1:
* "The retransmission delay SHOULD be doubled with subsequent
* retransmissions up to a maximum of 64 seconds.
+ *
+ * The maximum is hit after 5 attempts (2 << 5 == 64)
*/
- client->attempt += 1;
- next_timeout = minsize(2 << client->attempt, 64);
- break;
+ if (client->attempt <= 5) {
+ next_timeout = 2 << client->attempt++;
+ break;
+ }
+
+ /*
+ * DHCP server is non-responsive after ~2 minutes, relay this to
+ * upper layers do decide how to proceed
+ */
+ CLIENT_DEBUG("Max request/discover retires reached");
+
+ dhcp_client_event_notify(client,
+ L_DHCP_CLIENT_EVENT_MAX_RETRIES_REACHED);
+ return;
case DHCP_STATE_INIT:
case DHCP_STATE_INIT_REBOOT:
case DHCP_STATE_REBOOTING:
diff --git a/ell/dhcp.h b/ell/dhcp.h
index 6ce4dde..4db573d 100644
--- a/ell/dhcp.h
+++ b/ell/dhcp.h
@@ -41,6 +41,7 @@ enum l_dhcp_client_event {
L_DHCP_CLIENT_EVENT_LEASE_EXPIRED,
L_DHCP_CLIENT_EVENT_LEASE_RENEWED,
L_DHCP_CLIENT_EVENT_NO_LEASE,
+ L_DHCP_CLIENT_EVENT_MAX_RETRIES_REACHED,
};
enum l_dhcp_server_event {
diff --git a/ell/netconfig.c b/ell/netconfig.c
index ab59299..1e6912a 100644
--- a/ell/netconfig.c
+++ b/ell/netconfig.c
@@ -548,6 +548,12 @@ static void netconfig_dhcp_event_handler(struct l_dhcp_client *client,
if (!l_dhcp_client_start(nc->dhcp_client))
netconfig_failed(nc, AF_INET);
+ break;
+ case L_DHCP_CLIENT_EVENT_MAX_RETRIES_REACHED:
+ L_WARN_ON(nc->v4_configured);
+
+ netconfig_failed(nc, AF_INET);
+
break;
}
}
--
2.34.1