Module Name:    src
Committed By:   roy
Date:           Fri Apr 20 15:57:23 UTC 2018

Modified Files:
        src/usr.sbin/rtadvd: config.c rtadvd.c rtadvd.h

Log Message:
Unicast solicited RA's as per RFC 7772.

This is done by having a secondary timer against rainfo so we
can delay unicasting by the required randomised amount of time
without affecting the unsolicited RA timer.


To generate a diff of this commit:
cvs rdiff -u -r1.39 -r1.40 src/usr.sbin/rtadvd/config.c
cvs rdiff -u -r1.64 -r1.65 src/usr.sbin/rtadvd/rtadvd.c
cvs rdiff -u -r1.16 -r1.17 src/usr.sbin/rtadvd/rtadvd.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.sbin/rtadvd/config.c
diff -u src/usr.sbin/rtadvd/config.c:1.39 src/usr.sbin/rtadvd/config.c:1.40
--- src/usr.sbin/rtadvd/config.c:1.39	Fri Apr 20 15:29:19 2018
+++ src/usr.sbin/rtadvd/config.c	Fri Apr 20 15:57:23 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: config.c,v 1.39 2018/04/20 15:29:19 roy Exp $	*/
+/*	$NetBSD: config.c,v 1.40 2018/04/20 15:57:23 roy Exp $	*/
 /*	$KAME: config.c,v 1.93 2005/10/17 14:40:02 suz Exp $	*/
 
 /*
@@ -113,6 +113,7 @@ free_rainfo(struct rainfo *rai)
 	struct dnssl_domain *dnsd;
 
 	rtadvd_remove_timer(&rai->timer);
+	rtadvd_remove_timer(&rai->timer_sol);
 
 	while ((sol = TAILQ_FIRST(&rai->soliciter))) {
 		TAILQ_REMOVE(&rai->soliciter, sol, next);
@@ -791,7 +792,8 @@ getconfig(const char *intface, int exith
 		return;
 	tmp->timer = rtadvd_add_timer(ra_timeout, ra_timer_update,
 				      tmp, tmp);
-	ra_timer_set_short_delay(tmp);
+	ra_timer_set_short_delay(tmp, tmp->timer);
+	tmp->timer_sol = rtadvd_add_timer(ra_timeout_sol, NULL, tmp, NULL);
 
 	return;
 

Index: src/usr.sbin/rtadvd/rtadvd.c
diff -u src/usr.sbin/rtadvd/rtadvd.c:1.64 src/usr.sbin/rtadvd/rtadvd.c:1.65
--- src/usr.sbin/rtadvd/rtadvd.c:1.64	Fri Apr 20 11:31:54 2018
+++ src/usr.sbin/rtadvd/rtadvd.c	Fri Apr 20 15:57:23 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: rtadvd.c,v 1.64 2018/04/20 11:31:54 roy Exp $	*/
+/*	$NetBSD: rtadvd.c,v 1.65 2018/04/20 15:57:23 roy Exp $	*/
 /*	$KAME: rtadvd.c,v 1.92 2005/10/17 14:40:02 suz Exp $	*/
 
 /*
@@ -166,7 +166,7 @@ static void rs_input(int, struct nd_rout
     struct in6_pktinfo *, struct sockaddr_in6 *);
 static void ra_input(int, struct nd_router_advert *,
     struct in6_pktinfo *, struct sockaddr_in6 *);
-static struct rainfo *ra_output(struct rainfo *);
+static struct rainfo *ra_output(struct rainfo *, bool);
 static int prefix_check(struct nd_opt_prefix_info *, struct rainfo *,
     struct sockaddr_in6 *);
 static int nd6_options(struct nd_opt_hdr *, int, union nd_opts *, uint32_t);
@@ -440,7 +440,7 @@ die(void)
 		rai->mininterval = MIN_DELAY_BETWEEN_RAS;
 		rai->maxinterval = MIN_DELAY_BETWEEN_RAS;
 		rai->leaving_adv = MAX_FINAL_RTR_ADVERTISEMENTS;
-		ra_output(rai);
+		ra_output(rai, false);
 		ra_timer_update(rai, &rai->timer->tm);
 		rtadvd_set_timer(&rai->timer->tm, rai->timer);
 	}
@@ -698,13 +698,16 @@ rtmsg_input(void)
 			    ra_timer_update, rai, rai);
 			ra_timer_update(rai, &rai->timer->tm);
 			rtadvd_set_timer(&rai->timer->tm, rai->timer);
+			rtadvd_remove_timer(&rai->timer_sol);
+			rai->timer_sol = rtadvd_add_timer(ra_timeout_sol,
+			    NULL, rai, NULL);
 		} else if (prefixchange && rai->ifflags & IFF_UP) {
 			/*
 			 * An advertised prefix has been added or invalidated.
 			 * Will notice the change in a short delay.
 			 */
 			rai->initcounter = 0;
-			ra_timer_set_short_delay(rai);
+			ra_timer_set_short_delay(rai, rai->timer);
 		}
 	}
 
@@ -965,12 +968,20 @@ rs_input(int len, struct nd_router_solic
 	 */
 
 	/* record sockaddr waiting for RA, if possible */
-	sol = malloc(sizeof(*sol));
-	if (sol) {
-		sol->addr = *from;
-		/* XXX RFC2553 need clarification on flowinfo */
-		sol->addr.sin6_flowinfo = 0;
-		TAILQ_INSERT_HEAD(&rai->soliciter, sol, next);
+	TAILQ_FOREACH(sol, &rai->soliciter, next) {
+		if (IN6_ARE_ADDR_EQUAL(&sol->addr.sin6_addr, &from->sin6_addr))
+			break;
+	}
+	if (sol == NULL) {
+		sol = malloc(sizeof(*sol));
+		if (sol == NULL) {
+			logit(LOG_ERR, "%s: malloc: %m", __func__);
+		} else {
+			sol->addr = *from;
+			/* XXX RFC2553 need clarification on flowinfo */
+			sol->addr.sin6_flowinfo = 0;
+			TAILQ_INSERT_TAIL(&rai->soliciter, sol, next);
+		}
 	}
 
 	/*
@@ -980,14 +991,14 @@ rs_input(int len, struct nd_router_solic
 	if (rai->waiting++)
 		goto done;
 
-	ra_timer_set_short_delay(rai);
+	ra_timer_set_short_delay(rai, rai->timer_sol);
 
 done:
 	free_ndopts(&ndopts);
 }
 
 void
-ra_timer_set_short_delay(struct rainfo *rai)
+ra_timer_set_short_delay(struct rainfo *rai, struct rtadvd_timer *timer)
 {
 	long delay;	/* must not be greater than 1000000 */
 	struct timespec interval, now, min_delay, tm_tmp, *rest;
@@ -1024,7 +1035,7 @@ ra_timer_set_short_delay(struct rainfo *
 		timespecsub(&min_delay, &tm_tmp, &min_delay);
 		timespecadd(&min_delay, &interval, &interval);
 	}
-	rtadvd_set_timer(&interval, rai->timer);
+	rtadvd_set_timer(&interval, timer);
 }
 
 static void
@@ -1503,7 +1514,8 @@ sock_open(void)
 		exit(EXIT_FAILURE);
 	}
 
-	sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo));
+	sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
+				CMSG_SPACE(sizeof(int));
 	sndcmsgbuf = malloc(sndcmsgbuflen);
 	if (sndcmsgbuf == NULL) {
 		logit(LOG_ERR, "%s: malloc: %m", __func__);
@@ -1522,6 +1534,12 @@ sock_open(void)
 		logit(LOG_ERR, "%s: IPV6_MULTICAST_HOPS: %m", __func__);
 		exit(EXIT_FAILURE);
 	}
+	on = 255;
+	if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &on,
+		       sizeof(on)) == -1) {
+		logit(LOG_ERR, "%s: IPV6_UNICAST_HOPS: %m", __func__);
+		exit(EXIT_FAILURE);
+	}
 
 	/* specify to tell receiving interface */
 	on = 1;
@@ -1661,7 +1679,7 @@ if_indextorainfo(unsigned int idx)
 }
 
 struct rainfo *
-ra_output(struct rainfo *rai)
+ra_output(struct rainfo *rai, bool solicited)
 {
 	int i;
 	struct cmsghdr *cm;
@@ -1680,8 +1698,8 @@ ra_output(struct rainfo *rai)
 	sndmhdr.msg_iov[0].iov_base = (void *)rai->ra_data;
 	sndmhdr.msg_iov[0].iov_len = rai->ra_datalen;
 
-	cm = CMSG_FIRSTHDR(&sndmhdr);
 	/* specify the outgoing interface */
+	cm = CMSG_FIRSTHDR(&sndmhdr);
 	cm->cmsg_level = IPPROTO_IPV6;
 	cm->cmsg_type = IPV6_PKTINFO;
 	cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
@@ -1693,8 +1711,32 @@ ra_output(struct rainfo *rai)
 	       "%s: send RA on %s, # of waitings = %d",
 	       __func__, rai->ifname, rai->waiting); 
 
-	i = prog_sendmsg(sock, &sndmhdr, 0);
+	if (solicited) {
+		/* unicast solicited RA's as per RFC 7772 */
+		while ((sol = TAILQ_FIRST(&rai->soliciter)) != NULL) {
+			sndmhdr.msg_name = (void *)&sol->addr;
+			i = prog_sendmsg(sock, &sndmhdr, 0);
+			if (i < 0 || (size_t)i != rai->ra_datalen)  {
+				if (i < 0) {
+					logit(LOG_ERR,
+					    "%s: unicast sendmsg on %s: %m",
+					    __func__, rai->ifname);
+				}
+			}
+			TAILQ_REMOVE(&rai->soliciter, sol, next);
+			free(sol);
+		}
+
+		/* reset waiting conter */
+		rai->waiting = 0;
+
+		/* disable timer */
+		rai->timer_sol->enabled = false;
 
+		return rai;
+	}
+
+	i = prog_sendmsg(sock, &sndmhdr, 0);
 	if (i < 0 || (size_t)i != rai->ra_datalen)  {
 		if (i < 0) {
 			logit(LOG_ERR, "%s: sendmsg on %s: %m",
@@ -1702,27 +1744,6 @@ ra_output(struct rainfo *rai)
 		}
 	}
 
-	/*
-	 * unicast advertisements
-	 * XXX commented out.  reason: though spec does not forbit it, unicast
-	 * advert does not really help
-	 */
-	while ((sol = TAILQ_FIRST(&rai->soliciter)) != NULL) {
-#if 0
-		sndmhdr.msg_name = (void *)&sol->addr;
-		i = sendmsg(sock, &sndmhdr, 0);
-		if (i < 0 || i != rai->ra_datalen)  {
-			if (i < 0) {
-				logit(LOG_ERR,
-				    "%s: unicast sendmsg on %s: %m",
-				    __func__, rai->ifname);
-			}
-		}
-#endif
-		TAILQ_REMOVE(&rai->soliciter, sol, next);
-		free(sol);
-	}
-
 	if (rai->leaving_adv > 0) {
 		if (--(rai->leaving_adv) == 0) {
 			/* leaving for ourself means we're shutting down */
@@ -1738,7 +1759,7 @@ ra_output(struct rainfo *rai)
 			rai->leaving_for->timer = rtadvd_add_timer(ra_timeout,
 			    ra_timer_update,
 			    rai->leaving_for, rai->leaving_for);
-			ra_timer_set_short_delay(rai->leaving_for);
+			ra_timer_set_short_delay(rai->leaving_for, rai->timer);
 			rai->leaving_for->leaving = NULL;
 			free_rainfo(rai);
 			return NULL;
@@ -1752,32 +1773,39 @@ ra_output(struct rainfo *rai)
 
 	/* update timestamp */
 	prog_clock_gettime(CLOCK_MONOTONIC, &rai->lastsent);
-
-	/* reset waiting conter */
-	rai->waiting = 0;
-
 	return rai;
 }
 
-/* process RA timer */
+/* process unsolicited RA timer */
 struct rtadvd_timer *
 ra_timeout(void *data)
 {
 	struct rainfo *rai = (struct rainfo *)data;
 
-#ifdef notyet
-	/* if necessary, reconstruct the packet. */
-#endif
-
 	logit(LOG_DEBUG,
-	       "%s: RA timer on %s is expired",
+	       "%s: unsolicited RA timer on %s is expired",
 	       __func__, rai->ifname);
 
-	if (ra_output(rai))
+	if (ra_output(rai, false))
 		return rai->timer;
 	return NULL;
 }
 
+/* process solicited RA timer */
+struct rtadvd_timer *
+ra_timeout_sol(void *data)
+{
+	struct rainfo *rai = (struct rainfo *)data;
+
+	logit(LOG_DEBUG,
+	       "%s: solicited RA timer on %s is expired",
+	       __func__, rai->ifname);
+
+	if (ra_output(rai, true))
+		return rai->timer_sol;
+	return NULL;
+}
+
 /* update RA timer */
 void
 ra_timer_update(void *data, struct timespec *tm)

Index: src/usr.sbin/rtadvd/rtadvd.h
diff -u src/usr.sbin/rtadvd/rtadvd.h:1.16 src/usr.sbin/rtadvd/rtadvd.h:1.17
--- src/usr.sbin/rtadvd/rtadvd.h:1.16	Fri Apr 20 10:39:37 2018
+++ src/usr.sbin/rtadvd/rtadvd.h	Fri Apr 20 15:57:23 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: rtadvd.h,v 1.16 2018/04/20 10:39:37 roy Exp $	*/
+/*	$NetBSD: rtadvd.h,v 1.17 2018/04/20 15:57:23 roy Exp $	*/
 /*	$KAME: rtadvd.h,v 1.30 2005/10/17 14:40:02 suz Exp $	*/
 
 /*
@@ -136,7 +136,8 @@ struct	rainfo {
 	TAILQ_ENTRY(rainfo) next;
 
 	/* timer related parameters */
-	struct rtadvd_timer *timer;
+	struct rtadvd_timer *timer;	/* unsolicited RA timer */
+	struct rtadvd_timer *timer_sol;	/* solicited RA timer */
 	int initcounter; /* counter for the first few advertisements */
 	struct timespec lastsent; /* timestamp when the latest RA was sent */
 	int waiting;		/* number of RS waiting for RA */
@@ -189,8 +190,9 @@ struct	rainfo {
 extern TAILQ_HEAD(ralist_head_t, rainfo) ralist;
 
 struct rtadvd_timer *ra_timeout(void *);
+struct rtadvd_timer *ra_timeout_sol(void *);
 void ra_timer_update(void *, struct timespec *);
-void ra_timer_set_short_delay(struct rainfo *);
+void ra_timer_set_short_delay(struct rainfo *, struct rtadvd_timer *);
 
 int prefix_match(struct in6_addr *, int, struct in6_addr *, int);
 struct rainfo *if_indextorainfo(unsigned int);

Reply via email to