]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
inet6: Only remove default route when router becomes unreachable
authorRoy Marples <roy@marples.name>
Fri, 23 Aug 2019 19:30:24 +0000 (20:30 +0100)
committerRoy Marples <roy@marples.name>
Fri, 23 Aug 2019 19:30:24 +0000 (20:30 +0100)
Rather than everything. DNS servers, subnets, etc could all
still be valid.
If no default router is available, start the solicitation
process again.

src/ipv6.c
src/ipv6nd.c
src/ipv6nd.h

index 31a0cae085661fd9454e8f2d53bb6f1698834cf5..a024356cf617fab2cc7c2db35d5300de9e4f7079 100644 (file)
@@ -2271,7 +2271,7 @@ inet6_raroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx)
                                rt_proto_add(routes, rt);
                        }
                }
-               if (rap->lifetime == 0)
+               if (rap->lifetime == 0 || !rap->isreachable)
                        continue;
                rt = inet6_makerouter(rap);
                if (rt == NULL)
index bb8cb4dc127ccb5d7aeca8ac89c33ac7419dd9e9..0169caef3d8d6256068812ce37d02cda834c5da3 100644 (file)
@@ -127,6 +127,7 @@ __CTASSERT(sizeof(struct nd_opt_rdnss) == 8);
 //
 
 static void ipv6nd_handledata(void *);
+static void ipv6nd_startrs1(void *);
 
 /*
  * Android ships buggy ICMP6 filter headers.
@@ -559,21 +560,21 @@ static void
 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);
@@ -584,16 +585,30 @@ ipv6nd_reachable(struct ra *rap, int flags)
 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 *
@@ -1026,6 +1041,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
                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) {
@@ -1044,7 +1060,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
         * 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);
@@ -1064,9 +1080,9 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
 
                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);
@@ -1399,7 +1415,7 @@ ipv6nd_env(FILE *fp, const struct interface *ifp)
        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);
@@ -1411,6 +1427,9 @@ ipv6nd_env(FILE *fp, const struct interface *ifp)
                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;
@@ -1503,7 +1522,7 @@ ipv6nd_expirera(void *arg)
        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;
@@ -1522,9 +1541,9 @@ ipv6nd_expirera(void *arg)
        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;
@@ -1533,8 +1552,8 @@ ipv6nd_expirera(void *arg)
                                if (!rap->expired) {
                                        logwarnx("%s: %s: router expired",
                                            ifp->name, rap->sfrom);
-                                       rap->expired = expired = 1;
                                        rap->lifetime = 0;
+                                       expired = true;
                                }
                        } else {
                                valid = true;
@@ -1552,7 +1571,7 @@ ipv6nd_expirera(void *arg)
                        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;
@@ -1576,7 +1595,7 @@ ipv6nd_expirera(void *arg)
                                if (!timespecisset(&next) ||
                                    timespeccmp(&next, &lt, >))
                                        next = lt;
-                               validone = true;
+                               valid = true;
                        }
                }
 
@@ -1626,7 +1645,7 @@ ipv6nd_expirera(void *arg)
                        if (ltime == 0)
                                continue;
                        if (ltime == ND6_INFINITE_LIFETIME) {
-                               validone = true;
+                               valid = true;
                                continue;
                        }
 
@@ -1643,15 +1662,15 @@ ipv6nd_expirera(void *arg)
                            timespeccmp(&next, &lt, >))
                        {
                                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);
        }
@@ -1670,7 +1689,7 @@ void
 ipv6nd_drop(struct interface *ifp)
 {
        struct ra *rap, *ran;
-       uint8_t expired = 0;
+       bool expired = false;
 
        if (ifp->ctx->ra_routers == NULL)
                return;
@@ -1678,7 +1697,7 @@ ipv6nd_drop(struct interface *ifp)
        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);
                }
        }
@@ -1755,7 +1774,8 @@ ipv6nd_handlena(struct dhcpcd_ctx *ctx, const char *sfrom,
        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;
index 7dbdcae70347e7567e92ff05d3d8db96bb67f828..e51271eb3536b205001db09655cd9f22091f3efc 100644 (file)
@@ -51,8 +51,9 @@ struct ra {
        uint32_t retrans;
        uint32_t mtu;
        struct ipv6_addrhead addrs;
-       uint8_t hasdns;
-       uint8_t expired;
+       bool hasdns;
+       bool expired;
+       bool isreachable;
 };
 
 TAILQ_HEAD(ra_head, ra);