From: Roy Marples Date: Tue, 17 Dec 2019 22:16:26 +0000 (+0000) Subject: DHCP6: Rework delegation deprecation X-Git-Tag: v7.2.4~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9b8fa49e98cf94e268131e5119a59b406fc34108;p=thirdparty%2Fdhcpcd.git DHCP6: Rework delegation deprecation Split ipv6_addaddrs out so ipv6_doaddr can operate on a single address. Call this when deprecating delegated addresses to avoid calling ipv6_addaddrs. This allows a more simple ipv6_addaddrs that doesn't need to test which address collection we are deleting from and removes DHCPv6 specific code from the generic IPv6 module. --- diff --git a/src/dhcp6.c b/src/dhcp6.c index b3f16b91..ed5fe8d6 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -2351,11 +2351,53 @@ dhcp6_findia(struct interface *ifp, struct dhcp6_message *m, size_t l, return i; } +#ifndef SMALL +static void +dhcp6_deprecatedele(struct ipv6_addr *ia) +{ + struct ipv6_addr *da, *dan, *dda; + struct timespec now; + struct dhcp6_state *state; + + timespecclear(&now); + TAILQ_FOREACH_SAFE(da, &ia->pd_pfxs, pd_next, dan) { + if (ia->prefix_vltime == 0) { + if (da->prefix_vltime != 0) + da->prefix_vltime = 0; + else + continue; + } else if (da->prefix_pltime != 0) + da->prefix_pltime = 0; + else + continue; + + if (ipv6_doaddr(da, &now) != -1) + continue; + + /* Delegation deleted, forget it. */ + TAILQ_REMOVE(&ia->pd_pfxs, da, pd_next); + + /* Delete it from the interface. */ + state = D6_STATE(da->iface); + TAILQ_FOREACH(dda, &state->addrs, next) { + if (IN6_ARE_ADDR_EQUAL(&dda->addr, &da->addr)) + break; + } + if (dda != NULL) { + TAILQ_REMOVE(&state->addrs, dda, next); + ipv6_freeaddr(dda); + } + } +} +#endif + static void dhcp6_deprecateaddrs(struct ipv6_addrhead *addrs) { struct ipv6_addr *ia, *ian; + struct timespec now; + timespecclear(&now); TAILQ_FOREACH_SAFE(ia, addrs, next, ian) { if (ia->flags & IPV6_AF_EXTENDED) ; @@ -2373,24 +2415,8 @@ dhcp6_deprecateaddrs(struct ipv6_addrhead *addrs) #ifndef SMALL /* If we delegated from this prefix, deprecate or remove * the delegations. */ - if (ia->flags & IPV6_AF_DELEGATEDPFX) { - struct ipv6_addr *da; - bool touched = false; - - TAILQ_FOREACH(da, &ia->pd_pfxs, pd_next) { - if (ia->prefix_vltime == 0) { - if (da->prefix_vltime != 0) { - da->prefix_vltime = 0; - touched = true; - } - } else if (da->prefix_pltime != 0) { - da->prefix_pltime = 0; - touched = true; - } - } - if (touched) - ipv6_addaddrs(&ia->pd_pfxs); - } + if (ia->flags & IPV6_AF_DELEGATEDPFX) + dhcp6_deprecatedele(ia); #endif if (ia->flags & IPV6_AF_REQUEST) { diff --git a/src/ipv6.c b/src/ipv6.c index d3dfe064..347cb303 100644 --- a/src/ipv6.c +++ b/src/ipv6.c @@ -898,52 +898,54 @@ ipv6_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr, unsigned int #endif } +int +ipv6_doaddr(struct ipv6_addr *ia, struct timespec *now) +{ + + /* A delegated prefix is not an address. */ + if (ia->flags & IPV6_AF_DELEGATEDPFX) + return 0; + + if (ia->prefix_vltime == 0) { + if (ia->flags & IPV6_AF_ADDED) + ipv6_deleteaddr(ia); + eloop_q_timeout_delete(ia->iface->ctx->eloop, + 0, NULL, ia); + if (ia->flags & IPV6_AF_REQUEST) { + ia->flags &= ~IPV6_AF_ADDED; + return 0; + } + return -1; + } + + if (ia->flags & IPV6_AF_STALE || + IN6_IS_ADDR_UNSPECIFIED(&ia->addr)) + return 0; + + if (!timespecisset(now)) + clock_gettime(CLOCK_MONOTONIC, now); + ipv6_addaddr(ia, now); + return ia->flags & IPV6_AF_NEW ? 1 : 0; +} + ssize_t -ipv6_addaddrs(struct ipv6_addrhead *addrs) +ipv6_addaddrs(struct ipv6_addrhead *iaddrs) { - struct ipv6_addr *ap, *apn; - ssize_t i; struct timespec now; + struct ipv6_addr *ia, *ian; + ssize_t i, r; i = 0; timespecclear(&now); - TAILQ_FOREACH_SAFE(ap, addrs, next, apn) { - /* A delegated prefix is not an address. */ - if (ap->flags & IPV6_AF_DELEGATEDPFX) - continue; - if (ap->prefix_vltime == 0) { - if (ap->flags & IPV6_AF_ADDED) { - ipv6_deleteaddr(ap); - i++; - } - eloop_q_timeout_delete(ap->iface->ctx->eloop, - 0, NULL, ap); - if (ap->flags & IPV6_AF_REQUEST) { - ap->flags &= ~IPV6_AF_ADDED; - } else { -#ifndef SMALL - if (ap->delegating_prefix != NULL && - addrs == &ap->delegating_prefix->pd_pfxs) { - TAILQ_REMOVE(addrs, ap, pd_next); - ap->delegating_prefix = NULL; - } else -#endif - { - TAILQ_REMOVE(addrs, ap, next); - ipv6_freeaddr(ap); - } - } - } else if (!(ap->flags & IPV6_AF_STALE) && - !IN6_IS_ADDR_UNSPECIFIED(&ap->addr)) - { - if (ap->flags & IPV6_AF_NEW) - i++; - if (!timespecisset(&now)) - clock_gettime(CLOCK_MONOTONIC, &now); - ipv6_addaddr(ap, &now); + TAILQ_FOREACH_SAFE(ia, iaddrs, next, ian) { + r = ipv6_doaddr(ia, &now); + if (r != 0) + i++; + if (r == -1) { + TAILQ_REMOVE(iaddrs, ia, next); + ipv6_freeaddr(ia); } } - return i; } diff --git a/src/ipv6.h b/src/ipv6.h index cc3e8a67..49c36765 100644 --- a/src/ipv6.h +++ b/src/ipv6.h @@ -247,6 +247,7 @@ void ipv6_checkaddrflags(void *); void ipv6_markaddrsstale(struct interface *, unsigned int); void ipv6_deletestaleaddrs(struct interface *); int ipv6_addaddr(struct ipv6_addr *, const struct timespec *); +int ipv6_doaddr(struct ipv6_addr *, struct timespec *); ssize_t ipv6_addaddrs(struct ipv6_addrhead *addrs); void ipv6_deleteaddr(struct ipv6_addr *); void ipv6_freedrop_addrs(struct ipv6_addrhead *, int,