| 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 |
| |