Index: sys/netinet/icmp6.h
===================================================================
--- sys/netinet/icmp6.h	(revision 222277)
+++ sys/netinet/icmp6.h	(working copy)
@@ -297,6 +297,8 @@
 #define ND_OPT_PREFIX_INFORMATION	3
 #define ND_OPT_REDIRECTED_HEADER	4
 #define ND_OPT_MTU			5
+#define ND_OPT_RDNSS			25	/* RFC 6016 */
+#define ND_OPT_DNSSL			31	/* RFC 6016 */
 
 #define ND_OPT_ROUTE_INFO		200	/* draft-ietf-ipngwg-router-preference, not officially assigned yet */
 
@@ -338,6 +340,22 @@
 	/* prefix follows */
 } __packed;
 
+struct nd_opt_rdnss {		/* RDNSS option (RFC 6106) */
+	u_int8_t	nd_opt_rdnss_type;
+	u_int8_t	nd_opt_rdnss_len;
+	u_int16_t	nd_opt_rdnss_reserved;
+	u_int32_t	nd_opt_rdnss_lifetime;
+	/* followed by list of recursive DNS servers */
+} __packed;
+
+struct nd_opt_dnssl {		/* DNSSL option (RFC 6106) */
+	u_int8_t	nd_opt_dnssl_type;
+	u_int8_t	nd_opt_dnssl_len;
+	u_int16_t	nd_opt_dnssl_reserved;
+	u_int32_t	nd_opt_dnssl_lifetime;
+	/* followed by list of DNS search domains */
+} __packed;
+
 /*
  * icmp6 namelookup
  */
Index: usr.sbin/rtadvd/if.c
===================================================================
--- usr.sbin/rtadvd/if.c	(revision 222402)
+++ usr.sbin/rtadvd/if.c	(working copy)
@@ -44,6 +44,7 @@
 #include <netinet/icmp6.h>
 #include <unistd.h>
 #include <errno.h>
+#include <netdb.h>
 #include <stdlib.h>
 #include <string.h>
 #include <syslog.h>
Index: usr.sbin/rtadvd/config.c
===================================================================
--- usr.sbin/rtadvd/config.c	(revision 222402)
+++ usr.sbin/rtadvd/config.c	(working copy)
@@ -53,6 +53,7 @@
 #include <stdio.h>
 #include <syslog.h>
 #include <errno.h>
+#include <netdb.h>
 #include <string.h>
 #include <search.h>
 #include <stdlib.h>
@@ -65,6 +66,11 @@
 #include "if.h"
 #include "config.h"
 
+/* label of tcapcode + number + domain name + zero octet */
+static char entbuf[10 + 3 + NI_MAXHOST + 1];
+static char oentbuf[10 + 3 + NI_MAXHOST + 1];
+static char abuf[DNAME_LABELENC_MAXLEN];
+
 static time_t prefix_timo = (60 * 120);	/* 2 hours.
 					 * XXX: should be configurable. */
 extern struct rainfo *ralist;
@@ -72,7 +78,33 @@
 static struct rtadvd_timer *prefix_timeout(void *);
 static void makeentry(char *, size_t, int, char *);
 static int getinet6sysctl(int);
+static size_t dname_labelenc(char *, const char *);
 
+/* Encode domain name label encoding in RFC 1035 Section 3.1 */
+static size_t
+dname_labelenc(char *dst, const char *src)
+{
+	char *dst_origin;
+	size_t len;
+
+	dst_origin = dst;
+	len = strlen(src);
+
+	/* Length fields per 63 octets + '\0' (<= DNAME_LABELENC_MAXLEN) */
+	memset(dst, 0, len + len / 64 + 1 + 1);
+
+	syslog(LOG_DEBUG, "<%s> labelenc = %s", __func__, src);
+	while ((len = strlen(src)) != 0) {
+		/* Put a length field with 63 octet limitation first. */
+		*dst++ = len = MIN(63, len + 1);
+		memcpy(dst, src, len);
+		dst += len;
+		src += len;
+	}
+	syslog(LOG_DEBUG, "<%s> labellen = %d", __func__, dst - dst_origin);
+	return (dst - dst_origin);
+}
+
 void
 getconfig(intface)
 	char *intface;
@@ -123,6 +155,10 @@
 #ifdef ROUTEINFO
 	tmp->route.next = tmp->route.prev = &tmp->route;
 #endif
+#ifdef RDNSS
+	TAILQ_INIT(&tmp->rdnss);
+	TAILQ_INIT(&tmp->dnssl);
+#endif
 
 	/* check if we are allowed to forward packets (if not determined) */
 	if (forwarding < 0) {
@@ -276,7 +312,6 @@
 	tmp->pfxs = 0;
 	for (i = -1; i < MAXPREFIX; i++) {
 		struct prefix *pfx;
-		char entbuf[256];
 
 		makeentry(entbuf, sizeof(entbuf), i, "addr");
 		addr = (char *)agetstr(entbuf, &bp);
@@ -442,7 +477,6 @@
 	tmp->routes = 0;
 	for (i = -1; i < MAXROUTE; i++) {
 		struct rtinfo *rti;
-		char entbuf[256], oentbuf[256];
 
 		makeentry(entbuf, sizeof(entbuf), i, "rtprefix");
 		addr = (char *)agetstr(entbuf, &bp);
@@ -585,6 +619,118 @@
 	}
 #endif
 
+#ifdef RDNSS
+	/* DNS server and DNS search list information */
+	for (i = -1; i < MAXRDNSSENT ; i++) {
+		struct rdnss *rdn;
+		struct rdnss_addr *rdna;
+		char *ap;
+		int c;
+
+		makeentry(entbuf, sizeof(entbuf), i, "rdnss");
+		addr = (char *)agetstr(entbuf, &bp);
+		if (addr == NULL)
+			break;
+		rdn = malloc(sizeof(*rdn));
+		if (rdn == NULL) {
+			syslog(LOG_ERR,
+			   "<%s> can't get allocate buffer for rdnss entry",
+			   __func__);
+			exit(1);
+		}
+		memset(rdn, 0, sizeof(*rdn));
+		TAILQ_INIT(&rdn->rd_list);
+
+		for (ap = addr; ap - addr < strlen(addr); ap += c+1) {
+			c = strcspn(ap, ",");
+			strncpy(abuf, ap, c);
+			abuf[c] = '\0';
+			rdna = malloc(sizeof(*rdna));
+			if (rdna == NULL) {
+				syslog(LOG_ERR,
+				    "<%s> can't get allocate buffer for "
+				    "rdnss_addr entry",
+				    __func__);
+				exit(1);
+			}
+			memset(rdna, 0, sizeof(*rdna));
+			if (inet_pton(AF_INET6, abuf, &rdna->ra_dns) != 1) {
+				syslog(LOG_ERR, "<%s> inet_pton failed for %s",
+				    __func__, abuf);
+				exit(1);
+			} 
+			TAILQ_INSERT_TAIL(&rdn->rd_list, rdna, ra_next);
+		}
+
+		makeentry(entbuf, sizeof(entbuf), i, "rdnssltime");
+		MAYHAVE(val, entbuf, (tmp->maxinterval * 3 / 2));
+		if (val < tmp->maxinterval || val > tmp->maxinterval * 2) {
+			syslog(LOG_ERR, "%s (%ld) on %s is invalid "
+			    "(must be between %d and %d)",
+			    entbuf, val, intface, tmp->maxinterval,
+			    tmp->maxinterval * 2);
+			exit(1);
+		}
+		rdn->rd_ltime = val;
+
+		/* link into chain */
+		insque(rdn, &tmp->rdnss);
+	}
+
+	for (i = -1; i < MAXDNSSLENT ; i++) {
+		struct dnssl *dns;
+		struct dnssl_addr *dnsa;
+		char *ap;
+		int c;
+		char *p, *q;
+
+		makeentry(entbuf, sizeof(entbuf), i, "dnssl");
+		addr = (char *)agetstr(entbuf, &bp);
+		if (addr == NULL)
+			break;
+		dns = malloc(sizeof(*dns));
+		if (dns == NULL) {
+			syslog(LOG_ERR,
+			       "<%s> can't get allocate buffer for dnssl entry",
+			       __func__);
+			exit(1);
+		}
+		memset(dns, 0, sizeof(*dns));
+		TAILQ_INIT(&dns->dn_list);
+
+		for (ap = addr; ap - addr < strlen(addr); ap += c+1) {
+			c = strcspn(ap, ",");
+			strncpy(abuf, ap, c);
+			abuf[c] = '\0';
+			dnsa = malloc(sizeof(struct dnssl_addr));
+			if (dnsa == NULL) {
+				syslog(LOG_ERR,
+				    "<%s> can't get allocate buffer for "
+				    "dnssl_addr entry", __func__);
+				exit(1);
+			}
+			memset(dnsa, 0, sizeof(*dnsa));
+			dnsa->da_len = dname_labelenc(dnsa->da_dom, abuf);
+			syslog(LOG_DEBUG, "<%s>: dnsa->da_len = %d", __func__,
+			    dnsa->da_len);
+			TAILQ_INSERT_TAIL(&dns->dn_list, dnsa, da_next);
+		}
+
+		makeentry(entbuf, sizeof(entbuf), i, "dnsslltime");
+		MAYHAVE(val, entbuf, (tmp->maxinterval * 3 / 2));
+		if (val < tmp->maxinterval || val > tmp->maxinterval * 2) {
+			syslog(LOG_ERR, "%s (%ld) on %s is invalid "
+			    "(must be between %d and %d)",
+			    entbuf, val, intface, tmp->maxinterval,
+			    tmp->maxinterval * 2);
+			exit(1);
+		}
+		dns->dn_ltime = val;
+
+		/* link into chain */
+		insque(dns, &tmp->dnssl);
+	}
+#endif
 	/* okey */
 	tmp->next = ralist;
 	ralist = tmp;
@@ -913,6 +1059,13 @@
 	struct nd_opt_route_info *ndopt_rti;
 	struct rtinfo *rti;
 #endif
+#ifdef RDNSS
+	struct nd_opt_rdnss *ndopt_rdnss;
+	struct rdnss *rdn;
+	struct nd_opt_dnssl *ndopt_dnssl;
+	struct dnssl *dns;
+	size_t len;
+#endif
 	struct prefix *pfx;
 
 	/* calculate total length */
@@ -936,7 +1089,30 @@
 		packlen += sizeof(struct nd_opt_route_info) + 
 			   ((rti->prefixlen + 0x3f) >> 6) * 8;
 #endif
+#ifdef RDNSS
+	TAILQ_FOREACH(rdn, &rainfo->rdnss, rd_next) {
+		struct rdnss_addr *rdna;
 
+		packlen += sizeof(struct nd_opt_rdnss);
+		TAILQ_FOREACH(rdna, &rdn->rd_list, ra_next)
+			packlen += sizeof(rdna->ra_dns);
+	}
+	TAILQ_FOREACH(dns, &rainfo->dnssl, dn_next) {
+		struct dnssl_addr *dnsa;
+
+		packlen += sizeof(struct nd_opt_dnssl);
+		len = 0;
+		TAILQ_FOREACH(dnsa, &dns->dn_list, da_next)
+			len += dnsa->da_len;
+
+		/* A zero octet and 8 octet boundary */
+		len++;
+		len += 8 - (len % 8);
+
+		packlen += len;
+	}
+#endif
+
 	/* allocate memory for the packet */
 	if ((buf = malloc(packlen)) == NULL) {
 		syslog(LOG_ERR,
@@ -944,6 +1120,7 @@
 		       __func__);
 		exit(1);
 	}
+	memset(buf, 0, packlen);
 	if (rainfo->ra_data) {
 		/* free the previous packet */
 		free(rainfo->ra_data);
@@ -1056,6 +1233,57 @@
 	}
 #endif
 
+#ifdef RDNSS
+	TAILQ_FOREACH(rdn, &rainfo->rdnss, rd_next) {
+		struct rdnss_addr *rdna;
+
+		ndopt_rdnss = (struct nd_opt_rdnss *)buf;
+		ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS;
+		ndopt_rdnss->nd_opt_rdnss_len = 0;
+		ndopt_rdnss->nd_opt_rdnss_reserved = 0;
+		ndopt_rdnss->nd_opt_rdnss_lifetime = htonl(rdn->rd_ltime);
+		buf += sizeof(struct nd_opt_rdnss);
+
+		TAILQ_FOREACH(rdna, &rdn->rd_list, ra_next) {
+			memcpy(buf, &rdna->ra_dns, sizeof(rdna->ra_dns));
+			buf += sizeof(rdna->ra_dns);
+		}
+		/* Length field should be in 8 octets */
+		ndopt_rdnss->nd_opt_rdnss_len = (buf - (char *)ndopt_rdnss) / 8;
+
+		syslog(LOG_DEBUG, "<%s>: nd_opt_dnss_len = %d", __func__,
+			ndopt_rdnss->nd_opt_rdnss_len);
+	}
+	TAILQ_FOREACH(dns, &rainfo->dnssl, dn_next) {
+		struct dnssl_addr *dnsa;
+		size_t len = 0;
+
+		ndopt_dnssl = (struct nd_opt_dnssl *)buf;
+		ndopt_dnssl->nd_opt_dnssl_type = ND_OPT_DNSSL;
+		ndopt_dnssl->nd_opt_dnssl_len = 0;
+		ndopt_dnssl->nd_opt_dnssl_reserved = 0;
+		ndopt_dnssl->nd_opt_dnssl_lifetime = htonl(dns->dn_ltime);
+		buf += sizeof(*ndopt_dnssl);
+
+		TAILQ_FOREACH(dnsa, &dns->dn_list, da_next) {
+			memcpy(buf, dnsa->da_dom, dnsa->da_len);
+			buf += dnsa->da_len;
+		}
+
+		/* A zero octet after encoded DNS server list. */
+		*buf++ = '\0';
+		
+		/* Padding to next 8 octets boundary */
+		len = buf - (char *)ndopt_dnssl;
+		len += 8 - (len % 8);
+
+		/* Length field must be in 8 octets */
+		ndopt_dnssl->nd_opt_dnssl_len = len / 8;
+
+		syslog(LOG_DEBUG, "<%s>: nd_opt_dnssl_len = %d", __func__,
+			ndopt_dnssl->nd_opt_dnssl_len);
+	}
+#endif
 	return;
 }
 
Index: usr.sbin/rtadvd/dump.c
===================================================================
--- usr.sbin/rtadvd/dump.c	(revision 222402)
+++ usr.sbin/rtadvd/dump.c	(working copy)
@@ -45,6 +45,7 @@
 
 #include <arpa/inet.h>
 
+#include <netdb.h>
 #include <time.h>
 #include <stdio.h>
 #include <stdarg.h>
@@ -63,6 +64,7 @@
 
 static char *ether_str(struct sockaddr_dl *);
 static void if_dump(void);
+static size_t dname_labeldec(char *, const char *);
 
 static char *rtpref_str[] = {
 	"medium",		/* 00 */
@@ -96,6 +98,10 @@
 #ifdef ROUTEINFO
 	struct rtinfo *rti;
 #endif
+#ifdef RDNSS
+	struct rdnss *rdn;
+	struct dnssl *dns;
+#endif
 	char prefixbuf[INET6_ADDRSTRLEN];
 	int first;
 	struct timeval now;
@@ -230,6 +236,44 @@
 			fprintf(fp, ")\n");
 		}
 #endif
+#ifdef RDNSS
+		TAILQ_FOREACH(rdn, &rai->rdnss, rd_next) {
+			struct rdnss_addr *rdna;
+
+			if (rdn == TAILQ_FIRST(&rai->rdnss))
+				fprintf(fp, "  Recursive DNS servers:\n"
+					    "    Lifetime\tServers\n");
+
+			fprintf(fp, "    % 8u\t", rdn->rd_ltime);
+			TAILQ_FOREACH(rdna, &rdn->rd_list, ra_next) {
+				inet_ntop(AF_INET6, &rdna->ra_dns,
+				    prefixbuf, sizeof(prefixbuf));
+				
+				if (rdna != TAILQ_FIRST(&rdn->rd_list))
+					fprintf(fp, "            \t");
+				fprintf(fp, "%s\n", prefixbuf);
+			}
+			fprintf(fp, "\n");
+		}
+
+		TAILQ_FOREACH(dns, &rai->dnssl, dn_next) {
+			struct dnssl_addr *dnsa;
+			char buf[NI_MAXHOST + 1];
+
+			if (dns == TAILQ_FIRST(&rai->dnssl))
+				fprintf(fp, "  DNS search list:\n"
+					    "    Lifetime\tDomains\n");
+
+			fprintf(fp, "    % 8u\t", dns->dn_ltime);
+			TAILQ_FOREACH(dnsa, &dns->dn_list, da_next) {
+				dname_labeldec(buf, dnsa->da_dom);
+				if (dnsa != TAILQ_FIRST(&dns->dn_list))
+					fprintf(fp, "            \t");
+				fprintf(fp, "%s(%d)\n", buf, dnsa->da_len);
+			}
+			fprintf(fp, "\n");
+		}
+#endif
 	}
 }
 
@@ -250,3 +294,23 @@
 
 	fclose(fp);
 }
+
+/* Decode domain name label encoding in RFC 1035 Section 3.1 */
+static size_t
+dname_labeldec(char *dst, const char *src)
+{
+	size_t len;
+	const char *src_origin;
+
+	src_origin = src;
+	while (*src && (len = (uint8_t)(*src++) & 0x3f) != 0) {
+		syslog(LOG_DEBUG, "<%s> labellen = %d", __func__, len);
+		memcpy(dst, src, len);
+		src += len;
+		dst += len;
+		if (*(dst - 1) == '\0')
+			break;
+	}
+
+	return (src - src_origin);
+}
Index: usr.sbin/rtadvd/rrenum.c
===================================================================
--- usr.sbin/rtadvd/rrenum.c	(revision 222402)
+++ usr.sbin/rtadvd/rrenum.c	(working copy)
@@ -45,6 +45,7 @@
 #include <arpa/inet.h>
 
 #include <errno.h>
+#include <netdb.h>
 #include <string.h>
 #include <stdlib.h>
 #include <syslog.h>
Index: usr.sbin/rtadvd/config.h
===================================================================
--- usr.sbin/rtadvd/config.h	(revision 222402)
+++ usr.sbin/rtadvd/config.h	(working copy)
@@ -45,3 +45,5 @@
  */
 #define MAXPREFIX	100
 #define MAXROUTE	100
+#define MAXRDNSSENT	100
+#define MAXDNSSLENT	100
Index: usr.sbin/rtadvd/rtadvd.c
===================================================================
--- usr.sbin/rtadvd/rtadvd.c	(revision 222402)
+++ usr.sbin/rtadvd/rtadvd.c	(working copy)
@@ -37,6 +37,7 @@
 #include <sys/queue.h>
 
 #include <net/if.h>
+#include <net/if_media.h>
 #include <net/route.h>
 #include <net/if_dl.h>
 #include <netinet/in.h>
@@ -52,6 +53,7 @@
 #include <err.h>
 #include <errno.h>
 #include <libutil.h>
+#include <netdb.h>
 #include <string.h>
 #include <stdlib.h>
 #include <syslog.h>
@@ -115,15 +117,26 @@
 #define nd_opts_mtu		nd_opt_each.mtu
 #define nd_opts_list		nd_opt_each.list
 
-#define NDOPT_FLAG_SRCLINKADDR 0x1
-#define NDOPT_FLAG_TGTLINKADDR 0x2
-#define NDOPT_FLAG_PREFIXINFO 0x4
-#define NDOPT_FLAG_RDHDR 0x8
-#define NDOPT_FLAG_MTU 0x10
+#define NDOPT_FLAG_SRCLINKADDR	(1 << 0)
+#define NDOPT_FLAG_TGTLINKADDR	(1 << 1)
+#define NDOPT_FLAG_PREFIXINFO	(1 << 2)
+#define NDOPT_FLAG_RDHDR	(1 << 3)
+#define NDOPT_FLAG_MTU		(1 << 4)
+#ifdef RDNSS
+#define NDOPT_FLAG_RDNSS	(1 << 5)
+#define NDOPT_FLAG_DNSSL	(1 << 6)
+#endif
 
 u_int32_t ndopt_flags[] = {
-	0, NDOPT_FLAG_SRCLINKADDR, NDOPT_FLAG_TGTLINKADDR,
-	NDOPT_FLAG_PREFIXINFO, NDOPT_FLAG_RDHDR, NDOPT_FLAG_MTU,
+	[ND_OPT_SOURCE_LINKADDR]	= NDOPT_FLAG_SRCLINKADDR,
+	[ND_OPT_TARGET_LINKADDR]	= NDOPT_FLAG_TGTLINKADDR,
+	[ND_OPT_PREFIX_INFORMATION]	= NDOPT_FLAG_PREFIXINFO,
+	[ND_OPT_REDIRECTED_HEADER]	= NDOPT_FLAG_RDHDR,
+	[ND_OPT_MTU]			= NDOPT_FLAG_MTU,
+#ifdef RDNSS
+	[ND_OPT_RDNSS]			= NDOPT_FLAG_RDNSS,
+	[ND_OPT_DNSSL]			= NDOPT_FLAG_DNSSL,
+#endif
 };
 
 int main(int, char *[]);
@@ -376,6 +389,10 @@
 die()
 {
 	struct rainfo *ra;
+#ifdef RDNSS
+	struct rdnss *rdn;
+	struct dnssl *dns;
+#endif
 	int i;
 	const int retrans = MAX_FINAL_RTR_ADVERTISEMENTS;
 
@@ -386,6 +403,12 @@
 
 	for (ra = ralist; ra; ra = ra->next) {
 		ra->lifetime = 0;
+#ifdef RDNSS
+		TAILQ_FOREACH(rdn, &ra->rdnss, rd_next)
+			rdn->rd_ltime = 0;
+		TAILQ_FOREACH(dns, &ra->dnssl, dn_next)
+			dns->dn_ltime = 0;
+#endif
 		make_packet(ra);
 	}
 	for (i = 0; i < retrans; i++) {
@@ -961,7 +984,11 @@
 	if (nd6_options((struct nd_opt_hdr *)(ra + 1),
 			len - sizeof(struct nd_router_advert),
 			&ndopts, NDOPT_FLAG_SRCLINKADDR |
-			NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU)) {
+			NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU
+#ifdef RDNSS
+			| NDOPT_FLAG_RDNSS | NDOPT_FLAG_DNSSL
+#endif
+	    )) {
 		syslog(LOG_INFO,
 		       "<%s> ND option check failed for an RA from %s on %s",
 		       __func__,
@@ -1300,7 +1327,12 @@
 			goto bad;
 		}
 
-		if (hdr->nd_opt_type > ND_OPT_MTU) {
+		if (hdr->nd_opt_type > ND_OPT_MTU
+#ifdef RDNSS
+		    && hdr->nd_opt_type != ND_OPT_RDNSS &&
+		       hdr->nd_opt_type != ND_OPT_DNSSL
+#endif
+		    ) {
 			syslog(LOG_INFO, "<%s> unknown ND option(type %d)",
 			    __func__, hdr->nd_opt_type);
 			continue;
@@ -1317,9 +1349,18 @@
 		 * options.
 		 */
 		if ((hdr->nd_opt_type == ND_OPT_MTU &&
-		    (optlen != sizeof(struct nd_opt_mtu))) ||
-		    ((hdr->nd_opt_type == ND_OPT_PREFIX_INFORMATION &&
-		    optlen != sizeof(struct nd_opt_prefix_info)))) {
+			optlen != sizeof(struct nd_opt_mtu)) ||
+#ifdef RDNSS
+		    (hdr->nd_opt_type == ND_OPT_RDNSS &&
+			(optlen < 24 ||
+			(optlen - sizeof(struct nd_opt_rdnss)) % 16 != 0)) ||
+		    (hdr->nd_opt_type == ND_OPT_DNSSL &&
+			(optlen < 16 ||
+			(optlen - sizeof(struct nd_opt_dnssl)) % 8 != 0)) ||
+#endif
+		    (hdr->nd_opt_type == ND_OPT_PREFIX_INFORMATION &&
+			optlen != sizeof(struct nd_opt_prefix_info))
+		) {
 			syslog(LOG_INFO, "<%s> invalid option length",
 			    __func__);
 			continue;
@@ -1328,6 +1369,10 @@
 		switch (hdr->nd_opt_type) {
 		case ND_OPT_TARGET_LINKADDR:
 		case ND_OPT_REDIRECTED_HEADER:
+#ifdef RDNSS
+		case ND_OPT_RDNSS:
+		case ND_OPT_DNSSL:
+#endif
 			break;	/* we don't care about these options */
 		case ND_OPT_SOURCE_LINKADDR:
 		case ND_OPT_MTU:
Index: usr.sbin/rtadvd/rtadvd.conf
===================================================================
--- usr.sbin/rtadvd/rtadvd.conf	(revision 222402)
+++ usr.sbin/rtadvd/rtadvd.conf	(working copy)
@@ -18,4 +18,5 @@
 #   this part by hand, and then invoke rtadvd with the -s option.
  
 #ef0:\
-#	:addr="3ffe:501:ffff:1000::":prefixlen#64:
+#	:addr="2001:db8:ffff:1000::":prefixlen#64:\
+#	:rddns="2001:db8:ffff:1000::1":dnssl="foo.com":
Index: usr.sbin/rtadvd/rtadvd.h
===================================================================
--- usr.sbin/rtadvd/rtadvd.h	(revision 222402)
+++ usr.sbin/rtadvd/rtadvd.h	(working copy)
@@ -94,6 +94,44 @@
 };
 #endif
 
+#ifdef RDNSS
+struct rdnss_addr {
+	TAILQ_ENTRY(rdnss_addr)	ra_next;
+
+	struct in6_addr ra_dns;	/* DNS server entry */
+};
+struct rdnss {
+	TAILQ_ENTRY(rdnss) rd_next;
+
+	TAILQ_HEAD(, rdnss_addr) rd_list; /* list of DNS servers */
+	int rd_cnt;		/* number of DNS servers */
+	u_int32_t rd_ltime;	/* number of seconds valid */
+};
+
+/*
+ * The maximum length of a domain name in a DNS search list is calculated
+ * by a domain name + length fields per * 63 octets * + a zero octet at
+ * the tail and adding 8 octet boundary padding.
+ */
+#define _DNAME_LABELENC_MAXLEN \
+	(NI_MAXHOST + (NI_MAXHOST / 64 + 1) + 1)
+#define DNAME_LABELENC_MAXLEN \
+	(_DNAME_LABELENC_MAXLEN + 8 - _DNAME_LABELENC_MAXLEN % 8)
+
+struct dnssl_addr {
+	TAILQ_ENTRY(dnssl_addr)	da_next;
+
+	int da_len;			/* length of entry */
+	char da_dom[DNAME_LABELENC_MAXLEN];	/* search domain name entry */
+};
+struct dnssl {
+	TAILQ_ENTRY(dnssl)	dn_next;
+
+	TAILQ_HEAD(, dnssl_addr) dn_list; /* list of search domains */
+	u_int32_t dn_ltime;	/* number of seconds valid */
+};
+#endif
+
 struct soliciter {
 	struct soliciter *next;
 	struct sockaddr_in6 addr;
@@ -130,6 +168,10 @@
 	u_int	hoplimit;	/* AdvCurHopLimit */
 	struct prefix prefix;	/* AdvPrefixList(link head) */
 	int	pfxs;		/* number of prefixes */
+#ifdef RDNSS
+	TAILQ_HEAD(, rdnss) rdnss;	/* DNS server list */
+	TAILQ_HEAD(, dnssl) dnssl;	/* search domain list */
+#endif
 	long	clockskew;	/* used for consisitency check of lifetimes */
 
 #ifdef ROUTEINFO
Index: usr.sbin/rtadvd/rtadvd.conf.5
===================================================================
--- usr.sbin/rtadvd/rtadvd.conf.5	(revision 222402)
+++ usr.sbin/rtadvd/rtadvd.conf.5	(working copy)
@@ -29,7 +29,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd May 17, 1998
+.Dd May 28, 2011
 .Dt RTADVD.CONF 5
 .Os
 .Sh NAME
@@ -355,6 +355,65 @@
 .Dq Li rtr
 have basically been obsoleted, and should not be used any more.
 .Pp
+The following items are for ICMPv6 Recursive DNS Server Option and
+DNS Search List Option
+.Pq RFC 6106 ,
+which will be attached to router advertisement header.
+These items are optional.
+.Bl -tag -width indent
+.It Cm \&rdnss
+(str) The IPv6 address of one or more recursive DNS servers.
+The argument must be inside double quotes.
+Multiple DNS servers can be specified in a comma-separated string.
+If different lifetimes are needed for different servers,
+separate entries can be given by using
+.Cm rdnss ,
+.Cm rdnss0 ,
+.Cm rdnss1 ,
+.Cm rdnss2 ...
+options with corresponding
+.Cm rdnssltime ,
+.Cm rdnssltime0 ,
+.Cm rdnssltime1 ,
+.Cm rdnssltime2 ...
+entries.
+Note that the maximum number of servers depends on the receiver side.
+See also
+.Xr resolver 5
+manual page for resolver implementation in
+.Fx .
+.It Cm \&rdnssltime
+The lifetime of the
+.Cm rdnss
+DNS server entries.  The default value is 3/2 of the interval
+time.
+.It Cm \&dnssl
+(str) One or more domain names in a comma-separated string.
+These domain names will be used when making DNS queries on a
+non-fully-qualified domain name.  If different lifetimes are needed for
+different domains, separate entries can be given by using
+.Cm dnssl ,
+.Cm dnssl0 ,
+.Cm dnssl1 ,
+.Cm dnssl2 ...
+options with corresponding
+.Cm dnsslltime ,
+.Cm dnsslltime0 ,
+.Cm dnsslltime1 ,
+.Cm dnsslltime2 ...
+entries.
+Note that the maximum number of names depends on the receiver side.
+See also
+.Xr resolver 5
+manual page for resolver implementation in
+.Fx .
+.It Cm \&dnsslltime
+The lifetime of the
+.Cm dnssl
+DNS search list entries.  The default value is 3/2 of the interval
+time.
+.El
+.Pp
 You can also refer one line from another by using
 .Cm tc
 capability.
@@ -388,9 +447,20 @@
 .Xr rtadvd 8 .
 .Bd -literal -offset
 ef0:\\
-	:addr="3ffe:501:ffff:1000::":prefixlen#64:
+	:addr="2001:db8:ffff:1000::":prefixlen#64:
 .Ed
 .Pp
+The following example configures the
+.Li wlan0
+interface and adds two DNS servers and a DNS domain search options
+using the default option lifetime values.
+.Bd -literal -offset
+wlan0:\\
+	:addr="2001:db8:ffff:1000::":prefixlen#64:\\
+	:rdnss="2001:db8:ffff::10,2001:db8:ffff::2:43:\\
+	:dnssl="foo.com":
+.Ed
+.Pp
 The following example presents the default values in an explicit manner.
 The configuration is provided just for reference purposes;
 YOU DO NOT NEED TO HAVE IT AT ALL.
@@ -399,10 +469,11 @@
 	:chlim#64:raflags#0:rltime#1800:rtime#0:retrans#0:\\
 	:pinfoflags="la":vltime#2592000:pltime#604800:mtu#0:
 ef0:\\
-	:addr="3ffe:501:ffff:1000::":prefixlen#64:tc=default:
+	:addr="2001:db8:ffff:1000::":prefixlen#64:tc=default:
 .Ed
 .Sh SEE ALSO
 .Xr termcap 5 ,
+.Xr resolver 5 ,
 .Xr rtadvd 8 ,
 .Xr rtsol 8
 .Rs
@@ -417,6 +488,14 @@
 .%T Default Router Preferences and More-Specific Routes
 .%R draft-ietf-ipngwg-router-selection-xx.txt
 .Re
+.Rs
+.%A J. Jeong
+.%A S. Park
+.%A L. Beloeil
+.%A S. Madanapalli
+.%T IPv6 Router Advertisement Options for DNS Configuration
+.%R RFC 6106
+.Re
 .Sh HISTORY
 The
 .Xr rtadvd 8
Index: usr.sbin/rtadvd/Makefile
===================================================================
--- usr.sbin/rtadvd/Makefile	(revision 222402)
+++ usr.sbin/rtadvd/Makefile	(working copy)
@@ -21,7 +21,7 @@
 DPADD=	${LIBUTIL}
 LDADD=	-lutil
 
-CFLAGS+= -DHAVE_ARC4RANDOM -DHAVE_POLL_H -DROUTEINFO
+CFLAGS+= -DHAVE_ARC4RANDOM -DHAVE_POLL_H -DROUTEINFO -DRDNSS
 
 WARNS?=	1
 
Index: usr.sbin/rtsold/rtsol.c
===================================================================
--- usr.sbin/rtsold/rtsol.c	(revision 222402)
+++ usr.sbin/rtsold/rtsol.c	(working copy)
@@ -50,6 +50,7 @@
 
 #include <arpa/inet.h>
 
+#include <netdb.h>
 #include <time.h>
 #include <fcntl.h>
 #include <unistd.h>
@@ -77,9 +78,24 @@
 	.sin6_family =	AF_INET6,
 };
 
-static void call_script(char *, char *);
+struct script_msg {
+	TAILQ_ENTRY(script_msg)	sm_next;
+
+	char *sm_msg;
+};
+
+static void call_script(char **, void *);
+static size_t dname_labeldec(char *, const char *);
 static int safefile(const char *);
 
+#define _ARGS_OTHER	otherconf_script, ifi->ifname
+#define _ARGS_RESCONF	resolvconf_script, "-a", ifi->ifname
+#define CALL_SCRIPT(name, sm_head)	\
+	do {						\
+		char *sarg[] = { _ARGS_##name, NULL };	\
+		call_script(sarg, sm_head);		\
+	} while(0);
+
 int
 sockopen(void)
 {
@@ -234,17 +250,34 @@
 {
 	u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
 	int ifindex = 0, *hlimp = NULL;
-	ssize_t i;
+	ssize_t msglen;
 	struct in6_pktinfo *pi = NULL;
 	struct ifinfo *ifi = NULL;
 	struct icmp6_hdr *icp;
 	struct nd_router_advert *nd_ra;
 	struct cmsghdr *cm;
+	char *raoptp;
+	char *p;
+	struct in6_addr *addr;
+	struct nd_opt_hdr *ndo;
+	struct nd_opt_rdnss *rdnss;
+	struct nd_opt_dnssl *dnssl;
+	size_t len;
+	struct script_msg *smp;
+	TAILQ_HEAD(, script_msg) sm_ns_head =
+		TAILQ_HEAD_INITIALIZER(sm_ns_head);
+	char nsbuf[11 + INET6_ADDRSTRLEN + 1 + IFNAMSIZ + 1 + 1];
+	/* 11 = sizeof("nameserver "), 1+1 = \n\0 termination */
+	TAILQ_HEAD(, script_msg) sm_sl_head =
+		TAILQ_HEAD_INITIALIZER(sm_sl_head);
+	char slbuf[7 + NI_MAXHOST + 1 + 1];
+	/* 7 = sizeof("search "), 1+1 = \n\0 termination */
+	char dname[NI_MAXHOST + 1];
 
 	/* get message.  namelen and controllen must always be initialized. */
 	rcvmhdr.msg_namelen = sizeof(from);
 	rcvmhdr.msg_controllen = rcvcmsglen;
-	if ((i = recvmsg(s, &rcvmhdr, 0)) < 0) {
+	if ((msglen = recvmsg(s, &rcvmhdr, 0)) < 0) {
 		warnmsg(LOG_ERR, __func__, "recvmsg: %s", strerror(errno));
 		return;
 	}
@@ -275,9 +308,9 @@
 		return;
 	}
 
-	if ((size_t)i < sizeof(struct nd_router_advert)) {
+	if ((size_t)msglen < sizeof(struct nd_router_advert)) {
 		warnmsg(LOG_INFO, __func__,
-		    "packet size(%zd) is too short", i);
+		    "packet size(%zd) is too short", msglen);
 		return;
 	}
 
@@ -354,9 +387,166 @@
 		warnmsg(LOG_DEBUG, __func__,
 		    "OtherConfigFlag on %s is turned on", ifi->ifname);
 		ifi->otherconfig = 1;
-		call_script(otherconf_script, ifi->ifname);
+		CALL_SCRIPT(OTHER, NULL);
 	}
 
+#define RA_OPT_NEXT_HDR(x)	(struct nd_opt_hdr *)((char *)x + \
+				(((struct nd_opt_hdr *)x)->nd_opt_len * 8))
+	raoptp = (char *)icp + sizeof(struct nd_router_advert);
+
+	warnmsg(LOG_DEBUG, __func__, "Processing RA");
+	/* Process RA options. */
+	while (raoptp < (char *)icp + msglen) {
+		ndo = (struct nd_opt_hdr *)raoptp;
+		warnmsg(LOG_DEBUG, __func__, "ndo = %p", raoptp);
+		warnmsg(LOG_DEBUG, __func__, "ndo->nd_opt_type = %d",
+		    ndo->nd_opt_type);
+		warnmsg(LOG_DEBUG, __func__, "ndo->nd_opt_len = %d",
+		    ndo->nd_opt_len);
+
+		switch (ndo->nd_opt_type) {
+		case ND_OPT_RDNSS:
+			if (resolvconf_script == NULL)
+				break;
+			rdnss = (struct nd_opt_rdnss *)raoptp;
+			/* XXX: no lifetime handling now */
+
+			addr = (struct in6_addr *)(raoptp + sizeof(*rdnss));
+			while ((char *)addr < (char *)RA_OPT_NEXT_HDR(raoptp)) {
+				if (inet_ntop(AF_INET6, addr, ntopbuf,
+				    INET6_ADDRSTRLEN) == NULL) {
+					warnmsg(LOG_INFO, __func__,
+		    			"an invalid address in RDNSS option "
+					"in RA from %s was ignored.",
+					inet_ntop(AF_INET6, &from.sin6_addr,
+					ntopbuf, INET6_ADDRSTRLEN));
+
+					continue;
+				}
+				if (IN6_IS_ADDR_LINKLOCAL(addr))
+					/* XXX: % has to be escaped here */
+					sprintf(nsbuf, "nameserver "
+					    "%s%c%c%c%c%s\n",
+					    ntopbuf,
+					    SCOPE_DELIMITER,
+					    SCOPE_DELIMITER,
+					    SCOPE_DELIMITER,
+					    SCOPE_DELIMITER,
+					    ifi->ifname);
+				else
+					sprintf(nsbuf, "nameserver %s\n",
+					    ntopbuf);
+				warnmsg(LOG_DEBUG, __func__, "nsbuf = %s",
+				    nsbuf);
+
+				smp = malloc(sizeof(*smp));
+				if (smp == NULL) {
+					warnmsg(LOG_ERR, __func__,
+					    "malloc failed: %s",
+					    strerror(errno));
+					continue;
+				}
+				memset(smp, 0, sizeof(*smp));
+				smp->sm_msg = strdup(nsbuf);
+				if (smp->sm_msg == NULL) {
+					warnmsg(LOG_ERR, __func__,
+					    "strdup failed: %s",
+					    strerror(errno));
+					free(smp);
+					continue;
+				}
+				TAILQ_INSERT_TAIL(&sm_ns_head, smp, sm_next);
+				addr++;
+			}
+			break;
+		case ND_OPT_DNSSL:
+			if (resolvconf_script == NULL)
+				break;
+			dnssl = (struct nd_opt_dnssl *)raoptp;
+			/* XXX: no lifetime handling now */
+
+			if (TAILQ_EMPTY(&sm_sl_head)) {
+				smp = malloc(sizeof(*smp));
+				if (smp == NULL) {
+					warnmsg(LOG_ERR, __func__,
+					    "malloc failed: %s",
+					    strerror(errno));
+					break;
+				}
+				smp = malloc(sizeof(*smp));
+				smp->sm_msg = strdup("search ");
+				if (smp->sm_msg == NULL) {
+					warnmsg(LOG_ERR, __func__,
+					    "strdup failed: %s",
+					    strerror(errno));
+					free(smp);
+					break;
+				}
+				TAILQ_INSERT_TAIL(&sm_sl_head, smp, sm_next);
+			}
+
+			p = raoptp + sizeof(*dnssl);
+			while (0 < (len = dname_labeldec(dname, p))) {
+				sprintf(slbuf, "%s ", dname);
+				warnmsg(LOG_DEBUG, __func__, "slbuf = %s",
+				    slbuf);
+
+				smp = malloc(sizeof(*smp));
+				if (smp == NULL) {
+					warnmsg(LOG_ERR, __func__,
+					    "malloc failed: %s",
+					    strerror(errno));
+					break;
+				}
+				memset(smp, 0, sizeof(*smp));
+				smp->sm_msg = strdup(slbuf);
+				if (smp->sm_msg == NULL) {
+					warnmsg(LOG_ERR, __func__,
+					    "strdup failed: %s",
+					    strerror(errno));
+					free(smp);
+					break;
+				}
+				TAILQ_INSERT_TAIL(&sm_sl_head, smp, sm_next);
+				p += len;
+			}
+			break;
+		default:  
+			/* nothing to do for other options */
+			break;
+		}
+		raoptp = (char *)RA_OPT_NEXT_HDR(raoptp);
+	}
+	if (!TAILQ_EMPTY(&sm_sl_head)) {
+		smp = malloc(sizeof(*smp));
+		if (smp == NULL) {
+			warnmsg(LOG_ERR, __func__, "malloc failed: %s",
+			    strerror(errno));
+			return;
+		}
+		smp = malloc(sizeof(*smp));
+		smp->sm_msg = strdup("\n");
+		if (smp->sm_msg == NULL) {
+			warnmsg(LOG_ERR, __func__, "strdup failed: %s",
+			    strerror(errno));
+			free(smp);
+			return;
+		}
+	}
+	TAILQ_CONCAT(&sm_ns_head, &sm_sl_head, sm_next);
+	if (!TAILQ_EMPTY(&sm_ns_head) || !TAILQ_EMPTY(&sm_sl_head)) {
+		struct script_msg *sm_tmp;
+
+		CALL_SCRIPT(RESCONF, &sm_ns_head);
+
+		/* Clear script message queue. */
+		smp = TAILQ_FIRST(&sm_ns_head);
+		while(smp != NULL) {
+			sm_tmp = TAILQ_NEXT(smp, sm_next);
+			free(smp);
+			smp = sm_tmp;
+		}
+	}
 	ifi->racnt++;
 
 	switch (ifi->state) {
@@ -372,22 +562,56 @@
 }
 
 static void
-call_script(char *scriptpath, char *ifname)
+call_script(char *argv[], void *head)
 {
+	char *scriptpath;
+	int fd[2];
+	int error;
 	pid_t pid, wpid;
+	TAILQ_HEAD(, script_msg) *sm_head = NULL;
 
-	if (scriptpath == NULL)
+	sm_head = head;
+	fd[0] = fd[1] = -1;
+	if ((scriptpath = argv[0]) == NULL)
 		return;
 
+	if (sm_head != NULL && !TAILQ_EMPTY(sm_head)) {
+		error = pipe(fd);
+		if (error) {
+			warnmsg(LOG_ERR, __func__,
+			    "failed to create a pipe: %s", strerror(errno));
+			return;
+		}
+	}
+
 	/* launch the script */
 	pid = fork();
 	if (pid < 0) {
 		warnmsg(LOG_ERR, __func__,
 		    "failed to fork: %s", strerror(errno));
 		return;
-	} else if (pid) {
+	} else if (pid) {	/* parent */
 		int wstatus;
 
+		if (fd[0] != -1) {	/* Send message to the child if any. */
+			ssize_t len;
+			struct script_msg *smp;
+
+			close(fd[0]);
+			TAILQ_FOREACH(smp, sm_head, sm_next) {
+				len = strlen(smp->sm_msg);
+				warnmsg(LOG_DEBUG, __func__,
+				    "write to child = %s(%d)",
+				    smp->sm_msg, len);
+				if (write(fd[1], smp->sm_msg, len) != len) {
+					warnmsg(LOG_ERR, __func__,
+					    "write to child failed: %s",
+					    strerror(errno));
+					break;
+				}
+			}
+			close(fd[1]);
+		}
 		do {
 			wpid = wait(&wstatus);
 		} while (wpid != pid && wpid > 0);
@@ -399,34 +623,44 @@
 			warnmsg(LOG_DEBUG, __func__,
 			    "script \"%s\" terminated", scriptpath);
 		}
-	} else {
-		char *argv[3];
-		int fd;
+	} else {		/* child */
+		int nullfd;
 
-		argv[0] = scriptpath;
-		argv[1] = ifname;
-		argv[2] = NULL;
-
 		if (safefile(scriptpath)) {
 			warnmsg(LOG_ERR, __func__,
 			    "script \"%s\" cannot be executed safely",
 			    scriptpath);
 			exit(1);
 		}
-
-		if ((fd = open("/dev/null", O_RDWR)) != -1) {
-			dup2(fd, STDIN_FILENO);
-			dup2(fd, STDOUT_FILENO);
-			dup2(fd, STDERR_FILENO);
-			if (fd > STDERR_FILENO)
-				close(fd);
+		nullfd = open("/dev/null", O_RDWR);
+		if (nullfd < 0) {
+			warnmsg(LOG_ERR, __func__,
+			    "open /dev/null: %s", strerror(errno));
+			exit(1);
 		}
+		if (fd[0] != -1) {	/* Receive message from STDIN if any. */
+			close(fd[1]);
+			if (fd[0] != STDIN_FILENO) {
+				/* Connect a pipe read-end to child's STDIN. */
+				if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {
+					warnmsg(LOG_ERR, __func__,
+					    "dup2 STDIN: %s", strerror(errno));
+					exit(1);
+				}
+				close(fd[0]);
+			}
+		} else
+			dup2(nullfd, STDIN_FILENO);
+	
+		dup2(nullfd, STDOUT_FILENO);
+		dup2(nullfd, STDERR_FILENO);
+		if (nullfd > STDERR_FILENO)
+			close(nullfd);
 
 		execv(scriptpath, argv);
-
 		warnmsg(LOG_ERR, __func__, "child: exec failed: %s",
 		    strerror(errno));
-		exit(0);
+		exit(1);
 	}
 
 	return;
@@ -471,3 +705,23 @@
 
 	return (0);
 }
+
+/* Decode domain name label encoding in RFC 1035 Section 3.1 */
+static size_t
+dname_labeldec(char *dst, const char *src)
+{
+	size_t len;
+	const char *src_origin;
+
+	src_origin = src;
+	while (*src && (len = (uint8_t)(*src++) & 0x3f) != 0) {
+		warnmsg(LOG_DEBUG, __func__, "labellen = %d", len);
+		memcpy(dst, src, len);
+		src += len;
+		dst += len;
+		if (*(dst - 1) == '\0')
+			break; 
+	}
+
+	return (src - src_origin);
+}
Index: usr.sbin/rtsold/rtsold.c
===================================================================
--- usr.sbin/rtsold/rtsold.c	(revision 222402)
+++ usr.sbin/rtsold/rtsold.c	(working copy)
@@ -73,6 +73,7 @@
 int dflag = 0;
 
 char *otherconf_script;
+char *resolvconf_script = "/sbin/resolvconf";
 
 /* protocol constants */
 #define MAX_RTR_SOLICITATION_DELAY	1 /* second */
@@ -133,9 +134,9 @@
 	if (argv0 && argv0[strlen(argv0) - 1] != 'd') {
 		fflag = 1;
 		once = 1;
-		opts = "adDFO:";
+		opts = "adDFO:R:";
 	} else
-		opts = "adDfFm1O:";
+		opts = "adDfFm1O:R:";
 
 	while ((ch = getopt(argc, argv, opts)) != -1) {
 		switch (ch) {
@@ -163,6 +164,9 @@
 		case 'O':
 			otherconf_script = optarg;
 			break;
+		case 'R':
+			resolvconf_script = optarg;
+			break;
 		default:
 			usage(argv0);
 			/*NOTREACHED*/
Index: usr.sbin/rtsold/rtsold.8
===================================================================
--- usr.sbin/rtsold/rtsold.8	(revision 222402)
+++ usr.sbin/rtsold/rtsold.8	(working copy)
@@ -29,7 +29,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd September 2, 2009
+.Dd May 28, 2011
 .Dt RTSOLD 8
 .Os
 .\"
@@ -41,18 +41,22 @@
 .Nm
 .Op Fl dDfFm1
 .Op Fl O Ar script-name
+.Op Fl R Ar script-name
 .Ar interface ...
 .Nm
 .Op Fl dDfFm1
 .Op Fl O Ar script-name
+.Op Fl R Ar script-name
 .Fl a
 .Nm rtsol
-.Op Fl dDF
+.Op Fl dD
 .Op Fl O Ar script-name
+.Op Fl R Ar script-name
 .Ar interface ...
 .Nm rtsol
 .Op Fl dD
 .Op Fl O Ar script-name
+.Op Fl R Ar script-name
 .Fl a
 .\"
 .Sh DESCRIPTION
@@ -221,6 +225,15 @@
 must be the absolute path from root to the script file, be a regular
 file, and be created by the same owner who runs
 .Nm .
+.It Fl R Ar script-name
+Specifies a script to run when router advertisment options
+.Dv RDNSS Pq Recursive DNS Server
+or
+.Dv DNSSL Pq DNS Search List
+are encountered.  The information of DNS servers and DNS search domains
+will be sent to standard input of this script.  The
+.Xr resolvconf 8
+script is used by default.
 .El
 .Sh FILES
 .Bl -tag -width /var/run/rtsold.dump -compact
@@ -235,6 +248,7 @@
 .Ex -std
 .\"
 .Sh SEE ALSO
+.Xr resolvconf 8 ,
 .Xr rtadvd 8 ,
 .Xr sysctl 8
 .\"
Index: usr.sbin/rtsold/rtsold.h
===================================================================
--- usr.sbin/rtsold/rtsold.h	(revision 222402)
+++ usr.sbin/rtsold/rtsold.h	(working copy)
@@ -69,6 +69,7 @@
 extern int aflag;
 extern int Fflag;
 extern char *otherconf_script;
+extern char *resolvconf_script;
 extern int ifconfig(char *);
 extern void iflist_init(void);
 struct ifinfo *find_ifinfo(int);
