xref: /netbsd-src/usr.sbin/rtadvd/rtadvd.c (revision 95d875fb90b1458e4f1de6950286ddcd6644bc61)
1 /*	$NetBSD: rtadvd.c,v 1.4 1999/12/10 05:47:51 itojun Exp $	*/
2 
3 /*
4  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the project nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/param.h>
33 #include <sys/socket.h>
34 #include <sys/uio.h>
35 #include <sys/time.h>
36 
37 #include <net/if.h>
38 #include <net/route.h>
39 #include <net/if_dl.h>
40 #include <netinet/in.h>
41 #include <netinet/ip6.h>
42 #include <netinet6/ip6_var.h>
43 #include <netinet/icmp6.h>
44 
45 #include <arpa/inet.h>
46 
47 #include <time.h>
48 #include <unistd.h>
49 #include <stdio.h>
50 #include <err.h>
51 #include <errno.h>
52 #include <string.h>
53 #include <stdlib.h>
54 #include <syslog.h>
55 #include "rtadvd.h"
56 #include "rrenum.h"
57 #include "advcap.h"
58 #include "timer.h"
59 #include "if.h"
60 #include "config.h"
61 
62 struct msghdr rcvmhdr;
63 static u_char rcvcmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo)) +
64 			CMSG_SPACE(sizeof(int))];
65 struct msghdr sndmhdr;
66 struct iovec rcviov[2];
67 struct iovec sndiov[2];
68 struct sockaddr_in6 from;
69 struct sockaddr_in6 sin6_allnodes = {sizeof(sin6_allnodes), AF_INET6};
70 int sock, rtsock;
71 int accept_rr = 1;
72 int dflag = 0, sflag = 0;
73 
74 u_char *conffile = NULL;
75 
76 struct rainfo *ralist = NULL;
77 struct nd_optlist {
78 	struct nd_optlist *next;
79 	struct nd_opt_hdr *opt;
80 };
81 union nd_opts {
82 	struct nd_opt_hdr *nd_opt_array[7];
83 	struct {
84 		struct nd_opt_hdr *zero;
85 		struct nd_opt_hdr *src_lladdr;
86 		struct nd_opt_hdr *tgt_lladdr;
87 		struct nd_opt_prefix_info *pi;
88 		struct nd_opt_rd_hdr *rh;
89 		struct nd_opt_mtu *mtu;
90 		struct nd_optlist *list;
91 	} nd_opt_each;
92 };
93 #define nd_opts_src_lladdr	nd_opt_each.src_lladdr
94 #define nd_opts_tgt_lladdr	nd_opt_each.tgt_lladdr
95 #define nd_opts_pi		nd_opt_each.pi
96 #define nd_opts_rh		nd_opt_each.rh
97 #define nd_opts_mtu		nd_opt_each.mtu
98 #define nd_opts_list		nd_opt_each.list
99 
100 #define NDOPT_FLAG_SRCLINKADDR 0x1
101 #define NDOPT_FLAG_TGTLINKADDR 0x2
102 #define NDOPT_FLAG_PREFIXINFO 0x4
103 #define NDOPT_FLAG_RDHDR 0x8
104 #define NDOPT_FLAG_MTU 0x10
105 
106 u_int32_t ndopt_flags[] = {
107 	0, NDOPT_FLAG_SRCLINKADDR, NDOPT_FLAG_TGTLINKADDR,
108 	NDOPT_FLAG_PREFIXINFO, NDOPT_FLAG_RDHDR, NDOPT_FLAG_MTU
109 };
110 
111 int main __P((int, char *[]));
112 static void sock_open __P((void));
113 static void rtsock_open __P((void));
114 static void rtadvd_input __P((void));
115 static void rs_input __P((int, struct nd_router_solicit *,
116 			  struct in6_pktinfo *, struct sockaddr_in6 *));
117 static void ra_input __P((int, struct nd_router_advert *,
118 			  struct in6_pktinfo *, struct sockaddr_in6 *));
119 static void prefix_check __P((struct nd_opt_prefix_info *, struct rainfo *,
120 			      struct sockaddr_in6 *));
121 static int nd6_options __P((struct nd_opt_hdr *, int,
122 			    union nd_opts *, u_int32_t));
123 static void free_ndopts __P((union nd_opts *));
124 static struct rainfo *if_indextorainfo __P((int));
125 static void ra_output __P((struct rainfo *));
126 static void rtmsg_input __P((void));
127 struct prefix *find_prefix __P((struct rainfo *, struct in6_addr *, int));
128 
129 
130 int
131 main(argc, argv)
132 	int argc;
133 	char *argv[];
134 {
135 	fd_set fdset;
136 	int maxfd = 0;
137 	struct timeval *timeout;
138 	int i, ch;
139 	int fflag = 0;
140 
141 	openlog(*argv, LOG_NDELAY|LOG_PID, LOG_DAEMON);
142 
143 	/* get command line options and arguments */
144 	while ((ch = getopt(argc, argv, "c:dDfs")) != -1) {
145 		switch(ch) {
146 		 case 'c':
147 			 conffile = optarg;
148 			 break;
149 		 case 'd':
150 			 dflag = 1;
151 			 break;
152 		 case 'D':
153 			 dflag = 2;
154 			 break;
155 		 case 'f':
156 			 fflag = 1;
157 			 break;
158 		 case 's':
159 			 sflag = 1;
160 		}
161 	}
162 	argc -= optind;
163 	argv += optind;
164 	if (argc == 0) {
165 		fprintf(stderr,
166 			"usage: rtadvd [-c conffile] [-d|D] [-f] [-s]"
167 			"interfaces...\n");
168 		exit(1);
169 	}
170 
171 	/* set log level */
172 	if (dflag == 0)
173 		(void)setlogmask(LOG_UPTO(LOG_ERR));
174 	if (dflag == 1)
175 		(void)setlogmask(LOG_UPTO(LOG_INFO));
176 
177 	/* timer initialization */
178 	rtadvd_timer_init();
179 
180 	/* random value initialization */
181 	srandom((u_long)time(NULL));
182 
183 	/* get iflist block from kernel */
184 	init_iflist();
185 
186 	while (argc--)
187 		getconfig(*argv++);
188 
189 	if (inet_pton(AF_INET6, ALLNODES, &sin6_allnodes.sin6_addr) != 1) {
190 		fprintf(stderr, "fatal: inet_pton failed\n");
191 		exit(1);
192 	}
193 	sock_open();
194 
195 	if (!fflag)
196 		daemon(1, 0);
197 
198 	FD_ZERO(&fdset);
199 	FD_SET(sock, &fdset);
200 	maxfd = sock;
201 	if (sflag == 0) {
202 		rtsock_open();
203 		FD_SET(rtsock, &fdset);
204 		if (rtsock > sock)
205 			maxfd = rtsock;
206 	}
207 
208 	while (1) {
209 		struct fd_set select_fd = fdset; /* reinitialize */
210 
211 		/* timer expiration check and reset the timer */
212 		timeout = rtadvd_check_timer();
213 
214 		syslog(LOG_DEBUG,
215 		       "<%s> set timer to %ld:%ld. waiting for inputs "
216 		       "or timeout",
217 		       __FUNCTION__,
218 		       timeout->tv_sec, timeout->tv_usec);
219 
220 		if ((i = select(maxfd + 1, &select_fd,
221 				NULL, NULL, timeout)) < 0){
222 			syslog(LOG_ERR, "<%s> select: %s",
223 			       __FUNCTION__, strerror(errno));
224 			continue;
225 		}
226 		if (i == 0)	/* timeout */
227 			continue;
228 		if (sflag == 0 && FD_ISSET(rtsock, &select_fd))
229 			rtmsg_input();
230 		if (FD_ISSET(sock, &select_fd))
231 			rtadvd_input();
232 	}
233 	exit(0);		/* NOTREACHED */
234 }
235 
236 static void
237 rtmsg_input()
238 {
239 	int n, type, ifindex, plen;
240 	size_t len;
241 	char msg[2048], *next, *lim;
242 	u_char ifname[16];
243 	struct prefix *prefix;
244 	struct rainfo *rai;
245 	struct in6_addr *addr;
246 	char addrbuf[INET6_ADDRSTRLEN];
247 
248 	n = read(rtsock, msg, 2048);
249 	if (dflag > 1) {
250 		syslog(LOG_DEBUG,
251 		       "<%s> received a routing message "
252 		       "(type = %d, len = %d)",
253 		       __FUNCTION__,
254 		       rtmsg_type(msg), n);
255 	}
256 	if (n > rtmsg_len(msg)) {
257 		/*
258 		 * This usually won't happen for messages received on
259 		 * an routing socket.
260 		 */
261 		if (dflag > 1)
262 			syslog(LOG_DEBUG,
263 			       "<%s> received data length is larger than"
264 			       "1st routing message len. multiple messages?"
265 			       " read %d bytes, but 1st msg len = %d",
266 			       __FUNCTION__, n, rtmsg_len(msg));
267 #if 0
268 		/* adjust length */
269 		n = rtmsg_len(msg);
270 #endif
271 	}
272 
273 	lim = msg + n;
274 	for (next = msg; next < lim; next += len) {
275 		next = get_next_msg(next, lim, 0, &len,
276 				    RTADV_TYPE2BITMASK(RTM_ADD) |
277 				    RTADV_TYPE2BITMASK(RTM_DELETE) |
278 				    RTADV_TYPE2BITMASK(RTM_NEWADDR) |
279 				    RTADV_TYPE2BITMASK(RTM_DELADDR) |
280 				    RTADV_TYPE2BITMASK(RTM_IFINFO));
281 		if (len == 0)
282 			break;
283 		type = rtmsg_type(next);
284 		switch (type) {
285 		case RTM_ADD:
286 		case RTM_DELETE:
287 			ifindex = get_rtm_ifindex(next);
288 			break;
289 		case RTM_NEWADDR:
290 		case RTM_DELADDR:
291 			ifindex = get_ifam_ifindex(next);
292 			break;
293 		case RTM_IFINFO:
294 			ifindex = get_ifm_ifindex(next);
295 			break;
296 		default:
297 			/* should not reach here */
298 			if (dflag > 1) {
299 				syslog(LOG_DEBUG,
300 				       "<%s:%d> unknown rtmsg %d on %s",
301 				       __FUNCTION__, __LINE__, type,
302 				       if_indextoname(ifindex, ifname));
303 			}
304 			return;
305 		}
306 
307 		if ((rai = if_indextorainfo(ifindex)) == NULL) {
308 			if (dflag > 1) {
309 				syslog(LOG_DEBUG,
310 				       "<%s> route changed on "
311 				       "non advertising interface(%s)",
312 				       __FUNCTION__,
313 				       if_indextoname(ifindex, ifname));
314 			}
315 			return;
316 		}
317 
318 		switch(type) {
319 		 case RTM_ADD:
320 			 /* init iffalgs because it may have changed */
321 			 iflist[ifindex]->ifm_flags =
322 			 	if_getflags(ifindex,
323 					    iflist[ifindex]->ifm_flags);
324 
325 			 addr = get_addr(msg);
326 			 plen = get_prefixlen(msg);
327 			 /* sanity check for plen */
328 			 if (plen < 4 /* as RFC2373, prefixlen is at least 4 */
329 			     || plen > 127) {
330 				syslog(LOG_INFO, "<%s> new interface route's"
331 				       "plen %d is invalid for a prefix",
332 				       __FUNCTION__, plen);
333 				return;
334 			 }
335 			 prefix = find_prefix(rai, addr, plen);
336 			 if (prefix) {
337 				 if (dflag > 1) {
338 					 syslog(LOG_DEBUG,
339 						"<%s> new prefix(%s/%d) "
340 						"added on %s, "
341 						"but it was already in list",
342 						__FUNCTION__,
343 						inet_ntop(AF_INET6,
344 							  addr, (char *)addrbuf,
345 							  INET6_ADDRSTRLEN),
346 						plen,
347 						rai->ifname);
348 				 }
349 				 return;
350 			 }
351 			 make_prefix(rai, ifindex, addr, plen);
352 			 break;
353 		 case RTM_DELETE:
354 			 /* init ifflags because it may have changed */
355 			 iflist[ifindex]->ifm_flags =
356 			 	if_getflags(ifindex,
357 					    iflist[ifindex]->ifm_flags);
358 
359 			 addr = get_addr(msg);
360 			 plen = get_prefixlen(msg);
361 			 /* sanity check for plen */
362 			 if (plen < 4 /* as RFC2373, prefixlen is at least 4 */
363 			     || plen > 127) {
364 				syslog(LOG_INFO, "<%s> deleted interface"
365 				       "route's"
366 				       "plen %d is invalid for a prefix",
367 				       __FUNCTION__, plen);
368 				return;
369 			 }
370 			 prefix = find_prefix(rai, addr, plen);
371 			 if (prefix == NULL) {
372 				 if (dflag > 1) {
373 					 syslog(LOG_DEBUG,
374 						"<%s> prefix(%s/%d) was "
375 						"deleted on %s, "
376 						"but it was not in list",
377 						__FUNCTION__,
378 						inet_ntop(AF_INET6,
379 							  addr, (char *)addrbuf,
380 							  INET6_ADDRSTRLEN),
381 						plen,
382 						rai->ifname);
383 				 }
384 				 return;
385 			 }
386 			 delete_prefix(rai, prefix);
387 			 break;
388 		case RTM_NEWADDR:
389 		case RTM_DELADDR:
390 			 /* init ifflags because it may have changed */
391 			 iflist[ifindex]->ifm_flags =
392 			 	if_getflags(ifindex,
393 					    iflist[ifindex]->ifm_flags);
394 			 break;
395 		case RTM_IFINFO:
396 			 iflist[ifindex]->ifm_flags = get_ifm_flags(next);
397 			 break;
398 		default:
399 			/* should not reach here */
400 			if (dflag > 1) {
401 				syslog(LOG_DEBUG,
402 				       "<%s:%d> unknown rtmsg %d on %s",
403 				       __FUNCTION__, __LINE__, type,
404 				       if_indextoname(ifindex, ifname));
405 			}
406 			return;
407 		}
408 	}
409 
410 	return;
411 }
412 
413 void
414 rtadvd_input()
415 {
416 	int i;
417 	int *hlimp = NULL;
418 #ifdef OLDRAWSOCKET
419 	struct ip6_hdr *ip;
420 #endif
421 	struct icmp6_hdr *icp;
422 	int ifindex = 0;
423 	struct cmsghdr *cm;
424 	struct in6_pktinfo *pi = NULL;
425 	u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
426 	struct in6_addr dst = in6addr_any;
427 
428 	/*
429 	 * Get message. We reset msg_controllen since the field could
430 	 * be modified if we had received a message before setting
431 	 * receive options.
432 	 */
433 	rcvmhdr.msg_controllen = sizeof(rcvcmsgbuf);
434 	if ((i = recvmsg(sock, &rcvmhdr, 0)) < 0)
435 		return;
436 
437 	/* extract optional information via Advanced API */
438 	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmhdr);
439 	     cm;
440 	     cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvmhdr, cm)) {
441 		if (cm->cmsg_level == IPPROTO_IPV6 &&
442 		    cm->cmsg_type == IPV6_PKTINFO &&
443 		    cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) {
444 			pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
445 			ifindex = pi->ipi6_ifindex;
446 			dst = pi->ipi6_addr;
447 		}
448 		if (cm->cmsg_level == IPPROTO_IPV6 &&
449 		    cm->cmsg_type == IPV6_HOPLIMIT &&
450 		    cm->cmsg_len == CMSG_LEN(sizeof(int)))
451 			hlimp = (int *)CMSG_DATA(cm);
452 	}
453 	if (ifindex == 0) {
454 		syslog(LOG_ERR,
455 		       "<%s> failed to get receiving interface",
456 		       __FUNCTION__);
457 		return;
458 	}
459 	if (hlimp == NULL) {
460 		syslog(LOG_ERR,
461 		       "<%s> failed to get receiving hop limit",
462 		       __FUNCTION__);
463 		return;
464 	}
465 
466 #ifdef OLDRAWSOCKET
467 	if (i < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)) {
468 		syslog(LOG_ERR,
469 		       "<%s> packet size(%d) is too short",
470 		       __FUNCTION__, i);
471 		return;
472 	}
473 
474 	ip = (struct ip6_hdr *)rcvmhdr.msg_iov[0].iov_base;
475 	icp = (struct icmp6_hdr *)(ip + 1); /* XXX: ext. hdr? */
476 #else
477 	if (i < sizeof(struct icmp6_hdr)) {
478 		syslog(LOG_ERR,
479 		       "<%s> packet size(%d) is too short",
480 		       __FUNCTION__, i);
481 		return;
482 	}
483 
484 	icp = (struct icmp6_hdr *)rcvmhdr.msg_iov[0].iov_base;
485 #endif
486 
487 	switch(icp->icmp6_type) {
488 	 case ND_ROUTER_SOLICIT:
489 		 /*
490 		  * Message verification - RFC-2461 6.1.1
491 		  * XXX: these checks must be done in the kernel as well,
492 		  *      but we can't completely rely on them.
493 		  */
494 		 if (*hlimp != 255) {
495 			 syslog(LOG_NOTICE,
496 				"<%s> RS with invalid hop limit(%d) "
497 				"received from %s on %s",
498 				__FUNCTION__, *hlimp,
499 				inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
500 					  INET6_ADDRSTRLEN),
501 				if_indextoname(pi->ipi6_ifindex, ifnamebuf));
502 			 return;
503 		 }
504 		 if (icp->icmp6_code) {
505 			 syslog(LOG_NOTICE,
506 				"<%s> RS with invalid ICMP6 code(%d) "
507 				"received from %s on %s",
508 				__FUNCTION__, icp->icmp6_code,
509 				inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
510 					  INET6_ADDRSTRLEN),
511 				if_indextoname(pi->ipi6_ifindex, ifnamebuf));
512 			 return;
513 		 }
514 		 if (i < sizeof(struct nd_router_solicit)) {
515 			 syslog(LOG_NOTICE,
516 				"<%s> RS from %s on %s does not have enough "
517 				"length (len = %d)",
518 				__FUNCTION__,
519 				inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
520 					  INET6_ADDRSTRLEN),
521 				if_indextoname(pi->ipi6_ifindex, ifnamebuf), i);
522 			 return;
523 		 }
524 		 rs_input(i, (struct nd_router_solicit *)icp, pi, &from);
525 		 break;
526 	 case ND_ROUTER_ADVERT:
527 		 /*
528 		  * Message verification - RFC-2461 6.1.2
529 		  * XXX: there's a same dilemma as above...
530 		  */
531 		 if (*hlimp != 255) {
532 			 syslog(LOG_NOTICE,
533 				"<%s> RA with invalid hop limit(%d) "
534 				"received from %s on %s",
535 				__FUNCTION__, *hlimp,
536 				inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
537 					  INET6_ADDRSTRLEN),
538 				if_indextoname(pi->ipi6_ifindex, ifnamebuf));
539 			 return;
540 		 }
541 		 if (icp->icmp6_code) {
542 			 syslog(LOG_NOTICE,
543 				"<%s> RA with invalid ICMP6 code(%d) "
544 				"received from %s on %s",
545 				__FUNCTION__, icp->icmp6_code,
546 				inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
547 					  INET6_ADDRSTRLEN),
548 				if_indextoname(pi->ipi6_ifindex, ifnamebuf));
549 			 return;
550 		 }
551 		 if (i < sizeof(struct nd_router_advert)) {
552 			 syslog(LOG_NOTICE,
553 				"<%s> RA from %s on %s does not have enough "
554 				"length (len = %d)",
555 				__FUNCTION__,
556 				inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
557 					  INET6_ADDRSTRLEN),
558 				if_indextoname(pi->ipi6_ifindex, ifnamebuf), i);
559 			 return;
560 		 }
561 		 ra_input(i, (struct nd_router_advert *)icp, pi, &from);
562 		 break;
563 	 case ICMP6_ROUTER_RENUMBERING:
564 		 if (accept_rr == 0) {
565 			 syslog(LOG_ERR,
566 				"<%s> received a router renumbering "
567 				"message, but not allowed to be accepted",
568 				__FUNCTION__);
569 			 break;
570 		 }
571 		 rr_input(i, (struct icmp6_router_renum *)icp, pi, &from,
572 			  &dst);
573 		 break;
574 	 default:
575 		 /*
576 		  * Note that this case is POSSIBLE, especially just
577 		  * after invocation of the daemon. This is because we
578 		  * could receive message after opening the socket and
579 		  * before setting ICMP6 type filter(see sock_open()).
580 		  */
581 		 syslog(LOG_ERR,
582 			"<%s> invalid icmp type(%d)",
583 			__FUNCTION__, icp->icmp6_type);
584 		 return;
585 	}
586 
587 	return;
588 }
589 
590 static void
591 rs_input(int len, struct nd_router_solicit *rs,
592 	 struct in6_pktinfo *pi, struct sockaddr_in6 *from)
593 {
594 	u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
595 	union nd_opts ndopts;
596 	struct rainfo *ra;
597 
598 	syslog(LOG_DEBUG,
599 	       "<%s> RS received from %s on %s",
600 	       __FUNCTION__,
601 	       inet_ntop(AF_INET6, &from->sin6_addr,
602 			 ntopbuf, INET6_ADDRSTRLEN),
603 	       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
604 
605 	/* ND option check */
606 	memset(&ndopts, 0, sizeof(ndopts));
607 	if (nd6_options((struct nd_opt_hdr *)(rs + 1),
608 			len - sizeof(struct nd_router_solicit),
609 			 &ndopts, NDOPT_FLAG_SRCLINKADDR)) {
610 		syslog(LOG_DEBUG,
611 		       "<%s> ND option check failed for an RS from %s on %s",
612 		       __FUNCTION__,
613 		       inet_ntop(AF_INET6, &from->sin6_addr,
614 				 ntopbuf, INET6_ADDRSTRLEN),
615 		       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
616 		return;
617 	}
618 
619 	/*
620 	 * If the IP source address is the unspecified address, there
621 	 * must be no source link-layer address option in the message.
622 	 * (RFC-2461 6.1.1)
623 	 */
624 	if (IN6_IS_ADDR_UNSPECIFIED(&from->sin6_addr) &&
625 	    ndopts.nd_opts_src_lladdr) {
626 		syslog(LOG_ERR,
627 		       "<%s> RS from unspecified src on %s has a link-layer"
628 		       " address option",
629 		       __FUNCTION__,
630 		       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
631 		goto done;
632 	}
633 
634 	ra = ralist;
635 	while (ra != NULL) {
636 		if (pi->ipi6_ifindex == ra->ifindex)
637 			break;
638 		ra = ra->next;
639 	}
640 	if (ra == NULL) {
641 		syslog(LOG_INFO,
642 		       "<%s> RS received on non advertising interface(%s)",
643 		       __FUNCTION__,
644 		       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
645 		goto done;
646 	}
647 
648 	/*
649 	 * Decide whether to send RA according to the rate-limit
650 	 * consideration.
651 	 */
652 	{
653 		long delay;	/* must not be greater than 1000000 */
654 		struct timeval interval, now, min_delay, tm_tmp, *rest;
655 
656 		/*
657 		 * If there is already a waiting RS packet, don't
658 		 * update the timer.
659 		 */
660 		if (ra->waiting++)
661 			goto done;
662 
663 		/*
664 		 * Compute a random delay. If the computed value
665 		 * corresponds to a time later than the time the next
666 		 * multicast RA is scheduled to be sent, ignore the random
667 		 * delay and send the advertisement at the
668 		 * already-scheduled time. RFC-2461 6.2.6
669 		 */
670 		delay = random() % MAX_RA_DELAY_TIME;
671 		interval.tv_sec = 0;
672 		interval.tv_usec = delay;
673 		rest = rtadvd_timer_rest(ra->timer);
674 		if (TIMEVAL_LT(*rest, interval)) {
675 			syslog(LOG_DEBUG,
676 			       "<%s> random delay is larger than "
677 			       "the rest of normal timer",
678 			       __FUNCTION__);
679 			interval = *rest;
680 		}
681 
682 		/*
683 		 * If we sent a multicast Router Advertisement within
684 		 * the last MIN_DELAY_BETWEEN_RAS seconds, schedule
685 		 * the advertisement to be sent at a time corresponding to
686 		 * MIN_DELAY_BETWEEN_RAS plus the random value after the
687 		 * previous advertisement was sent.
688 		 */
689 		gettimeofday(&now, NULL);
690 		TIMEVAL_SUB(&now, &ra->lastsent, &tm_tmp);
691 		min_delay.tv_sec = MIN_DELAY_BETWEEN_RAS;
692 		min_delay.tv_usec = 0;
693 		if (TIMEVAL_LT(tm_tmp, min_delay)) {
694 			TIMEVAL_SUB(&min_delay, &tm_tmp, &min_delay);
695 			TIMEVAL_ADD(&min_delay, &interval, &interval);
696 		}
697 		rtadvd_set_timer(&interval, ra->timer);
698 			goto done;
699 	}
700 
701   done:
702 	free_ndopts(&ndopts);
703 	return;
704 }
705 
706 static void
707 ra_input(int len, struct nd_router_advert *ra,
708 	 struct in6_pktinfo *pi, struct sockaddr_in6 *from)
709 {
710 	struct rainfo *rai;
711 	u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
712 	union nd_opts ndopts;
713 	char *on_off[] = {"OFF", "ON"};
714 	u_int32_t reachabletime, retranstimer, mtu;
715 
716 	syslog(LOG_DEBUG,
717 	       "<%s> RA received from %s on %s",
718 	       __FUNCTION__,
719 	       inet_ntop(AF_INET6, &from->sin6_addr,
720 			 ntopbuf, INET6_ADDRSTRLEN),
721 	       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
722 
723 	/* ND option check */
724 	memset(&ndopts, 0, sizeof(ndopts));
725 	if (nd6_options((struct nd_opt_hdr *)(ra + 1),
726 			len - sizeof(struct nd_router_advert),
727 			 &ndopts,
728 			NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU)) {
729 		syslog(LOG_ERR,
730 		       "<%s> ND option check failed for an RA from %s on %s",
731 		       __FUNCTION__,
732 		       inet_ntop(AF_INET6, &from->sin6_addr,
733 				 ntopbuf, INET6_ADDRSTRLEN),
734 		       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
735 		return;
736 	}
737 
738 	/*
739 	 * RA consistency check according to RFC-2461 6.2.7
740 	 */
741 	if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == 0) {
742 		syslog(LOG_INFO,
743 		       "<%s> received RA from %s on non-advertising"
744 		       " interface(%s)",
745 		       __FUNCTION__,
746 		       inet_ntop(AF_INET6, &from->sin6_addr,
747 				 ntopbuf, INET6_ADDRSTRLEN),
748 		       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
749 		goto done;
750 	}
751 	/* Cur Hop Limit value */
752 	if (ra->nd_ra_curhoplimit && rai->hoplimit &&
753 	    ra->nd_ra_curhoplimit != rai->hoplimit) {
754 		syslog(LOG_WARNING,
755 		       "<%s> CurHopLimit inconsistent on %s:"
756 		       " %d from %s, %d from us",
757 		       __FUNCTION__,
758 		       rai->ifname,
759 		       ra->nd_ra_curhoplimit,
760 		       inet_ntop(AF_INET6, &from->sin6_addr,
761 				 ntopbuf, INET6_ADDRSTRLEN),
762 		       rai->hoplimit);
763 	}
764 	/* M flag */
765 	if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) !=
766 	    rai->managedflg) {
767 		syslog(LOG_WARNING,
768 		       "<%s> M flag inconsistent on %s:"
769 		       " %s from %s, %s from us",
770 		       __FUNCTION__,
771 		       rai->ifname,
772 		       on_off[!rai->managedflg],
773 		       inet_ntop(AF_INET6, &from->sin6_addr,
774 				 ntopbuf, INET6_ADDRSTRLEN),
775 		       on_off[rai->managedflg]);
776 	}
777 	/* O flag */
778 	if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) !=
779 	    rai->otherflg) {
780 		syslog(LOG_WARNING,
781 		       "<%s> O flag inconsistent on %s:"
782 		       " %s from %s, %s from us",
783 		       __FUNCTION__,
784 		       rai->ifname,
785 		       on_off[!rai->otherflg],
786 		       inet_ntop(AF_INET6, &from->sin6_addr,
787 				 ntopbuf, INET6_ADDRSTRLEN),
788 		       on_off[rai->otherflg]);
789 	}
790 	/* Reachable Time */
791 	reachabletime = ntohl(ra->nd_ra_reachable);
792 	if (reachabletime && rai->reachabletime &&
793 	    reachabletime != rai->reachabletime) {
794 		syslog(LOG_WARNING,
795 		       "<%s> ReachableTime inconsistent on %s:"
796 		       " %d from %s, %d from us",
797 		       __FUNCTION__,
798 		       rai->ifname,
799 		       reachabletime,
800 		       inet_ntop(AF_INET6, &from->sin6_addr,
801 				 ntopbuf, INET6_ADDRSTRLEN),
802 		       rai->reachabletime);
803 	}
804 	/* Retrans Timer */
805 	retranstimer = ntohl(ra->nd_ra_retransmit);
806 	if (retranstimer && rai->retranstimer &&
807 	    retranstimer != rai->retranstimer) {
808 		syslog(LOG_WARNING,
809 		       "<%s> RetranceTimer inconsistent on %s:"
810 		       " %d from %s, %d from us",
811 		       __FUNCTION__,
812 		       rai->ifname,
813 		       retranstimer,
814 		       inet_ntop(AF_INET6, &from->sin6_addr,
815 				 ntopbuf, INET6_ADDRSTRLEN),
816 		       rai->retranstimer);
817 	}
818 	/* Values in the MTU options */
819 	if (ndopts.nd_opts_mtu) {
820 		mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu);
821 		if (mtu && rai->linkmtu && mtu != rai->linkmtu) {
822 			syslog(LOG_WARNING,
823 			       "<%s> MTU option value inconsistent on %s:"
824 			       " %d from %s, %d from us",
825 			       __FUNCTION__,
826 			       rai->ifname, mtu,
827 			       inet_ntop(AF_INET6, &from->sin6_addr,
828 					 ntopbuf, INET6_ADDRSTRLEN),
829 			       rai->linkmtu);
830 		}
831 	}
832 	/* Preferred and Valid Lifetimes for prefixes */
833 	{
834 		struct nd_optlist *optp = ndopts.nd_opts_list;
835 
836 		if (ndopts.nd_opts_pi)
837 			prefix_check(ndopts.nd_opts_pi, rai, from);
838 		while (optp) {
839 			prefix_check((struct nd_opt_prefix_info *)optp->opt,
840 				     rai, from);
841 			optp = optp->next;
842 		}
843 	}
844 
845   done:
846 	free_ndopts(&ndopts);
847 	return;
848 }
849 
850 static void
851 prefix_check(struct nd_opt_prefix_info *pinfo,
852 	     struct rainfo *rai, struct sockaddr_in6 *from)
853 {
854 	u_int32_t preferred_time, valid_time;
855 	struct prefix *pp;
856 	u_char ntopbuf[INET6_ADDRSTRLEN], prefixbuf[INET6_ADDRSTRLEN];
857 
858 #if 0				/* impossible */
859 	if (pinfo->nd_opt_pi_type != ND_OPT_PREFIX_INFORMATION)
860 		return;
861 #endif
862 
863 	/*
864 	 * log if the adveritsed prefix has link-local scope(sanity check?)
865 	 */
866 	if (IN6_IS_ADDR_LINKLOCAL(&pinfo->nd_opt_pi_prefix)) {
867 		syslog(LOG_INFO,
868 		       "<%s> link-local prefix %s/%d is advertised "
869 		       "from %s on %s",
870 		       __FUNCTION__,
871 		       inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
872 				 prefixbuf, INET6_ADDRSTRLEN),
873 		       pinfo->nd_opt_pi_prefix_len,
874 		       inet_ntop(AF_INET6, &from->sin6_addr,
875 				 ntopbuf, INET6_ADDRSTRLEN),
876 		       rai->ifname);
877 	}
878 
879 	if ((pp = find_prefix(rai, &pinfo->nd_opt_pi_prefix,
880 			      pinfo->nd_opt_pi_prefix_len)) == NULL) {
881 		syslog(LOG_INFO,
882 		       "<%s> prefix %s/%d from %s on %s is not in our list",
883 		       __FUNCTION__,
884 		       inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
885 				 prefixbuf, INET6_ADDRSTRLEN),
886 		       pinfo->nd_opt_pi_prefix_len,
887 		       inet_ntop(AF_INET6, &from->sin6_addr,
888 				 ntopbuf, INET6_ADDRSTRLEN),
889 		       rai->ifname);
890 		return;
891 	}
892 
893 	preferred_time = ntohl(pinfo->nd_opt_pi_preferred_time);
894 	if (preferred_time != pp->preflifetime)
895 		syslog(LOG_WARNING,
896 		       "<%s> prefeerred lifetime for %s/%d"
897 		       " inconsistent on %s:"
898 		       " %d from %s, %d from us",
899 		       __FUNCTION__,
900 		       inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
901 				 prefixbuf, INET6_ADDRSTRLEN),
902 		       pinfo->nd_opt_pi_prefix_len,
903 		       rai->ifname, preferred_time,
904 		       inet_ntop(AF_INET6, &from->sin6_addr,
905 				 ntopbuf, INET6_ADDRSTRLEN),
906 		       pp->preflifetime);
907 
908 	valid_time = ntohl(pinfo->nd_opt_pi_valid_time);
909 	if (valid_time != pp->validlifetime)
910 		syslog(LOG_WARNING,
911 		       "<%s> valid lifetime for %s/%d"
912 		       " inconsistent on %s:"
913 		       " %d from %s, %d from us",
914 		       __FUNCTION__,
915 		       inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
916 				 prefixbuf, INET6_ADDRSTRLEN),
917 		       pinfo->nd_opt_pi_prefix_len,
918 		       rai->ifname, valid_time,
919 		       inet_ntop(AF_INET6, &from->sin6_addr,
920 				 ntopbuf, INET6_ADDRSTRLEN),
921 		       pp->validlifetime);
922 }
923 
924 struct prefix *
925 find_prefix(struct rainfo *rai, struct in6_addr *prefix, int plen)
926 {
927 	struct prefix *pp;
928 	int bytelen, bitlen;
929 
930 	for (pp = rai->prefix.next; pp != &rai->prefix; pp = pp->next) {
931 		if (plen != pp->prefixlen)
932 			continue;
933 		bytelen = plen / 8;
934 		bitlen = plen % 8;
935 		if (memcmp((void *)prefix, (void *)&pp->prefix, bytelen))
936 			continue;
937 		if (prefix->s6_addr[bytelen] >> (8 - bitlen) ==
938 		    pp->prefix.s6_addr[bytelen] >> (8 - bitlen))
939 			return(pp);
940 	}
941 
942 	return(NULL);
943 }
944 
945 static int
946 nd6_options(struct nd_opt_hdr *hdr, int limit,
947 	    union nd_opts *ndopts, u_int32_t optflags)
948 {
949 	int optlen = 0;
950 
951 	for (; limit > 0; limit -= optlen) {
952 		hdr = (struct nd_opt_hdr *)((caddr_t)hdr + optlen);
953 		optlen = hdr->nd_opt_len << 3;
954 		if (hdr->nd_opt_len == 0) {
955 			syslog(LOG_ERR,
956 			       "<%s> bad ND option length(0) (type = %d)",
957 			       __FUNCTION__, hdr->nd_opt_type);
958 			goto bad;
959 		}
960 
961 		if (hdr->nd_opt_type > ND_OPT_MTU) {
962 			syslog(LOG_INFO,
963 			       "<%s> unknown ND option(type %d)",
964 			       __FUNCTION__,
965 			       hdr->nd_opt_type);
966 			continue;
967 		}
968 
969 		if ((ndopt_flags[hdr->nd_opt_type] & optflags) == 0) {
970 			syslog(LOG_INFO,
971 			       "<%s> unexpected ND option(type %d)",
972 			       __FUNCTION__,
973 			       hdr->nd_opt_type);
974 			continue;
975 		}
976 
977 		switch(hdr->nd_opt_type) {
978 		 case ND_OPT_SOURCE_LINKADDR:
979 		 case ND_OPT_TARGET_LINKADDR:
980 		 case ND_OPT_REDIRECTED_HEADER:
981 		 case ND_OPT_MTU:
982 			 if (ndopts->nd_opt_array[hdr->nd_opt_type]) {
983 				 syslog(LOG_INFO,
984 					"<%s> duplicated ND option"
985 					" (type = %d)",
986 					__FUNCTION__,
987 					hdr->nd_opt_type);
988 			 }
989 			 ndopts->nd_opt_array[hdr->nd_opt_type] = hdr;
990 			 break;
991 		 case ND_OPT_PREFIX_INFORMATION:
992 		 {
993 			 struct nd_optlist *pfxlist;
994 
995 			 if (ndopts->nd_opts_pi == 0) {
996 				 ndopts->nd_opts_pi =
997 					 (struct nd_opt_prefix_info *)hdr;
998 				 continue;
999 			 }
1000 			 if ((pfxlist = malloc(sizeof(*pfxlist))) == NULL) {
1001 				 syslog(LOG_ERR,
1002 					"<%s> can't allocate memory",
1003 					__FUNCTION__);
1004 				 goto bad;
1005 			 }
1006 			 pfxlist->next = ndopts->nd_opts_list;
1007 			 pfxlist->opt = hdr;
1008 			 ndopts->nd_opts_list = pfxlist;
1009 
1010 			 break;
1011 		 }
1012 		 default:	/* impossible */
1013 			 break;
1014 		}
1015 	}
1016 
1017 	return(0);
1018 
1019   bad:
1020 	free_ndopts(ndopts);
1021 
1022 	return(-1);
1023 }
1024 
1025 static void
1026 free_ndopts(union nd_opts *ndopts)
1027 {
1028 	struct nd_optlist *opt = ndopts->nd_opts_list, *next;
1029 
1030 	while(opt) {
1031 		next = opt->next;
1032 		free(opt);
1033 		opt = next;
1034 	}
1035 }
1036 
1037 void
1038 sock_open()
1039 {
1040 	struct icmp6_filter filt;
1041 	struct ipv6_mreq mreq;
1042 	struct rainfo *ra = ralist;
1043 	int on;
1044 	/* XXX: should be max MTU attached to the node */
1045 	static u_char answer[1500];
1046 	static u_char sndcmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo)) +
1047 				CMSG_SPACE(sizeof(int))];
1048 
1049 	if ((sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
1050 		syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__,
1051 		       strerror(errno));
1052 		exit(1);
1053 	}
1054 
1055 	/* specify to tell receiving interface */
1056 	on = 1;
1057 	if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &on,
1058 		       sizeof(on)) < 0) {
1059 		syslog(LOG_ERR, "<%s> IPV6_PKTINFO: %s",
1060 		       __FUNCTION__, strerror(errno));
1061 		exit(1);
1062 	}
1063 
1064 	on = 1;
1065 	/* specify to tell value of hoplimit field of received IP6 hdr */
1066 	if (setsockopt(sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
1067 		       sizeof(on)) < 0) {
1068 		syslog(LOG_ERR, "<%s> IPV6_HOPLIMIT: %s",
1069 		       __FUNCTION__, strerror(errno));
1070 		exit(1);
1071 	}
1072 
1073 	ICMP6_FILTER_SETBLOCKALL(&filt);
1074 	ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt);
1075 	ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
1076 	if (accept_rr)
1077 		ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt);
1078 	if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
1079 		       sizeof(filt)) < 0) {
1080 		syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s",
1081 		       __FUNCTION__, strerror(errno));
1082 		exit(1);
1083 	}
1084 
1085 	/*
1086 	 * join all routers multicast address on each advertising interface.
1087 	 */
1088 	if (inet_pton(AF_INET6, ALLROUTERS, &mreq.ipv6mr_multiaddr.s6_addr)
1089 	    != 1) {
1090 		syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)",
1091 		       __FUNCTION__);
1092 		exit(1);
1093 	}
1094 	while(ra) {
1095 		mreq.ipv6mr_interface = ra->ifindex;
1096 		if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
1097 			       &mreq,
1098 			       sizeof(mreq)) < 0) {
1099 			syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP on %s: %s",
1100 			       __FUNCTION__, ra->ifname, strerror(errno));
1101 			exit(1);
1102 		}
1103 		ra = ra->next;
1104 	}
1105 
1106 	/* initialize msghdr for receiving packets */
1107 	rcviov[0].iov_base = (caddr_t)answer;
1108 	rcviov[0].iov_len = sizeof(answer);
1109 	rcvmhdr.msg_name = (caddr_t)&from;
1110 	rcvmhdr.msg_namelen = sizeof(from);
1111 	rcvmhdr.msg_iov = rcviov;
1112 	rcvmhdr.msg_iovlen = 1;
1113 	rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf;
1114 	rcvmhdr.msg_controllen = sizeof(rcvcmsgbuf);
1115 
1116 	/* initialize msghdr for sending packets */
1117 	sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
1118 	sndmhdr.msg_iov = sndiov;
1119 	sndmhdr.msg_iovlen = 1;
1120 	sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
1121 	sndmhdr.msg_controllen = sizeof(sndcmsgbuf);
1122 
1123 	return;
1124 }
1125 
1126 /* open a routing socket to watch the routing table */
1127 static void
1128 rtsock_open()
1129 {
1130 	if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
1131 		syslog(LOG_ERR,
1132 		       "<%s> socket: %s", __FUNCTION__, strerror(errno));
1133 		exit(1);
1134 	}
1135 }
1136 
1137 static struct rainfo *
1138 if_indextorainfo(int index)
1139 {
1140 	struct rainfo *rai = ralist;
1141 
1142 	for (rai = ralist; rai; rai = rai->next) {
1143 		if (rai->ifindex == index)
1144 			return(rai);
1145 	}
1146 
1147 	return(NULL);		/* search failed */
1148 }
1149 
1150 static void
1151 ra_output(rainfo)
1152 struct rainfo *rainfo;
1153 {
1154 	int i;
1155 
1156 	struct cmsghdr *cm;
1157 	struct in6_pktinfo *pi;
1158 
1159 	sndmhdr.msg_name = (caddr_t)&sin6_allnodes;
1160 	sndmhdr.msg_iov[0].iov_base = (caddr_t)rainfo->ra_data;
1161 	sndmhdr.msg_iov[0].iov_len = rainfo->ra_datalen;
1162 
1163 	cm = CMSG_FIRSTHDR(&sndmhdr);
1164 	/* specify the outgoing interface */
1165 	cm->cmsg_level = IPPROTO_IPV6;
1166 	cm->cmsg_type = IPV6_PKTINFO;
1167 	cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
1168 	pi = (struct in6_pktinfo *)CMSG_DATA(cm);
1169 	memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr));	/*XXX*/
1170 	pi->ipi6_ifindex = rainfo->ifindex;
1171 
1172 	/* specify the hop limit of the packet */
1173 	{
1174 		int hoplimit = 255;
1175 
1176 		cm = CMSG_NXTHDR(&sndmhdr, cm);
1177 		cm->cmsg_level = IPPROTO_IPV6;
1178 		cm->cmsg_type = IPV6_HOPLIMIT;
1179 		cm->cmsg_len = CMSG_LEN(sizeof(int));
1180 		memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int));
1181 	}
1182 
1183 	syslog(LOG_DEBUG,
1184 	       "<%s> send RA on %s, # of waitings = %d",
1185 	       __FUNCTION__, rainfo->ifname, rainfo->waiting);
1186 
1187 	i = sendmsg(sock, &sndmhdr, 0);
1188 
1189 	if (i < 0 || i != rainfo->ra_datalen)  {
1190 		if (i < 0) {
1191 			syslog(LOG_ERR, "<%s> sendmsg on %s: %s",
1192 			       __FUNCTION__, rainfo->ifname,
1193 			       strerror(errno));
1194 		}
1195 	}
1196 
1197 	/* update counter */
1198 	if (rainfo->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS)
1199 		rainfo->initcounter++;
1200 
1201 	/* update timestamp */
1202 	gettimeofday(&rainfo->lastsent, NULL);
1203 
1204 	/* reset waiting conter */
1205 	rainfo->waiting = 0;
1206 }
1207 
1208 /* process RA timer */
1209 void
1210 ra_timeout(void *data)
1211 {
1212 	struct rainfo *rai = (struct rainfo *)data;
1213 
1214 #ifdef notyet
1215 	/* if necessary, reconstruct the packet. */
1216 #endif
1217 
1218 	syslog(LOG_DEBUG,
1219 	       "<%s> RA timer on %s is expired",
1220 	       __FUNCTION__, rai->ifname);
1221 
1222 	if (iflist[rai->ifindex]->ifm_flags & IFF_UP)
1223 		ra_output(rai);
1224 	else
1225 		syslog(LOG_DEBUG, "<%s> %s is not up, skip sending RA",
1226 		       __FUNCTION__, rai->ifname);
1227 }
1228 
1229 /* update RA timer */
1230 void
1231 ra_timer_update(void *data, struct timeval *tm)
1232 {
1233 	struct rainfo *rai = (struct rainfo *)data;
1234 	long interval;
1235 
1236 	/*
1237 	 * Whenever a multicast advertisement is sent from an interface,
1238 	 * the timer is reset to a uniformly-distributed random value
1239 	 * between the interface's configured MinRtrAdvInterval and
1240 	 * MaxRtrAdvInterval(discovery-v2-02 6.2.4).
1241 	 */
1242 	interval = rai->mininterval;
1243 	interval += random() % (rai->maxinterval - rai->mininterval);
1244 
1245 	/*
1246 	 * For the first few advertisements (up to
1247 	 * MAX_INITIAL_RTR_ADVERTISEMENTS), if the randomly chosen interval
1248 	 * is greater than MAX_INITIAL_RTR_ADVERT_INTERVAL, the timer
1249 	 * SHOULD be set to MAX_INITIAL_RTR_ADVERT_INTERVAL instead.
1250 	 * (RFC-2461 6.2.4)
1251 	 */
1252 	if (rai->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS &&
1253 	    interval > MAX_INITIAL_RTR_ADVERT_INTERVAL)
1254 		interval = MAX_INITIAL_RTR_ADVERT_INTERVAL;
1255 
1256 	tm->tv_sec = interval;
1257 	tm->tv_usec = 0;
1258 
1259 	syslog(LOG_DEBUG,
1260 	       "<%s> RA timer on %s is set to %ld:%ld",
1261 	       __FUNCTION__, rai->ifname, tm->tv_sec, tm->tv_usec);
1262 
1263 	return;
1264 }
1265