From: Roy Marples Date: Mon, 15 Jun 2015 09:59:37 +0000 (+0000) Subject: Remove a pre-existing IPv4LL address when binding a DHCP address. X-Git-Tag: v6.9.1~50 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f282a7b1269af9c08db4e6f804f1bdc8374f2542;p=thirdparty%2Fdhcpcd.git Remove a pre-existing IPv4LL address when binding a DHCP address. --- diff --git a/dhcp.c b/dhcp.c index b250db77..b311ec09 100644 --- a/dhcp.c +++ b/dhcp.c @@ -1895,9 +1895,6 @@ dhcp_arp_probed(struct arp_state *astate) } dhcp_close(astate->iface); - /* Stop IPv4LL now we have a working DHCP address */ - ipv4ll_drop(astate->iface); - eloop_timeout_delete(astate->iface->ctx->eloop, NULL, astate->iface); #ifdef IN_IFF_TENTATIVE logger(astate->iface->ctx, LOG_DEBUG, "%s: DAD completed for %s", @@ -1907,6 +1904,9 @@ dhcp_arp_probed(struct arp_state *astate) #else dhcp_bind(astate->iface, astate); #endif + + /* Stop IPv4LL now we have a working DHCP address */ + ipv4ll_drop(astate->iface); } static void diff --git a/ipv4ll.c b/ipv4ll.c index 6a7e70fb..48c18b8e 100644 --- a/ipv4ll.c +++ b/ipv4ll.c @@ -201,7 +201,7 @@ ipv4ll_conflicted(struct arp_state *astate, const struct arp_msg *amsg) fail = astate->addr.s_addr; /* RFC 3927 2.5, Conflict Defense */ - if (IN_LINKLOCAL(htonl(state->addr.s_addr)) && + if (IN_LINKLOCAL(ntohl(state->addr.s_addr)) && amsg && amsg->sip.s_addr == state->addr.s_addr) fail = state->addr.s_addr; @@ -331,11 +331,10 @@ ipv4ll_freedrop(struct interface *ifp, int drop) struct ipv4ll_state *state; assert(ifp != NULL); - if ((state = IPV4LL_STATE(ifp)) == NULL) - return; + state = IPV4LL_STATE(ifp); /* Free ARP state first because ipv4_deladdr might also ... */ - if (state->arp) { + if (state && state->arp) { eloop_timeout_delete(ifp->ctx->eloop, NULL, state->arp); arp_free(state->arp); state->arp = NULL; @@ -344,11 +343,24 @@ ipv4ll_freedrop(struct interface *ifp, int drop) /* Unlike other protocols, we don't run a script on stopping IPv4LL * because we piggy back on the state of DHCP. */ if (drop && (ifp->options->options & DHCPCD_NODROP) != DHCPCD_NODROP) { - if (state->addr.s_addr != INADDR_ANY) { + struct ipv4_state *istate; + struct ipv4_addr *ia, *ian; + + if (state && state->addr.s_addr != INADDR_ANY) { ipv4_deladdr(ifp, &state->addr, &inaddr_llmask); state->addr.s_addr = INADDR_ANY; } + + /* Free any other link local addresses that might exist. */ + istate = IPV4_STATE(ifp); + TAILQ_FOREACH_SAFE(ia, &istate->addrs, next, ian) { + if (IN_LINKLOCAL(ntohl(ia->addr.s_addr))) + ipv4_deladdr(ifp, &ia->addr, &ia->net); + } + } + + if (state) { + free(state); + ifp->if_data[IF_DATA_IPV4LL] = NULL; } - free(state); - ifp->if_data[IF_DATA_IPV4LL] = NULL; }