diff --git a/src/dhcp6.c b/src/dhcp6.c index 07ffeb50..732a8e95 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -2276,7 +2276,8 @@ dhcp6_findna(struct interface *ifp, uint16_t ot, const uint8_t *iaid, a->acquired = *acquired; a->prefix_pltime = ia.pltime; if (a->prefix_vltime != ia.vltime) { - a->flags |= IPV6_AF_NEW; + if (ia.vltime == 0) + a->flags |= IPV6_AF_NEW; a->prefix_vltime = ia.vltime; } if (a->prefix_pltime && a->prefix_pltime < state->lowpl) @@ -2365,7 +2366,7 @@ dhcp6_findpd(struct interface *ifp, const uint8_t *iaid, uint8_t *d, size_t l, if (!(a->flags & IPV6_AF_PFXDELEGATION)) a->flags |= IPV6_AF_NEW | IPV6_AF_PFXDELEGATION; a->flags &= ~(IPV6_AF_STALE | IPV6_AF_EXTENDED); - if (a->prefix_vltime != pdp_vltime) + if (pdp_vltime == 0 && a->prefix_vltime != pdp_vltime) a->flags |= IPV6_AF_NEW; } @@ -3153,12 +3154,23 @@ dhcp6_bind(struct interface *ifp, const char *op, const char *sfrom) struct timespec now; if (state->state == DH6S_RENEW) { + /* + * Ignore unfulfilled requested addresses + * and Prefix Delegations. + * As most requests will be the unspecified address and + * optionally prefix length, this is expected behaviour. + */ loglevel = LOG_DEBUG; TAILQ_FOREACH(ia, &state->addrs, next) { - if (ia->flags & IPV6_AF_NEW) { - loglevel = LOG_INFO; - break; - } + if (!(ia->flags & IPV6_AF_NEW)) + continue; + if (ia->flags & IPV6_AF_STALE && + ia->flags & IPV6_AF_REQUEST) + continue; + /* This address is either coming or going, so promote + * the priority. */ + loglevel = LOG_INFO; + break; } } else if (state->state == DH6S_INFORM) loglevel = state->new_start ? LOG_INFO : LOG_DEBUG; diff --git a/src/ipv6.c b/src/ipv6.c index 80ee4ad3..3997dafe 100644 --- a/src/ipv6.c +++ b/src/ipv6.c @@ -679,6 +679,7 @@ ipv6_deleteaddr(struct ipv6_addr *ia) errno != ESRCH && errno != ENXIO && errno != ENODEV) logerr(__func__); + ia->flags &= ~IPV6_AF_ADDED; ipv6_deletedaddr(ia); state = IPV6_STATE(ia->iface); @@ -921,13 +922,19 @@ int ipv6_findaddrmatch(const struct ipv6_addr *addr, const struct in6_addr *match, unsigned int flags) { + bool vltime = false; + + if (flags & IPV6_AF_USEABLE) { + vltime = true; + flags &= ~IPV6_AF_USEABLE; + } + if (match == NULL) { if ((addr->flags & (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)) == (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)) return 1; - } else if (addr->prefix_vltime && - IN6_ARE_ADDR_EQUAL(&addr->addr, match) && - (!flags || addr->flags & flags)) + } else if (IN6_ARE_ADDR_EQUAL(&addr->addr, match) && + (!flags || addr->flags & flags) && (!vltime || addr->prefix_vltime)) return 1; return 0; @@ -971,11 +978,7 @@ ipv6_doaddr(struct ipv6_addr *ia, struct timespec *now) ipv6_deleteaddr(ia); eloop_q_timeout_delete(ia->iface->ctx->eloop, ELOOP_QUEUE_ALL, NULL, ia); - if (ia->flags & IPV6_AF_REQUEST) { - ia->flags &= ~IPV6_AF_ADDED; - return 0; - } - return -1; + return ia->flags & IPV6_AF_REQUEST ? 0 : -1; } if (ia->flags & IPV6_AF_STALE || IN6_IS_ADDR_UNSPECIFIED(&ia->addr)) @@ -1066,7 +1069,7 @@ ipv6_freedrop_addrs(struct ipv6_addrhead *addrs, int drop, TAILQ_REMOVE(addrs, ap, next); /* Find the same address somewhere else */ apf = ipv6_findaddr(ap->iface->ctx, &ap->addr, - 0); + IPV6_AF_USEABLE); if ((apf == NULL || (apf->iface != ap->iface))) ipv6_deleteaddr(ap); if (!(ap->iface->options->options & diff --git a/src/ipv6.h b/src/ipv6.h index 1b78532f..f09205cc 100644 --- a/src/ipv6.h +++ b/src/ipv6.h @@ -227,8 +227,9 @@ struct ipv6_addr { #define IPV6_AF_REGEN (1U << 14) #define IPV6_AF_ROUTER (1U << 15) #define IPV6_AF_ADVERTISED (1U << 16) +#define IPV6_AF_USEABLE (1U << 17) #ifdef IPV6_MANAGETEMPADDR -#define IPV6_AF_TEMPORARY (1U << 17) +#define IPV6_AF_TEMPORARY (1U << 18) #endif struct ll_callback {