From: Roy Marples Date: Fri, 24 Oct 2014 11:00:03 +0000 (+0000) Subject: Improve IPv4LL -> DHCP state transitions X-Git-Tag: v6.6.0~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=741dbf636d821d3e5f857c353fdc4da140c1deb8;p=thirdparty%2Fdhcpcd.git Improve IPv4LL -> DHCP state transitions --- diff --git a/arp.c b/arp.c index d7c4652f..0db52c14 100644 --- a/arp.c +++ b/arp.c @@ -301,6 +301,13 @@ arp_new(struct interface *ifp) { return astate; } +void +arp_cancel(struct arp_state *astate) +{ + + eloop_timeout_delete(astate->iface->ctx->eloop, NULL, astate); +} + void arp_free(struct arp_state *astate) { diff --git a/arp.h b/arp.h index 77c40e7a..ccea3603 100644 --- a/arp.h +++ b/arp.h @@ -69,6 +69,7 @@ void arp_report_conflicted(const struct arp_state *, const struct arp_msg *); void arp_announce(struct arp_state *); void arp_probe(struct arp_state *); struct arp_state *arp_new(struct interface *); +void arp_cancel(struct arp_state *); void arp_free(struct arp_state *); void arp_close(struct interface *); #endif diff --git a/dhcp.c b/dhcp.c index 2207b9e5..9cbd8bf0 100644 --- a/dhcp.c +++ b/dhcp.c @@ -1415,7 +1415,6 @@ dhcp_close(struct interface *ifp) if (state == NULL) return; - arp_close(ifp); if (state->raw_fd != -1) { eloop_event_delete(ifp->ctx->eloop, state->raw_fd, 0); close(state->raw_fd); @@ -1669,7 +1668,7 @@ send_message(struct interface *iface, uint8_t type, default: if (!(iface->ctx->options & DHCPCD_TEST)) dhcp_drop(iface, "FAIL"); - dhcp_close(iface); + dhcp_free(iface); eloop_timeout_delete(iface->ctx->eloop, NULL, iface); callback = NULL; @@ -1778,7 +1777,6 @@ dhcp_expire(void *arg) eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); dhcp_drop(ifp, "EXPIRE"); unlink(state->leasefile); - state->interval = 0; dhcp_discover(ifp); } @@ -1924,7 +1922,7 @@ dhcp_bind(struct interface *ifp, struct arp_state *astate) return; } if (state->reason == NULL) { - if (state->old) { + if (state->old && state->new->cookie != htonl(MAGIC_COOKIE)) { if (state->old->yiaddr == state->new->yiaddr && lease->server.s_addr) state->reason = "RENEW"; @@ -2158,15 +2156,18 @@ dhcp_drop(struct interface *ifp, const char *reason) struct timespec ts; #endif + state = D_STATE(ifp); /* dhcp_start may just have been called and we don't yet have a state * but we do have a timeout, so punt it. */ - eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); - - state = D_STATE(ifp); - if (state == NULL) + if (state == NULL) { + eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); return; - dhcp_auth_reset(&state->auth); - dhcp_close(ifp); + } + if (state->state != DHS_IPV4LL_BOUND) { + eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); + dhcp_auth_reset(&state->auth); + dhcp_close(ifp); + } if (ifp->options->options & DHCPCD_RELEASE) { unlink(state->leasefile); if (ifp->carrier != LINK_DOWN && @@ -2348,6 +2349,7 @@ dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg) return; } dhcp_close(astate->iface); + arp_close(astate->iface); eloop_timeout_delete(astate->iface->ctx->eloop, NULL, astate->iface); dhcpcd_startinterface(astate->iface); @@ -2538,7 +2540,8 @@ dhcp_handledhcp(struct interface *iface, struct dhcp_message **dhcpp, case 0: log_dhcp(LOG_WARNING, "IPv4LL disabled from", iface, dhcp, from); - dhcp_close(iface); + dhcp_drop(iface, "EXPIRE"); + arp_close(iface); eloop_timeout_delete(iface->ctx->eloop, NULL, iface); eloop_timeout_add_sec(iface->ctx->eloop, @@ -2769,6 +2772,7 @@ dhcp_handlepacket(void *arg) syslog(LOG_ERR, "%s: dhcp if_readrawpacket: %m", ifp->name); dhcp_close(ifp); + arp_close(ifp); break; } if (valid_udp_packet(ifp->ctx->packet, bytes, @@ -2919,6 +2923,7 @@ dhcp_free(struct interface *ifp) struct dhcpcd_ctx *ctx; dhcp_close(ifp); + arp_close(ifp); if (state) { free(state->old); free(state->new); @@ -3064,9 +3069,6 @@ dhcp_start1(void *arg) return; } - /* Close any pre-existing sockets as we're starting over */ - dhcp_close(ifp); - state = D_STATE(ifp); state->start_uptime = uptime(); free(state->offer); diff --git a/ipv4ll.c b/ipv4ll.c index b4cb14f4..eaa56435 100644 --- a/ipv4ll.c +++ b/ipv4ll.c @@ -174,12 +174,13 @@ ipv4ll_conflicted(struct arp_state *astate, const struct arp_msg *amsg) } } + arp_cancel(astate); if (++state->conflicts == MAX_CONFLICTS) syslog(LOG_ERR, "%s: failed to acquire an IPv4LL address", astate->iface->name); astate->addr.s_addr = ipv4ll_pick_addr(astate); eloop_timeout_add_sec(astate->iface->ctx->eloop, - state->conflicts > MAX_CONFLICTS ? + state->conflicts >= MAX_CONFLICTS ? RATE_LIMIT_INTERVAL : PROBE_WAIT, ipv4ll_probe, astate); }