diff options
| author | Roy Marples <roy@marples.name> | 2014-02-12 00:39:46 +0000 |
|---|---|---|
| committer | Roy Marples <roy@marples.name> | 2014-02-12 00:39:46 +0000 |
| commit | 4eb7b4896f7b4a74da17b1a0acc9119072866c3e (patch) | |
| tree | 1b756fb2ec7afb302fdf7edeaa946dabd13fd929 /ipv6nd.c | |
| parent | 06e4195f573dd03e9791ffecff64d54641f59c01 (diff) | |
| download | dhcpcd-4eb7b4896f7b4a74da17b1a0acc9119072866c3e.tar.xz | |
Move all global variables into contexts, with a small exception for
signal handling.
This allows dhcpcd to work better in a threaded environment such as rtems.
Diffstat (limited to 'ipv6nd.c')
| -rw-r--r-- | ipv6nd.c | 417 |
1 files changed, 188 insertions, 229 deletions
@@ -45,6 +45,14 @@ #include <syslog.h> #include <unistd.h> +/* Currently, no known kernel allows us to send from the unspecified address + * which is required for DAD to work. This isn't that much of a problem as + * the kernel will do DAD for us correctly, however we don't know the exact + * randomness the kernel applies to the timeouts. So we just follow the same + * logic and have a little faith. + * This define is purely for completeness */ +// #define IPV6_SEND_DAD + #define ELOOP_QUEUE 2 #include "common.h" #include "dhcpcd.h" @@ -124,32 +132,6 @@ struct nd_opt_dnssl { /* DNSSL option RFC 6106 */ //#define DEBUG_NS // -/* Currently, no known kernel allows us to send from the unspecified address - * which is required for DAD to work. This isn't that much of a problem as - * the kernel will do DAD for us correctly, however we don't know the exact - * randomness the kernel applies to the timeouts. So we just follow the same - * logic and have a little faith. - * This define is purely for completeness */ -// #define IPV6_SEND_DAD - -static int sock = -1; -#ifdef IPV6_SEND_DAD -static int unspec_sock = -1; -#endif -static struct sockaddr_in6 allrouters, from; -static struct msghdr sndhdr; -static struct iovec sndiov[2]; -static unsigned char *sndbuf; -static struct msghdr rcvhdr; -static struct iovec rcviov[2]; -static unsigned char *rcvbuf; -static unsigned char ansbuf[1500]; -static char ntopbuf[INET6_ADDRSTRLEN]; -static const char *sfrom; -static struct icmp6_filter filt; - -struct rahead ipv6_routers = TAILQ_HEAD_INITIALIZER(ipv6_routers); - static void ipv6nd_handledata(void *arg); /* @@ -181,10 +163,11 @@ static void ipv6nd_handledata(void *arg); #endif static int -ipv6nd_open(void) +ipv6nd_open(struct dhcpcd_ctx *dctx) { + struct ipv6_ctx *ctx; int on; - int len; + struct icmp6_filter filt; #ifdef IPV6_SEND_DAD union { struct sockaddr sa; @@ -192,125 +175,75 @@ ipv6nd_open(void) } su; #endif - sock = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, + ctx = dctx->ipv6; + if (ctx->nd_fd != -1) + goto unspec; + ctx->nd_fd = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_ICMPV6); - if (sock == -1) + if (ctx->nd_fd == -1) return -1; - memset(&allrouters, 0, sizeof(allrouters)); - allrouters.sin6_family = AF_INET6; -#ifdef SIN6_LEN - allrouters.sin6_len = sizeof(allrouters); -#endif - if (inet_pton(AF_INET6, ALLROUTERS, &allrouters.sin6_addr.s6_addr) != 1) - goto eexit; on = 1; - if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, - &on, sizeof(on)) == -1) + if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, + &on, sizeof(on)) == -1) goto eexit; on = 1; - if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, - &on, sizeof(on)) == -1) + if (setsockopt(ctx->nd_fd, 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(sock, IPPROTO_ICMPV6, ICMP6_FILTER, - &filt, sizeof(filt)) == -1) - goto eexit; - - len = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)); - sndbuf = calloc(1, len); - if (sndbuf == NULL) - goto eexit; - sndhdr.msg_namelen = sizeof(struct sockaddr_in6); - sndhdr.msg_iov = sndiov; - sndhdr.msg_iovlen = 1; - sndhdr.msg_control = sndbuf; - sndhdr.msg_controllen = len; - rcvbuf = calloc(1, len); - if (rcvbuf == NULL) + if (setsockopt(ctx->nd_fd, IPPROTO_ICMPV6, ICMP6_FILTER, + &filt, sizeof(filt)) == -1) goto eexit; - rcvhdr.msg_name = &from; - rcvhdr.msg_namelen = sizeof(from); - rcvhdr.msg_iov = rcviov; - rcvhdr.msg_iovlen = 1; - rcvhdr.msg_control = rcvbuf; - rcvhdr.msg_controllen = len; - rcviov[0].iov_base = ansbuf; - rcviov[0].iov_len = sizeof(ansbuf); - return sock; -eexit: - close(sock); - sock = -1; - free(sndbuf); - sndbuf = NULL; - free(rcvbuf); - rcvbuf = NULL; - return -1; -} + eloop_event_add(dctx->eloop, ctx->nd_fd, ipv6nd_handledata, dctx); -static int -ipv6nd_naopen(void) -{ - static int naopen = 0; - struct icmp6_filter unspec_filt; +unspec: #ifdef IPV6_SEND_DAD - union { - struct sockaddr sa; - struct sockaddr_in6 sin; - } su; -#endif - - if (naopen) - return sock; + if (ctx->unspec_fd != -1) + return ctx->nd_fd; - ICMP6_FILTER_SETBLOCKALL(&unspec_filt); + ICMP6_FILTER_SETBLOCKALL(&filt); -#ifdef IPV6_SEND_DAD /* We send DAD requests from the unspecified address. */ - unspec_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); - if (unspec_sock == -1) - return -1; - if (setsockopt(unspec_sock, IPPROTO_ICMPV6, ICMP6_FILTER, - &unspec_filt, sizeof(unspec_filt)) == -1) + ctx->unspec_fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + if (ctx->unspec_fd == -1) + goto eexit; + if (setsockopt(ctx->unspec_fd, IPPROTO_ICMPV6, ICMP6_FILTER, + &filt, sizeof(filt)) == -1) goto eexit; memset(&su, 0, sizeof(su)); su.sin.sin6_family = AF_INET6; #ifdef SIN6_LEN su.sin.sin6_len = sizeof(su.sin); #endif - if (bind(unspec_sock, &su.sa, sizeof(su.sin)) == -1) + if (bind(ctx->unspec_fd, &su.sa, sizeof(su.sin)) == -1) goto eexit; #endif - if (sock == -1) { - if (ipv6nd_open() == -1) - goto eexit; - eloop_event_add(sock, ipv6nd_handledata, NULL); - } - - ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filt); - if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, - &filt, sizeof(filt)) == -1) - goto eexit; - #ifdef LISTEN_DAD syslog(LOG_WARNING, "kernel does not report DAD results to userland"); syslog(LOG_WARNING, "warning listening to duplicated addresses on the wire"); #endif - naopen = sock; - return sock; + return ctx->nd_fd; eexit: - syslog(LOG_ERR, "%s: %m", __func__); + if (ctx->nd_fd != -1) { + close(ctx->nd_fd); + eloop_event_delete(dctx->eloop, ctx->nd_fd); + ctx->nd_fd = -1; + } #ifdef IPV6_SEND_DAD - close(unspec_sock); - unspec_sock = -1; + if (ctx->unpsec_fd != -1) { + close(ctx->unspec_fd); + ctx->unspec_fd = -1; + } #endif return -1; } @@ -344,6 +277,7 @@ static void ipv6nd_sendrsprobe(void *arg) { struct interface *ifp = arg; + struct ipv6_ctx *ctx; struct rs_state *state; struct sockaddr_in6 dst; struct cmsghdr *cm; @@ -358,16 +292,25 @@ ipv6nd_sendrsprobe(void *arg) return; } - dst = allrouters; + memset(&dst, 0, sizeof(dst)); + dst.sin6_family = AF_INET6; +#ifdef SIN6_LEN + dst.sin6_len = sizeof(dst); +#endif dst.sin6_scope_id = ifp->index; + if (inet_pton(AF_INET6, ALLROUTERS, &dst.sin6_addr.s6_addr) != 1) { + syslog(LOG_ERR, "%s: %m", __func__); + return; + } state = RS_STATE(ifp); - sndhdr.msg_name = (caddr_t)&dst; - sndhdr.msg_iov[0].iov_base = state->rs; - sndhdr.msg_iov[0].iov_len = state->rslen; + ctx = ifp->ctx->ipv6; + ctx->sndhdr.msg_name = (caddr_t)&dst; + ctx->sndhdr.msg_iov[0].iov_base = state->rs; + ctx->sndhdr.msg_iov[0].iov_len = state->rslen; /* Set the outbound interface */ - cm = CMSG_FIRSTHDR(&sndhdr); + cm = CMSG_FIRSTHDR(&ctx->sndhdr); cm->cmsg_level = IPPROTO_IPV6; cm->cmsg_type = IPV6_PKTINFO; cm->cmsg_len = CMSG_LEN(sizeof(pi)); @@ -376,14 +319,14 @@ ipv6nd_sendrsprobe(void *arg) memcpy(CMSG_DATA(cm), &pi, sizeof(pi)); /* Hop limit */ - cm = CMSG_NXTHDR(&sndhdr, cm); + cm = CMSG_NXTHDR(&ctx->sndhdr, cm); cm->cmsg_level = IPPROTO_IPV6; cm->cmsg_type = IPV6_HOPLIMIT; cm->cmsg_len = CMSG_LEN(sizeof(hoplimit)); memcpy(CMSG_DATA(cm), &hoplimit, sizeof(hoplimit)); syslog(LOG_DEBUG, "%s: sending Router Solicitation", ifp->name); - if (sendmsg(sock, &sndhdr, 0) == -1) { + if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1) { syslog(LOG_ERR, "%s: %s: sendmsg: %m", ifp->name, __func__); ipv6nd_drop(ifp); ifp->options->options &= ~(DHCPCD_IPV6 | DHCPCD_IPV6RS); @@ -391,8 +334,8 @@ ipv6nd_sendrsprobe(void *arg) } if (state->rsprobes++ < MAX_RTR_SOLICITATIONS) - eloop_timeout_add_sec(RTR_SOLICITATION_INTERVAL, - ipv6nd_sendrsprobe, ifp); + eloop_timeout_add_sec(ifp->ctx->eloop, + RTR_SOLICITATION_INTERVAL, ipv6nd_sendrsprobe, ifp); else syslog(LOG_WARNING, "%s: no IPv6 Routers available", ifp->name); } @@ -410,12 +353,12 @@ ipv6nd_free_opts(struct ra *rap) } int -ipv6nd_addrexists(const struct ipv6_addr *addr) +ipv6nd_addrexists(struct dhcpcd_ctx *ctx, const struct ipv6_addr *addr) { struct ra *rap; struct ipv6_addr *ap; - TAILQ_FOREACH(rap, &ipv6_routers, next) { + TAILQ_FOREACH(rap, ctx->ipv6->ra_routers, next) { TAILQ_FOREACH(ap, &rap->addrs, next) { if (addr == NULL) { if ((ap->flags & @@ -432,10 +375,10 @@ ipv6nd_addrexists(const struct ipv6_addr *addr) void ipv6nd_freedrop_ra(struct ra *rap, int drop) { - eloop_timeout_delete(NULL, rap->iface); - eloop_timeout_delete(NULL, rap); + eloop_timeout_delete(rap->iface->ctx->eloop, NULL, rap->iface); + eloop_timeout_delete(rap->iface->ctx->eloop, NULL, rap); if (!drop) - TAILQ_REMOVE(&ipv6_routers, rap, next); + TAILQ_REMOVE(rap->iface->ctx->ipv6->ra_routers, rap, next); ipv6_freedrop_addrs(&rap->addrs, drop, NULL); ipv6nd_free_opts(rap); free(rap->data); @@ -448,6 +391,7 @@ ipv6nd_free(struct interface *ifp) { struct rs_state *state; struct ra *rap, *ran; + struct dhcpcd_ctx *ctx; ssize_t n; state = RS_STATE(ifp); @@ -458,7 +402,7 @@ ipv6nd_free(struct interface *ifp) free(state); ifp->if_data[IF_DATA_IPV6ND] = NULL; n = 0; - TAILQ_FOREACH_SAFE(rap, &ipv6_routers, next, ran) { + TAILQ_FOREACH_SAFE(rap, ifp->ctx->ipv6->ra_routers, next, ran) { if (rap->iface == ifp) { ipv6nd_free_ra(rap); n++; @@ -467,20 +411,17 @@ ipv6nd_free(struct interface *ifp) /* If we don't have any more IPv6 enabled interfaces, * close the global socket and release resources */ - TAILQ_FOREACH(ifp, ifaces, next) { + ctx = ifp->ctx; + TAILQ_FOREACH(ifp, ctx->ifaces, next) { if (RS_STATE(ifp)) break; } if (ifp == NULL) { - if (sock != -1) { - close(sock); - eloop_event_delete(sock); - sock = -1; + if (ctx->ipv6->nd_fd != -1) { + close(ctx->ipv6->nd_fd); + eloop_event_delete(ctx->eloop, ctx->ipv6->nd_fd); + ctx->ipv6->nd_fd = -1; } - free(sndbuf); - free(rcvbuf); - sndbuf = NULL; - rcvbuf = NULL; } return n; @@ -506,11 +447,11 @@ rtpref(struct ra *rap) } static void -add_router(struct ra *router) +add_router(struct ipv6_ctx *ctx, struct ra *router) { struct ra *rap; - TAILQ_FOREACH(rap, &ipv6_routers, next) { + TAILQ_FOREACH(rap, ctx->ra_routers, next) { if (router->iface->metric < rap->iface->metric || (router->iface->metric == rap->iface->metric && rtpref(router) > rtpref(rap))) @@ -519,7 +460,7 @@ add_router(struct ra *router) return; } } - TAILQ_INSERT_TAIL(&ipv6_routers, router, next); + TAILQ_INSERT_TAIL(ctx->ra_routers, router, next); } static int @@ -565,7 +506,7 @@ ipv6nd_scriptrun(struct ra *rap) script_runreason(rap->iface, "ROUTERADVERT"); if (hasdns) - hasdns = daemonise(); + hasdns = daemonise(rap->iface->ctx); #if 0 else if (options & DHCPCD_DAEMONISE && !(options & DHCPCD_DAEMONISED) && new_data) @@ -601,7 +542,7 @@ ipv6nd_dadcallback(void *arg) if (!wascompleted) { ifp = ap->iface; - TAILQ_FOREACH(rap, &ipv6_routers, next) { + TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) { if (rap->iface != ifp) continue; wascompleted = 1; @@ -629,7 +570,8 @@ ipv6nd_dadcallback(void *arg) } static void -ipv6nd_handlera(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len) +ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp, + struct icmp6_hdr *icp, ssize_t len) { ssize_t l, m, n, olen; struct nd_router_advert *nd_ra; @@ -651,25 +593,26 @@ ipv6nd_handlera(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len) uint8_t new_rap, new_data; if ((size_t)len < sizeof(struct nd_router_advert)) { - syslog(LOG_ERR, "IPv6 RA packet too short from %s", sfrom); + syslog(LOG_ERR, "IPv6 RA packet too short from %s", ctx->sfrom); return; } - if (!IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) { - syslog(LOG_ERR, "RA from non local address %s", sfrom); + if (!IN6_IS_ADDR_LINKLOCAL(&ctx->from.sin6_addr)) { + syslog(LOG_ERR, "RA from non local address %s", ctx->sfrom); return; } if (ifp == NULL) { #ifdef DEBUG_RS - syslog(LOG_DEBUG, "RA for unexpected interface from %s", sfrom); + syslog(LOG_DEBUG, "RA for unexpected interface from %s", + ctx->sfrom); #endif return; } if (!(ifp->options->options & DHCPCD_IPV6RS)) { #ifdef DEBUG_RS syslog(LOG_DEBUG, "%s: unexpected RA from %s", - ifp->name, sfrom); + ifp->name, ctx->sfrom); #endif return; } @@ -678,14 +621,14 @@ ipv6nd_handlera(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len) if (ipv6_linklocal(ifp) == NULL) { #ifdef DEBUG_RS syslog(LOG_DEBUG, "%s: received RA from %s (no link-local)", - ifp->name, sfrom); + ifp->name, ctx->sfrom); #endif return; } - TAILQ_FOREACH(rap, &ipv6_routers, next) { + TAILQ_FOREACH(rap, ctx->ra_routers, next) { if (ifp == rap->iface && - memcmp(rap->from.s6_addr, from.sin6_addr.s6_addr, + memcmp(rap->from.s6_addr, ctx->from.sin6_addr.s6_addr, sizeof(rap->from.s6_addr)) == 0) break; } @@ -714,7 +657,7 @@ ipv6nd_handlera(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len) new_data = 0; if (new_data || ifp->options->options & DHCPCD_DEBUG) syslog(LOG_INFO, "%s: Router Advertisement from %s", - ifp->name, sfrom); + ifp->name, ctx->sfrom); if (rap == NULL) { rap = calloc(1, sizeof(*rap)); @@ -723,9 +666,9 @@ ipv6nd_handlera(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len) return; } rap->iface = ifp; - memcpy(rap->from.s6_addr, from.sin6_addr.s6_addr, + memcpy(rap->from.s6_addr, ctx->from.sin6_addr.s6_addr, sizeof(rap->from.s6_addr)); - strlcpy(rap->sfrom, sfrom, sizeof(rap->sfrom)); + strlcpy(rap->sfrom, ctx->sfrom, sizeof(rap->sfrom)); TAILQ_INIT(&rap->addrs); TAILQ_INIT(&rap->options); new_rap = 1; @@ -765,7 +708,7 @@ ipv6nd_handlera(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len) lifetime = ~0U; for (olen = 0; len > 0; p += olen, len -= olen) { if ((size_t)len < sizeof(struct nd_opt_hdr)) { - syslog(LOG_ERR, "%s: Short option", ifp->name); + syslog(LOG_ERR, "%s: short option", ifp->name); break; } ndo = (struct nd_opt_hdr *)p; @@ -841,7 +784,7 @@ ipv6nd_handlera(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len) pi->nd_opt_pi_prefix_len); cbp = inet_ntop(AF_INET6, ap->addr.s6_addr, - ntopbuf, INET6_ADDRSTRLEN); + buf, sizeof(buf)); if (cbp) snprintf(ap->saddr, sizeof(ap->saddr), @@ -1001,13 +944,13 @@ ipv6nd_handlera(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len) } if (new_rap) - add_router(rap); - if (options & DHCPCD_TEST) { + add_router(ifp->ctx->ipv6, rap); + if (ifp->ctx->options & DHCPCD_TEST) { script_runreason(ifp, "TEST"); goto handle_flag; } ipv6nd_probeaddrs(&rap->addrs); - ipv6_buildroutes(); + ipv6_buildroutes(ifp->ctx); /* We will get run by the expire function */ if (rap->lifetime) { @@ -1015,8 +958,8 @@ ipv6nd_handlera(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len) return; } - eloop_timeout_delete(NULL, ifp); - eloop_timeout_delete(NULL, rap); /* reachable timer */ + eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); + eloop_timeout_delete(ifp->ctx->eloop, NULL, rap); /* reachable timer */ /* If we're owning the RA then we need to try and ensure the * router is actually reachable */ @@ -1041,8 +984,8 @@ handle_flag: if (rap->lifetime && new_data) syslog(LOG_DEBUG, "%s: No DHCPv6 instruction in RA", ifp->name); - if (options & DHCPCD_TEST) { - eloop_exit(EXIT_SUCCESS); + if (ifp->ctx->options & DHCPCD_TEST) { + eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS); return; } } @@ -1056,7 +999,7 @@ ipv6nd_has_ra(const struct interface *ifp) { const struct ra *rap; - TAILQ_FOREACH(rap, &ipv6_routers, next) + TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) if (rap->iface == ifp) return 1; return 0; @@ -1076,7 +1019,7 @@ ipv6nd_env(char **env, const char *prefix, const struct interface *ifp) i = 0; l = 0; - TAILQ_FOREACH(rap, &ipv6_routers, next) { + TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) { i++; if (rap->iface != ifp) continue; @@ -1174,12 +1117,14 @@ ipv6nd_env(char **env, const char *prefix, const struct interface *ifp) } void -ipv6nd_handleifa(int cmd, const char *ifname, +ipv6nd_handleifa(struct dhcpcd_ctx *ctx, int cmd, const char *ifname, const struct in6_addr *addr, int flags) { struct ra *rap; - TAILQ_FOREACH(rap, &ipv6_routers, next) { + if (ctx->ipv6 == NULL) + return; + TAILQ_FOREACH(rap, ctx->ipv6->ra_routers, next) { if (strcmp(rap->iface->name, ifname)) continue; ipv6_handleifa_addrs(cmd, &rap->addrs, addr, flags); @@ -1200,7 +1145,7 @@ ipv6nd_expirera(void *arg) expired = 0; timerclear(&next); - TAILQ_FOREACH_SAFE(rap, &ipv6_routers, next, ran) { + TAILQ_FOREACH_SAFE(rap, ifp->ctx->ipv6->ra_routers, next, ran) { if (rap->iface != ifp) continue; lt.tv_sec = rap->lifetime; @@ -1267,9 +1212,10 @@ ipv6nd_expirera(void *arg) } if (timerisset(&next)) - eloop_timeout_add_tv(&next, ipv6nd_expirera, ifp); + eloop_timeout_add_tv(ifp->ctx->eloop, + &next, ipv6nd_expirera, ifp); if (expired) { - ipv6_buildroutes(); + ipv6_buildroutes(ifp->ctx); script_runreason(ifp, "ROUTERADVERT"); } } @@ -1281,12 +1227,12 @@ ipv6nd_drop(struct interface *ifp) int expired = 0; TAILQ_HEAD(rahead, ra) rtrs; - eloop_timeout_delete(NULL, ifp); + eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); TAILQ_INIT(&rtrs); - TAILQ_FOREACH(rap, &ipv6_routers, next) { + TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) { if (rap->iface == ifp) { rap->expired = expired = 1; - TAILQ_REMOVE(&ipv6_routers, rap, next); + TAILQ_REMOVE(ifp->ctx->ipv6->ra_routers, rap, next); TAILQ_INSERT_TAIL(&rtrs, rap, next); } } @@ -1295,7 +1241,7 @@ ipv6nd_drop(struct interface *ifp) TAILQ_REMOVE(&rtrs, rap, next); ipv6nd_drop_ra(rap); } - ipv6_buildroutes(); + ipv6_buildroutes(ifp->ctx); if ((ifp->options->options & (DHCPCD_EXITING | DHCPCD_PERSISTENT)) != (DHCPCD_EXITING | DHCPCD_PERSISTENT)) @@ -1314,7 +1260,7 @@ ipv6nd_unreachable(void *arg) syslog(LOG_WARNING, "%s: %s is unreachable, expiring it", rap->iface->name, rap->sfrom); rap->expired = 1; - ipv6_buildroutes(); + ipv6_buildroutes(rap->iface->ctx); script_runreason(rap->iface, "ROUTERADVERT"); /* XXX not RA */ /* We should still test if it's reachable or not so @@ -1325,7 +1271,8 @@ ipv6nd_unreachable(void *arg) tv.tv_sec = REACHABLE_TIME; tv.tv_usec = 0; } - eloop_timeout_add_tv(&tv, ipv6nd_proberouter, rap); + eloop_timeout_add_tv(rap->iface->ctx->eloop, + &tv, ipv6nd_proberouter, rap); } #ifdef LISTEN_DAD @@ -1333,9 +1280,9 @@ void ipv6nd_cancelprobeaddr(struct ipv6_addr *ap) { - eloop_timeout_delete(ipv6nd_probeaddr, ap); + eloop_timeout_delete(ap->iface->ctx->eloop, ipv6nd_probeaddr, ap); if (ap->dadcallback) - eloop_timeout_delete(ap->dadcallback, ap); + eloop_timeout_delete(ap->iface->ctx->eloop, ap->dadcallback,ap); } #endif @@ -1372,8 +1319,10 @@ ipv6nd_probeaddr(void *arg) return; } - if (ipv6nd_naopen() == -1) + if (ipv6nd_open(ap->iface->ctx) == -1) { + syslog(LOG_ERR, "%s: ipv6nd_open: %m", __func__); return; + } ap->flags &= ~IPV6_AF_DADCOMPLETED; @@ -1453,7 +1402,7 @@ ipv6nd_probeaddr(void *arg) (MAX_RANDOM_FACTOR_U - MIN_RANDOM_FACTOR_U); timeradd(&tv, &rtv, &tv); - eloop_timeout_add_tv(&tv, + eloop_timeout_add_tv(ap->iface->ctx->eloop, &tv, ++(ap->nsprobes) < ap->iface->options->dadtransmits ? ipv6nd_probeaddr : ap->dadcallback, ap); @@ -1476,7 +1425,8 @@ ipv6nd_probeaddr(void *arg) timeradd(&tv, &rtv, &tv); timeradd(&mtv, &tv, &mtv); } - eloop_timeout_add_tv(&mtv, ap->dadcallback, ap); + eloop_timeout_add_tv(ap->iface->ctx->eloop, + &mtv, ap->dadcallback, ap); } #endif #endif /* IPV6_SEND_DAD */ @@ -1502,8 +1452,8 @@ ipv6nd_probeaddrs(struct ipv6_addrhead *addrs) syslog(LOG_ERR, "del_address6 %m"); } if (ap->dadcallback) - eloop_q_timeout_delete(0, NULL, - ap->dadcallback); + eloop_q_timeout_delete(ap->iface->ctx->eloop, + 0, NULL, ap->dadcallback); free(ap); } else if (!IN6_IS_ADDR_UNSPECIFIED(&ap->addr)) { ipv6nd_probeaddr(ap); @@ -1526,9 +1476,12 @@ ipv6nd_proberouter(void *arg) struct in6_pktinfo pi; int hoplimit = HOPLIMIT; struct timeval tv, rtv; + struct ipv6_ctx *ctx; - if (ipv6nd_naopen() == -1) + if (ipv6nd_open(rap->iface->ctx) == -1) { + syslog(LOG_ERR, "%s: ipv6nd_open: %m", __func__); return; + } if (!rap->ns) { rap->nslen = sizeof(*ns) + ROUNDUP8(rap->iface->hwlen + 2); @@ -1557,12 +1510,13 @@ ipv6nd_proberouter(void *arg) memcpy(&dst.sin6_addr, &rap->from, sizeof(dst.sin6_addr)); dst.sin6_scope_id = rap->iface->index; - sndhdr.msg_name = (caddr_t)&dst; - sndhdr.msg_iov[0].iov_base = rap->ns; - sndhdr.msg_iov[0].iov_len = rap->nslen; + ctx = rap->iface->ctx->ipv6; + ctx->sndhdr.msg_name = (caddr_t)&dst; + ctx->sndhdr.msg_iov[0].iov_base = rap->ns; + ctx->sndhdr.msg_iov[0].iov_len = rap->nslen; /* Set the outbound interface */ - cm = CMSG_FIRSTHDR(&sndhdr); + cm = CMSG_FIRSTHDR(&ctx->sndhdr); cm->cmsg_level = IPPROTO_IPV6; cm->cmsg_type = IPV6_PKTINFO; cm->cmsg_len = CMSG_LEN(sizeof(pi)); @@ -1571,7 +1525,7 @@ ipv6nd_proberouter(void *arg) memcpy(CMSG_DATA(cm), &pi, sizeof(pi)); /* Hop limit */ - cm = CMSG_NXTHDR(&sndhdr, cm); + cm = CMSG_NXTHDR(&ctx->sndhdr, cm); cm->cmsg_level = IPPROTO_IPV6; cm->cmsg_type = IPV6_HOPLIMIT; cm->cmsg_len = CMSG_LEN(sizeof(hoplimit)); @@ -1581,7 +1535,7 @@ ipv6nd_proberouter(void *arg) syslog(LOG_INFO, "%s: sending IPv6 NS for %s", rap->iface->name, rap->sfrom); #endif - if (sendmsg(sock, &sndhdr, 0) == -1) { + if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1) { syslog(LOG_ERR, "%s: %s: sendmsg: %m", rap->iface->name, __func__); return; @@ -1593,24 +1547,25 @@ ipv6nd_proberouter(void *arg) rtv.tv_sec = 0; rtv.tv_usec = arc4random() % (MAX_RANDOM_FACTOR_U -MIN_RANDOM_FACTOR_U); timeradd(&tv, &rtv, &tv); - eloop_timeout_add_tv(&tv, ipv6nd_proberouter, rap); + eloop_timeout_add_tv(rap->iface->ctx->eloop, + &tv, ipv6nd_proberouter, rap); if (rap->nsprobes++ == 0) - eloop_timeout_add_sec(DELAY_FIRST_PROBE_TIME, - ipv6nd_unreachable, rap); + eloop_timeout_add_sec(rap->iface->ctx->eloop, + DELAY_FIRST_PROBE_TIME, ipv6nd_unreachable, rap); } void ipv6nd_cancelproberouter(struct ra *rap) { - eloop_timeout_delete(ipv6nd_proberouter, rap); - eloop_timeout_delete(ipv6nd_unreachable, rap); + eloop_timeout_delete(rap->iface->ctx->eloop, ipv6nd_proberouter, rap); + eloop_timeout_delete(rap->iface->ctx->eloop, ipv6nd_unreachable, rap); } -/* ARGSUSED */ static void -ipv6nd_handlena(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len) +ipv6nd_handlena(struct ipv6_ctx *ctx, struct interface *ifp, + struct icmp6_hdr *icp, ssize_t len) { struct nd_neighbor_advert *nd_na; struct ra *rap; @@ -1626,13 +1581,14 @@ ipv6nd_handlena(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len) #endif if ((size_t)len < sizeof(struct nd_neighbor_advert)) { - syslog(LOG_ERR, "IPv6 NA packet too short from %s", sfrom); + syslog(LOG_ERR, "IPv6 NA packet too short from %s", ctx->sfrom); return; } if (ifp == NULL) { #ifdef DEBUG_NS - syslog(LOG_DEBUG, "NA for unexpected interface from %s", sfrom); + syslog(LOG_DEBUG, "NA for unexpected interface from %s", + ctx->sfrom); #endif return; } @@ -1643,14 +1599,14 @@ ipv6nd_handlena(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len) if (IN6_IS_ADDR_MULTICAST(&nd_na->nd_na_target)) { syslog(LOG_ERR, "%s: NA for multicast address from %s", - ifp->name, sfrom); + ifp->name, ctx->sfrom); return; } #ifdef DEBUG_NS found = 0; #endif - TAILQ_FOREACH(rap, &ipv6_routers, next) { + TAILQ_FOREACH(rap, ctx->ra_routers, next) { if (rap->iface != ifp) continue; if (memcmp(rap->from.s6_addr, nd_na->nd_na_target.s6_addr, @@ -1695,23 +1651,23 @@ ipv6nd_handlena(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len) #ifdef DEBUG_NS if (found == 0) syslog(LOG_DEBUG, "%s: unexpected NA from %s", - ifp->name, sfrom); + ifp->name, ctx->sfrom); #endif return; } #ifdef DEBUG_NS syslog(LOG_DEBUG, "%s: %sNA from %s", - ifp->name, is_solicited ? "solicited " : "", sfrom); + ifp->name, is_solicited ? "solicited " : "", ctx->sfrom); #endif /* Node is no longer a router, so remove it from consideration */ if (!is_router && !rap->expired) { syslog(LOG_INFO, "%s: %s is no longer a router", - ifp->name, sfrom); + ifp->name, ctx->sfrom); rap->expired = 1; ipv6nd_cancelproberouter(rap); - ipv6_buildroutes(); + ipv6_buildroutes(ifp->ctx); script_runreason(ifp, "ROUTERADVERT"); return; } @@ -1720,8 +1676,8 @@ ipv6nd_handlena(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len) if (rap->expired) { rap->expired = 0; syslog(LOG_INFO, "%s: %s is reachable again", - ifp->name, sfrom); - ipv6_buildroutes(); + ifp->name, ctx->sfrom); + ipv6_buildroutes(ifp->ctx); script_runreason(rap->iface, "ROUTERADVERT"); /* XXX */ } rap->nsprobes = 0; @@ -1731,15 +1687,18 @@ ipv6nd_handlena(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len) tv.tv_sec = REACHABLE_TIME; tv.tv_usec = 0; } - eloop_timeout_add_tv(&tv, ipv6nd_proberouter, rap); - eloop_timeout_delete(ipv6nd_unreachable, rap); + eloop_timeout_add_tv(rap->iface->ctx->eloop, + &tv, ipv6nd_proberouter, rap); + eloop_timeout_delete(rap->iface->ctx->eloop, + ipv6nd_unreachable, rap); } } -/* ARGSUSED */ static void -ipv6nd_handledata(__unused void *arg) +ipv6nd_handledata(void *arg) { + struct dhcpcd_ctx *dhcpcd_ctx; + struct ipv6_ctx *ctx; ssize_t len; struct cmsghdr *cm; int hoplimit; @@ -1747,22 +1706,25 @@ ipv6nd_handledata(__unused void *arg) struct icmp6_hdr *icp; struct interface *ifp; - len = recvmsg(sock, &rcvhdr, 0); + dhcpcd_ctx = arg; + ctx = dhcpcd_ctx->ipv6; + len = recvmsg(ctx->nd_fd, &ctx->rcvhdr, 0); if (len == -1) { syslog(LOG_ERR, "recvmsg: %m"); return; } - sfrom = inet_ntop(AF_INET6, &from.sin6_addr, - ntopbuf, INET6_ADDRSTRLEN); + ctx->sfrom = inet_ntop(AF_INET6, &ctx->from.sin6_addr, + ctx->ntopbuf, INET6_ADDRSTRLEN); if ((size_t)len < sizeof(struct icmp6_hdr)) { - syslog(LOG_ERR, "IPv6 ICMP packet too short from %s", sfrom); + syslog(LOG_ERR, "IPv6 ICMP packet too short from %s", + ctx->sfrom); return; } pkt.ipi6_ifindex = hoplimit = 0; - for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvhdr); + for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&ctx->rcvhdr); cm; - cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvhdr, cm)) + cm = (struct cmsghdr *)CMSG_NXTHDR(&ctx->rcvhdr, cm)) { if (cm->cmsg_level != IPPROTO_IPV6) continue; @@ -1780,30 +1742,30 @@ ipv6nd_handledata(__unused void *arg) if (pkt.ipi6_ifindex == 0 || hoplimit == 0) { syslog(LOG_ERR, - "IPv6 RA did not contain index or hop limit from %s", - sfrom); + "IPv6 RA/NA did not contain index or hop limit from %s", + ctx->sfrom); return; } - TAILQ_FOREACH(ifp, ifaces, next) { + TAILQ_FOREACH(ifp, dhcpcd_ctx->ifaces, next) { if (ifp->index == (unsigned int)pkt.ipi6_ifindex) break; } - icp = (struct icmp6_hdr *)rcvhdr.msg_iov[0].iov_base; + icp = (struct icmp6_hdr *)ctx->rcvhdr.msg_iov[0].iov_base; if (icp->icmp6_code == 0) { switch(icp->icmp6_type) { case ND_NEIGHBOR_ADVERT: - ipv6nd_handlena(ifp, icp, len); + ipv6nd_handlena(ctx, ifp, icp, len); return; case ND_ROUTER_ADVERT: - ipv6nd_handlera(ifp, icp, len); + ipv6nd_handlera(ctx, ifp, icp, len); return; } } syslog(LOG_ERR, "invalid IPv6 type %d or code %d from %s", - icp->icmp6_type, icp->icmp6_code, sfrom); + icp->icmp6_type, icp->icmp6_code, ctx->sfrom); } int @@ -1812,15 +1774,12 @@ ipv6nd_startrs(struct interface *ifp) struct rs_state *state; syslog(LOG_INFO, "%s: soliciting an IPv6 router", ifp->name); - if (sock == -1) { - if (ipv6nd_open() == -1) { - syslog(LOG_ERR, "%s: ipv6nd_open: %m", __func__); - return -1; - } - eloop_event_add(sock, ipv6nd_handledata, NULL); + if (ipv6nd_open(ifp->ctx) == -1) { + syslog(LOG_ERR, "%s: ipv6nd_open: %m", __func__); + return -1; } - eloop_timeout_delete(NULL, ifp); + eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); state = RS_STATE(ifp); if (state == NULL) { |
