config.c revision 222732
1/*	$FreeBSD: head/usr.sbin/rtadvd/config.c 222732 2011-06-06 03:06:43Z hrs $	*/
2/*	$KAME: config.c,v 1.84 2003/08/05 12:34:23 itojun Exp $	*/
3
4/*
5 * Copyright (C) 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/param.h>
34#include <sys/ioctl.h>
35#include <sys/socket.h>
36#include <sys/time.h>
37
38#include <net/if.h>
39#include <net/if_var.h>
40#include <net/route.h>
41#include <net/if_dl.h>
42
43#include <netinet/in.h>
44#include <netinet/in_var.h>
45#include <netinet/ip6.h>
46#include <netinet6/ip6_var.h>
47#include <netinet/icmp6.h>
48#include <netinet6/nd6.h>
49
50#include <arpa/inet.h>
51
52#include <stdio.h>
53#include <syslog.h>
54#include <errno.h>
55#include <netdb.h>
56#include <string.h>
57#include <search.h>
58#include <stdlib.h>
59#include <unistd.h>
60#include <ifaddrs.h>
61
62#include "rtadvd.h"
63#include "advcap.h"
64#include "timer.h"
65#include "if.h"
66#include "config.h"
67
68/* label of tcapcode + number + domain name + zero octet */
69static char entbuf[10 + 3 + NI_MAXHOST + 1];
70static char oentbuf[10 + 3 + NI_MAXHOST + 1];
71static char abuf[DNAME_LABELENC_MAXLEN];
72
73static time_t prefix_timo = (60 * 120);	/* 2 hours.
74					 * XXX: should be configurable. */
75
76static struct rtadvd_timer *prefix_timeout(void *);
77static void makeentry(char *, size_t, int, const char *);
78static size_t dname_labelenc(char *, const char *);
79
80/* Encode domain name label encoding in RFC 1035 Section 3.1 */
81static size_t
82dname_labelenc(char *dst, const char *src)
83{
84	char *dst_origin;
85	char *p;
86	size_t len;
87
88	dst_origin = dst;
89	len = strlen(src);
90
91	/* Length fields per 63 octets + '\0' (<= DNAME_LABELENC_MAXLEN) */
92	memset(dst, 0, len + len / 64 + 1 + 1);
93
94	syslog(LOG_DEBUG, "<%s> labelenc = %s", __func__, src);
95	while (src && (len = strlen(src)) != 0) {
96		/* Put a length field with 63 octet limitation first. */
97		p = strchr(src, '.');
98		if (p == NULL)
99			*dst++ = len = MIN(63, len);
100		else
101			*dst++ = len = MIN(63, p - src);
102		/* Copy 63 octets at most. */
103		memcpy(dst, src, len);
104		dst += len;
105		if (p == NULL) /* the last label */
106			break;
107		src = p + 1;
108	}
109	/* Always need a 0-length label at the tail. */
110	*dst++ = '\0';
111
112	syslog(LOG_DEBUG, "<%s> labellen = %d", __func__, dst - dst_origin);
113	return (dst - dst_origin);
114}
115
116#define	MUSTHAVE(var, cap)						\
117    do {								\
118	int64_t t;							\
119	if ((t = agetnum(cap)) < 0) {					\
120		fprintf(stderr, "rtadvd: need %s for interface %s\n",	\
121			cap, intface);					\
122		exit(1);						\
123	}								\
124	var = t;							\
125     } while (0)
126
127#define	MAYHAVE(var, cap, def)						\
128     do {								\
129	if ((var = agetnum(cap)) < 0)					\
130		var = def;						\
131     } while (0)
132
133#define	ELM_MALLOC(p,error_action)					\
134	do {								\
135		p = malloc(sizeof(*p));					\
136		if (p == NULL) {					\
137			syslog(LOG_ERR, "<%s> malloc failed: %s",	\
138			    __func__, strerror(errno));			\
139			error_action;					\
140		}							\
141		memset(p, 0, sizeof(*p));				\
142	} while(0)
143
144int
145rmconfig(int idx)
146{
147	struct rainfo *rai;
148	struct prefix *pfx;
149	struct soliciter *sol;
150	struct rdnss *rdn;
151	struct rdnss_addr *rdna;
152	struct dnssl *dns;
153	struct rtinfo *rti;
154
155	rai = if_indextorainfo(idx);
156	if (rai == NULL) {
157		syslog(LOG_ERR, "<%s>: rainfo not found (idx=%d)",
158		    __func__, idx);
159		return (-1);
160	}
161
162	TAILQ_REMOVE(&railist, rai, rai_next);
163	syslog(LOG_DEBUG, "<%s>: rainfo (idx=%d) removed.",
164	    __func__, idx);
165
166	/* Free all of allocated memories for this entry. */
167	rtadvd_remove_timer(rai->rai_timer);
168
169	if (rai->rai_ra_data != NULL)
170		free(rai->rai_ra_data);
171
172	if (rai->rai_sdl != NULL)
173		free(rai->rai_sdl);
174
175	while ((pfx = TAILQ_FIRST(&rai->rai_prefix)) != NULL) {
176		TAILQ_REMOVE(&rai->rai_prefix, pfx, pfx_next);
177		free(pfx);
178	}
179	while ((sol = TAILQ_FIRST(&rai->rai_soliciter)) != NULL) {
180		TAILQ_REMOVE(&rai->rai_soliciter, sol, sol_next);
181		free(sol);
182	}
183	while ((rdn = TAILQ_FIRST(&rai->rai_rdnss)) != NULL) {
184		TAILQ_REMOVE(&rai->rai_rdnss, rdn, rd_next);
185		while ((rdna = TAILQ_FIRST(&rdn->rd_list)) != NULL) {
186			TAILQ_REMOVE(&rdn->rd_list, rdna, ra_next);
187			free(rdna);
188		}
189		free(rdn);
190	}
191	while ((dns = TAILQ_FIRST(&rai->rai_dnssl)) != NULL) {
192		TAILQ_REMOVE(&rai->rai_dnssl, dns, dn_next);
193		free(dns);
194	}
195	while ((rti = TAILQ_FIRST(&rai->rai_route)) != NULL) {
196		TAILQ_REMOVE(&rai->rai_route, rti, rti_next);
197		free(rti);
198	}
199	free(rai);
200
201	return (0);
202}
203
204int
205getconfig(int idx)
206{
207	int stat, i;
208	char tbuf[BUFSIZ];
209	struct rainfo *rai;
210	long val;
211	int64_t val64;
212	char buf[BUFSIZ];
213	char *bp = buf;
214	char *addr, *flagstr;
215	char intface[IFNAMSIZ];
216
217	if (if_indextoname(idx, intface) == NULL) {
218		syslog(LOG_ERR, "<%s> invalid index number (%d)",
219		    __func__, idx);
220		return (-1);
221	}
222
223	if ((stat = agetent(tbuf, intface)) <= 0) {
224		memset(tbuf, 0, sizeof(tbuf));
225		syslog(LOG_INFO,
226		    "<%s> %s isn't defined in the configuration file"
227		    " or the configuration file doesn't exist."
228		    " Treat it as default",
229		     __func__, intface);
230	}
231
232	rai = malloc(sizeof(*rai));
233	if (rai == NULL) {
234		syslog(LOG_INFO, "<%s> %s: can't allocate enough memory",
235		    __func__, intface);
236		exit(1);
237	}
238	memset(rai, 0, sizeof(*rai));
239	TAILQ_INIT(&rai->rai_prefix);
240#ifdef ROUTEINFO
241	TAILQ_INIT(&rai->rai_route);
242#endif
243	TAILQ_INIT(&rai->rai_rdnss);
244	TAILQ_INIT(&rai->rai_dnssl);
245	TAILQ_INIT(&rai->rai_soliciter);
246
247	/* gather on-link prefixes from the network interfaces. */
248	if (agetflag("noifprefix"))
249		rai->rai_advifprefix = 0;
250	else
251		rai->rai_advifprefix = 1;
252
253	/* get interface information */
254	if (agetflag("nolladdr"))
255		rai->rai_advlinkopt = 0;
256	else
257		rai->rai_advlinkopt = 1;
258	if (rai->rai_advlinkopt) {
259		if ((rai->rai_sdl = if_nametosdl(intface)) == NULL) {
260			syslog(LOG_ERR,
261			    "<%s> can't get information of %s",
262			    __func__, intface);
263			return (-1);
264		}
265		rai->rai_ifindex = rai->rai_sdl->sdl_index;
266	} else
267		rai->rai_ifindex = if_nametoindex(intface);
268	strncpy(rai->rai_ifname, intface, sizeof(rai->rai_ifname));
269	syslog(LOG_DEBUG,
270	    "<%s> ifindex = %d on %s", __func__, rai->rai_ifindex,
271	    rai->rai_ifname);
272
273	if ((rai->rai_phymtu = if_getmtu(intface)) == 0) {
274		rai->rai_phymtu = IPV6_MMTU;
275		syslog(LOG_WARNING,
276		    "<%s> can't get interface mtu of %s. Treat as %d",
277		    __func__, intface, IPV6_MMTU);
278	}
279
280	/*
281	 * set router configuration variables.
282	 */
283	MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL);
284	if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) {
285		syslog(LOG_ERR,
286		    "<%s> maxinterval (%ld) on %s is invalid "
287		    "(must be between %u and %u)", __func__, val,
288		    intface, MIN_MAXINTERVAL, MAX_MAXINTERVAL);
289		return (-1);
290	}
291	rai->rai_maxinterval = (u_int)val;
292
293	MAYHAVE(val, "mininterval", rai->rai_maxinterval/3);
294	if ((u_int)val < MIN_MININTERVAL ||
295	    (u_int)val > (rai->rai_maxinterval * 3) / 4) {
296		syslog(LOG_ERR,
297		    "<%s> mininterval (%ld) on %s is invalid "
298		    "(must be between %d and %d)",
299		    __func__, val, intface, MIN_MININTERVAL,
300		    (rai->rai_maxinterval * 3) / 4);
301		return (-1);
302	}
303	rai->rai_mininterval = (u_int)val;
304
305	MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT);
306	rai->rai_hoplimit = val & 0xff;
307
308	if ((flagstr = (char *)agetstr("raflags", &bp))) {
309		val = 0;
310		if (strchr(flagstr, 'm'))
311			val |= ND_RA_FLAG_MANAGED;
312		if (strchr(flagstr, 'o'))
313			val |= ND_RA_FLAG_OTHER;
314		if (strchr(flagstr, 'h'))
315			val |= ND_RA_FLAG_RTPREF_HIGH;
316		if (strchr(flagstr, 'l')) {
317			if ((val & ND_RA_FLAG_RTPREF_HIGH)) {
318				syslog(LOG_ERR, "<%s> the \'h\' and \'l\'"
319				    " router flags are exclusive", __func__);
320				return (-1);
321			}
322			val |= ND_RA_FLAG_RTPREF_LOW;
323		}
324	} else
325		MAYHAVE(val, "raflags", 0);
326
327	rai->rai_managedflg = val & ND_RA_FLAG_MANAGED;
328	rai->rai_otherflg = val & ND_RA_FLAG_OTHER;
329#ifndef ND_RA_FLAG_RTPREF_MASK
330#define ND_RA_FLAG_RTPREF_MASK	0x18 /* 00011000 */
331#define ND_RA_FLAG_RTPREF_RSV	0x10 /* 00010000 */
332#endif
333	rai->rai_rtpref = val & ND_RA_FLAG_RTPREF_MASK;
334	if (rai->rai_rtpref == ND_RA_FLAG_RTPREF_RSV) {
335		syslog(LOG_ERR, "<%s> invalid router preference (%02x) on %s",
336		    __func__, rai->rai_rtpref, intface);
337		return (-1);
338	}
339
340	MAYHAVE(val, "rltime", rai->rai_maxinterval * 3);
341	if ((u_int)val && ((u_int)val < rai->rai_maxinterval ||
342	    (u_int)val > MAXROUTERLIFETIME)) {
343		syslog(LOG_ERR,
344		    "<%s> router lifetime (%ld) on %s is invalid "
345		    "(must be 0 or between %d and %d)",
346		    __func__, val, intface, rai->rai_maxinterval,
347		    MAXROUTERLIFETIME);
348		return (-1);
349	}
350	rai->rai_lifetime = val & 0xffff;
351
352	MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME);
353	if (val < 0 || val > MAXREACHABLETIME) {
354		syslog(LOG_ERR,
355		    "<%s> reachable time (%ld) on %s is invalid "
356		    "(must be no greater than %d)",
357		    __func__, val, intface, MAXREACHABLETIME);
358		return (-1);
359	}
360	rai->rai_reachabletime = (u_int32_t)val;
361
362	MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER);
363	if (val64 < 0 || val64 > 0xffffffff) {
364		syslog(LOG_ERR, "<%s> retrans time (%lld) on %s out of range",
365		    __func__, (long long)val64, intface);
366		return (-1);
367	}
368	rai->rai_retranstimer = (u_int32_t)val64;
369
370	if (agetnum("hapref") != -1 || agetnum("hatime") != -1) {
371		syslog(LOG_ERR,
372		    "<%s> mobile-ip6 configuration not supported",
373		    __func__);
374		return (-1);
375	}
376	/* prefix information */
377
378	/*
379	 * This is an implementation specific parameter to consider
380	 * link propagation delays and poorly synchronized clocks when
381	 * checking consistency of advertised lifetimes.
382	 */
383	MAYHAVE(val, "clockskew", 0);
384	rai->rai_clockskew = val;
385
386	rai->rai_pfxs = 0;
387	for (i = -1; i < MAXPREFIX; i++) {
388		struct prefix *pfx;
389
390		makeentry(entbuf, sizeof(entbuf), i, "addr");
391		addr = (char *)agetstr(entbuf, &bp);
392		if (addr == NULL)
393			continue;
394
395		/* allocate memory to store prefix information */
396		ELM_MALLOC(pfx, exit(1));
397
398		/* link into chain */
399		TAILQ_INSERT_TAIL(&rai->rai_prefix, pfx, pfx_next);
400		rai->rai_pfxs++;
401		pfx->pfx_origin = PREFIX_FROM_CONFIG;
402
403		if (inet_pton(AF_INET6, addr, &pfx->pfx_prefix) != 1) {
404			syslog(LOG_ERR,
405			    "<%s> inet_pton failed for %s",
406			    __func__, addr);
407			return (-1);
408		}
409		if (IN6_IS_ADDR_MULTICAST(&pfx->pfx_prefix)) {
410			syslog(LOG_ERR,
411			    "<%s> multicast prefix (%s) must "
412			    "not be advertised on %s",
413			    __func__, addr, intface);
414			return (-1);
415		}
416		if (IN6_IS_ADDR_LINKLOCAL(&pfx->pfx_prefix))
417			syslog(LOG_NOTICE,
418			    "<%s> link-local prefix (%s) will be"
419			    " advertised on %s",
420			    __func__, addr, intface);
421
422		makeentry(entbuf, sizeof(entbuf), i, "prefixlen");
423		MAYHAVE(val, entbuf, 64);
424		if (val < 0 || val > 128) {
425			syslog(LOG_ERR, "<%s> prefixlen (%ld) for %s "
426			    "on %s out of range",
427			    __func__, val, addr, intface);
428			return (-1);
429		}
430		pfx->pfx_prefixlen = (int)val;
431
432		makeentry(entbuf, sizeof(entbuf), i, "pinfoflags");
433		if ((flagstr = (char *)agetstr(entbuf, &bp))) {
434			val = 0;
435			if (strchr(flagstr, 'l'))
436				val |= ND_OPT_PI_FLAG_ONLINK;
437			if (strchr(flagstr, 'a'))
438				val |= ND_OPT_PI_FLAG_AUTO;
439		} else {
440			MAYHAVE(val, entbuf,
441			    (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO));
442		}
443		pfx->pfx_onlinkflg = val & ND_OPT_PI_FLAG_ONLINK;
444		pfx->pfx_autoconfflg = val & ND_OPT_PI_FLAG_AUTO;
445
446		makeentry(entbuf, sizeof(entbuf), i, "vltime");
447		MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME);
448		if (val64 < 0 || val64 > 0xffffffff) {
449			syslog(LOG_ERR, "<%s> vltime (%lld) for "
450			    "%s/%d on %s is out of range",
451			    __func__, (long long)val64,
452			    addr, pfx->pfx_prefixlen, intface);
453			return (-1);
454		}
455		pfx->pfx_validlifetime = (u_int32_t)val64;
456
457		makeentry(entbuf, sizeof(entbuf), i, "vltimedecr");
458		if (agetflag(entbuf)) {
459			struct timeval now;
460			gettimeofday(&now, 0);
461			pfx->pfx_vltimeexpire =
462				now.tv_sec + pfx->pfx_validlifetime;
463		}
464
465		makeentry(entbuf, sizeof(entbuf), i, "pltime");
466		MAYHAVE(val64, entbuf, DEF_ADVPREFERREDLIFETIME);
467		if (val64 < 0 || val64 > 0xffffffff) {
468			syslog(LOG_ERR,
469			    "<%s> pltime (%lld) for %s/%d on %s "
470			    "is out of range",
471			    __func__, (long long)val64,
472			    addr, pfx->pfx_prefixlen, intface);
473			return (-1);
474		}
475		pfx->pfx_preflifetime = (u_int32_t)val64;
476
477		makeentry(entbuf, sizeof(entbuf), i, "pltimedecr");
478		if (agetflag(entbuf)) {
479			struct timeval now;
480			gettimeofday(&now, 0);
481			pfx->pfx_pltimeexpire =
482			    now.tv_sec + pfx->pfx_preflifetime;
483		}
484	}
485	if (rai->rai_advifprefix && rai->rai_pfxs == 0)
486		get_prefix(rai);
487
488	MAYHAVE(val, "mtu", 0);
489	if (val < 0 || (u_int)val > 0xffffffff) {
490		syslog(LOG_ERR,
491		    "<%s> mtu (%ld) on %s out of range",
492		    __func__, val, intface);
493		return (-1);
494	}
495	rai->rai_linkmtu = (u_int32_t)val;
496	if (rai->rai_linkmtu == 0) {
497		char *mtustr;
498
499		if ((mtustr = (char *)agetstr("mtu", &bp)) &&
500		    strcmp(mtustr, "auto") == 0)
501			rai->rai_linkmtu = rai->rai_phymtu;
502	}
503	else if (rai->rai_linkmtu < IPV6_MMTU ||
504	    rai->rai_linkmtu > rai->rai_phymtu) {
505		syslog(LOG_ERR,
506		    "<%s> advertised link mtu (%lu) on %s is invalid (must "
507		    "be between least MTU (%d) and physical link MTU (%d)",
508		    __func__, (unsigned long)rai->rai_linkmtu, intface,
509		    IPV6_MMTU, rai->rai_phymtu);
510		return (-1);
511	}
512
513#ifdef SIOCSIFINFO_IN6
514	{
515		struct in6_ndireq ndi;
516		int s;
517
518		if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
519			syslog(LOG_ERR, "<%s> socket: %s", __func__,
520			    strerror(errno));
521			exit(1);
522		}
523		memset(&ndi, 0, sizeof(ndi));
524		strncpy(ndi.ifname, intface, IFNAMSIZ);
525		if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&ndi) < 0)
526			syslog(LOG_INFO, "<%s> ioctl:SIOCGIFINFO_IN6 at %s: %s",
527			    __func__, intface, strerror(errno));
528
529		/* reflect the RA info to the host variables in kernel */
530		ndi.ndi.chlim = rai->rai_hoplimit;
531		ndi.ndi.retrans = rai->rai_retranstimer;
532		ndi.ndi.basereachable = rai->rai_reachabletime;
533		if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&ndi) < 0)
534			syslog(LOG_INFO, "<%s> ioctl:SIOCSIFINFO_IN6 at %s: %s",
535			    __func__, intface, strerror(errno));
536
537		close(s);
538	}
539#endif
540
541	/* route information */
542#ifdef ROUTEINFO
543	rai->rai_routes = 0;
544	for (i = -1; i < MAXROUTE; i++) {
545		struct rtinfo *rti;
546
547		makeentry(entbuf, sizeof(entbuf), i, "rtprefix");
548		addr = (char *)agetstr(entbuf, &bp);
549		if (addr == NULL) {
550			makeentry(oentbuf, sizeof(oentbuf), i, "rtrprefix");
551			addr = (char *)agetstr(oentbuf, &bp);
552			if (addr)
553				fprintf(stderr, "%s was obsoleted.  Use %s.\n",
554				    oentbuf, entbuf);
555		}
556		if (addr == NULL)
557			continue;
558
559		/* allocate memory to store prefix information */
560		ELM_MALLOC(rti, exit(1));
561
562		/* link into chain */
563		TAILQ_INSERT_TAIL(&rai->rai_route, rti, rti_next);
564		rai->rai_routes++;
565
566		if (inet_pton(AF_INET6, addr, &rti->rti_prefix) != 1) {
567			syslog(LOG_ERR, "<%s> inet_pton failed for %s",
568			    __func__, addr);
569			return (-1);
570		}
571#if 0
572		/*
573		 * XXX: currently there's no restriction in route information
574		 * prefix according to
575		 * draft-ietf-ipngwg-router-selection-00.txt.
576		 * However, I think the similar restriction be necessary.
577		 */
578		MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME);
579		if (IN6_IS_ADDR_MULTICAST(&rti->prefix)) {
580			syslog(LOG_ERR,
581			    "<%s> multicast route (%s) must "
582			    "not be advertised on %s",
583			    __func__, addr, intface);
584			return (-1);
585		}
586		if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) {
587			syslog(LOG_NOTICE,
588			    "<%s> link-local route (%s) will "
589			    "be advertised on %s",
590			    __func__, addr, intface);
591			return (-1);
592		}
593#endif
594
595		makeentry(entbuf, sizeof(entbuf), i, "rtplen");
596		/* XXX: 256 is a magic number for compatibility check. */
597		MAYHAVE(val, entbuf, 256);
598		if (val == 256) {
599			makeentry(oentbuf, sizeof(oentbuf), i, "rtrplen");
600			MAYHAVE(val, oentbuf, 256);
601			if (val != 256)
602				fprintf(stderr, "%s was obsoleted.  Use %s.\n",
603				    oentbuf, entbuf);
604			else
605				val = 64;
606		}
607		if (val < 0 || val > 128) {
608			syslog(LOG_ERR, "<%s> prefixlen (%ld) for %s on %s "
609			    "out of range",
610			    __func__, val, addr, intface);
611			return (-1);
612		}
613		rti->rti_prefixlen = (int)val;
614
615		makeentry(entbuf, sizeof(entbuf), i, "rtflags");
616		if ((flagstr = (char *)agetstr(entbuf, &bp))) {
617			val = 0;
618			if (strchr(flagstr, 'h'))
619				val |= ND_RA_FLAG_RTPREF_HIGH;
620			if (strchr(flagstr, 'l')) {
621				if ((val & ND_RA_FLAG_RTPREF_HIGH)) {
622					syslog(LOG_ERR,
623					    "<%s> the \'h\' and \'l\' route"
624					    " preferences are exclusive",
625					    __func__);
626					exit(1);
627				}
628				val |= ND_RA_FLAG_RTPREF_LOW;
629			}
630		} else
631			MAYHAVE(val, entbuf, 256); /* XXX */
632		if (val == 256) {
633			makeentry(oentbuf, sizeof(oentbuf), i, "rtrflags");
634			MAYHAVE(val, oentbuf, 256);
635			if (val != 256) {
636				fprintf(stderr, "%s was obsoleted.  Use %s.\n",
637				    oentbuf, entbuf);
638			} else
639				val = 0;
640		}
641		rti->rti_rtpref = val & ND_RA_FLAG_RTPREF_MASK;
642		if (rti->rti_rtpref == ND_RA_FLAG_RTPREF_RSV) {
643			syslog(LOG_ERR, "<%s> invalid route preference (%02x) "
644			    "for %s/%d on %s",
645			    __func__, rti->rti_rtpref, addr,
646			    rti->rti_prefixlen, intface);
647			return (-1);
648		}
649
650		/*
651		 * Since the spec does not a default value, we should make
652		 * this entry mandatory.  However, FreeBSD 4.4 has shipped
653		 * with this field being optional, we use the router lifetime
654		 * as an ad-hoc default value with a warning message.
655		 */
656		makeentry(entbuf, sizeof(entbuf), i, "rtltime");
657		MAYHAVE(val64, entbuf, -1);
658		if (val64 == -1) {
659			makeentry(oentbuf, sizeof(oentbuf), i, "rtrltime");
660			MAYHAVE(val64, oentbuf, -1);
661			if (val64 != -1)
662				fprintf(stderr, "%s was obsoleted.  Use %s.\n",
663				    oentbuf, entbuf);
664			else {
665				fprintf(stderr, "%s should be specified "
666				    "for interface %s.\n", entbuf, intface);
667				val64 = rai->rai_lifetime;
668			}
669		}
670		if (val64 < 0 || val64 > 0xffffffff) {
671			syslog(LOG_ERR, "<%s> route lifetime (%lld) for "
672			    "%s/%d on %s out of range", __func__,
673			    (long long)val64, addr, rti->rti_prefixlen, intface);
674			return (-1);
675		}
676		rti->rti_ltime = (u_int32_t)val64;
677	}
678#endif
679	/* DNS server and DNS search list information */
680	for (i = -1; i < MAXRDNSSENT ; i++) {
681		struct rdnss *rdn;
682		struct rdnss_addr *rdna;
683		char *ap;
684		int c;
685
686		makeentry(entbuf, sizeof(entbuf), i, "rdnss");
687		addr = (char *)agetstr(entbuf, &bp);
688		if (addr == NULL)
689			break;
690		ELM_MALLOC(rdn, exit(1));
691
692		TAILQ_INIT(&rdn->rd_list);
693
694		for (ap = addr; ap - addr < (ssize_t)strlen(addr); ap += c+1) {
695			c = strcspn(ap, ",");
696			strncpy(abuf, ap, c);
697			abuf[c] = '\0';
698			ELM_MALLOC(rdna, exit(1));
699			if (inet_pton(AF_INET6, abuf, &rdna->ra_dns) != 1) {
700				syslog(LOG_ERR, "<%s> inet_pton failed for %s",
701				    __func__, abuf);
702				free(rdna);
703				return (-1);
704			}
705			TAILQ_INSERT_TAIL(&rdn->rd_list, rdna, ra_next);
706		}
707
708		makeentry(entbuf, sizeof(entbuf), i, "rdnssltime");
709		MAYHAVE(val, entbuf, (rai->rai_maxinterval * 3 / 2));
710		if ((u_int)val < rai->rai_maxinterval ||
711		    (u_int)val > rai->rai_maxinterval * 2) {
712			syslog(LOG_ERR, "%s (%ld) on %s is invalid "
713			    "(must be between %d and %d)",
714			    entbuf, val, intface, rai->rai_maxinterval,
715			    rai->rai_maxinterval * 2);
716			return (-1);
717		}
718		rdn->rd_ltime = val;
719
720		/* link into chain */
721		TAILQ_INSERT_TAIL(&rai->rai_rdnss, rdn, rd_next);
722	}
723
724	for (i = -1; i < MAXDNSSLENT ; i++) {
725		struct dnssl *dns;
726		struct dnssl_addr *dnsa;
727		char *ap;
728		int c;
729
730		makeentry(entbuf, sizeof(entbuf), i, "dnssl");
731		addr = (char *)agetstr(entbuf, &bp);
732		if (addr == NULL)
733			break;
734
735		ELM_MALLOC(dns, exit(1));
736
737		TAILQ_INIT(&dns->dn_list);
738
739		for (ap = addr; ap - addr < (ssize_t)strlen(addr); ap += c+1) {
740			c = strcspn(ap, ",");
741			strncpy(abuf, ap, c);
742			abuf[c] = '\0';
743			ELM_MALLOC(dnsa, exit(1));
744			dnsa->da_len = dname_labelenc(dnsa->da_dom, abuf);
745			syslog(LOG_DEBUG, "<%s>: dnsa->da_len = %d", __func__,
746			    dnsa->da_len);
747			TAILQ_INSERT_TAIL(&dns->dn_list, dnsa, da_next);
748		}
749
750		makeentry(entbuf, sizeof(entbuf), i, "dnsslltime");
751		MAYHAVE(val, entbuf, (rai->rai_maxinterval * 3 / 2));
752		if ((u_int)val < rai->rai_maxinterval ||
753		    (u_int)val > rai->rai_maxinterval * 2) {
754			syslog(LOG_ERR, "%s (%ld) on %s is invalid "
755			    "(must be between %d and %d)",
756			    entbuf, val, intface, rai->rai_maxinterval,
757			    rai->rai_maxinterval * 2);
758			return (-1);
759		}
760		dns->dn_ltime = val;
761
762		/* link into chain */
763		TAILQ_INSERT_TAIL(&rai->rai_dnssl, dns, dn_next);
764	}
765	/* construct the sending packet */
766	make_packet(rai);
767	TAILQ_INSERT_TAIL(&railist, rai, rai_next);
768
769	/* set timer */
770	rai->rai_timer = rtadvd_add_timer(ra_timeout, ra_timer_update,
771				      rai, rai);
772	ra_timer_update((void *)rai, &rai->rai_timer->rat_tm);
773	rtadvd_set_timer(&rai->rai_timer->rat_tm, rai->rai_timer);
774
775	return (0);
776}
777
778void
779get_prefix(struct rainfo *rai)
780{
781	struct ifaddrs *ifap, *ifa;
782	struct prefix *pfx;
783	struct in6_addr *a;
784	u_char *p, *ep, *m, *lim;
785	u_char ntopbuf[INET6_ADDRSTRLEN];
786
787	if (getifaddrs(&ifap) < 0) {
788		syslog(LOG_ERR,
789		    "<%s> can't get interface addresses",
790		    __func__);
791		exit(1);
792	}
793
794	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
795		int plen;
796
797		if (strcmp(ifa->ifa_name, rai->rai_ifname) != 0)
798			continue;
799		if (ifa->ifa_addr->sa_family != AF_INET6)
800			continue;
801		a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
802		if (IN6_IS_ADDR_LINKLOCAL(a))
803			continue;
804		/* get prefix length */
805		m = (u_char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
806		lim = (u_char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len;
807		plen = prefixlen(m, lim);
808		if (plen <= 0 || plen > 128) {
809			syslog(LOG_ERR, "<%s> failed to get prefixlen "
810			    "or prefix is invalid",
811			    __func__);
812			exit(1);
813		}
814		if (plen == 128)	/* XXX */
815			continue;
816		if (find_prefix(rai, a, plen)) {
817			/* ignore a duplicated prefix. */
818			continue;
819		}
820
821		/* allocate memory to store prefix info. */
822		ELM_MALLOC(pfx, exit(1));
823
824		/* set prefix, sweep bits outside of prefixlen */
825		pfx->pfx_prefixlen = plen;
826		memcpy(&pfx->pfx_prefix, a, sizeof(*a));
827		p = (u_char *)&pfx->pfx_prefix;
828		ep = (u_char *)(&pfx->pfx_prefix + 1);
829		while (m < lim && p < ep)
830			*p++ &= *m++;
831		while (p < ep)
832			*p++ = 0x00;
833	        if (!inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf,
834	            sizeof(ntopbuf))) {
835			syslog(LOG_ERR, "<%s> inet_ntop failed", __func__);
836			exit(1);
837		}
838		syslog(LOG_DEBUG,
839		    "<%s> add %s/%d to prefix list on %s",
840		    __func__, ntopbuf, pfx->pfx_prefixlen, rai->rai_ifname);
841
842		/* set other fields with protocol defaults */
843		pfx->pfx_validlifetime = DEF_ADVVALIDLIFETIME;
844		pfx->pfx_preflifetime = DEF_ADVPREFERREDLIFETIME;
845		pfx->pfx_onlinkflg = 1;
846		pfx->pfx_autoconfflg = 1;
847		pfx->pfx_origin = PREFIX_FROM_KERNEL;
848		pfx->pfx_rainfo = rai;
849
850		/* link into chain */
851		TAILQ_INSERT_TAIL(&rai->rai_prefix, pfx, pfx_next);
852
853		/* counter increment */
854		rai->rai_pfxs++;
855	}
856
857	freeifaddrs(ifap);
858}
859
860static void
861makeentry(char *buf, size_t len, int id, const char *string)
862{
863
864	if (id < 0)
865		strlcpy(buf, string, len);
866	else
867		snprintf(buf, len, "%s%d", string, id);
868}
869
870/*
871 * Add a prefix to the list of specified interface and reconstruct
872 * the outgoing packet.
873 * The prefix must not be in the list.
874 * XXX: other parameters of the prefix (e.g. lifetime) should be
875 * able to be specified.
876 */
877static void
878add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr)
879{
880	struct prefix *pfx;
881	u_char ntopbuf[INET6_ADDRSTRLEN];
882
883	ELM_MALLOC(pfx, return);
884	pfx->pfx_prefix = ipr->ipr_prefix.sin6_addr;
885	pfx->pfx_prefixlen = ipr->ipr_plen;
886	pfx->pfx_validlifetime = ipr->ipr_vltime;
887	pfx->pfx_preflifetime = ipr->ipr_pltime;
888	pfx->pfx_onlinkflg = ipr->ipr_raf_onlink;
889	pfx->pfx_autoconfflg = ipr->ipr_raf_auto;
890	pfx->pfx_origin = PREFIX_FROM_DYNAMIC;
891
892	TAILQ_INSERT_TAIL(&rai->rai_prefix, pfx, pfx_next);
893	pfx->pfx_rainfo = rai;
894
895	syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s",
896	    __func__,
897	    inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf,
898		sizeof(ntopbuf)), ipr->ipr_plen, rai->rai_ifname);
899
900	/* reconstruct the packet */
901	rai->rai_pfxs++;
902	make_packet(rai);
903}
904
905/*
906 * Delete a prefix to the list of specified interface and reconstruct
907 * the outgoing packet.
908 * The prefix must be in the list.
909 */
910void
911delete_prefix(struct prefix *pfx)
912{
913	u_char ntopbuf[INET6_ADDRSTRLEN];
914	struct rainfo *rai;
915
916	rai = pfx->pfx_rainfo;
917	TAILQ_REMOVE(&rai->rai_prefix, pfx, pfx_next);
918	syslog(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s",
919	    __func__,
920	    inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf,
921		sizeof(ntopbuf)), pfx->pfx_prefixlen, rai->rai_ifname);
922	if (pfx->pfx_timer)
923		rtadvd_remove_timer(pfx->pfx_timer);
924	free(pfx);
925	rai->rai_pfxs--;
926	make_packet(rai);
927}
928
929void
930invalidate_prefix(struct prefix *pfx)
931{
932	u_char ntopbuf[INET6_ADDRSTRLEN];
933	struct timeval timo;
934	struct rainfo *rai;
935
936	rai = pfx->pfx_rainfo;
937	if (pfx->pfx_timer) {	/* sanity check */
938		syslog(LOG_ERR,
939		    "<%s> assumption failure: timer already exists",
940		    __func__);
941		exit(1);
942	}
943
944	syslog(LOG_DEBUG, "<%s> prefix %s/%d was invalidated on %s, "
945	    "will expire in %ld seconds", __func__,
946	    inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf, sizeof(ntopbuf)),
947	    pfx->pfx_prefixlen, rai->rai_ifname, (long)prefix_timo);
948
949	/* set the expiration timer */
950	pfx->pfx_timer = rtadvd_add_timer(prefix_timeout, NULL, pfx, NULL);
951	if (pfx->pfx_timer == NULL) {
952		syslog(LOG_ERR, "<%s> failed to add a timer for a prefix. "
953		    "remove the prefix", __func__);
954		delete_prefix(pfx);
955	}
956	timo.tv_sec = prefix_timo;
957	timo.tv_usec = 0;
958	rtadvd_set_timer(&timo, pfx->pfx_timer);
959}
960
961static struct rtadvd_timer *
962prefix_timeout(void *arg)
963{
964
965	delete_prefix((struct prefix *)arg);
966
967	return (NULL);
968}
969
970void
971update_prefix(struct prefix *pfx)
972{
973	u_char ntopbuf[INET6_ADDRSTRLEN];
974	struct rainfo *rai;
975
976	rai = pfx->pfx_rainfo;
977	if (pfx->pfx_timer == NULL) { /* sanity check */
978		syslog(LOG_ERR,
979		    "<%s> assumption failure: timer does not exist",
980		    __func__);
981		exit(1);
982	}
983
984	syslog(LOG_DEBUG, "<%s> prefix %s/%d was re-enabled on %s",
985	    __func__, inet_ntop(AF_INET6, &pfx->pfx_prefix, ntopbuf,
986		sizeof(ntopbuf)), pfx->pfx_prefixlen, rai->rai_ifname);
987
988	/* stop the expiration timer */
989	rtadvd_remove_timer(pfx->pfx_timer);
990	pfx->pfx_timer = NULL;
991}
992
993/*
994 * Try to get an in6_prefixreq contents for a prefix which matches
995 * ipr->ipr_prefix and ipr->ipr_plen and belongs to
996 * the interface whose name is ipr->ipr_name[].
997 */
998static int
999init_prefix(struct in6_prefixreq *ipr)
1000{
1001#if 0
1002	int s;
1003
1004	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1005		syslog(LOG_ERR, "<%s> socket: %s", __func__,
1006		    strerror(errno));
1007		exit(1);
1008	}
1009
1010	if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) {
1011		syslog(LOG_INFO, "<%s> ioctl:SIOCGIFPREFIX %s", __func__,
1012		    strerror(errno));
1013
1014		ipr->ipr_vltime = DEF_ADVVALIDLIFETIME;
1015		ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME;
1016		ipr->ipr_raf_onlink = 1;
1017		ipr->ipr_raf_auto = 1;
1018		/* omit other field initialization */
1019	}
1020	else if (ipr->ipr_origin < PR_ORIG_RR) {
1021		u_char ntopbuf[INET6_ADDRSTRLEN];
1022
1023		syslog(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is"
1024		    "lower than PR_ORIG_RR(router renumbering)."
1025		    "This should not happen if I am router", __func__,
1026		    inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf,
1027			sizeof(ntopbuf)), ipr->ipr_origin);
1028		close(s);
1029		return (1);
1030	}
1031
1032	close(s);
1033	return (0);
1034#else
1035	ipr->ipr_vltime = DEF_ADVVALIDLIFETIME;
1036	ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME;
1037	ipr->ipr_raf_onlink = 1;
1038	ipr->ipr_raf_auto = 1;
1039	return (0);
1040#endif
1041}
1042
1043void
1044make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen)
1045{
1046	struct in6_prefixreq ipr;
1047
1048	memset(&ipr, 0, sizeof(ipr));
1049	if (if_indextoname(ifindex, ipr.ipr_name) == NULL) {
1050		syslog(LOG_ERR, "<%s> Prefix added interface No.%d doesn't"
1051		    "exist. This should not happen! %s", __func__,
1052		    ifindex, strerror(errno));
1053		exit(1);
1054	}
1055	ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix);
1056	ipr.ipr_prefix.sin6_family = AF_INET6;
1057	ipr.ipr_prefix.sin6_addr = *addr;
1058	ipr.ipr_plen = plen;
1059
1060	if (init_prefix(&ipr))
1061		return; /* init failed by some error */
1062	add_prefix(rai, &ipr);
1063}
1064
1065void
1066make_packet(struct rainfo *rai)
1067{
1068	size_t packlen, lladdroptlen = 0;
1069	char *buf;
1070	struct nd_router_advert *ra;
1071	struct nd_opt_prefix_info *ndopt_pi;
1072	struct nd_opt_mtu *ndopt_mtu;
1073#ifdef ROUTEINFO
1074	struct nd_opt_route_info *ndopt_rti;
1075	struct rtinfo *rti;
1076#endif
1077	struct nd_opt_rdnss *ndopt_rdnss;
1078	struct rdnss *rdn;
1079	struct nd_opt_dnssl *ndopt_dnssl;
1080	struct dnssl *dns;
1081	size_t len;
1082	struct prefix *pfx;
1083
1084	/* calculate total length */
1085	packlen = sizeof(struct nd_router_advert);
1086	if (rai->rai_advlinkopt) {
1087		if ((lladdroptlen = lladdropt_length(rai->rai_sdl)) == 0) {
1088			syslog(LOG_INFO,
1089			    "<%s> link-layer address option has"
1090			    " null length on %s.  Treat as not included.",
1091			    __func__, rai->rai_ifname);
1092			rai->rai_advlinkopt = 0;
1093		}
1094		packlen += lladdroptlen;
1095	}
1096	if (rai->rai_pfxs)
1097		packlen += sizeof(struct nd_opt_prefix_info) * rai->rai_pfxs;
1098	if (rai->rai_linkmtu)
1099		packlen += sizeof(struct nd_opt_mtu);
1100#ifdef ROUTEINFO
1101	TAILQ_FOREACH(rti, &rai->rai_route, rti_next)
1102		packlen += sizeof(struct nd_opt_route_info) +
1103			   ((rti->rti_prefixlen + 0x3f) >> 6) * 8;
1104#endif
1105	TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
1106		struct rdnss_addr *rdna;
1107
1108		packlen += sizeof(struct nd_opt_rdnss);
1109		TAILQ_FOREACH(rdna, &rdn->rd_list, ra_next)
1110			packlen += sizeof(rdna->ra_dns);
1111	}
1112	TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) {
1113		struct dnssl_addr *dnsa;
1114
1115		packlen += sizeof(struct nd_opt_dnssl);
1116		len = 0;
1117		TAILQ_FOREACH(dnsa, &dns->dn_list, da_next)
1118			len += dnsa->da_len;
1119
1120		/* A zero octet and 8 octet boundary */
1121		len++;
1122		len += (len % 8) ? 8 - len % 8 : 0;
1123
1124		packlen += len;
1125	}
1126	/* allocate memory for the packet */
1127	if ((buf = malloc(packlen)) == NULL) {
1128		syslog(LOG_ERR,
1129		    "<%s> can't get enough memory for an RA packet",
1130		    __func__);
1131		exit(1);
1132	}
1133	memset(buf, 0, packlen);
1134	if (rai->rai_ra_data)	/* Free old data if any. */
1135		free(rai->rai_ra_data);
1136	rai->rai_ra_data = buf;
1137	/* XXX: what if packlen > 576? */
1138	rai->rai_ra_datalen = packlen;
1139
1140	/*
1141	 * construct the packet
1142	 */
1143	ra = (struct nd_router_advert *)buf;
1144	ra->nd_ra_type = ND_ROUTER_ADVERT;
1145	ra->nd_ra_code = 0;
1146	ra->nd_ra_cksum = 0;
1147	ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rai->rai_hoplimit);
1148	ra->nd_ra_flags_reserved = 0; /* just in case */
1149	/*
1150	 * XXX: the router preference field, which is a 2-bit field, should be
1151	 * initialized before other fields.
1152	 */
1153	ra->nd_ra_flags_reserved = 0xff & rai->rai_rtpref;
1154	ra->nd_ra_flags_reserved |=
1155		rai->rai_managedflg ? ND_RA_FLAG_MANAGED : 0;
1156	ra->nd_ra_flags_reserved |=
1157		rai->rai_otherflg ? ND_RA_FLAG_OTHER : 0;
1158	ra->nd_ra_router_lifetime = htons(rai->rai_lifetime);
1159	ra->nd_ra_reachable = htonl(rai->rai_reachabletime);
1160	ra->nd_ra_retransmit = htonl(rai->rai_retranstimer);
1161	buf += sizeof(*ra);
1162
1163	if (rai->rai_advlinkopt) {
1164		lladdropt_fill(rai->rai_sdl, (struct nd_opt_hdr *)buf);
1165		buf += lladdroptlen;
1166	}
1167
1168	if (rai->rai_linkmtu) {
1169		ndopt_mtu = (struct nd_opt_mtu *)buf;
1170		ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU;
1171		ndopt_mtu->nd_opt_mtu_len = 1;
1172		ndopt_mtu->nd_opt_mtu_reserved = 0;
1173		ndopt_mtu->nd_opt_mtu_mtu = htonl(rai->rai_linkmtu);
1174		buf += sizeof(struct nd_opt_mtu);
1175	}
1176
1177	TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
1178		u_int32_t vltime, pltime;
1179		struct timeval now;
1180
1181		ndopt_pi = (struct nd_opt_prefix_info *)buf;
1182		ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
1183		ndopt_pi->nd_opt_pi_len = 4;
1184		ndopt_pi->nd_opt_pi_prefix_len = pfx->pfx_prefixlen;
1185		ndopt_pi->nd_opt_pi_flags_reserved = 0;
1186		if (pfx->pfx_onlinkflg)
1187			ndopt_pi->nd_opt_pi_flags_reserved |=
1188				ND_OPT_PI_FLAG_ONLINK;
1189		if (pfx->pfx_autoconfflg)
1190			ndopt_pi->nd_opt_pi_flags_reserved |=
1191				ND_OPT_PI_FLAG_AUTO;
1192		if (pfx->pfx_timer)
1193			vltime = 0;
1194		else {
1195			if (pfx->pfx_vltimeexpire || pfx->pfx_pltimeexpire)
1196				gettimeofday(&now, NULL);
1197			if (pfx->pfx_vltimeexpire == 0)
1198				vltime = pfx->pfx_validlifetime;
1199			else
1200				vltime = (pfx->pfx_vltimeexpire > now.tv_sec) ?
1201				    pfx->pfx_vltimeexpire - now.tv_sec : 0;
1202		}
1203		if (pfx->pfx_timer)
1204			pltime = 0;
1205		else {
1206			if (pfx->pfx_pltimeexpire == 0)
1207				pltime = pfx->pfx_preflifetime;
1208			else
1209				pltime = (pfx->pfx_pltimeexpire > now.tv_sec) ?
1210				    pfx->pfx_pltimeexpire - now.tv_sec : 0;
1211		}
1212		if (vltime < pltime) {
1213			/*
1214			 * this can happen if vltime is decrement but pltime
1215			 * is not.
1216			 */
1217			pltime = vltime;
1218		}
1219		ndopt_pi->nd_opt_pi_valid_time = htonl(vltime);
1220		ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime);
1221		ndopt_pi->nd_opt_pi_reserved2 = 0;
1222		ndopt_pi->nd_opt_pi_prefix = pfx->pfx_prefix;
1223
1224		buf += sizeof(struct nd_opt_prefix_info);
1225	}
1226
1227#ifdef ROUTEINFO
1228	TAILQ_FOREACH(rti, &rai->rai_route, rti_next) {
1229		u_int8_t psize = (rti->rti_prefixlen + 0x3f) >> 6;
1230
1231		ndopt_rti = (struct nd_opt_route_info *)buf;
1232		ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO;
1233		ndopt_rti->nd_opt_rti_len = 1 + psize;
1234		ndopt_rti->nd_opt_rti_prefixlen = rti->rti_prefixlen;
1235		ndopt_rti->nd_opt_rti_flags = 0xff & rti->rti_rtpref;
1236		ndopt_rti->nd_opt_rti_lifetime = htonl(rti->rti_ltime);
1237		memcpy(ndopt_rti + 1, &rti->rti_prefix, psize * 8);
1238		buf += sizeof(struct nd_opt_route_info) + psize * 8;
1239	}
1240#endif
1241	TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
1242		struct rdnss_addr *rdna;
1243
1244		ndopt_rdnss = (struct nd_opt_rdnss *)buf;
1245		ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS;
1246		ndopt_rdnss->nd_opt_rdnss_len = 0;
1247		ndopt_rdnss->nd_opt_rdnss_reserved = 0;
1248		ndopt_rdnss->nd_opt_rdnss_lifetime = htonl(rdn->rd_ltime);
1249		buf += sizeof(struct nd_opt_rdnss);
1250
1251		TAILQ_FOREACH(rdna, &rdn->rd_list, ra_next) {
1252			memcpy(buf, &rdna->ra_dns, sizeof(rdna->ra_dns));
1253			buf += sizeof(rdna->ra_dns);
1254		}
1255		/* Length field should be in 8 octets */
1256		ndopt_rdnss->nd_opt_rdnss_len = (buf - (char *)ndopt_rdnss) / 8;
1257
1258		syslog(LOG_DEBUG, "<%s>: nd_opt_dnss_len = %d", __func__,
1259		    ndopt_rdnss->nd_opt_rdnss_len);
1260	}
1261	TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) {
1262		struct dnssl_addr *dnsa;
1263
1264		ndopt_dnssl = (struct nd_opt_dnssl *)buf;
1265		ndopt_dnssl->nd_opt_dnssl_type = ND_OPT_DNSSL;
1266		ndopt_dnssl->nd_opt_dnssl_len = 0;
1267		ndopt_dnssl->nd_opt_dnssl_reserved = 0;
1268		ndopt_dnssl->nd_opt_dnssl_lifetime = htonl(dns->dn_ltime);
1269		buf += sizeof(*ndopt_dnssl);
1270
1271		TAILQ_FOREACH(dnsa, &dns->dn_list, da_next) {
1272			memcpy(buf, dnsa->da_dom, dnsa->da_len);
1273			buf += dnsa->da_len;
1274		}
1275
1276		/* A zero octet after encoded DNS server list. */
1277		*buf++ = '\0';
1278
1279		/* Padding to next 8 octets boundary */
1280		len = buf - (char *)ndopt_dnssl;
1281		len += (len % 8) ? 8 - len % 8 : 0;
1282
1283		/* Length field must be in 8 octets */
1284		ndopt_dnssl->nd_opt_dnssl_len = len / 8;
1285
1286		syslog(LOG_DEBUG, "<%s>: nd_opt_dnssl_len = %d", __func__,
1287		    ndopt_dnssl->nd_opt_dnssl_len);
1288	}
1289	return;
1290}
1291