]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Do the same for IPv6 as the prior patch.
authorRoy Marples <roy@marples.name>
Mon, 1 Feb 2016 22:47:46 +0000 (22:47 +0000)
committerRoy Marples <roy@marples.name>
Mon, 1 Feb 2016 22:47:46 +0000 (22:47 +0000)
if-bsd.c
ipv6.c
ipv6.h

index 910063765d1083efc48f88c24e1af657ad74fef2..8a480d1ff0d95090cf2f62106acbd7d15bddfee2 100644 (file)
--- a/if-bsd.c
+++ b/if-bsd.c
@@ -826,6 +826,8 @@ if_copyrt6(struct dhcpcd_ctx *ctx, struct rt6 *rt, struct rt_msghdr *rtm)
        char *cp;
        struct sockaddr *sa, *rti_info[RTAX_MAX];
        struct sockaddr_dl *sdl;
+       struct sockaddr_in6 *sin;
+       struct ipv6_addr *ia;
 
        cp = (char *)(void *)(rtm + 1);
        sa = (struct sockaddr *)(void *)cp;
@@ -905,9 +907,22 @@ if_copyrt6(struct dhcpcd_ctx *ctx, struct rt6 *rt, struct rt_msghdr *rtm)
                sdl = (struct sockaddr_dl *)(void *)rti_info[RTAX_IFP];
                rt->iface = if_findsdl(ctx, sdl);
        } else if (rtm->rtm_addrs & RTA_GATEWAY) {
-               sdl = (struct sockaddr_dl *)(void *)rti_info[RTAX_GATEWAY];
-               if (sdl->sdl_family == AF_LINK)
+               sa = rti_info[RTAX_GATEWAY];
+               switch (sa->sa_family) {
+               case AF_LINK:
+                       sdl = (void *)sa;
                        rt->iface = if_findsdl(ctx, sdl);
+                       break;
+               case AF_INET6:
+                       sin = (void *)sa;
+                       if ((ia = ipv6_findmaskaddr(ctx, &sin->sin6_addr)))
+                               rt->iface = ia->iface;
+                       break;
+               default:
+                       errno = EAFNOSUPPORT;
+                       logger(ctx, LOG_ERR, "%s: %m", __func__);
+                       return -1;
+               }
        }
 
        /* If we don't have an interface and it's a host route, it maybe
@@ -915,8 +930,6 @@ if_copyrt6(struct dhcpcd_ctx *ctx, struct rt6 *rt, struct rt_msghdr *rtm)
        if (rt->iface == NULL &&
            !(~rtm->rtm_flags & (RTF_HOST | RTF_GATEWAY)))
        {
-               struct ipv6_addr *ia;
-
                if ((ia = ipv6_findaddr(ctx, &rt->dest, 0)))
                        rt->iface = ia->iface;
        }
diff --git a/ipv6.c b/ipv6.c
index b381df329dda074c97b44e42643888b7e921dd06..ebb616c0c03648a0d5a658ed9ef48d4334450312 100644 (file)
--- a/ipv6.c
+++ b/ipv6.c
@@ -1090,6 +1090,39 @@ ipv6_iffindaddr(const struct interface *ifp, const struct in6_addr *addr)
        return NULL;
 }
 
+static struct ipv6_addr *
+ipv6_iffindmaskaddr(const struct interface *ifp, const struct in6_addr *addr)
+{
+       struct ipv6_state *state;
+       struct ipv6_addr *ap;
+       struct in6_addr mask;
+
+       state = IPV6_STATE(ifp);
+       if (state) {
+               TAILQ_FOREACH(ap, &state->addrs, next) {
+                       if (ipv6_mask(&mask, ap->prefix_len) == -1)
+                               continue;
+                       if (IN6_ARE_MASKED_ADDR_EQUAL(&ap->addr, addr, &mask))
+                               return ap;
+               }
+       }
+       return NULL;
+}
+
+struct ipv6_addr *
+ipv6_findmaskaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr)
+{
+       struct interface *ifp;
+       struct ipv6_addr *ap;
+
+       TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+               ap = ipv6_iffindmaskaddr(ifp, addr);
+               if (ap != NULL)
+                       return ap;
+       }
+       return NULL;
+}
+
 int
 ipv6_addlinklocalcallback(struct interface *ifp,
     void (*callback)(void *), void *arg)
diff --git a/ipv6.h b/ipv6.h
index c01e05b80ee1486d09b81dbf8429949ac7bce9e6..d96fa54e667c852b6d77f09793b558267fe186b8 100644 (file)
--- a/ipv6.h
+++ b/ipv6.h
 #define IDGEN_RETRIES  3
 #define IDGEN_DELAY    1 /* second */
 
+#ifndef IN6_ARE_MASKED_ADDR_EQUAL
+#define IN6_ARE_MASKED_ADDR_EQUAL(d, a, m)     (       \
+       (((d)->s6_addr32[0] ^ (a)->s6_addr32[0]) & (m)->s6_addr32[0]) == 0 && \
+       (((d)->s6_addr32[1] ^ (a)->s6_addr32[1]) & (m)->s6_addr32[1]) == 0 && \
+       (((d)->s6_addr32[2] ^ (a)->s6_addr32[2]) & (m)->s6_addr32[2]) == 0 && \
+       (((d)->s6_addr32[3] ^ (a)->s6_addr32[3]) & (m)->s6_addr32[3]) == 0 )
+#endif
+
 /*
  * BSD kernels don't inform userland of DAD results.
  * See the discussion here:
@@ -263,6 +271,8 @@ int ipv6_findaddrmatch(const struct ipv6_addr *, const struct in6_addr *,
     short);
 struct ipv6_addr *ipv6_findaddr(struct dhcpcd_ctx *,
     const struct in6_addr *, short);
+struct ipv6_addr *ipv6_findmaskaddr(struct dhcpcd_ctx *,
+    const struct in6_addr *);
 #define ipv6_linklocal(ifp) ipv6_iffindaddr((ifp), NULL)
 int ipv6_addlinklocalcallback(struct interface *, void (*)(void *), void *);
 void ipv6_freeaddr(struct ipv6_addr *);