From: Roy Marples Date: Mon, 29 Jun 2015 15:03:31 +0000 (+0000) Subject: Add an option to keep arp state when deleting addresses, which is needed X-Git-Tag: v6.9.1~20 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b2f9b24191d99551ec33bc8c29d6169c8bdeea47;p=thirdparty%2Fdhcpcd.git Add an option to keep arp state when deleting addresses, which is needed for IPv4LL. Call IPV4LL instead of EXPIRE when removing the IPV4LL address, which is similar to how ROUTERADVERT works. --- diff --git a/arp.c b/arp.c index f4369047..9f6b00df 100644 --- a/arp.c +++ b/arp.c @@ -28,6 +28,8 @@ #include #include +#include + #include #include #include @@ -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 1b35924c..80ca5962 100644 --- 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 42d8d969..a4b64396 100644 --- 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 0fec7628..53f94e1c 100644 --- 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 *); diff --git a/ipv4ll.c b/ipv4ll.c index 136c5c9d..6a8af811 100644 --- a/ipv4ll.c +++ b/ipv4ll.c @@ -25,6 +25,8 @@ * SUCH DAMAGE. */ +#include + #include #include #include @@ -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) {