blob: 2a2e2703bcface2b882cabcc148f446be34b3cd6 [file] [log] [blame]
From 610536003081133dd1ee1d347f2561109a1add85 Mon Sep 17 00:00:00 2001
From: Paul Stewart <pstew@chromium.org>
Date: Wed, 13 May 2015 14:32:31 -0700
Subject: [PATCH] Accept an ACK after a NAK
When a NAK is received, wait for a response interval before
acting on it. In doing so, this allows for networks that
may have duelling DHCP servers which both consider themselves
authoritative on a network. Since other DHCP clients also
act in a similar manner, issues of this sort end up undetected
and network administrators thus consider this situation nominal.
BUG=chromium:384897
TEST=New network_DhcpNak test subcase in CL:208214
Reviewed-on: https://chromium-review.googlesource.com/208207
---
dhcp.c | 43 ++++++++++++++++++++++++++++---------------
1 file changed, 28 insertions(+), 15 deletions(-)
diff --git a/dhcp.c b/dhcp.c
index 7196f13..e57f6e0 100644
--- a/dhcp.c
+++ b/dhcp.c
@@ -2631,6 +2631,30 @@ dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
}
static void
+handle_nak(void *arg)
+{
+ struct interface *ifp = arg;
+ struct dhcp_state *state = D_STATE(ifp);
+
+ logger(ifp->ctx, LOG_INFO, "%s: Handling deferred NAK", ifp->name);
+ if (!(ifp->ctx->options & DHCPCD_TEST)) {
+ dhcp_drop(ifp, "NAK");
+ unlink(state->leasefile);
+ }
+
+ /* If we constantly get NAKS then we should slowly back off */
+ eloop_timeout_add_sec(ifp->ctx->eloop,
+ state->nakoff, dhcp_discover, ifp);
+ if (state->nakoff == 0)
+ state->nakoff = 1;
+ else {
+ state->nakoff *= 2;
+ if (state->nakoff > NAKOFF_MAX)
+ state->nakoff = NAKOFF_MAX;
+ }
+}
+
+static void
dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
const struct in_addr *from)
{
@@ -2748,8 +2772,6 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
}
if (type == DHCP_NAK) {
- /* We should restart on a NAK */
- log_dhcp(LOG_WARNING, "NAK:", ifp, dhcp, from);
if ((msg = get_option_string(ifp->ctx, dhcp, DHO_MESSAGE))) {
logger(ifp->ctx, LOG_WARNING, "%s: message: %s",
ifp->name, msg);
@@ -2757,21 +2779,11 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
}
if (state->state == DHS_INFORM) /* INFORM should not be NAKed */
return;
- if (!(ifp->ctx->options & DHCPCD_TEST)) {
- dhcp_drop(ifp, "NAK");
- unlink(state->leasefile);
- }
- /* If we constantly get NAKS then we should slowly back off */
+ log_dhcp(LOG_WARNING, "NAK (deferred):", ifp, dhcp, from);
eloop_timeout_add_sec(ifp->ctx->eloop,
- state->nakoff, dhcp_discover, ifp);
- if (state->nakoff == 0)
- state->nakoff = 1;
- else {
- state->nakoff *= 2;
- if (state->nakoff > NAKOFF_MAX)
- state->nakoff = NAKOFF_MAX;
- }
+ DHCP_BASE, handle_nak, ifp);
+
return;
}
@@ -2888,6 +2900,7 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
return;
}
eloop_timeout_delete(ifp->ctx->eloop, send_discover, ifp);
+ eloop_timeout_delete(ifp->ctx->eloop, handle_nak, ifp);
/* We don't request BOOTP addresses */
if (type) {
/* We used to ARP check here, but that seems to be in
--
2.2.0.rc0.207.ga3a616c