From: Roy Marples Date: Thu, 6 Feb 2020 12:54:11 +0000 (+0000) Subject: inet6: Ensure expired routers are cleared after a carrier loss X-Git-Tag: v8.1.7~13 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8cd6efabfcf2e361b65fa62c18ce6b2ac17a604e;p=thirdparty%2Fdhcpcd.git inet6: Ensure expired routers are cleared after a carrier loss When we lose carrier, mark all RAs as willexpire and add the timeout to expire to it's own queue. On receipt of a matching RA, clear the willexpire flag. When the above timeout occours, set doexpire on all RA's with withexpire and then call the general expirera function. This is needed because expirera can be called at any point. --- diff --git a/src/ipv6nd.c b/src/ipv6nd.c index 90fdecf4..683d0252 100644 --- a/src/ipv6nd.c +++ b/src/ipv6nd.c @@ -379,10 +379,8 @@ ipv6nd_sendrsprobe(void *arg) if (state->rsprobes++ < MAX_RTR_SOLICITATIONS) eloop_timeout_add_sec(ifp->ctx->eloop, RTR_SOLICITATION_INTERVAL, ipv6nd_sendrsprobe, ifp); - else { + else logwarnx("%s: no IPv6 Routers available", ifp->name); - ipv6nd_drop(ifp); - } } #ifdef ND6_ADVERTISE @@ -531,19 +529,13 @@ ipv6nd_expire(void *arg) { struct interface *ifp = arg; struct ra *rap; - struct ipv6_addr *ia; - struct timespec now = { .tv_sec = 1 }; if (ifp->ctx->ra_routers == NULL) return; TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) { - if (rap->iface == ifp) - continue; - rap->acquired = now; - TAILQ_FOREACH(ia, &rap->addrs, next) { - ia->acquired = now; - } + if (rap->iface == ifp && rap->willexpire) + rap->doexpire = true; } ipv6nd_expirera(ifp); } @@ -551,9 +543,17 @@ ipv6nd_expire(void *arg) void ipv6nd_startexpire(struct interface *ifp) { + struct ra *rap; + + if (ifp->ctx->ra_routers == NULL) + return; - eloop_timeout_add_sec(ifp->ctx->eloop, RTR_CARRIER_EXPIRE, - ipv6nd_expire, ifp); + TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) { + if (rap->iface == ifp) + rap->willexpire = true; + } + eloop_q_timeout_add_sec(ifp->ctx->eloop, ELOOP_IPV6RA_EXPIRE, + RTR_CARRIER_EXPIRE, ipv6nd_expire, ifp); } static int @@ -584,10 +584,12 @@ ipv6nd_sortrouters(struct dhcpcd_ctx *ctx) while ((ra1 = TAILQ_FIRST(ctx->ra_routers)) != NULL) { TAILQ_REMOVE(ctx->ra_routers, ra1, next); TAILQ_FOREACH(ra2, &sorted_routers, next) { - if (ra1->iface->metric < ra2->iface->metric) + if (ra1->iface->metric > ra2->iface->metric) continue; if (ra1->expired && !ra2->expired) continue; + if (ra1->willexpire && !ra2->willexpire) + continue; if (ra1->lifetime == 0 && ra2->lifetime != 0) continue; if (!ra1->isreachable && ra2->reachable) @@ -1117,7 +1119,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, rap->retrans = ntohl(nd_ra->nd_ra_retransmit); else rap->retrans = RETRANS_TIMER; - rap->expired = false; + rap->expired = rap->willexpire = rap->doexpire = false; rap->hasdns = false; rap->isreachable = true; has_address = false; @@ -1397,7 +1399,8 @@ ipv6nd_hasralifetime(const struct interface *ifp, bool lifetime) if (ifp->ctx->ra_routers) { TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) - if (rap->iface == ifp && !rap->expired && + if (rap->iface == ifp && + !rap->expired && (!lifetime ||rap->lifetime)) return true; } @@ -1405,15 +1408,16 @@ ipv6nd_hasralifetime(const struct interface *ifp, bool lifetime) } bool -ipv6nd_hasradhcp(const struct interface *ifp) +ipv6nd_hasradhcp(const struct interface *ifp, bool managed) { const struct ra *rap; if (ifp->ctx->ra_routers) { TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) { if (rap->iface == ifp && - !rap->expired && - (rap->flags &(ND_RA_FLAG_MANAGED|ND_RA_FLAG_OTHER))) + !rap->expired && !rap->willexpire && + ((managed && rap->flags & ND_RA_FLAG_MANAGED) || + (!managed && rap->flags & ND_RA_FLAG_OTHER))) return true; } } @@ -1604,7 +1608,7 @@ ipv6nd_expirera(void *arg) lt.tv_sec = (time_t)rap->lifetime; lt.tv_nsec = 0; timespecadd(&rap->acquired, <, &expire); - if (timespeccmp(&now, &expire, >)) { + if (timespeccmp(&now, &expire, >) || rap->doexpire) { if (!rap->expired) { logwarnx("%s: %s: router expired", ifp->name, rap->sfrom); @@ -1626,14 +1630,16 @@ ipv6nd_expirera(void *arg) TAILQ_FOREACH(ia, &rap->addrs, next) { if (ia->prefix_vltime == 0) continue; - if (ia->prefix_vltime == ND6_INFINITE_LIFETIME) { + if (ia->prefix_vltime == ND6_INFINITE_LIFETIME && + !rap->doexpire) + { valid = true; continue; } lt.tv_sec = (time_t)ia->prefix_vltime; lt.tv_nsec = 0; timespecadd(&ia->acquired, <, &expire); - if (timespeccmp(&now, &expire, >)) { + if (timespeccmp(&now, &expire, >) || rap->doexpire) { if (ia->flags & IPV6_AF_ADDED) { logwarnx("%s: expired address %s", ia->iface->name, ia->saddr); @@ -1700,6 +1706,10 @@ ipv6nd_expirera(void *arg) if (ltime == 0) continue; + if (rap->doexpire) { + expired = true; + continue; + } if (ltime == ND6_INFINITE_LIFETIME) { valid = true; continue; @@ -1735,7 +1745,8 @@ ipv6nd_expirera(void *arg) eloop_timeout_add_tv(ifp->ctx->eloop, &next, ipv6nd_expirera, ifp); if (expired) { - logwarnx("%s: part of Router Advertisement expired", ifp->name); + logwarnx("%s: part of a Router Advertisement expired", + ifp->name); rt_build(ifp->ctx, AF_INET6); script_runreason(ifp, "ROUTERADVERT"); } diff --git a/src/ipv6nd.h b/src/ipv6nd.h index 82e024e5..6b41cee4 100644 --- a/src/ipv6nd.h +++ b/src/ipv6nd.h @@ -54,6 +54,8 @@ struct ra { struct ipv6_addrhead addrs; bool hasdns; bool expired; + bool willexpire; + bool doexpire; bool isreachable; }; @@ -108,7 +110,7 @@ ssize_t ipv6nd_free(struct interface *); void ipv6nd_expirera(void *arg); bool ipv6nd_hasralifetime(const struct interface *, bool); #define ipv6nd_hasra(i) ipv6nd_hasralifetime((i), false) -bool ipv6nd_hasradhcp(const struct interface *); +bool ipv6nd_hasradhcp(const struct interface *, bool); void ipv6nd_handleifa(int, struct ipv6_addr *, pid_t); int ipv6nd_dadcompleted(const struct interface *); void ipv6nd_advertise(struct ipv6_addr *);