//
static void ipv6nd_handledata(void *);
+static void ipv6nd_startrs1(void *);
/*
* Android ships buggy ICMP6 filter headers.
ipv6nd_reachable(struct ra *rap, int flags)
{
- if (rap->lifetime == 0)
+ if (rap->expired)
return;
if (flags & IPV6ND_REACHABLE) {
- if (rap->expired == 0)
+ if (rap->isreachable)
return;
loginfox("%s: %s is reachable again",
rap->iface->name, rap->sfrom);
- rap->expired = 0;
+ rap->isreachable = true;
} else {
- if (rap->expired != 0)
+ if (!rap->isreachable)
return;
- logwarnx("%s: %s is unreachable, expiring it",
+ logwarnx("%s: %s is unreachable",
rap->iface->name, rap->sfrom);
- rap->expired = 1;
+ rap->isreachable = false;
}
rt_build(rap->iface->ctx, AF_INET6);
void
ipv6nd_neighbour(struct dhcpcd_ctx *ctx, struct in6_addr *addr, int flags)
{
- struct ra *rap;
+ struct ra *rap, *rapr;
- if (ctx->ra_routers) {
- TAILQ_FOREACH(rap, ctx->ra_routers, next) {
- if (IN6_ARE_ADDR_EQUAL(&rap->from, addr)) {
- ipv6nd_reachable(rap, flags);
- break;
- }
+ if (ctx->ra_routers == NULL)
+ return;
+
+ TAILQ_FOREACH(rap, ctx->ra_routers, next) {
+ if (IN6_ARE_ADDR_EQUAL(&rap->from, addr)) {
+ ipv6nd_reachable(rap, flags);
+ break;
}
}
+ if (rap == NULL || flags & IPV6ND_REACHABLE)
+ return;
+
+ /* If we have no reachable default routers, try and solicit one. */
+ TAILQ_FOREACH(rapr, ctx->ra_routers, next) {
+ if (rap == rapr || rap->iface != rapr->iface)
+ continue;
+ if (rapr->isreachable && !rapr->expired && rapr->lifetime)
+ break;
+ }
+
+ if (rapr == NULL)
+ ipv6nd_startrs1(rap->iface);
}
const struct ipv6_addr *
strlcpy(rap->sfrom, sfrom, sizeof(rap->sfrom));
TAILQ_INIT(&rap->addrs);
new_rap = true;
+ rap->isreachable = true;
} else
new_rap = false;
if (rap->data_len == 0) {
* routers like to decrease the advertised valid and preferred times
* in accordance with the own prefix times which would result in too
* much needless log spam. */
- logfunc = new_rap ? loginfox : logdebugx,
+ logfunc = new_rap || !rap->isreachable ? loginfox : logdebugx,
logfunc("%s: Router Advertisement from %s", ifp->name, rap->sfrom);
clock_gettime(CLOCK_MONOTONIC, &rap->acquired);
state->retrans = rap->retrans = ntohl(nd_ra->nd_ra_retransmit);
}
- if (rap->lifetime)
- rap->expired = 0;
- rap->hasdns = 0;
+ rap->expired = false;
+ rap->hasdns = false;
+ rap->isreachable = true;
#ifdef IPV6_AF_TEMPORARY
ipv6_markaddrsstale(ifp, IPV6_AF_TEMPORARY);
clock_gettime(CLOCK_MONOTONIC, &now);
i = n = 0;
TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) {
- if (rap->iface != ifp)
+ if (rap->iface != ifp || rap->expired)
continue;
i++;
snprintf(ndprefix, sizeof(ndprefix), "nd%zu", i);
if (efprintf(fp, "%s_now=%lld", ndprefix,
(long long)now.tv_sec) == -1)
return -1;
+ if (efprintf(fp, "%s_isreachable=%s", ndprefix,
+ rap->isreachable ? "true" : "false") == -1)
+ return -1;
/* Zero our indexes */
for (j = 0, opt = rap->iface->ctx->nd_opts;
struct interface *ifp;
struct ra *rap, *ran;
struct timespec now, lt, expire, next;
- bool expired, valid, validone;
+ bool expired, valid;
struct ipv6_addr *ia;
size_t len, olen;
uint8_t *p;
timespecclear(&next);
TAILQ_FOREACH_SAFE(rap, ifp->ctx->ra_routers, next, ran) {
- if (rap->iface != ifp)
+ if (rap->iface != ifp || rap->expired)
continue;
- valid = validone = false;
+ valid = false;
if (rap->lifetime) {
lt.tv_sec = (time_t)rap->lifetime;
lt.tv_nsec = 0;
if (!rap->expired) {
logwarnx("%s: %s: router expired",
ifp->name, rap->sfrom);
- rap->expired = expired = 1;
rap->lifetime = 0;
+ expired = true;
}
} else {
valid = true;
if (ia->prefix_vltime == 0)
continue;
if (ia->prefix_vltime == ND6_INFINITE_LIFETIME) {
- validone = true;
+ valid = true;
continue;
}
lt.tv_sec = (time_t)ia->prefix_vltime;
if (!timespecisset(&next) ||
timespeccmp(&next, <, >))
next = lt;
- validone = true;
+ valid = true;
}
}
if (ltime == 0)
continue;
if (ltime == ND6_INFINITE_LIFETIME) {
- validone = true;
+ valid = true;
continue;
}
timespeccmp(&next, <, >))
{
next = lt;
- validone = true;
+ valid = true;
}
}
- if (valid || validone)
+ if (valid)
continue;
- /* Router has expired. Let's not keep a lot of them.
- * We should work out if all the options have expired .... */
+ /* Router has expired. Let's not keep a lot of them. */
+ rap->expired = true;
if (++nexpired > EXPIRED_MAX)
ipv6nd_free_ra(rap);
}
ipv6nd_drop(struct interface *ifp)
{
struct ra *rap, *ran;
- uint8_t expired = 0;
+ bool expired = false;
if (ifp->ctx->ra_routers == NULL)
return;
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
TAILQ_FOREACH_SAFE(rap, ifp->ctx->ra_routers, next, ran) {
if (rap->iface == ifp) {
- rap->expired = expired = 1;
+ rap->expired = expired = true;
ipv6nd_drop_ra(rap);
}
}
if (!is_router && !rap->expired) {
loginfox("%s: %s not a router (%s)",
ifp->name, taddr, sfrom);
- rap->expired = 1;
+ rap->expired = true;
+ rap->lifetime = 0;
rt_build(ifp->ctx, AF_INET6);
script_runreason(ifp, "ROUTERADVERT");
return;