]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
IPv4LL: Fix for prior on NetBSD at least.
authorRoy Marples <roy@marples.name>
Wed, 20 May 2020 11:17:00 +0000 (12:17 +0100)
committerRoy Marples <roy@marples.name>
Wed, 20 May 2020 11:17:00 +0000 (12:17 +0100)
src/arp.c
src/arp.h
src/ipv4ll.c
src/ipv4ll.h

index b81277c9d42bc62029359f2d746acbe3142bb5ee..b458e4512e01b1ad820e4dd6c47bcdce065e7e00 100644 (file)
--- a/src/arp.c
+++ b/src/arp.c
@@ -509,7 +509,7 @@ arp_announceaddr(struct dhcpcd_ctx *ctx, const struct in_addr *ia)
                if (iap == NULL)
                        continue;
 #ifdef IN_IFF_NOTUSEABLE
-               if (!(iap->addr_flags & IN_IFF_NOTUSEABLE))
+               if (iap->addr_flags & IN_IFF_NOTUSEABLE)
                        continue;
 #endif
                if (iff != NULL && iff->metric < ifp->metric)
index f072802700dc416e27bc9aaba7c55809d6fcbb3d..f1074fa3527e0fb5b932cf82ecdad9b4c291c944 100644 (file)
--- a/src/arp.h
+++ b/src/arp.h
@@ -47,7 +47,8 @@
 
 #ifdef IN_IFF_DUPLICATED
 /* NetBSD gained RFC 5227 support in the kernel.
- * This means dhcpcd doesn't need ARP except for ARPing support. */
+ * This means dhcpcd doesn't need ARP except for ARPing support
+ * and ARP announcing an address. */
 #if defined(__NetBSD_Version__) && __NetBSD_Version__ >= 799003900
 #define KERNEL_RFC5227
 #endif
index 5832703d1d734ccc8c0dc49da9c74d4121cef339..efddc2a3afc917604af23064b2a400c0177b7b3f 100644 (file)
@@ -57,8 +57,6 @@ static const struct in_addr inaddr_llbcast = {
        .s_addr = HTONL(LINKLOCAL_BCAST)
 };
 
-static void ipv4ll_start1(struct interface *, struct arp_state *);
-
 static in_addr_t
 ipv4ll_pickaddr(struct interface *ifp)
 {
@@ -170,17 +168,19 @@ ipv4ll_env(FILE *fp, const char *prefix, const struct interface *ifp)
        return 5;
 }
 
+#ifndef KERNEL_RFC5227
 static void
 ipv4ll_announced_arp(struct arp_state *astate)
 {
        struct ipv4ll_state *state = IPV4LL_STATE(astate->iface);
 
        state->conflicts = 0;
-#ifdef KERNEL_RFC5227
        arp_free(astate);
-#endif
+       if (state->arp == astate)
+               state->arp = NULL;
 }
 
+/* This is the callback by ARP freeing */
 static void
 ipv4ll_arpfree(struct arp_state *astate)
 {
@@ -191,23 +191,32 @@ ipv4ll_arpfree(struct arp_state *astate)
                state->arp = NULL;
 }
 
+/* This is us freeing any ARP state */
+static void
+ipv4ll_freearp(struct interface *ifp)
+{
+       struct ipv4ll_state *state;
+
+       state = IPV4LL_STATE(ifp);
+       if (state == NULL || state->arp == NULL)
+               return;
+
+       eloop_timeout_delete(ifp->ctx->eloop, NULL, state->arp);
+       arp_free(state->arp);
+       state->arp = NULL;
+}
+#else
+#define        ipv4ll_freearp(ifp)
+#endif
+
 static void
 ipv4ll_not_found(struct interface *ifp)
 {
        struct ipv4ll_state *state;
        struct ipv4_addr *ia;
-#ifdef KERNEL_RFC5227
-       struct arp_state *astate;
-       bool new_addr;
-#endif
 
        state = IPV4LL_STATE(ifp);
-       assert(state != NULL);
-
        ia = ipv4_iffindaddr(ifp, &state->pickedaddr, &inaddr_llmask);
-#ifdef KERNEL_RFC5227
-       new_addr = ia == NULL;
-#endif
 #ifdef IN_IFF_NOTREADY
        if (ia == NULL || ia->addr_flags & IN_IFF_NOTREADY)
 #endif
@@ -227,6 +236,7 @@ ipv4ll_not_found(struct interface *ifp)
                return;
        logdebugx("%s: DAD completed for %s", ifp->name, ia->saddr);
 #endif
+
 test:
        state->addr = ia;
        state->down = false;
@@ -236,41 +246,17 @@ test:
                return;
        }
        rt_build(ifp->ctx, AF_INET);
-#ifdef KERNEL_RFC5227
-       if (!new_addr) {
-               astate = arp_new(ifp, &ia->addr);
-               if (ifp->ctx->options & DHCPCD_FORKED)
-                       return;
-               if (astate != NULL) {
-                       astate->announced_cb = ipv4ll_announced_arp;
-                       astate->free_cb = ipv4ll_arpfree;
-                       arp_announce(astate);
-               }
-       }
-#else
-       arp_announce(state->arp);
-#endif
+       arp_announceaddr(ifp->ctx, &ia->addr);
        script_runreason(ifp, "IPV4LL");
        dhcpcd_daemonise(ifp->ctx);
 }
 
-static void
-ipv4ll_startifp(void *arg)
-{
-       struct interface *ifp = arg;
-       struct ipv4ll_state *state;
-
-       state = IPV4LL_STATE(ifp);
-       ipv4ll_start1(ifp, state->arp);
-}
-
 static void
 ipv4ll_found(struct interface *ifp)
 {
        struct ipv4ll_state *state = IPV4LL_STATE(ifp);
 
-       if (state->arp != NULL)
-               arp_cancel(state->arp);
+       ipv4ll_freearp(ifp);
        if (++state->conflicts == MAX_CONFLICTS)
                logerrx("%s: failed to acquire an IPv4LL address",
                    ifp->name);
@@ -278,7 +264,7 @@ ipv4ll_found(struct interface *ifp)
        eloop_timeout_add_sec(ifp->ctx->eloop,
            state->conflicts >= MAX_CONFLICTS ?
            RATE_LIMIT_INTERVAL : PROBE_WAIT,
-           ipv4ll_startifp, ifp);
+           ipv4ll_start, ifp);
 }
 
 static void
@@ -286,62 +272,49 @@ ipv4ll_defend_failed(struct interface *ifp)
 {
        struct ipv4ll_state *state = IPV4LL_STATE(ifp);
 
-       if (state->arp != NULL)
-               arp_cancel(state->arp);
+       ipv4ll_freearp(ifp);
        ipv4_deladdr(state->addr, 1);
-       state->down = true;
        state->addr = NULL;
        rt_build(ifp->ctx, AF_INET);
        script_runreason(ifp, "IPV4LL");
        state->pickedaddr.s_addr = ipv4ll_pickaddr(ifp);
-       ipv4ll_start1(ifp, state->arp);
+       ipv4ll_start(ifp);
 }
 
 #ifndef KERNEL_RFC5227
 static void
 ipv4ll_not_found_arp(struct arp_state *astate)
 {
-       struct interface *ifp;
-       struct ipv4ll_state *state;
-
-       assert(astate != NULL);
-       assert(astate->iface != NULL);
 
-       ifp = astate->iface;
-       state = IPV4LL_STATE(ifp);
-       assert(state != NULL);
-       assert(state->arp == astate);
-       ipv4ll_not_found(ifp);
+       ipv4ll_not_found(astate->iface);
 }
 
 static void
 ipv4ll_found_arp(struct arp_state *astate, __unused const struct arp_msg *amsg)
 {
-       struct interface *ifp = astate->iface;
-       struct ipv4ll_state *state = IPV4LL_STATE(ifp);
 
-       assert(state->arp == astate);
-       ipv4ll_found(ifp);
+       ipv4ll_found(astate->iface);
 }
 
 static void
 ipv4ll_defend_failed_arp(struct arp_state *astate)
 {
-       struct ipv4ll_state *state = IPV4LL_STATE(astate->iface);
 
-       assert(state->arp == astate);
        ipv4ll_defend_failed(astate->iface);
 }
 #endif
 
-static void
-ipv4ll_start1(struct interface *ifp, struct arp_state *astate)
+void
+ipv4ll_start(void *arg)
 {
+       struct interface *ifp = arg;
        struct ipv4ll_state *state;
        struct ipv4_addr *ia;
        bool repick;
+#ifndef KERNEL_RFC5227
+       struct arp_state *astate;
+#endif
 
-       assert(ifp != NULL);
        if ((state = IPV4LL_STATE(ifp)) == NULL) {
                ifp->if_data[IF_DATA_IPV4LL] = calloc(1, sizeof(*state));
                if ((state = IPV4LL_STATE(ifp)) == NULL) {
@@ -377,26 +350,6 @@ ipv4ll_start1(struct interface *ifp, struct arp_state *astate)
                state->seeded = true;
        }
 
-#ifndef KERNEL_RFC5227
-       if (astate == NULL) {
-               if (state->arp != NULL)
-                       return;
-               if ((astate = arp_new(ifp, NULL)) == NULL)
-                       return;
-               astate->found_cb = ipv4ll_found_arp;
-               astate->not_found_cb = ipv4ll_not_found_arp;
-               astate->announced_cb = ipv4ll_announced_arp;
-               astate->defend_failed_cb = ipv4ll_defend_failed_arp;
-               astate->free_cb = ipv4ll_arpfree;
-               state->arp = astate;
-       } else
-               assert(state->arp == astate);
-#else
-       UNUSED(astate);
-#endif
-
-       state->down = true;
-
        /* Find the previosuly used address. */
        if (state->pickedaddr.s_addr != INADDR_ANY)
                ia = ipv4_iffindaddr(ifp, &state->pickedaddr, NULL);
@@ -418,11 +371,9 @@ ipv4ll_start1(struct interface *ifp, struct arp_state *astate)
 #endif
 
        state->addr = ia;
+       state->down = true;
        if (ia != NULL) {
                state->pickedaddr = ia->addr;
-#ifndef KERNEL_RFC5227
-               astate->addr = ia->addr;
-#endif
 #ifdef IN_IFF_TENTATIVE
                if (ia->addr_flags & (IN_IFF_TENTATIVE | IN_IFF_DETACHED)) {
                        loginfox("%s: waiting for DAD to complete on %s",
@@ -440,9 +391,20 @@ ipv4ll_start1(struct interface *ifp, struct arp_state *astate)
        loginfox("%s: probing for an IPv4LL address", ifp->name);
        if (repick || state->pickedaddr.s_addr == INADDR_ANY)
                state->pickedaddr.s_addr = ipv4ll_pickaddr(ifp);
+
 #ifndef KERNEL_RFC5227
-       astate->addr = state->pickedaddr;
+       ipv4ll_freearp(ifp);
+       state->arp = astate = arp_new(ifp, NULL);
+       if (state->arp == NULL)
+               return;
+
+       astate->found_cb = ipv4ll_found_arp;
+       astate->not_found_cb = ipv4ll_not_found_arp;
+       astate->announced_cb = ipv4ll_announced_arp;
+       astate->defend_failed_cb = ipv4ll_defend_failed_arp;
+       astate->free_cb = ipv4ll_arpfree;
 #endif
+
 #ifdef IN_IFF_DUPLICATED
        ipv4ll_not_found(ifp);
 #else
@@ -450,26 +412,6 @@ ipv4ll_start1(struct interface *ifp, struct arp_state *astate)
 #endif
 }
 
-void
-ipv4ll_start(void *arg)
-{
-
-       ipv4ll_start1(arg, NULL);
-}
-
-static void
-ipv4ll_freearp(struct interface *ifp)
-{
-       struct ipv4ll_state *state;
-
-       state = IPV4LL_STATE(ifp);
-       if (state == NULL || state->arp == NULL)
-               return;
-
-       eloop_timeout_delete(ifp->ctx->eloop, NULL, state->arp);
-       arp_free(state->arp);
-}
-
 void
 ipv4ll_drop(struct interface *ifp)
 {
@@ -516,6 +458,7 @@ ipv4ll_reset(struct interface *ifp)
 
        if (state == NULL)
                return;
+       ipv4ll_freearp(ifp);
        state->pickedaddr.s_addr = INADDR_ANY;
        state->seeded = false;
 }
@@ -587,9 +530,7 @@ ipv4ll_handleifa(int cmd, struct ipv4_addr *ia, pid_t pid)
                ipv4ll_not_found(ifp);
        else if (ia->addr_flags & IN_IFF_DUPLICATED) {
                logerrx("%s: DAD detected %s", ifp->name, ia->saddr);
-#ifdef KERNEL_RFC5227
-               arp_freeaddr(ifp, &ia->addr);
-#endif
+               ipv4ll_freearp(ifp);
                ipv4_deladdr(ia, 1);
                state->addr = NULL;
                rt_build(ifp->ctx, AF_INET);
index b986cfb6fd4edc1aab7ce4eb02583279ffbcda7f..bdf4c67da5ebe559d39f4b780fcf2399fa6654d0 100644 (file)
 struct ipv4ll_state {
        struct in_addr pickedaddr;
        struct ipv4_addr *addr;
-       struct arp_state *arp;
        char randomstate[128];
        bool seeded;
        bool down;
        size_t conflicts;
+#ifndef KERNEL_RFC5227
+       struct arp_state *arp;
+#endif
 };
 
 #define        IPV4LL_STATE(ifp)                                                      \