diff options
| author | Roy Marples <roy@marples.name> | 2020-02-06 12:54:11 +0000 |
|---|---|---|
| committer | Roy Marples <roy@marples.name> | 2020-02-06 12:54:11 +0000 |
| commit | 4a775363802338d4608163fae752557531955a6e (patch) | |
| tree | ebb9dcd0939dea59561f5654054bc85dd12886b4 /src/ipv6nd.c | |
| parent | 8df4aa4ec2e8dfc7de92f66b029f9a61d6920adf (diff) | |
| download | dhcpcd-4a775363802338d4608163fae752557531955a6e.tar.xz | |
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.
Diffstat (limited to 'src/ipv6nd.c')
| -rw-r--r-- | src/ipv6nd.c | 57 |
1 files changed, 34 insertions, 23 deletions
diff --git a/src/ipv6nd.c b/src/ipv6nd.c index 9457545e..58da9562 100644 --- a/src/ipv6nd.c +++ b/src/ipv6nd.c @@ -391,10 +391,8 @@ sent: 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 @@ -554,19 +552,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); } @@ -574,9 +566,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 @@ -607,10 +607,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) @@ -1137,7 +1139,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; @@ -1416,7 +1418,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; } @@ -1424,15 +1427,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; } } @@ -1622,7 +1626,7 @@ ipv6nd_expirera(void *arg) if (rap->lifetime) { elapsed = (uint32_t)eloop_timespec_diff(&now, &rap->acquired, NULL); - if (elapsed > rap->lifetime) { + if (elapsed > rap->lifetime || rap->doexpire) { if (!rap->expired) { logwarnx("%s: %s: router expired", ifp->name, rap->sfrom); @@ -1643,13 +1647,15 @@ 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; } elapsed = (uint32_t)eloop_timespec_diff(&now, &ia->acquired, NULL); - if (elapsed > ia->prefix_vltime) { + if (elapsed > ia->prefix_vltime || rap->doexpire) { if (ia->flags & IPV6_AF_ADDED) { logwarnx("%s: expired %s %s", ia->iface->name, @@ -1720,6 +1726,10 @@ ipv6nd_expirera(void *arg) if (ltime == 0) continue; + if (rap->doexpire) { + expired = true; + continue; + } if (ltime == ND6_INFINITE_LIFETIME) { valid = true; continue; @@ -1750,7 +1760,8 @@ ipv6nd_expirera(void *arg) eloop_timeout_add_sec(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"); } |
