Mercurial > hg > dhcpcd
changeset 2456:ef4a50a6763f draft
The unreachable timer should start AFTER the initial discovery packet is
sent, and that is first send after the retransmission timer has fired.
| author | Roy Marples <roy@marples.name> |
|---|---|
| date | Fri, 02 May 2014 10:16:00 +0000 |
| parents | b6e215ab7552 |
| children | 7cf4ee9e75b5 |
| files | ipv6nd.c ipv6nd.h |
| diffstat | 2 files changed, 128 insertions(+), 122 deletions(-) [+] |
line wrap: on
line diff
--- a/ipv6nd.c Fri May 02 06:40:21 2014 +0000 +++ b/ipv6nd.c Fri May 02 10:16:00 2014 +0000 @@ -121,6 +121,7 @@ // static void ipv6nd_handledata(void *arg); +static void ipv6nd_proberouter(void *arg); /* * Android ships buggy ICMP6 filter headers. @@ -1091,6 +1092,133 @@ } } +static void +ipv6nd_unreachable(void *arg) +{ + struct ra *rap = arg; + struct timeval tv; + + /* We could add an unreachable flag and persist the information, + * but that is more effort than it's probably worth. */ + syslog(LOG_WARNING, "%s: %s is unreachable, expiring it", + rap->iface->name, rap->sfrom); + rap->expired = 1; + ipv6_buildroutes(rap->iface->ctx); + script_runreason(rap->iface, "ROUTERADVERT"); /* XXX not RA */ + + /* We should still test if it's reachable or not so + * incase it comes back to life and it's preferable. */ + if (rap->reachable) { + ms_to_tv(&tv, rap->reachable); + } else { + tv.tv_sec = REACHABLE_TIME; + tv.tv_usec = 0; + } + eloop_timeout_add_tv(rap->iface->ctx->eloop, + &tv, ipv6nd_proberouter, rap); +} + +static void +ipv6nd_proberouter1(struct ra *rap) +{ + struct nd_neighbor_solicit *ns; + struct nd_opt_hdr *nd; + struct sockaddr_in6 dst; + struct cmsghdr *cm; + struct in6_pktinfo pi; + struct ipv6_ctx *ctx; + + 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); + rap->ns = calloc(1, rap->nslen); + if (rap->ns == NULL) { + syslog(LOG_ERR, "%s: %m", __func__); + return; + } + ns = (struct nd_neighbor_solicit *)(void *)rap->ns; + ns->nd_ns_type = ND_NEIGHBOR_SOLICIT; + //ns->nd_ns_cksum = 0; + //ns->nd_ns_code = 0; + //ns->nd_ns_reserved = 0; + ns->nd_ns_target = rap->from; + nd = (struct nd_opt_hdr *)(rap->ns + sizeof(*ns)); + nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR; + nd->nd_opt_len = (ROUNDUP8(rap->iface->hwlen + 2)) >> 3; + memcpy(nd + 1, rap->iface->hwaddr, rap->iface->hwlen); + } + + memset(&dst, 0, sizeof(dst)); + dst.sin6_family = AF_INET6; +#ifdef SIN6_LEN + dst.sin6_len = sizeof(dst); +#endif + memcpy(&dst.sin6_addr, &rap->from, sizeof(dst.sin6_addr)); + dst.sin6_scope_id = rap->iface->index; + + 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(&ctx->sndhdr); + if (cm == NULL) /* unlikely */ + return; + cm->cmsg_level = IPPROTO_IPV6; + cm->cmsg_type = IPV6_PKTINFO; + cm->cmsg_len = CMSG_LEN(sizeof(pi)); + memset(&pi, 0, sizeof(pi)); + pi.ipi6_ifindex = rap->iface->index; + memcpy(CMSG_DATA(cm), &pi, sizeof(pi)); + +#ifdef DEBUG_NS + syslog(LOG_INFO, "%s: sending IPv6 NS for %s", + rap->iface->name, rap->sfrom); +#endif + if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1) { + syslog(LOG_ERR, "%s: %s: sendmsg: %m", + rap->iface->name, __func__); + return; + } + + ipv6nd_proberouter(rap); + + if (rap->nsprobes++ == 0) + eloop_timeout_add_sec(rap->iface->ctx->eloop, + DELAY_FIRST_PROBE_TIME, ipv6nd_unreachable, rap); +} + +static void +ipv6nd_proberouter(void *arg) +{ + struct ra *rap = arg; + struct timeval tv, rtv; + + ms_to_tv(&tv, rap->retrans == 0 ? RETRANS_TIMER : rap->retrans); + ms_to_tv(&rtv, MIN_RANDOM_FACTOR); + timeradd(&tv, &rtv, &tv); + rtv.tv_sec = 0; + rtv.tv_usec = arc4random() % (MAX_RANDOM_FACTOR_U -MIN_RANDOM_FACTOR_U); + timeradd(&tv, &rtv, &tv); + eloop_timeout_add_tv(rap->iface->ctx->eloop, + &tv, ipv6nd_proberouter1, rap); + + /* The unreachable timer starts AFTER first probe is actually send */ +} + +static void +ipv6nd_cancelproberouter(struct ra *rap) +{ + + eloop_timeout_delete(rap->iface->ctx->eloop, ipv6nd_proberouter, rap); + eloop_timeout_delete(rap->iface->ctx->eloop, ipv6nd_unreachable, rap); +} + void ipv6nd_expirera(void *arg) { @@ -1216,124 +1344,6 @@ } static void -ipv6nd_unreachable(void *arg) -{ - struct ra *rap = arg; - struct timeval tv; - - /* We could add an unreachable flag and persist the information, - * but that is more effort than it's probably worth. */ - syslog(LOG_WARNING, "%s: %s is unreachable, expiring it", - rap->iface->name, rap->sfrom); - rap->expired = 1; - ipv6_buildroutes(rap->iface->ctx); - script_runreason(rap->iface, "ROUTERADVERT"); /* XXX not RA */ - - /* We should still test if it's reachable or not so - * incase it comes back to life and it's preferable. */ - if (rap->reachable) { - ms_to_tv(&tv, rap->reachable); - } else { - tv.tv_sec = REACHABLE_TIME; - tv.tv_usec = 0; - } - eloop_timeout_add_tv(rap->iface->ctx->eloop, - &tv, ipv6nd_proberouter, rap); -} - -void -ipv6nd_proberouter(void *arg) -{ - struct ra *rap = arg; - struct nd_neighbor_solicit *ns; - struct nd_opt_hdr *nd; - struct sockaddr_in6 dst; - struct cmsghdr *cm; - struct in6_pktinfo pi; - struct timeval tv, rtv; - struct ipv6_ctx *ctx; - - 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); - rap->ns = calloc(1, rap->nslen); - if (rap->ns == NULL) { - syslog(LOG_ERR, "%s: %m", __func__); - return; - } - ns = (struct nd_neighbor_solicit *)(void *)rap->ns; - ns->nd_ns_type = ND_NEIGHBOR_SOLICIT; - //ns->nd_ns_cksum = 0; - //ns->nd_ns_code = 0; - //ns->nd_ns_reserved = 0; - ns->nd_ns_target = rap->from; - nd = (struct nd_opt_hdr *)(rap->ns + sizeof(*ns)); - nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR; - nd->nd_opt_len = (ROUNDUP8(rap->iface->hwlen + 2)) >> 3; - memcpy(nd + 1, rap->iface->hwaddr, rap->iface->hwlen); - } - - memset(&dst, 0, sizeof(dst)); - dst.sin6_family = AF_INET6; -#ifdef SIN6_LEN - dst.sin6_len = sizeof(dst); -#endif - memcpy(&dst.sin6_addr, &rap->from, sizeof(dst.sin6_addr)); - dst.sin6_scope_id = rap->iface->index; - - 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(&ctx->sndhdr); - if (cm == NULL) /* unlikely */ - return; - cm->cmsg_level = IPPROTO_IPV6; - cm->cmsg_type = IPV6_PKTINFO; - cm->cmsg_len = CMSG_LEN(sizeof(pi)); - memset(&pi, 0, sizeof(pi)); - pi.ipi6_ifindex = rap->iface->index; - memcpy(CMSG_DATA(cm), &pi, sizeof(pi)); - -#ifdef DEBUG_NS - syslog(LOG_INFO, "%s: sending IPv6 NS for %s", - rap->iface->name, rap->sfrom); -#endif - if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1) { - syslog(LOG_ERR, "%s: %s: sendmsg: %m", - rap->iface->name, __func__); - return; - } - - ms_to_tv(&tv, rap->retrans == 0 ? RETRANS_TIMER : rap->retrans); - ms_to_tv(&rtv, MIN_RANDOM_FACTOR); - timeradd(&tv, &rtv, &tv); - rtv.tv_sec = 0; - rtv.tv_usec = arc4random() % (MAX_RANDOM_FACTOR_U -MIN_RANDOM_FACTOR_U); - timeradd(&tv, &rtv, &tv); - eloop_timeout_add_tv(rap->iface->ctx->eloop, - &tv, ipv6nd_proberouter, rap); - - if (rap->nsprobes++ == 0) - eloop_timeout_add_sec(rap->iface->ctx->eloop, - DELAY_FIRST_PROBE_TIME, ipv6nd_unreachable, rap); -} - -void -ipv6nd_cancelproberouter(struct ra *rap) -{ - - eloop_timeout_delete(rap->iface->ctx->eloop, ipv6nd_proberouter, rap); - eloop_timeout_delete(rap->iface->ctx->eloop, ipv6nd_unreachable, rap); -} - -static void ipv6nd_handlena(struct ipv6_ctx *ctx, struct interface *ifp, struct icmp6_hdr *icp, size_t len) {
--- a/ipv6nd.h Fri May 02 06:40:21 2014 +0000 +++ b/ipv6nd.h Fri May 02 10:16:00 2014 +0000 @@ -93,10 +93,6 @@ void ipv6nd_handleifa(struct dhcpcd_ctx *, int, const char *, const struct in6_addr *, int); void ipv6nd_drop(struct interface *); - -void ipv6nd_proberouter(void *); -void ipv6nd_cancelproberouter(struct ra *); - #else #define ipv6nd_startrs(a) {} #define ipv6nd_addrexists(a, b) (0)
