]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
INET6: Apply hoplimit, reachable and retrans timer values from RA.
authorRoy Marples <roy@marples.name>
Sat, 9 Nov 2019 22:03:19 +0000 (22:03 +0000)
committerRoy Marples <roy@marples.name>
Sat, 9 Nov 2019 22:03:19 +0000 (22:03 +0000)
Only tested thus far on NetBSD.
While here, fix prior to not lose the first sorted route.

src/if-bsd.c
src/if-linux.c
src/if-sun.c
src/if.h
src/ipv6nd.c
src/ipv6nd.h

index d2e910ef74d2b473c9213cd5eb7be33da02a7945..eb7673a23516134d711ae25e40cb7ac4925327b8 100644 (file)
@@ -1484,6 +1484,22 @@ inet6_sysctl(int code, int val, int action)
 }
 #endif
 
+int
+if_applyra(const struct ra *rap)
+{
+       struct in6_ndireq ndi = { .ndi.chlim = 0 };
+       struct priv *priv = rap->iface->ctx->priv;
+
+       strncpy(ndi.ifname, rap->iface->name, sizeof(ndi.ifname));
+       if (ioctl(priv->pf_inet6_fd, SIOCGIFINFO_IN6, &ndi) == -1)
+               return -1;
+
+       ndi.ndi.chlim = rap->hoplimit;
+       ndi.ndi.retrans = rap->retrans;
+       ndi.ndi.basereachable = rap->reachable;
+       return ioctl(priv->pf_inet6_fd, SIOCSIFINFO_IN6, &ndi);
+}
+
 #ifdef IPV6_MANAGETEMPADDR
 #ifndef IPV6CTL_TEMPVLTIME
 #define get_inet6_sysctlbyname(code) inet6_sysctlbyname(code, 0, 0)
index f7f280bd1d91a24ecaecb11ce0dc5ec1d4603023..681213004b24b861e17895bbb43e94e852712589 100644 (file)
@@ -229,7 +229,7 @@ check_proc_hex(const char *path, unsigned int *value)
 }
 
 static ssize_t
-if_writepathstr(const char *path, const char *val)
+if_writepathuint(const char *path, unsigned int val)
 {
        FILE *fp;
        ssize_t r;
@@ -237,7 +237,7 @@ if_writepathstr(const char *path, const char *val)
        fp = fopen(path, "w");
        if (fp == NULL)
                return -1;
-       r = fprintf(fp, "%s\n", val);
+       r = fprintf(fp, "%u\n", val);
        fclose(fp);
        return r;
 }
@@ -261,7 +261,7 @@ if_init(struct interface *ifp)
                return errno == ENOENT ? 0 : -1;
        if (n == 1)
                return 0;
-       return if_writepathstr(path, "1") == -1 ? -1 : 0;
+       return if_writepathuint(path, 1) == -1 ? -1 : 0;
 }
 
 int
@@ -1875,7 +1875,7 @@ if_setup_inet6(const struct interface *ifp)
        snprintf(path, sizeof(path), "%s/%s/autoconf", prefix, ifp->name);
        ra = check_proc_int(path);
        if (ra != 1 && ra != -1) {
-               if (if_writepathstr(path, "0") == -1)
+               if (if_writepathuint(path, 0) == -1)
                        logerr("%s: %s", __func__, path);
        }
 
@@ -1888,11 +1888,29 @@ if_setup_inet6(const struct interface *ifp)
                 * error as such so just log it and continue */
                logfunc("%s", path);
        } else if (ra != 0) {
-               if (if_writepathstr(path, "0") == -1)
+               if (if_writepathuint(path, 0) == -1)
                        logerr("%s: %s", __func__, path);
        }
 }
 
+int
+if_applyra(const struct ra *rap)
+{
+       int error = 0;
+
+       snprintf(path, sizeof(path), "%s/%s/hop_limit", prefix, ifp->name);
+       if (if_writepathuint(path, rap->hoplimit) == -1)
+               error = -1;
+       snprintf(path, sizeof(path), "%s/%s/retrans_time", prefix, ifp->name);
+       if (if_writepathuint(path, rap->retrans) == -1)
+               error = -1;
+       snprintf(path, sizeof(path), "%s/%s/base_reachable_time", prefix,
+           ifp->name);
+       if (if_writepathuint(path, rap->reachable) == -1)
+               error = -1;
+       return error;
+}
+
 #ifdef IPV6_MANAGETEMPADDR
 int
 ip6_use_tempaddr(const char *ifname)
index 39e217c2e186015da01a980feba0e6af74ac54b1..6f6f5915569cbf24e14c2a8610648fb478cc53ba 100644 (file)
@@ -1711,6 +1711,20 @@ if_getlifetime6(struct ipv6_addr *addr)
        return -1;
 }
 
+int
+if_applyra(const struct ra *rap)
+{
+       struct lifreq           lifr = {
+               .lifr_ifinfo.lir_maxhops = rap->hoplimit,
+               .lifr_ifinfo.lir_reachtime = rap->reachable,
+               .lifr_ifinfo.lir_reachretrans = rap->retrans,
+       };
+
+       strlcpy(lifr.lifr_ifname, rap->iface->name, sizeof(lifr.lifr_ifname));
+       if (ioctl(rap->iface->ctx->pf_inet_fd, SIOCSLIFLNKINFO, &lifr) == -1)
+               return -1;
+}
+
 void
 if_setup_inet6(__unused const struct interface *ifp)
 {
index ecfdb1027d7cbaf36506db5510f459203423e1b1..cc62cc948fa5caa82235f25fcb05fc41566cd91d 100644 (file)
--- a/src/if.h
+++ b/src/if.h
@@ -65,6 +65,7 @@
 #include "dhcpcd.h"
 #include "ipv4.h"
 #include "ipv6.h"
+#include "ipv6nd.h"
 #include "route.h"
 
 #define EUI64_ADDR_LEN                 8
@@ -206,6 +207,7 @@ int ip6_temp_valid_lifetime(const char *ifname);
 #endif
 int ip6_forwarding(const char *ifname);
 
+int if_applyra(const struct ra *);
 int if_address6(unsigned char, const struct ipv6_addr *);
 int if_addrflags6(const struct interface *, const struct in6_addr *,
     const char *);
index 783ceaedc6bebe4c164ee1cd59ddb02550a03ce4..3cf697136a1c0f7dd87b0c8c9686bb59cde0af39 100644 (file)
@@ -581,9 +581,6 @@ ipv6nd_sortrouters(struct dhcpcd_ctx *ctx)
        struct ra_head sorted_routers = TAILQ_HEAD_INITIALIZER(sorted_routers);
        struct ra *ra1, *ra2;
 
-       /* Pop the first router off */
-       ra1 = TAILQ_FIRST(ctx->ra_routers);
-       TAILQ_REMOVE(ctx->ra_routers, ra1, next);
        while ((ra1 = TAILQ_FIRST(ctx->ra_routers)) != NULL) {
                TAILQ_REMOVE(ctx->ra_routers, ra1, next);
                TAILQ_FOREACH(ra2, &sorted_routers, next) {
@@ -610,6 +607,25 @@ ipv6nd_sortrouters(struct dhcpcd_ctx *ctx)
        TAILQ_CONCAT(ctx->ra_routers, &sorted_routers, next);
 }
 
+static void
+ipv6nd_applyra(struct dhcpcd_ctx *ctx, struct interface *ifp)
+{
+       struct ra *rap;
+       struct rs_state *state = RS_STATE(ifp);
+
+       TAILQ_FOREACH(rap, ctx->ra_routers, next) {
+               if (rap->iface == ifp)
+                       break;
+       }
+
+       if (rap == NULL)
+               return;
+
+       state->retrans = rap->retrans;
+       if (if_applyra(rap) == -1)
+               logerr(__func__);
+}
+
 /*
  * Neighbour reachability.
  *
@@ -645,6 +661,7 @@ ipv6nd_neighbour(struct dhcpcd_ctx *ctx, struct in6_addr *addr, bool reachable)
 
        /* See if we can install a reachable default router. */
        ipv6nd_sortrouters(ctx);
+       ipv6nd_applyra(ctx, rap->iface);
        rt_build(ctx, AF_INET6);
 
        /* If we have no reachable default routers, try and solicit one. */
@@ -1082,16 +1099,20 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
        if (!new_rap && rap->lifetime == 0 && old_lifetime != 0)
                logwarnx("%s: %s: no longer a default router",
                    ifp->name, rap->sfrom);
-       if (nd_ra->nd_ra_reachable) {
+       if (nd_ra->nd_ra_curhoplimit != 0)
+               rap->hoplimit = nd_ra->nd_ra_curhoplimit;
+       else
+               rap->hoplimit = IPV6_DEFHLIM;
+       if (nd_ra->nd_ra_reachable != 0) {
                rap->reachable = ntohl(nd_ra->nd_ra_reachable);
                if (rap->reachable > MAX_REACHABLE_TIME)
                        rap->reachable = 0;
-       }
-       if (nd_ra->nd_ra_retransmit) {
-               struct rs_state *state = RS_STATE(ifp);
-
-               state->retrans = rap->retrans = ntohl(nd_ra->nd_ra_retransmit);
-       }
+       } else
+               rap->reachable = REACHABLE_TIME;
+       if (nd_ra->nd_ra_retransmit != 0)
+               rap->retrans = ntohl(nd_ra->nd_ra_retransmit);
+       else
+               rap->retrans = RETRANS_TIMER;
        rap->expired = false;
        rap->hasdns = false;
        rap->isreachable = true;
@@ -1311,6 +1332,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
                script_runreason(ifp, "TEST");
                goto handle_flag;
        }
+       ipv6nd_applyra(ifp->ctx, ifp);
        ipv6_addaddrs(&rap->addrs);
 #ifdef IPV6_MANAGETEMPADDR
        ipv6_addtempaddrs(ifp, &rap->acquired);
index 16c4dc79504183fa899c9721d993d670e82e559d..1097a88a83da6a786bd55bedb856b1586e441080 100644 (file)
@@ -50,6 +50,7 @@ struct ra {
        uint32_t reachable;
        uint32_t retrans;
        uint32_t mtu;
+       uint8_t hoplimit;
        struct ipv6_addrhead addrs;
        bool hasdns;
        bool expired;