]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Remove a pre-existing IPv4LL address when binding a DHCP address.
authorRoy Marples <roy@marples.name>
Mon, 15 Jun 2015 09:59:37 +0000 (09:59 +0000)
committerRoy Marples <roy@marples.name>
Mon, 15 Jun 2015 09:59:37 +0000 (09:59 +0000)
dhcp.c
ipv4ll.c

diff --git a/dhcp.c b/dhcp.c
index b250db778cd77abab0a9bfa671cdad626f104138..b311ec09af991763e4495249246a57c4009b6b0f 100644 (file)
--- 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
index 6a7e70fb4ca7c8352fb0ba4b1154f9cfe8c5c609..48c18b8ed07c6b65c4d5c97ab35c14e2f0e28bfb 100644 (file)
--- 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;
 }