changeset 2458:4050e5af02d9 draft

Once reachability + randomisation has passed, wait DELAY_FIRST_PROBE_TIME seconds and then send MAX_UNICAST_SOLICIT probes at retranstimer intervals. If no confirmation and another retranstimer interval has passed, expire the address. More RFC4861 conformant.
author Roy Marples <roy@marples.name>
date Fri, 02 May 2014 12:31:21 +0000
parents 7cf4ee9e75b5
children 4d3db760a69a
files ipv6nd.c ipv6nd.h
diffstat 2 files changed, 35 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/ipv6nd.c	Fri May 02 11:03:46 2014 +0000
+++ b/ipv6nd.c	Fri May 02 12:31:21 2014 +0000
@@ -121,7 +121,7 @@
 //
 
 static void ipv6nd_handledata(void *);
-static void ipv6nd_proberouter(struct ra *);
+static void ipv6nd_startproberouter(struct ra *);
 
 /*
  * Android ships buggy ICMP6 filter headers.
@@ -933,7 +933,7 @@
 	{
 		rap->nsprobes = 0;
 		if (rap->lifetime)
-			ipv6nd_proberouter(rap);
+			ipv6nd_startproberouter(rap);
 	}
 
 handle_flag:
@@ -1107,7 +1107,7 @@
 }
 
 static void
-ipv6nd_proberouter1(void *arg)
+ipv6nd_proberouter(void *arg)
 {
 	struct ra *rap = arg;
 	struct nd_neighbor_solicit *ns;
@@ -1116,6 +1116,7 @@
 	struct cmsghdr *cm;
 	struct in6_pktinfo pi;
 	struct ipv6_ctx *ctx;
+	struct timeval tv;
 
 	if (ipv6nd_open(rap->iface->ctx) == -1) {
 		syslog(LOG_ERR, "%s: ipv6nd_open: %m", __func__);
@@ -1175,41 +1176,48 @@
 		return;
 	}
 
-	if (rap->nsprobes++ == 0)
-		eloop_timeout_add_sec(rap->iface->ctx->eloop,
-		    DELAY_FIRST_PROBE_TIME, ipv6nd_unreachable, rap);
+	ms_to_tv(&tv, rap->retrans ? rap->retrans :  RETRANS_TIMER);
+	eloop_timeout_add_tv(rap->iface->ctx->eloop, &tv,
+	    ++rap->nsprobes < MAX_UNICAST_SOLICIT ?
+	    ipv6nd_proberouter : ipv6nd_unreachable,
+	    rap);
+}
 
-	if (rap->nsprobes < MAX_UNICAST_SOLICIT)
-		ipv6nd_proberouter(rap);
+static void
+ipv6nd_stalerouter(void *arg)
+{
+	struct ra *rap = arg;
+
+	rap->nsprobes = 0;
+	eloop_timeout_add_sec(rap->iface->ctx->eloop, DELAY_FIRST_PROBE_TIME,
+	    ipv6nd_proberouter, rap);
 }
 
 static void
-ipv6nd_proberouter(struct ra *rap)
+ipv6nd_cancelproberouter(struct ra *rap)
+{
+
+	eloop_timeout_delete(rap->iface->ctx->eloop, ipv6nd_proberouter, rap);
+	eloop_timeout_delete(rap->iface->ctx->eloop, ipv6nd_stalerouter, rap);
+	eloop_timeout_delete(rap->iface->ctx->eloop, ipv6nd_unreachable, rap);
+}
+
+
+static void
+ipv6nd_startproberouter(struct ra *rap)
 {
 	struct timeval tv, rtv;
 
-	if (rap->nsprobes == 0) {
-		ms_to_tv(&tv, rap->reachable ? rap->reachable : REACHABLE_TIME);
-	} else {
-		ms_to_tv(&tv, rap->retrans ? rap->retrans :  RETRANS_TIMER);
-	}
+	ipv6nd_cancelproberouter(rap);
+
+	ms_to_tv(&tv, rap->reachable ? rap->reachable : REACHABLE_TIME);
 	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_proberouter1, rap);
-	eloop_timeout_delete(rap->iface->ctx->eloop, ipv6nd_unreachable, rap);
+	    &tv, ipv6nd_stalerouter, rap);
 }
 
 void
@@ -1405,10 +1413,7 @@
 			ipv6_buildroutes(ifp->ctx);
 			script_runreason(rap->iface, "ROUTERADVERT"); /* XXX */
 		}
-		eloop_timeout_delete(rap->iface->ctx->eloop,
-		    ipv6nd_unreachable, rap);
-		rap->nsprobes = 0;
-		ipv6nd_proberouter(rap);
+		ipv6nd_startproberouter(rap);
 	}
 }
 
--- a/ipv6nd.h	Fri May 02 11:03:46 2014 +0000
+++ b/ipv6nd.h	Fri May 02 12:31:21 2014 +0000
@@ -77,7 +77,7 @@
 
 #define MAX_UNICAST_SOLICIT	3	/* 3 transmissions */
 
-#define MAX_REACHABLE_TIME	3600	/* seconds */
+#define MAX_REACHABLE_TIME	3600000	/* milliseconds */
 #define REACHABLE_TIME		30000	/* milliseconds */
 #define RETRANS_TIMER		1000	/* milliseconds */
 #define DELAY_FIRST_PROBE_TIME	5	/* seconds */