summaryrefslogtreecommitdiffstats
path: root/src/ipv6nd.c
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2020-02-06 12:54:11 +0000
committerRoy Marples <roy@marples.name>2020-02-06 12:54:11 +0000
commit3e0c93a4bbb16e250510dbbadba6b6d8971f8d2c (patch)
treeebb9dcd0939dea59561f5654054bc85dd12886b4 /src/ipv6nd.c
parent3c9cea4b63110de18c1ef880b6180a348d3e769d (diff)
downloaddhcpcd-3e0c93a4bbb16e250510dbbadba6b6d8971f8d2c.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.c57
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");
}