]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
ARP: Refactor so that ACD is available for all inet addresses
authorRoy Marples <roy@marples.name>
Thu, 18 Apr 2019 13:54:47 +0000 (14:54 +0100)
committerRoy Marples <roy@marples.name>
Thu, 18 Apr 2019 13:54:47 +0000 (14:54 +0100)
Callbacks have also been improved so they are more descriptive.

src/arp.c
src/arp.h
src/dhcp.c
src/ipv4.c
src/ipv4.h
src/ipv4ll.c
src/ipv4ll.h

index cbcefa8dc33c6cc8fee37c83503f25481205e20f..faf8be1ca2b47f2cbba6f0377d5e3c1de9b71fc8 100644 (file)
--- a/src/arp.c
+++ b/src/arp.c
@@ -62,8 +62,9 @@
 /* Assert the correct structure size for on wire */
 __CTASSERT(sizeof(struct arphdr) == 8);
 
-ssize_t
-arp_request(const struct interface *ifp, in_addr_t sip, in_addr_t tip)
+static ssize_t
+arp_request(const struct interface *ifp,
+    const struct in_addr *sip, const struct in_addr *tip)
 {
        uint8_t arp_buffer[ARP_LEN];
        struct arphdr ar;
@@ -74,7 +75,7 @@ arp_request(const struct interface *ifp, in_addr_t sip, in_addr_t tip)
        ar.ar_hrd = htons(ifp->family);
        ar.ar_pro = htons(ETHERTYPE_IP);
        ar.ar_hln = ifp->hwlen;
-       ar.ar_pln = sizeof(sip);
+       ar.ar_pln = sizeof(tip->s_addr);
        ar.ar_op = htons(ARPOP_REQUEST);
 
        p = arp_buffer;
@@ -93,9 +94,12 @@ arp_request(const struct interface *ifp, in_addr_t sip, in_addr_t tip)
 
        APPEND(&ar, sizeof(ar));
        APPEND(ifp->hwaddr, ifp->hwlen);
-       APPEND(&sip, sizeof(sip));
+       if (sip != NULL)
+               APPEND(&sip->s_addr, sizeof(sip->s_addr));
+       else
+               ZERO(sizeof(tip->s_addr));
        ZERO(ifp->hwlen);
-       APPEND(&tip, sizeof(tip));
+       APPEND(&tip->s_addr, sizeof(tip->s_addr));
 
        state = ARP_CSTATE(ifp);
        return bpf_send(ifp, state->bpf_fd, ETHERTYPE_ARP, arp_buffer, len);
@@ -105,6 +109,77 @@ eexit:
        return -1;
 }
 
+static void
+arp_report_conflicted(const struct arp_state *astate,
+    const struct arp_msg *amsg)
+{
+       char buf[HWADDR_LEN * 3];
+
+       if (amsg == NULL) {
+               logerrx("%s: DAD detected %s",
+                   astate->iface->name, inet_ntoa(astate->addr));
+               return;
+       }
+
+       logerrx("%s: hardware address %s claims %s",
+           astate->iface->name,
+           hwaddr_ntoa(amsg->sha, astate->iface->hwlen, buf, sizeof(buf)),
+           inet_ntoa(astate->addr));
+}
+
+
+static void
+arp_found(struct arp_state *astate, const struct arp_msg *amsg)
+{
+       struct interface *ifp;
+       struct ivp4_addr *ia;
+#ifndef KERNEL_RFC5227
+       struct timespec now, defend;
+#endif
+
+       arp_report_conflicted(astate, amsg);
+       ifp = astate->iface;
+
+#pragma GCC diagnostic push /* GCC is clearly wrong about this warning. */
+#pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
+       /* If we haven't added the address we're doing a probe. */
+       ia = ipv4_iffindaddr(ifp, &astate->addr, NULL);
+#pragma GCC diagnostic pop
+       if (ia == NULL) {
+               if (astate->found_cb != NULL)
+                       astate->found_cb(astate, amsg);
+               return;
+       }
+
+#ifndef KERNEL_RFC5227
+       /* RFC 3927 Section 2.5 says a defence should
+        * broadcast an ARP announcement.
+        * Because the kernel will also unicast a reply to the
+        * hardware address which requested the IP address
+        * the other IPv4LL client will receieve two ARP
+        * messages.
+        * If another conflict happens within DEFEND_INTERVAL
+        * then we must drop our address and negotiate a new one. */
+       defend.tv_sec = astate->defend.tv_sec + DEFEND_INTERVAL;
+       defend.tv_nsec = astate->defend.tv_nsec;
+       clock_gettime(CLOCK_MONOTONIC, &now);
+       if (timespeccmp(&defend, &now, >))
+               logwarnx("%s: %d second defence failed for %s",
+                   ifp->name, DEFEND_INTERVAL, inet_ntoa(astate->addr));
+       else if (arp_request(ifp, &astate->addr, &astate->addr) == -1)
+               logerr(__func__);
+       else {
+               logdebugx("%s: defended address %s",
+                   ifp->name, inet_ntoa(astate->addr));
+               astate->defend = now;
+               return;
+       }
+#endif
+
+       if (astate->defend_failed_cb != NULL)
+               astate->defend_failed_cb(astate);
+}
+
 static void
 arp_packet(struct interface *ifp, uint8_t *data, size_t len)
 {
@@ -164,14 +239,13 @@ arp_packet(struct interface *ifp, uint8_t *data, size_t len)
        memcpy(&arm.tha, hw_t, ar.ar_hln);
        memcpy(&arm.tip.s_addr, hw_t + ar.ar_hln, ar.ar_pln);
 
-       /* Run the conflicts */
+       /* Match the ARP probe to our states */
        state = ARP_CSTATE(ifp);
        TAILQ_FOREACH_SAFE(astate, &state->arp_states, next, astaten) {
-               if (arm.sip.s_addr != astate->addr.s_addr &&
-                   arm.tip.s_addr != astate->addr.s_addr)
-                       continue;
-               if (astate->conflicted_cb)
-                       astate->conflicted_cb(astate, &arm);
+               if (IN_ARE_ADDR_EQUAL(&arm.sip, &astate->addr) ||
+                   (IN_IS_ADDR_UNSPECIFIED(&arm.sip) &&
+                   IN_ARE_ADDR_EQUAL(&arm.tip, &astate->addr)))
+                       arp_found(astate, &arm);
        }
 }
 
@@ -243,7 +317,7 @@ arp_read(void *arg)
        }
 }
 
-int
+static int
 arp_open(struct interface *ifp)
 {
        struct iarp_state *state;
@@ -265,7 +339,8 @@ arp_probed(void *arg)
 {
        struct arp_state *astate = arg;
 
-       astate->probed_cb(astate);
+       timespecclear(&astate->defend);
+       astate->not_found_cb(astate);
 }
 
 static void
@@ -290,7 +365,7 @@ arp_probe1(void *arg)
            ifp->name, inet_ntoa(astate->addr),
            astate->probes ? astate->probes : PROBE_NUM, PROBE_NUM,
            timespec_to_double(&tv));
-       if (arp_request(ifp, 0, astate->addr.s_addr) == -1)
+       if (arp_request(ifp, NULL, &astate->addr) == -1)
                logerr(__func__);
 }
 
@@ -314,6 +389,23 @@ arp_probe(struct arp_state *astate)
 }
 #endif /* ARP */
 
+static struct arp_state *
+arp_find(struct interface *ifp, const struct in_addr *addr)
+{
+       struct iarp_state *state;
+       struct arp_state *astate;
+
+       if ((state = ARP_STATE(ifp)) == NULL)
+               goto out;
+       TAILQ_FOREACH(astate, &state->arp_states, next) {
+               if (astate->addr.s_addr == addr->s_addr && astate->iface == ifp)
+                       return astate;
+       }
+out:
+       errno = ESRCH;
+       return NULL;
+}
+
 static void
 arp_announced(void *arg)
 {
@@ -342,7 +434,7 @@ arp_announce1(void *arg)
                logdebugx("%s: ARP announcing %s (%d of %d)",
                    ifp->name, inet_ntoa(astate->addr),
                    astate->claims, ANNOUNCE_NUM);
-       if (arp_request(ifp, astate->addr.s_addr, astate->addr.s_addr) == -1)
+       if (arp_request(ifp, &astate->addr, &astate->addr) == -1)
                logerr(__func__);
        eloop_timeout_add_sec(ifp->ctx->eloop, ANNOUNCE_WAIT,
            astate->claims < ANNOUNCE_NUM ? arp_announce1 : arp_announced,
@@ -400,12 +492,26 @@ arp_announce(struct arp_state *astate)
        arp_announce1(astate);
 }
 
+void
+arp_ifannounceaddr(struct interface *ifp, const struct in_addr *ia)
+{
+       struct arp_state *astate;
+
+       astate = arp_find(ifp, ia);
+       if (astate == NULL) {
+               astate = arp_new(ifp, ia);
+               if (astate == NULL)
+                       return;
+               astate->announced_cb = arp_free;
+       }
+       arp_announce(astate);
+}
+
 void
 arp_announceaddr(struct dhcpcd_ctx *ctx, const struct in_addr *ia)
 {
        struct interface *ifp;
        struct ipv4_addr *iaf;
-       struct arp_state *astate;
 
        TAILQ_FOREACH(ifp, ctx->ifaces, next) {
                iaf = ipv4_iffindaddr(ifp, ia, NULL);
@@ -419,54 +525,7 @@ arp_announceaddr(struct dhcpcd_ctx *ctx, const struct in_addr *ia)
        if (ifp == NULL)
                return;
 
-       astate = arp_find(ifp, ia);
-       if (astate != NULL)
-               arp_announce(astate);
-}
-
-void
-arp_ifannounceaddr(struct interface *ifp, const struct in_addr *ia)
-{
-       struct arp_state *astate;
-
-       astate = arp_new(ifp, ia);
-       if (astate != NULL)
-               arp_announce(astate);
-}
-
-void
-arp_report_conflicted(const struct arp_state *astate,
-    const struct arp_msg *amsg)
-{
-
-       if (amsg != NULL) {
-               char buf[HWADDR_LEN * 3];
-
-               logerrx("%s: hardware address %s claims %s",
-                   astate->iface->name,
-                   hwaddr_ntoa(amsg->sha, astate->iface->hwlen,
-                   buf, sizeof(buf)),
-                   inet_ntoa(astate->failed));
-       } else
-               logerrx("%s: DAD detected %s",
-                   astate->iface->name, inet_ntoa(astate->failed));
-}
-
-struct arp_state *
-arp_find(struct interface *ifp, const struct in_addr *addr)
-{
-       struct iarp_state *state;
-       struct arp_state *astate;
-
-       if ((state = ARP_STATE(ifp)) == NULL)
-               goto out;
-       TAILQ_FOREACH(astate, &state->arp_states, next) {
-               if (astate->addr.s_addr == addr->s_addr && astate->iface == ifp)
-                       return astate;
-       }
-out:
-       errno = ESRCH;
-       return NULL;
+       arp_ifannounceaddr(ifp, ia);
 }
 
 struct arp_state *
@@ -532,61 +591,28 @@ arp_free(struct arp_state *astate)
        arp_tryfree(ifp);
 }
 
-static void
-arp_free_but1(struct interface *ifp, struct arp_state *astate)
-{
-       struct iarp_state *state;
-
-       if ((state = ARP_STATE(ifp)) != NULL) {
-               struct arp_state *p, *n;
-
-               TAILQ_FOREACH_SAFE(p, &state->arp_states, next, n) {
-                       if (p != astate)
-                               arp_free(p);
-               }
-       }
-}
-
 void
-arp_free_but(struct arp_state *astate)
+arp_freeaddr(struct interface *ifp, const struct in_addr *ia)
 {
+       struct arp_state *astate;
 
-       arp_free_but1(astate->iface, astate);
+       astate = arp_find(ifp, ia);
+       arp_free(astate);
 }
 
 void
 arp_drop(struct interface *ifp)
-{
-
-       arp_free_but1(ifp, NULL);
-       arp_close(ifp);
-}
-
-void
-arp_handleifa(int cmd, struct ipv4_addr *addr)
 {
        struct iarp_state *state;
-       struct arp_state *astate, *asn;
+       struct arp_state *astate;
 
-       state = ARP_STATE(addr->iface);
+       state = ARP_STATE(ifp);
        if (state == NULL)
                return;
 
-       TAILQ_FOREACH_SAFE(astate, &state->arp_states, next, asn) {
-               if (astate->addr.s_addr != addr->addr.s_addr)
-                       continue;
-               if (cmd == RTM_DELADDR)
-                       arp_free(astate);
-#ifdef IN_IFF_DUPLICATED
-               if (cmd != RTM_NEWADDR)
-                       continue;
-               if (addr->addr_flags & IN_IFF_DUPLICATED) {
-                       if (astate->conflicted_cb)
-                               astate->conflicted_cb(astate, NULL);
-               } else if (!(addr->addr_flags & IN_IFF_NOTUSEABLE)) {
-                       if (astate->probed_cb)
-                               astate->probed_cb(astate);
-               }
-#endif
+       while ((astate = TAILQ_FIRST(&state->arp_states)) != NULL) {
+               arp_free(astate);
        }
+
+       /* No need to close because the last free will close */
 }
index 1c0be04351e1758c90f63f75f6ff78bb561a5e9b..d29b06b857c8af90ac1b61478f89deb40c88d237 100644 (file)
--- a/src/arp.h
+++ b/src/arp.h
@@ -63,15 +63,16 @@ struct arp_state {
        TAILQ_ENTRY(arp_state) next;
        struct interface *iface;
 
-       void (*probed_cb)(struct arp_state *);
+       void (*found_cb)(struct arp_state *, const struct arp_msg *);
+       void (*not_found_cb)(struct arp_state *);
        void (*announced_cb)(struct arp_state *);
-       void (*conflicted_cb)(struct arp_state *, const struct arp_msg *);
+       void (*defend_failed_cb)(struct arp_state *);
        void (*free_cb)(struct arp_state *);
 
        struct in_addr addr;
        int probes;
        int claims;
-       struct in_addr failed;
+       struct timespec defend;
 };
 TAILQ_HEAD(arp_statehead, arp_state);
 
@@ -87,20 +88,14 @@ struct iarp_state {
        ((const struct iarp_state *)(ifp)->if_data[IF_DATA_ARP])
 
 #ifdef ARP
-int arp_open(struct interface *);
-ssize_t arp_request(const struct interface *, in_addr_t, in_addr_t);
-void arp_probe(struct arp_state *);
-void arp_report_conflicted(const struct arp_state *, const struct arp_msg *);
 struct arp_state *arp_new(struct interface *, const struct in_addr *);
-struct arp_state *arp_find(struct interface *, const struct in_addr *);
+void arp_probe(struct arp_state *);
 void arp_announce(struct arp_state *);
 void arp_announceaddr(struct dhcpcd_ctx *, const struct in_addr *);
 void arp_ifannounceaddr(struct interface *, const struct in_addr *);
 void arp_cancel(struct arp_state *);
 void arp_free(struct arp_state *);
-void arp_free_but(struct arp_state *);
+void arp_freeaddr(struct interface *, const struct in_addr *);
 void arp_drop(struct interface *);
-
-void arp_handleifa(int, struct ipv4_addr *);
 #endif /* ARP */
 #endif /* ARP_H */
index f7cdefc9fb8afc4786fb9873bff15359a442bb63..f20c73fa3ba2f913d319b52feed87f55fde8e1fa 100644 (file)
@@ -124,8 +124,9 @@ static const char * const dhcp_params[] = {
 };
 
 static int dhcp_openbpf(struct interface *);
+static void dhcp_start1(void *);
 #ifdef ARP
-static void dhcp_arp_conflicted(struct arp_state *, const struct arp_msg *);
+static void dhcp_arp_found(struct arp_state *, const struct arp_msg *);
 #endif
 static void dhcp_handledhcp(struct interface *, struct bootp *, size_t,
     const struct in_addr *);
@@ -1921,35 +1922,6 @@ dhcp_request(void *arg)
        send_request(ifp);
 }
 
-static int
-dhcp_leaseextend(struct interface *ifp)
-{
-
-#ifdef ARP
-       if (ifp->options->options & DHCPCD_ARP) {
-               const struct dhcp_state *state;
-               struct arp_state *astate;
-
-               state = D_CSTATE(ifp);
-               if ((astate = arp_new(ifp, &state->lease.addr)) == NULL)
-                       return -1;
-               astate->conflicted_cb = dhcp_arp_conflicted;
-
-#ifndef KERNEL_RFC5227
-               if (arp_open(ifp) == -1)
-                       return -1;
-#endif
-
-               logwarnx("%s: extending lease until DaD failure or DHCP",
-                   ifp->name);
-               return 0;
-       }
-#endif
-
-       logwarnx("%s: extending lease", ifp->name);
-       return 0;
-}
-
 static void
 dhcp_expire1(struct interface *ifp)
 {
@@ -1968,12 +1940,12 @@ dhcp_expire(void *arg)
 {
        struct interface *ifp = arg;
 
-       logerrx("%s: DHCP lease expired", ifp->name);
        if (ifp->options->options & DHCPCD_LASTLEASE_EXTEND) {
-               if (dhcp_leaseextend(ifp) == 0)
-                       return;
-               logerr(__func__);
+               logwarnx("%s: DHCP lease expired, extending lease", ifp->name);
+               return;
        }
+
+       logerrx("%s: DHCP lease expired", ifp->name);
        dhcp_expire1(ifp);
 }
 
@@ -2039,41 +2011,18 @@ dhcp_rebind(void *arg)
        send_rebind(ifp);
 }
 
-#ifdef ARP
 static void
-dhcp_arp_probed(struct arp_state *astate)
+dhcp_finish_dad(struct interface *ifp, struct in_addr *ia)
 {
-       struct interface *ifp;
-       struct dhcp_state *state;
-       struct if_options *ifo;
+       struct dhcp_state *state = D_STATE(ifp);
 
-       ifp = astate->iface;
-       state = D_STATE(ifp);
-       ifo = ifp->options;
-#ifdef ARPING
-       if (ifo->arping_len && state->arping_index < ifo->arping_len) {
-               /* We didn't find a profile for this
-                * address or hwaddr, so move to the next
-                * arping profile */
-               if (++state->arping_index < ifo->arping_len) {
-                       astate->addr.s_addr =
-                           ifo->arping[state->arping_index];
-                       arp_probe(astate);
-                       return;
-               }
-               arp_free(astate);
-               dhcpcd_startinterface(ifp);
+       if (state->state != DHS_PROBE)
                return;
-       }
-#endif
-
-       /* Already bound so DAD has worked */
-       if (state->state == DHS_BOUND)
+       if (state->offer == NULL || state->offer->yiaddr != ia->s_addr)
                return;
 
-       logdebugx("%s: DAD completed for %s",
-           ifp->name, inet_ntoa(astate->addr));
-       if (!(ifo->options & DHCPCD_INFORM))
+       logdebugx("%s: DAD completed for %s", ifp->name, inet_ntoa(*ia));
+       if (!(ifp->options->options & DHCPCD_INFORM))
                dhcp_bind(ifp);
 #ifndef IN_IFF_TENTATIVE
        else {
@@ -2100,23 +2049,79 @@ dhcp_arp_probed(struct arp_state *astate)
        ipv4ll_drop(ifp);
 #endif
 
-       if (ifo->options & DHCPCD_INFORM)
+       if (ifp->options->options & DHCPCD_INFORM)
                dhcp_inform(ifp);
 }
 
+
+static void
+dhcp_addr_duplicated(struct interface *ifp, struct in_addr *ia)
+{
+       struct dhcp_state *state = D_STATE(ifp);
+#ifdef IN_IFF_DUPLICATED
+       struct ipv4_addr *iap;
+#endif
+
+       if ((state->offer == NULL || state->offer->yiaddr != ia->s_addr) &&
+           !IN_ARE_ADDR_EQUAL(ia, &state->lease.addr))
+               return;
+
+       /* RFC 2131 3.1.5, Client-server interaction */
+       logerrx("%s: DAD detected %s", ifp->name, inet_ntoa(*ia));
+       unlink(state->leasefile);
+       if (!(ifp->options->options & DHCPCD_STATIC) && !state->lease.frominfo)
+               dhcp_decline(ifp);
+#ifdef IN_IFF_DUPLICATED
+       if ((iap = ipv4_iffindaddr(ifp, ia, NULL)) != NULL)
+               ipv4_deladdr(iap, 0);
+#endif
+       eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+       eloop_timeout_add_sec(ifp->ctx->eloop,
+           DHCP_RAND_MAX, dhcp_discover, ifp);
+}
+
+#ifdef ARP
 static void
-dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
+dhcp_arp_not_found(struct arp_state *astate)
 {
        struct interface *ifp;
        struct dhcp_state *state;
-#ifdef ARPING
        struct if_options *ifo;
-#endif
 
        ifp = astate->iface;
        state = D_STATE(ifp);
+       ifo = ifp->options;
+#ifdef ARPING
+       if (ifo->arping_len && state->arping_index < ifo->arping_len) {
+               /* We didn't find a profile for this
+                * address or hwaddr, so move to the next
+                * arping profile */
+               if (++state->arping_index < ifo->arping_len) {
+                       astate->addr.s_addr =
+                           ifo->arping[state->arping_index];
+                       arp_probe(astate);
+                       return;
+               }
+               arp_free(astate);
+               dhcpcd_startinterface(ifp);
+               return;
+       }
+#endif
 
+       dhcp_finish_dad(ifp, &astate->addr);
+}
+
+static void
+dhcp_arp_found(struct arp_state *astate, const struct arp_msg *amsg)
+{
 #ifdef ARPING
+       struct interface *ifp;
+       struct dhcp_state *state;
+       struct if_options *ifo;
+
+       ifp = astate->iface;
+       state = D_STATE(ifp);
+
        ifo = ifp->options;
        if (state->arping_index != -1 &&
            state->arping_index < ifo->arping_len &&
@@ -2125,17 +2130,14 @@ dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
        {
                char buf[HWADDR_LEN * 3];
 
-               astate->failed.s_addr = ifo->arping[state->arping_index];
-               arp_report_conflicted(astate, amsg);
                hwaddr_ntoa(amsg->sha, ifp->hwlen, buf, sizeof(buf));
                if (dhcpcd_selectprofile(ifp, buf) == -1 &&
-                   dhcpcd_selectprofile(ifp,
-                       inet_ntoa(astate->failed)) == -1)
+                   dhcpcd_selectprofile(ifp, inet_ntoa(amsg->sip)) == -1)
                {
                        /* We didn't find a profile for this
                         * address or hwaddr, so move to the next
                         * arping profile */
-                       dhcp_arp_probed(astate);
+                       dhcp_arp_not_found(astate);
                        return;
                }
                arp_free(astate);
@@ -2145,65 +2147,18 @@ dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
        }
 #endif
 
-       /* RFC 2131 3.1.5, Client-server interaction
-        * NULL amsg means IN_IFF_DUPLICATED */
-       if (amsg == NULL || (state->offer &&
-           (amsg->sip.s_addr == state->offer->yiaddr ||
-           (amsg->sip.s_addr == 0 &&
-           amsg->tip.s_addr == state->offer->yiaddr))))
-       {
-#ifdef IN_IFF_DUPLICATED
-               struct ipv4_addr *ia;
-#endif
-
-               if (amsg)
-                       astate->failed.s_addr = state->offer->yiaddr;
-               else
-                       astate->failed = astate->addr;
-               arp_report_conflicted(astate, amsg);
-               unlink(state->leasefile);
-#ifdef ARP
-               if (!(ifp->options->options & DHCPCD_STATIC) &&
-                   !state->lease.frominfo)
-                       dhcp_decline(ifp);
-#endif
-#ifdef IN_IFF_DUPLICATED
-               if ((ia = ipv4_iffindaddr(ifp, &astate->addr, NULL)) != NULL)
-                       ipv4_deladdr(ia, 1);
-#endif
-               arp_free(astate);
-               eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
-               eloop_timeout_add_sec(ifp->ctx->eloop,
-                   DHCP_RAND_MAX, dhcp_discover, ifp);
-               return;
-       }
-
-       /* Bound address */
-       if (amsg && state->addr &&
-           amsg->sip.s_addr == state->addr->addr.s_addr)
-       {
-               astate->failed = state->addr->addr;
-               arp_report_conflicted(astate, amsg);
-               if (state->state == DHS_BOUND) {
-                       /* For now, just report the duplicated address */
-               } else {
-                       arp_free(astate);
-                       dhcp_expire1(ifp);
-               }
-               return;
-       }
+       dhcp_addr_duplicated(astate->iface, &astate->addr);
 }
 
+#ifdef KERNEL_RFC5227
 static void
 dhcp_arp_announced(struct arp_state *state)
 {
 
-// TODO: DHCP addresses handle ACD?
-//#ifdef KERNEL_RFC5227
        arp_free(state);
-//#endif
 }
-#endif
+#endif /* KERNEL_RFC5227 */
+#endif /* ARP */
 
 void
 dhcp_bind(struct interface *ifp)
@@ -2357,12 +2312,6 @@ dhcp_lastlease(void *arg)
        if (ifp->ctx->options & DHCPCD_FORKED)
                return;
        state->interval = 0;
-       if (ifp->options->options & DHCPCD_LASTLEASE_EXTEND &&
-           dhcp_leaseextend(ifp) == -1)
-       {
-               logerr("%s: %s", ifp->name, __func__);
-               dhcp_expire(ifp);
-       }
        dhcp_discover(ifp);
 }
 
@@ -2395,17 +2344,32 @@ dhcp_message_new(struct bootp **bootp,
 }
 
 #ifdef ARP
+#ifndef KERNEL_RFC5227
+static void
+dhcp_arp_defend_failed(struct arp_state *astate)
+{
+
+       dhcp_drop(astate->iface, "EXPIRED");
+       dhcp_start1(astate->iface);
+}
+#endif
+
 static struct arp_state *
 dhcp_arp_new(struct interface *ifp, struct in_addr *addr)
 {
        struct arp_state *astate;
+
        astate = arp_new(ifp, addr);
        if (astate == NULL)
                return NULL;
 
-       astate->probed_cb = dhcp_arp_probed;
-       astate->conflicted_cb = dhcp_arp_conflicted;
+       astate->found_cb = dhcp_arp_found;
+       astate->not_found_cb = dhcp_arp_not_found;
+#ifdef KERNEL_RFC5227
        astate->announced_cb = dhcp_arp_announced;
+#else
+       astate->defend_failed_cb = dhcp_arp_defend_failed;
+#endif
        return astate;
 }
 
@@ -2415,7 +2379,6 @@ dhcp_arp_address(struct interface *ifp)
        struct dhcp_state *state;
        struct in_addr addr;
        struct ipv4_addr *ia;
-       struct arp_state *astate;
 
        eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
 
@@ -2425,10 +2388,6 @@ dhcp_arp_address(struct interface *ifp)
        /* If the interface already has the address configured
         * then we can't ARP for duplicate detection. */
        ia = ipv4_iffindaddr(ifp, &addr, NULL);
-       astate = dhcp_arp_new(ifp, &addr);
-       if (astate == NULL)
-               return -1;
-
 #ifdef IN_IFF_TENTATIVE
        if (ia == NULL || ia->addr_flags & IN_IFF_NOTUSEABLE) {
                state->state = DHS_PROBE;
@@ -2445,8 +2404,13 @@ dhcp_arp_address(struct interface *ifp)
        }
 #else
        if (ifp->options->options & DHCPCD_ARP && ia == NULL) {
+               struct arp_state *astate;
                struct dhcp_lease l;
 
+               astate = dhcp_arp_new(ifp, &addr);
+               if (astate == NULL)
+                       return -1;
+
                state->state = DHS_PROBE;
                get_lease(ifp, &l, state->offer, state->offer_len);
                loginfox("%s: probing address %s/%d",
@@ -2703,9 +2667,14 @@ dhcp_drop(struct interface *ifp, const char *reason)
                return;
        }
 
+#ifdef ARP
+       if (state->addr != NULL)
+               arp_freeaddr(ifp, &state->addr->addr);
+#endif
 #ifdef ARPING
        state->arping_index = -1;
 #endif
+
        if (ifp->options->options & DHCPCD_RELEASE &&
            !(ifp->options->options & DHCPCD_INFORM))
        {
@@ -3764,7 +3733,7 @@ dhcp_start1(void *arg)
 
                astate = dhcp_arp_new(ifp, NULL);
                if (astate)
-                       dhcp_arp_probed(astate);
+                       dhcp_arp_not_found(astate);
                return;
        }
 #endif
@@ -4016,8 +3985,10 @@ dhcp_handleifa(int cmd, struct ipv4_addr *ia, pid_t pid)
                return;
 
 #ifdef IN_IFF_NOTUSEABLE
-       if (ia->addr_flags & IN_IFF_NOTUSEABLE)
-               return;
+       if (!(ia->addr_flags & IN_IFF_NOTUSEABLE))
+               dhcp_finish_dad(ifp, &ia->addr);
+       else if (ia->addr_flags & IN_IFF_DUPLICATED)
+               dhcp_addr_duplicated(ifp, &ia->addr);
 #endif
 
        ifo = ifp->options;
index 7a39c2c5d0ddd5e8899df6ed98a5cd44b1cbb92b..74f49439082e805473d81a914d3bfe8f0ad299b0 100644 (file)
@@ -468,11 +468,6 @@ ipv4_deladdr(struct ipv4_addr *addr, int keeparp)
        int r;
        struct ipv4_state *state;
        struct ipv4_addr *ap;
-#ifdef ARP
-       struct arp_state *astate;
-#else
-       UNUSED(keeparp);
-#endif
 
        logdebugx("%s: deleting IP address %s",
            addr->iface->name, addr->saddr);
@@ -484,8 +479,8 @@ ipv4_deladdr(struct ipv4_addr *addr, int keeparp)
                logerr("%s: %s", addr->iface->name, __func__);
 
 #ifdef ARP
-       if (!keeparp && (astate = arp_find(addr->iface, &addr->addr)) != NULL)
-               arp_free(astate);
+       if (!keeparp)
+               arp_freeaddr(addr->iface, &addr->addr);
 #endif
 
        state = IPV4_STATE(addr->iface);
@@ -523,6 +518,7 @@ delete_address(struct interface *ifp)
            ifo->options & DHCPCD_INFORM ||
            (ifo->options & DHCPCD_STATIC && ifo->req_addr.s_addr == 0))
                return 0;
+       arp_freeaddr(ifp, &state->addr->addr);
        r = ipv4_deladdr(state->addr, 0);
        return r;
 }
@@ -897,10 +893,10 @@ ipv4_handleifa(struct dhcpcd_ctx *ctx,
        }
 
        if (addr->s_addr != INADDR_ANY && addr->s_addr != INADDR_BROADCAST) {
-#ifdef ARP
-               arp_handleifa(cmd, ia);
-#endif
                dhcp_handleifa(cmd, ia, pid);
+#ifdef IPV4LL
+               ipv4ll_handleifa(cmd, ia, pid);
+#endif
        }
 
        if (cmd == RTM_DELADDR)
index 496b8ecd23a2d743e8c500d479adef98499a1a3e..1038a5f56c190788c7bf0a6579998ac781666fa9 100644 (file)
@@ -72,6 +72,9 @@
         (IN_IFF_TENTATIVE | IN_IFF_DUPLICATED | IN_IFF_DETACHED)
 #endif
 
+#define IN_ARE_ADDR_EQUAL(a, b)                ((a)->s_addr == (b)->s_addr)
+#define IN_IS_ADDR_UNSPECIFIED(a)      ((a)->s_addr == INADDR_ANY)
+
 struct ipv4_addr {
        TAILQ_ENTRY(ipv4_addr) next;
        struct in_addr addr;
index 51cd4f5b2d169c2f061f71166b4466876b7ea900..81919befce451e0722d44622870cba7b61730907 100644 (file)
@@ -47,7 +47,6 @@
 #include "sa.h"
 #include "script.h"
 
-#ifdef IPV4LL
 static const struct in_addr inaddr_llmask = {
        .s_addr = HTONL(LINKLOCAL_MASK)
 };
@@ -55,18 +54,21 @@ 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 arp_state *astate)
+ipv4ll_pickaddr(struct interface *ifp)
 {
        struct in_addr addr;
-       struct ipv4ll_state *istate;
+       struct ipv4ll_state *state;
 
-       istate = IPV4LL_STATE(astate->iface);
-       setstate(istate->randomstate);
+       state = IPV4LL_STATE(ifp);
+       setstate(state->randomstate);
 
        do {
                long r;
 
+again:
                /* RFC 3927 Section 2.1 states that the first 256 and
                 * last 256 addresses are reserved for future use.
                 * See ipv4ll_start for why we don't use arc4random. */
@@ -76,13 +78,13 @@ ipv4ll_pickaddr(struct arp_state *astate)
                    ((uint32_t)(r % 0xFD00) + 0x0100));
 
                /* No point using a failed address */
-               if (addr.s_addr == astate->failed.s_addr)
-                       continue;
+               if (IN_ARE_ADDR_EQUAL(&addr, &state->pickedaddr))
+                       goto again;
                /* Ensure we don't have the address on another interface */
-       } while (ipv4_findaddr(astate->iface->ctx, &addr) != NULL);
+       } while (ipv4_findaddr(ifp->ctx, &addr) != NULL);
 
        /* Restore the original random state */
-       setstate(istate->arp->iface->ctx->randomstate);
+       setstate(ifp->ctx->randomstate);
        return addr.s_addr;
 }
 
@@ -171,29 +173,46 @@ ipv4ll_env(char **env, const char *prefix, const struct interface *ifp)
 }
 
 static void
-ipv4ll_probed(struct arp_state *astate)
+ipv4ll_announced(struct arp_state *astate)
+{
+       struct ipv4ll_state *state = IPV4LL_STATE(astate->iface);
+
+       state->conflicts = 0;
+#ifdef KERNEL_RFC5227
+       arp_free(astate);
+#endif
+}
+
+static void
+ipv4ll_arpfree(struct arp_state *astate)
 {
-       struct interface *ifp;
        struct ipv4ll_state *state;
-       struct ipv4_addr *ia;
 
-       assert(astate != NULL);
-       assert(astate->iface != NULL);
+       state = IPV4LL_STATE(astate->iface);
+       if (state != NULL && state->arp == astate)
+               state->arp = NULL;
+}
+
+static void
+ipv4ll_not_found(struct interface *ifp)
+{
+       struct ipv4ll_state *state;
+       struct ipv4_addr *ia;
+       struct arp_state *astate;
 
-       ifp = astate->iface;
        state = IPV4LL_STATE(ifp);
        assert(state != NULL);
 
-       ia = ipv4_iffindaddr(ifp, &astate->addr, &inaddr_llmask);
+       ia = ipv4_iffindaddr(ifp, &state->pickedaddr, &inaddr_llmask);
 #ifdef IN_IFF_NOTREADY
        if (ia == NULL || ia->addr_flags & IN_IFF_NOTREADY)
 #endif
                loginfox("%s: using IPv4LL address %s",
-                 ifp->name, inet_ntoa(astate->addr));
+                 ifp->name, inet_ntoa(state->pickedaddr));
        if (ia == NULL) {
                if (ifp->ctx->options & DHCPCD_TEST)
                        goto test;
-               ia = ipv4_addaddr(ifp, &astate->addr,
+               ia = ipv4_addaddr(ifp, &state->pickedaddr,
                    &inaddr_llmask, &inaddr_llbcast);
        }
        if (ia == NULL)
@@ -201,153 +220,117 @@ ipv4ll_probed(struct arp_state *astate)
 #ifdef IN_IFF_NOTREADY
        if (ia->addr_flags & IN_IFF_NOTREADY)
                return;
-       logdebugx("%s: DAD completed for %s",
-           ifp->name, inet_ntoa(astate->addr));
+       logdebugx("%s: DAD completed for %s", ifp->name, ia->saddr);
 #endif
 test:
        state->addr = ia;
+       state->down = false;
        if (ifp->ctx->options & DHCPCD_TEST) {
                script_runreason(ifp, "TEST");
                eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
                return;
        }
-       timespecclear(&state->defend);
        if_initrt(ifp->ctx, AF_INET);
        rt_build(ifp->ctx, AF_INET);
-       arp_announce(astate);
+#ifdef KERNEL_RFC5227
+       astate = arp_new(ifp, &ia->addr);
+       if (astate != NULL) {
+               astate->announced_cb = ipv4ll_announced;
+               astate->free_cb = ipv4ll_arpfree;
+               arp_announce(astate);
+       }
+#else
+       arp_annnounce(state->arp);
+#endif
        script_runreason(ifp, "IPV4LL");
        dhcpcd_daemonise(ifp->ctx);
 }
 
 static void
-ipv4ll_announced(struct arp_state *astate)
+ipv4ll_startifp(void *arg)
 {
-       struct ipv4ll_state *state = IPV4LL_STATE(astate->iface);
+       struct interface *ifp = arg;
+       struct ipv4ll_state *state;
 
-       state->conflicts = 0;
-       /* Need to keep the arp state so we can defend our IP. */
+       state = IPV4LL_STATE(ifp);
+       ipv4ll_start1(ifp, state->arp);
 }
 
 static void
-ipv4ll_probe(void *arg)
+ipv4ll_found(struct interface *ifp)
 {
+       struct ipv4ll_state *state = IPV4LL_STATE(ifp);
 
-#ifdef IN_IFF_TENTATIVE
-       ipv4ll_probed(arg);
-#else
-       arp_probe(arg);
-#endif
+       arp_cancel(state->arp);
+       if (++state->conflicts == MAX_CONFLICTS)
+               logerr("%s: failed to acquire an IPv4LL address",
+                   ifp->name);
+       eloop_timeout_add_sec(ifp->ctx->eloop,
+           state->conflicts >= MAX_CONFLICTS ?
+           RATE_LIMIT_INTERVAL : PROBE_WAIT,
+           ipv4ll_startifp, ifp);
+}
+
+static void
+ipv4ll_defend_failed(struct interface *ifp)
+{
+       struct ipv4ll_state *state = IPV4LL_STATE(ifp);
+
+       ipv4_deladdr(state->addr, 1);
+       state->down = true;
+       state->addr = NULL;
+       if_initrt(ifp->ctx, AF_INET);
+       rt_build(ifp->ctx, AF_INET);
+       script_runreason(ifp, "IPV4LL");
+       ipv4ll_start1(ifp, state->arp);
 }
 
+#ifndef KERNEL_RFC5227
 static void
-ipv4ll_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
+ipv4ll_not_found_arp(struct arp_state *astate)
 {
        struct interface *ifp;
        struct ipv4ll_state *state;
-#ifdef IN_IFF_DUPLICATED
        struct ipv4_addr *ia;
-#endif
 
        assert(astate != NULL);
        assert(astate->iface != NULL);
+
        ifp = astate->iface;
        state = IPV4LL_STATE(ifp);
        assert(state != NULL);
+       assert(state->arp == astate);
+       ipv4ll_not_found_arp(state);
+}
 
-       /*
-        * NULL amsg means kernel detected DAD.
-        * We always fail on matching sip.
-        * We only fail on matching tip and we haven't added that address yet.
-        */
-       if (amsg == NULL ||
-           amsg->sip.s_addr == astate->addr.s_addr ||
-           (amsg->sip.s_addr == 0 && amsg->tip.s_addr == astate->addr.s_addr
-            && ipv4_iffindaddr(ifp, &amsg->tip, NULL) == NULL))
-               astate->failed = astate->addr;
-       else
-               return;
-
-       arp_report_conflicted(astate, amsg);
-
-       if (state->addr != NULL &&
-           astate->failed.s_addr == state->addr->addr.s_addr)
-       {
-#ifdef KERNEL_RFC5227
-               logwarnx("%s: IPv4LL defence failed for %s",
-                   ifp->name, state->addr->saddr);
-#else
-               struct timespec now, defend;
-
-               /* RFC 3927 Section 2.5 says a defence should
-                * broadcast an ARP announcement.
-                * Because the kernel will also unicast a reply to the
-                * hardware address which requested the IP address
-                * the other IPv4LL client will receieve two ARP
-                * messages.
-                * If another conflict happens within DEFEND_INTERVAL
-                * then we must drop our address and negotiate a new one. */
-               defend.tv_sec = state->defend.tv_sec + DEFEND_INTERVAL;
-               defend.tv_nsec = state->defend.tv_nsec;
-               clock_gettime(CLOCK_MONOTONIC, &now);
-               if (timespeccmp(&defend, &now, >))
-                       logwarnx("%s: IPv4LL %d second defence failed for %s",
-                           ifp->name, DEFEND_INTERVAL, state->addr->saddr);
-               else if (arp_request(ifp,
-                   state->addr->addr.s_addr, state->addr->addr.s_addr) == -1)
-                       logerr(__func__);
-               else {
-                       logdebugx("%s: defended IPv4LL address %s",
-                           ifp->name, state->addr->saddr);
-                       state->defend = now;
-                       return;
-               }
-#endif
-               ipv4_deladdr(state->addr, 1);
-               state->down = 1;
-               state->addr = NULL;
-               if_initrt(ifp->ctx, AF_INET);
-               rt_build(ifp->ctx, AF_INET);
-               script_runreason(ifp, "IPV4LL");
-       }
-
-#ifdef IN_IFF_DUPLICATED
-       ia = ipv4_iffindaddr(ifp, &astate->addr, NULL);
-       if (ia != NULL && ia->addr_flags & IN_IFF_DUPLICATED)
-               ipv4_deladdr(ia, 1);
-#endif
+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);
 
-       arp_cancel(astate);
-       if (++state->conflicts == MAX_CONFLICTS)
-               logerr("%s: failed to acquire an IPv4LL address",
-                   ifp->name);
-       state->pickedaddr.s_addr = ipv4ll_pickaddr(astate);
-       astate->addr = state->pickedaddr;
-       eloop_timeout_add_sec(ifp->ctx->eloop,
-               state->conflicts >= MAX_CONFLICTS ?
-               RATE_LIMIT_INTERVAL : PROBE_WAIT,
-               ipv4ll_probe, astate);
+       assert(state->arp == astate);
+       ipv4ll_found(ifp);
 }
 
 static void
-ipv4ll_arpfree(struct arp_state *astate)
+ipv4ll_defend_failed_arp(struct arp_state *astate)
 {
-       struct ipv4ll_state *state;
+       struct ipv4ll_state *state = IPV4LL_STATE(astate->ifp);
 
-       state = IPV4LL_STATE(astate->iface);
-       if (state != NULL && state->arp == astate)
-               state->arp = NULL;
+       assert(state->arp == astate);
+       ipv4ll_defend_failed1(astate->iface);
 }
+#endif
 
-void
-ipv4ll_start(void *arg)
+static void
+ipv4ll_start1(struct interface *ifp, struct arp_state *astate)
 {
-       struct interface *ifp;
        struct ipv4ll_state *state;
-       struct arp_state *astate;
        struct ipv4_addr *ia;
+       bool repick;
 
-       assert(arg != NULL);
-       ifp = arg;
+       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) {
@@ -383,16 +366,25 @@ ipv4ll_start(void *arg)
                state->seeded = true;
        }
 
-       if (state->arp != NULL)
-               return;
-       if ((astate = arp_new(ifp, NULL)) == NULL)
-               return;
+#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->arp = astate;
-       astate->probed_cb = ipv4ll_probed;
-       astate->announced_cb = ipv4ll_announced;
-       astate->conflicted_cb = ipv4ll_conflicted;
-       astate->free_cb = ipv4ll_arpfree;
+       state->down = true;
 
        /* Find the previosuly used address. */
        if (state->pickedaddr.s_addr != INADDR_ANY)
@@ -404,15 +396,22 @@ ipv4ll_start(void *arg)
        if (ia == NULL)
                ia = ipv4_iffindlladdr(ifp);
 
+       repick = false;
 #ifdef IN_IFF_TENTATIVE
        if (ia != NULL && ia->addr_flags & IN_IFF_DUPLICATED) {
+               state->pickedaddr = ia->addr; /* So it's not picked again. */
+               repick = true;
                ipv4_deladdr(ia, 0);
                ia = NULL;
        }
 #endif
 
+       state->addr = ia;
        if (ia != NULL) {
-               state->pickedaddr = astate->addr = ia->addr;
+               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",
@@ -421,21 +420,30 @@ ipv4ll_start(void *arg)
                }
                loginfox("%s: using IPv4LL address %s", ifp->name, ia->saddr);
 #endif
-               ipv4ll_probed(astate);
+               ipv4ll_not_found(ifp);
                return;
        }
 
        loginfox("%s: probing for an IPv4LL address", ifp->name);
-       if (state->pickedaddr.s_addr == INADDR_ANY)
-               state->pickedaddr.s_addr = ipv4ll_pickaddr(astate);
+       if (repick || state->pickedaddr.s_addr == INADDR_ANY)
+               state->pickedaddr.s_addr = ipv4ll_pickaddr(ifp);
+#ifndef KERNEL_RFC5227
        astate->addr = state->pickedaddr;
+#endif
 #ifdef IN_IFF_TENTATIVE
-       ipv4ll_probed(astate);
+       ipv4ll_not_found(ifp);
 #else
        arp_probe(astate);
 #endif
 }
 
+void
+ipv4ll_start(void *arg)
+{
+
+       ipv4ll_start1(arg, NULL);
+}
+
 static void
 ipv4ll_freearp(struct interface *ifp)
 {
@@ -447,7 +455,6 @@ ipv4ll_freearp(struct interface *ifp)
 
        eloop_timeout_delete(ifp->ctx->eloop, NULL, state->arp);
        arp_free(state->arp);
-       state->arp = NULL;
 }
 
 void
@@ -461,9 +468,7 @@ ipv4ll_drop(struct interface *ifp)
 
        ipv4ll_freearp(ifp);
 
-#ifndef IN_IFF_TENATIVE
        if ((ifp->options->options & DHCPCD_NODROP) == DHCPCD_NODROP)
-#endif
                return;
 
        state = IPV4LL_STATE(ifp);
@@ -543,4 +548,34 @@ ipv4ll_recvrt(__unused int cmd, const struct rt *rt)
        return 0;
 }
 #endif
+
+void
+ipv4ll_handleifa(int cmd, struct ipv4_addr *ia, pid_t pid)
+{
+       struct interface *ifp;
+       struct ipv4ll_state *state;
+
+       ifp = ia->iface;
+       state = IPV4LL_STATE(ifp);
+       if (state == NULL || state->addr == NULL ||
+           !IN_ARE_ADDR_EQUAL(&state->addr->addr, &ia->addr))
+               return;
+
+       if (cmd == RTM_DELADDR) {
+               loginfox("%s: pid %d deleted IP address %s",
+                   ifp->name, pid, ia->saddr);
+               ipv4ll_defend_failed(ifp);
+       }
+
+#ifdef IN_IFF_DUPLICATED
+       if (cmd != RTM_NEWADDR)
+               return;
+       if (!(ia->addr_flags & IN_IFF_NOTUSEABLE))
+               ipv4ll_not_found(ifp);
+       else if (ia->addr_flags & IN_IFF_DUPLICATED) {
+               logerrx("%s: DAD detected %s", ifp->name, ia->saddr);
+               ipv4_deladdr(state->addr, 1);
+               ipv4ll_found(ifp);
+       }
 #endif
+}
index 23fad1b1232a230558a4728f5a72b7aace0b4205..6b95c180477d026f9c4227848ef215801fa10a4f 100644 (file)
@@ -43,11 +43,10 @@ struct ipv4ll_state {
        struct in_addr pickedaddr;
        struct ipv4_addr *addr;
        struct arp_state *arp;
-       unsigned int conflicts;
-       struct timespec defend;
        char randomstate[128];
        bool seeded;
-       uint8_t down;
+       bool down;
+       size_t conflicts;
 };
 
 #define        IPV4LL_STATE(ifp)                                                      \
@@ -64,6 +63,7 @@ ssize_t ipv4ll_env(char **, const char *, const struct interface *);
 void ipv4ll_start(void *);
 void ipv4ll_claimed(void *);
 void ipv4ll_handle_failure(void *);
+void ipv4ll_handleifa(int, struct ipv4_addr *, pid_t pid);
 #ifdef HAVE_ROUTE_METRIC
 int ipv4ll_recvrt(int, const struct rt *);
 #endif