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)