From: Roy Marples Date: Tue, 23 Apr 2019 17:27:52 +0000 (+0000) Subject: sun: Open an IPv6ND socket per interface X-Git-Tag: v7.2.1~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b2edc30309800a42123b45d280332b6b24a2146f;p=thirdparty%2Fdhcpcd.git sun: Open an IPv6ND socket per interface This is needed because we need to join the all-nodes multi-cast group and that only works per interface. --- diff --git a/src/dhcpcd.h b/src/dhcpcd.h index 02b830c0..24782cbc 100644 --- a/src/dhcpcd.h +++ b/src/dhcpcd.h @@ -180,7 +180,9 @@ struct dhcpcd_ctx { uint8_t *secret; size_t secret_len; +#ifndef __sun int nd_fd; +#endif struct ra_head *ra_routers; int dhcp6_fd; diff --git a/src/ipv6.c b/src/ipv6.c index 38b838c7..de8570f0 100644 --- a/src/ipv6.c +++ b/src/ipv6.c @@ -137,7 +137,9 @@ ipv6_init(struct dhcpcd_ctx *ctx) return -1; TAILQ_INIT(ctx->ra_routers); +#ifndef __sun ctx->nd_fd = -1; +#endif ctx->dhcp6_fd = -1; return 0; } diff --git a/src/ipv6nd.c b/src/ipv6nd.c index bef77b2a..59742ad2 100644 --- a/src/ipv6nd.c +++ b/src/ipv6nd.c @@ -160,6 +160,12 @@ static void ipv6nd_handledata(void *); #define IPV6_RECVPKTINFO IPV6_PKTINFO #endif +#ifdef __sun +struct in6_addr all_nodes_mcast = { .s6_addr = { + 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } }; +#endif + /* Handy defines */ #define ipv6nd_free_ra(ra) ipv6nd_freedrop_ra((ra), 0) #define ipv6nd_drop_ra(ra) ipv6nd_freedrop_ra((ra), 1) @@ -190,54 +196,94 @@ ipv6nd_printoptions(const struct dhcpcd_ctx *ctx, } static int -ipv6nd_open(struct dhcpcd_ctx *ctx) +ipv6nd_open0() { - int on; + int s, on; struct icmp6_filter filt; - if (ctx->nd_fd != -1) - return ctx->nd_fd; #define SOCK_FLAGS SOCK_CLOEXEC | SOCK_NONBLOCK - ctx->nd_fd = xsocket(PF_INET6, SOCK_RAW | SOCK_FLAGS, IPPROTO_ICMPV6); + s = xsocket(PF_INET6, SOCK_RAW | SOCK_FLAGS, IPPROTO_ICMPV6); #undef SOCK_FLAGS - if (ctx->nd_fd == -1) + if (s == -1) return -1; /* RFC4861 4.1 */ on = 255; - if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, - &on, sizeof(on)) == -1) - goto eexit; - - on = 1; - if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, + if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &on, sizeof(on)) == -1) goto eexit; on = 1; - if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on)) == -1) goto eexit; ICMP6_FILTER_SETBLOCKALL(&filt); ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filt); ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); - if (setsockopt(ctx->nd_fd, IPPROTO_ICMPV6, ICMP6_FILTER, + if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt)) == -1) goto eexit; - eloop_event_add(ctx->eloop, ctx->nd_fd, ipv6nd_handledata, ctx); - return ctx->nd_fd; + return s; eexit: - if (ctx->nd_fd != -1) { - eloop_event_delete(ctx->eloop, ctx->nd_fd); - close(ctx->nd_fd); - ctx->nd_fd = -1; - } + close(s); return -1; } +#ifdef __sun +static int +ipv6nd_open(struct interface *ifp) +{ + int s; + struct ipv6_mreq mreq = { + .ipv6mr_multiaddr = all_nodes_mcast, + .ipv6mr_interface = ifp->index + }; + struct rs_state *state = RS_STATE(ifp); + + if (state->nd_fd != -1) + return state->nd_fd; + + s = ipv6nd_open0(); + if (s == -1) + return -1; + + if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, + &mreq, sizeof(mreq)) == -1) + { + close(s); + return -1; + } + + state->nd_fd = s; + eloop_event_add(ifp->ctx->eloop, s, ipv6nd_handledata, ifp); + return s; +} +#else +static int +ipv6nd_open(struct dhcpcd_ctx *ctx) +{ + int on; + + if (ctx->nd_fd != -1) + return ctx->nd_fd; + + on = 1; + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, + &on, sizeof(on)) == -1) + { + close(s); + return -1; + } + + ctx->nd_fd = s; + eloop_event_add(ctx->eloop, s, ipv6nd_handledata, ctx); + return s; +} +#endif + static int ipv6nd_makersprobe(struct interface *ifp) { @@ -273,7 +319,6 @@ static void ipv6nd_sendrsprobe(void *arg) { struct interface *ifp = arg; - struct dhcpcd_ctx *ctx; struct rs_state *state = RS_STATE(ifp); struct sockaddr_in6 dst = { .sin6_family = AF_INET6 }; struct iovec iov = { .iov_base = state->rs, .iov_len = state->rslen }; @@ -285,6 +330,7 @@ ipv6nd_sendrsprobe(void *arg) }; struct cmsghdr *cm; struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index }; + int s; if (ipv6_linklocal(ifp) == NULL) { logdebugx("%s: delaying Router Solicitation for LL address", @@ -302,8 +348,6 @@ ipv6nd_sendrsprobe(void *arg) return; } - ctx = ifp->ctx; - /* Set the outbound interface */ cm = CMSG_FIRSTHDR(&msg); if (cm == NULL) /* unlikely */ @@ -314,7 +358,12 @@ ipv6nd_sendrsprobe(void *arg) memcpy(CMSG_DATA(cm), &pi, sizeof(pi)); logdebugx("%s: sending Router Solicitation", ifp->name); - if (sendmsg(ctx->nd_fd, &msg, 0) == -1) { +#ifdef __sun + s = state->nd_fd; +#else + s = ifp->ctx->nd_fd; +#endif + if (sendmsg(s, &msg, 0) == -1) { logerr(__func__); /* Allow IPv6ND to continue .... at most a few errors * would be logged. @@ -354,6 +403,7 @@ ipv6nd_sendadvertisement(void *arg) struct cmsghdr *cm; struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index }; const struct rs_state *state = RS_CSTATE(ifp); + int s; if (state == NULL || ifp->carrier <= LINK_DOWN) goto freeit; @@ -375,7 +425,12 @@ ipv6nd_sendadvertisement(void *arg) memcpy(CMSG_DATA(cm), &pi, sizeof(pi)); logdebugx("%s: sending NA for %s", ifp->name, ia->saddr); - if (sendmsg(ctx->nd_fd, &msg, 0) == -1) +#ifdef __sun + s = state->nd_fd; +#else + s = ctx->nd_fd; +#endif + if (sendmsg(s, &msg, 0) == -1) logerr(__func__); if (++ia->na_count < MAX_NEIGHBOR_ADVERTISEMENT) { @@ -619,6 +674,11 @@ ipv6nd_free(struct interface *ifp) if (state == NULL) return 0; + ctx = ifp->ctx; +#ifdef __sun + eloop_event_delete(ctx->eloop, state->nd_fd); + close(state->nd_fd); +#endif free(state->rs); free(state); ifp->if_data[IF_DATA_IPV6ND] = NULL; @@ -630,9 +690,9 @@ ipv6nd_free(struct interface *ifp) } } +#ifndef __sun /* If we don't have any more IPv6 enabled interfaces, * close the global socket and release resources */ - ctx = ifp->ctx; TAILQ_FOREACH(ifp, ctx->ifaces, next) { if (RS_STATE(ifp)) break; @@ -644,6 +704,7 @@ ipv6nd_free(struct interface *ifp) ctx->nd_fd = -1; } } +#endif return n; } @@ -1659,6 +1720,7 @@ static void ipv6nd_handledata(void *arg) { struct dhcpcd_ctx *ctx; + int s; struct sockaddr_in6 from; unsigned char buf[64 * 1024]; /* Maximum ICMPv6 size */ struct iovec iov = { @@ -1677,8 +1739,18 @@ ipv6nd_handledata(void *arg) struct icmp6_hdr *icp; struct interface *ifp; +#ifdef __sun + struct rs_state *state; + + ifp = arg; + state = RS_STATE(ifp); + ctx = ifp->ctx; + s = state->nd_fd; +#else ctx = arg; - len = recvmsg(ctx->nd_fd, &msg, 0); + s = ctx->nd_fd; +#endif + len = recvmsg(s, &msg, 0); if (len == -1) { logerr(__func__); return; @@ -1689,11 +1761,15 @@ ipv6nd_handledata(void *arg) return; } +#ifdef __sun + if_findifpfromcmsg(ctx, &msg, &hoplimit); +#else ifp = if_findifpfromcmsg(ctx, &msg, &hoplimit); if (ifp == NULL) { logerr(__func__); return; } +#endif /* Don't do anything if the user hasn't configured it. */ if (ifp->active != IF_ACTIVE_USER || @@ -1725,11 +1801,6 @@ ipv6nd_startrs1(void *arg) struct rs_state *state; loginfox("%s: soliciting an IPv6 router", ifp->name); - if (ipv6nd_open(ifp->ctx) == -1) { - logerr(__func__); - return; - } - state = RS_STATE(ifp); if (state == NULL) { ifp->if_data[IF_DATA_IPV6ND] = calloc(1, sizeof(*state)); @@ -1738,8 +1809,21 @@ ipv6nd_startrs1(void *arg) logerr(__func__); return; } + state->nd_fd = -1; } +#ifdef __sun + if (ipv6nd_open(ifp) == -1) { + logerr(__func__); + return; + } +#else + if (ipv6nd_open(ifp->ctx) == -1) { + logerr(__func__); + return; + } +#endif + /* Always make a new probe as the underlying hardware * address could have changed. */ ipv6nd_makersprobe(ifp); diff --git a/src/ipv6nd.h b/src/ipv6nd.h index 07f2d02e..7b959814 100644 --- a/src/ipv6nd.h +++ b/src/ipv6nd.h @@ -61,6 +61,9 @@ struct rs_state { size_t rslen; int rsprobes; uint32_t retrans; +#ifdef __sun + int nd_fd; +#endif }; #define RS_STATE(a) ((struct rs_state *)(ifp)->if_data[IF_DATA_IPV6ND])