]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Add an option to keep arp state when deleting addresses, which is needed
authorRoy Marples <roy@marples.name>
Mon, 29 Jun 2015 15:03:31 +0000 (15:03 +0000)
committerRoy Marples <roy@marples.name>
Mon, 29 Jun 2015 15:03:31 +0000 (15:03 +0000)
for IPv4LL.
Call IPV4LL instead of EXPIRE when removing the IPV4LL address,
which is similar to how ROUTERADVERT works.

arp.c
dhcp.c
ipv4.c
ipv4.h
ipv4ll.c

diff --git a/arp.c b/arp.c
index f4369047fb4387c242f177057ac1746db8bd168d..9f6b00dfe69cc623a531f11c502224a772b3e1d3 100644 (file)
--- a/arp.c
+++ b/arp.c
@@ -28,6 +28,8 @@
 #include <sys/socket.h>
 #include <sys/types.h>
 
+#include <arpa/inet.h>
+
 #include <net/if.h>
 #include <netinet/in.h>
 #include <netinet/if_ether.h>
@@ -44,7 +46,6 @@
 #include "if.h"
 #include "ipv4.h"
 #include "common.h"
-#include "dhcp.h"
 #include "dhcpcd.h"
 #include "eloop.h"
 #include "if.h"
@@ -135,7 +136,7 @@ arp_packet(void *arg)
                if (bytes == -1) {
                        logger(ifp->ctx, LOG_ERR,
                            "%s: arp if_readrawpacket: %m", ifp->name);
-                       dhcp_close(ifp);
+                       arp_close(ifp);
                        return;
                }
                /* We must have a full ARP header */
diff --git a/dhcp.c b/dhcp.c
index 1b35924c0c8a80f07424b5bc50eab1ad1dd2f05c..80ca5962533b1a493670d7027627c1f4a0bd716e 100644 (file)
--- a/dhcp.c
+++ b/dhcp.c
@@ -1976,7 +1976,7 @@ dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
 #ifdef IN_IFF_DUPLICATED
                ia = ipv4_iffindaddr(ifp, &astate->addr, NULL);
                if (ia)
-                       ipv4_deladdr(ifp, &ia->addr, &ia->net);
+                       ipv4_deladdr(ifp, &ia->addr, &ia->net, 1);
 #endif
                arp_free(astate);
                eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
@@ -2653,7 +2653,7 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
                    ifp, dhcp, from);
                if (type)
                        dhcp_decline(ifp);
-               ipv4_deladdr(ifp, &ia->addr, &ia->net);
+               ipv4_deladdr(ifp, &ia->addr, &ia->net, 0);
                eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
                eloop_timeout_add_sec(ifp->ctx->eloop,
                    DHCP_RAND_MAX, dhcp_discover, ifp);
diff --git a/ipv4.c b/ipv4.c
index 42d8d969e4fd06f6542e256193dd4af19340fe50..a4b643964d49f1af51544996c988e8a0e9b9e94d 100644 (file)
--- a/ipv4.c
+++ b/ipv4.c
@@ -209,11 +209,13 @@ ipv4_protocol_fd(const struct interface *ifp, uint16_t protocol)
                const struct iarp_state *istate;
 
                istate = ARP_CSTATE(ifp);
+               assert(istate != NULL);
                return istate->fd;
        } else {
                const struct dhcp_state *dstate;
 
                dstate = D_CSTATE(ifp);
+               assert(dstate != NULL);
                return dstate->raw_fd;
        }
 }
@@ -752,7 +754,7 @@ ipv4_buildroutes(struct dhcpcd_ctx *ctx)
 
 int
 ipv4_deladdr(struct interface *ifp,
-    const struct in_addr *addr, const struct in_addr *net)
+    const struct in_addr *addr, const struct in_addr *net, int keeparp)
 {
        struct dhcp_state *dstate;
        int r;
@@ -768,7 +770,7 @@ ipv4_deladdr(struct interface *ifp,
            errno != ENODEV)
                logger(ifp->ctx, LOG_ERR, "%s: %s: %m", ifp->name, __func__);
 
-       if ((astate = arp_find(ifp, addr)) != NULL)
+       if (!keeparp && (astate = arp_find(ifp, addr)) != NULL)
                arp_free(astate);
 
        state = IPV4_STATE(ifp);
@@ -808,7 +810,7 @@ delete_address(struct interface *ifp)
        if (ifo->options & DHCPCD_INFORM ||
            (ifo->options & DHCPCD_STATIC && ifo->req_addr.s_addr == 0))
                return 0;
-       r = ipv4_deladdr(ifp, &state->addr, &state->net);
+       r = ipv4_deladdr(ifp, &state->addr, &state->net, 0);
        return r;
 }
 
@@ -851,7 +853,7 @@ ipv4_addaddr(struct interface *ifp, const struct in_addr *addr,
 
                TAILQ_FOREACH_SAFE(ia, &state->addrs, next, ian) {
                        if (ia->addr.s_addr != addr->s_addr)
-                               ipv4_deladdr(ifp, &ia->addr, &ia->net);
+                               ipv4_deladdr(ifp, &ia->addr, &ia->net, 0);
                }
        }
 
@@ -989,7 +991,7 @@ ipv4_applyaddr(void *arg)
                            ifn->name,
                            inet_ntoa(lease->addr),
                            ifp->name);
-                       ipv4_deladdr(ifn, &nstate->addr, &nstate->net);
+                       ipv4_deladdr(ifn, &nstate->addr, &nstate->net, 0);
                        break;
                }
        }
@@ -1001,14 +1003,14 @@ ipv4_applyaddr(void *arg)
                                continue;
                        ap = ipv4_iffindaddr(ifn, &lease->addr, NULL);
                        if (ap)
-                               ipv4_deladdr(ifn, &ap->addr, &ap->net);
+                               ipv4_deladdr(ifn, &ap->addr, &ap->net, 0);
                }
        }
 
        /* If the netmask is different, delete the addresss */
        ap = ipv4_iffindaddr(ifp, &lease->addr, NULL);
        if (ap && ap->net.s_addr != lease->net.s_addr)
-               ipv4_deladdr(ifp, &ap->addr, &ap->net);
+               ipv4_deladdr(ifp, &ap->addr, &ap->net, 0);
 
        if (ipv4_iffindaddr(ifp, &lease->addr, &lease->net))
                logger(ifp->ctx, LOG_DEBUG,
diff --git a/ipv4.h b/ipv4.h
index 0fec7628605dbf12ca999ceec70f7fd2f057aa01..53f94e1c20338e826e725dfe11b28b03cfe4e2d9 100644 (file)
--- a/ipv4.h
+++ b/ipv4.h
@@ -107,7 +107,7 @@ int ipv4_hasaddr(const struct interface *);
 
 void ipv4_buildroutes(struct dhcpcd_ctx *);
 int ipv4_deladdr(struct interface *, const struct in_addr *,
-    const struct in_addr *);
+    const struct in_addr *, int);
 int ipv4_preferanother(struct interface *);
 struct ipv4_addr *ipv4_addaddr(struct interface *,
     const struct in_addr *, const struct in_addr *, const struct in_addr *);
index 136c5c9defdac9fcc8337bb1b6e265a8cda735ea..6a8af8115b9fb2e83a89ab1b3a8c38b615e647d4 100644 (file)
--- a/ipv4ll.c
+++ b/ipv4ll.c
@@ -25,6 +25,8 @@
  * SUCH DAMAGE.
  */
 
+#include <arpa/inet.h>
+
 #include <assert.h>
 #include <errno.h>
 #include <signal.h>
@@ -36,7 +38,6 @@
 #include "config.h"
 #include "arp.h"
 #include "common.h"
-#include "dhcp.h"
 #include "eloop.h"
 #include "if.h"
 #include "if-options.h"
@@ -187,12 +188,14 @@ ipv4ll_probe(void *arg)
 static void
 ipv4ll_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
 {
+       struct interface *ifp;
        struct ipv4ll_state *state;
        in_addr_t fail;
 
        assert(astate != NULL);
        assert(astate->iface != NULL);
-       state = IPV4LL_STATE(astate->iface);
+       ifp = astate->iface;
+       state = IPV4LL_STATE(ifp);
        assert(state != NULL);
 
        fail = 0;
@@ -221,15 +224,17 @@ ipv4ll_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
                defend.tv_nsec = state->defend.tv_nsec;
                clock_gettime(CLOCK_MONOTONIC, &now);
                if (timespeccmp(&defend, &now, >)) {
-                       logger(astate->iface->ctx, LOG_WARNING,
+                       logger(ifp->ctx, LOG_WARNING,
                            "%s: IPv4LL %d second defence failed for %s",
-                           astate->iface->name, DEFEND_INTERVAL,
+                           ifp->name, DEFEND_INTERVAL,
                            inet_ntoa(state->addr));
-                       dhcp_drop(astate->iface, "EXPIRE");
+                       ipv4_deladdr(ifp, &state->addr, &inaddr_llmask, 1);
+                       state->addr.s_addr = INADDR_ANY;
+                       script_runreason(ifp, "IPV4LL");
                } else {
-                       logger(astate->iface->ctx, LOG_DEBUG,
+                       logger(ifp->ctx, LOG_DEBUG,
                            "%s: defended IPv4LL address %s",
-                           astate->iface->name, inet_ntoa(state->addr));
+                           ifp->name, inet_ntoa(state->addr));
                        state->defend = now;
                        return;
                }
@@ -237,11 +242,11 @@ ipv4ll_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
 
        arp_cancel(astate);
        if (++state->conflicts == MAX_CONFLICTS)
-               logger(astate->iface->ctx, LOG_ERR,
+               logger(ifp->ctx, LOG_ERR,
                    "%s: failed to acquire an IPv4LL address",
-                   astate->iface->name);
+                   ifp->name);
        astate->addr.s_addr = ipv4ll_pick_addr(astate);
-       eloop_timeout_add_sec(astate->iface->ctx->eloop,
+       eloop_timeout_add_sec(ifp->ctx->eloop,
                state->conflicts >= MAX_CONFLICTS ?
                RATE_LIMIT_INTERVAL : PROBE_WAIT,
                ipv4ll_probe, astate);
@@ -309,7 +314,7 @@ ipv4ll_start(void *arg)
        ia = ipv4_iffindlladdr(ifp);
 #ifdef IN_IFF_TENTATIVE
        if (ia != NULL && ia->addr_flags & IN_IFF_DUPLICATED) {
-               ipv4_deladdr(ifp, &ia->addr, &ia->net);
+               ipv4_deladdr(ifp, &ia->addr, &ia->net, 0);
                ia = NULL;
        }
 #endif
@@ -355,13 +360,11 @@ ipv4ll_freedrop(struct interface *ifp, int drop)
                state->arp = NULL;
        }
 
-       /* 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) {
                struct ipv4_state *istate;
 
                if (state && state->addr.s_addr != INADDR_ANY) {
-                       ipv4_deladdr(ifp, &state->addr, &inaddr_llmask);
+                       ipv4_deladdr(ifp, &state->addr, &inaddr_llmask, 1);
                        state->addr.s_addr = INADDR_ANY;
                }
 
@@ -371,9 +374,11 @@ ipv4ll_freedrop(struct interface *ifp, int drop)
 
                        TAILQ_FOREACH_SAFE(ia, &istate->addrs, next, ian) {
                                if (IN_LINKLOCAL(ntohl(ia->addr.s_addr)))
-                                       ipv4_deladdr(ifp, &ia->addr, &ia->net);
+                                       ipv4_deladdr(ifp, &ia->addr,
+                                           &ia->net, 0);
                        }
                }
+               script_runreason(ifp, "IPV4LL");
        }
 
        if (state) {