From: Roy Marples Date: Mon, 1 Feb 2016 22:47:46 +0000 (+0000) Subject: Do the same for IPv6 as the prior patch. X-Git-Tag: v6.10.2~84 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=eeb3d111931a5b3e72638b5efecb054eb79549d2;p=thirdparty%2Fdhcpcd.git Do the same for IPv6 as the prior patch. --- diff --git a/if-bsd.c b/if-bsd.c index 91006376..8a480d1f 100644 --- 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 b381df32..ebb616c0 100644 --- 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 c01e05b8..d96fa54e 100644 --- a/ipv6.h +++ b/ipv6.h @@ -70,6 +70,14 @@ #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 *);