]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[dhcp] Handle DHCPNAK by returning to discovery state
authorMichael Brown <mcb30@ipxe.org>
Thu, 11 Mar 2021 15:54:26 +0000 (15:54 +0000)
committerMichael Brown <mcb30@ipxe.org>
Thu, 11 Mar 2021 16:04:19 +0000 (16:04 +0000)
Handle a DHCPNAK by returning to the discovery state to allow iPXE to
attempt to obtain a replacement IPv4 address.

Reuse the existing logic for deferring discovery when the link is
blocked: this avoids hammering a misconfigured DHCP server with a
non-stop stream of requests and allows the DHCP process to eventually
time out and fail.

Originally-implemented-by: Blake Rouse <blake.rouse@canonical.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/net/udp/dhcp.c

index 4ebd38bbbbc587cc42a8dcbff46489edc0b7b720..a335a778a125b7254bef516e50015847a49c5831 100644 (file)
@@ -443,6 +443,26 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
        dhcp_set_state ( dhcp, &dhcp_state_request );
 }
 
+/**
+ * Defer DHCP discovery
+ *
+ * @v dhcp             DHCP session
+ */
+static void dhcp_defer ( struct dhcp_session *dhcp ) {
+
+       /* Do nothing if we have reached the deferral limit */
+       if ( dhcp->count > DHCP_DISC_MAX_DEFERRALS )
+               return;
+
+       /* Return to discovery state */
+       DBGC ( dhcp, "DHCP %p deferring discovery\n", dhcp );
+       dhcp_set_state ( dhcp, &dhcp_state_discover );
+
+       /* Delay first DHCPDISCOVER */
+       start_timer_fixed ( &dhcp->timer,
+                           ( DHCP_DISC_START_TIMEOUT_SEC * TICKS_PER_SEC ) );
+}
+
 /**
  * Handle timer expiry during DHCP discovery
  *
@@ -462,14 +482,8 @@ static void dhcp_discovery_expired ( struct dhcp_session *dhcp ) {
        dhcp_tx ( dhcp );
 
        /* If link is blocked, defer DHCP discovery timeout */
-       if ( netdev_link_blocked ( dhcp->netdev ) &&
-            ( dhcp->count <= DHCP_DISC_MAX_DEFERRALS ) ) {
-               DBGC ( dhcp, "DHCP %p deferring discovery timeout\n", dhcp );
-               dhcp->start = currticks();
-               start_timer_fixed ( &dhcp->timer,
-                                   ( DHCP_DISC_START_TIMEOUT_SEC *
-                                     TICKS_PER_SEC ) );
-       }
+       if ( netdev_link_blocked ( dhcp->netdev ) )
+            dhcp_defer ( dhcp );
 }
 
 /** DHCP discovery state operations */
@@ -553,9 +567,17 @@ static void dhcp_request_rx ( struct dhcp_session *dhcp,
                DBGC ( dhcp, " for %s", inet_ntoa ( ip ) );
        DBGC ( dhcp, "\n" );
 
-       /* Filter out unacceptable responses */
+       /* Filter out invalid port */
        if ( peer->sin_port != htons ( BOOTPS_PORT ) )
                return;
+
+       /* Handle DHCPNAK */
+       if ( msgtype == DHCPNAK ) {
+               dhcp_defer ( dhcp );
+               return;
+       }
+
+       /* Filter out unacceptable responses */
        if ( msgtype /* BOOTP */ && ( msgtype != DHCPACK ) )
                return;
        if ( server_id.s_addr != dhcp->server.s_addr )