From 9fef538b5b28d63b8f9cc12a9c8578c180cc23c1 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Fri, 15 Mar 2019 23:09:13 +0100 Subject: [PATCH] DHCP: fix timeout handling We allowed a delay only for few DHCP states. As a result, DHCP requests would timeout immediately after sending the initial discover, and moreover the code would then switch to "renew" state, trying to renew without an assigned address. The result is a quick succession of DISCOVER and empty REQUEST messages. Eventually, the server could send us an OFFER as reply to our DISCOVER, unless it decided that the empty REQUEST means "I'm requesting from another server", which would lead it to cancelling its lease. This would only work by luck on unbusy networks unlike the one I'm using today. Change-Id: I86905b341dc70f7dbcc780b954005e39e7c39ee0 Reviewed-on: https://review.haiku-os.org/c/1296 Reviewed-by: waddlesplash --- src/servers/net/DHCPClient.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/servers/net/DHCPClient.cpp b/src/servers/net/DHCPClient.cpp index 8781fef802..3f752e041b 100644 --- a/src/servers/net/DHCPClient.cpp +++ b/src/servers/net/DHCPClient.cpp @@ -949,10 +949,24 @@ DHCPClient::_TimeoutShift(int socket, dhcp_state& state, socket_timeout& timeout) { bigtime_t stateMaxTime = -1; + + // Compute the date at which we must consider the DHCP negociation failed. + // This varies depending on the current state. In renewing and rebinding + // states, it is based on the lease expiration. + // We can stay for up to 1 minute in the selecting and requesting states + // (these correspond to sending DHCP_DISCOVER and DHCP_REQUEST, + // respectively). + // All other states time out immediately after a single try. + // If this timeout expires, the DHCP negociation is aborted and starts + // over. As long as the timeout is not expired, we repeat the message with + // increasing delays (the delay is computed in timeout.shift below, and is + // at most equal to the timeout, but usually much shorter). if (state == RENEWING) stateMaxTime = fRebindingTime; else if (state == REBINDING) stateMaxTime = fLeaseTime; + else if (state == SELECTING || state == REQUESTING) + stateMaxTime = fRequestTime + AS_USECS(MAX_TIMEOUT); if (system_time() > stateMaxTime) { state = state == REBINDING ? INIT : REBINDING;