xref: /freebsd/usr.sbin/rtadvd/rtadvd.c (revision 77a0943ded95b9e6438f7db70c4a28e4d93946d4)
1 /*	$KAME: rtadvd.c,v 1.30 2000/06/22 20:16:12 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  * $FreeBSD$
32  */
33 
34 #include <sys/param.h>
35 #include <sys/socket.h>
36 #include <sys/uio.h>
37 #include <sys/time.h>
38 
39 #include <net/if.h>
40 #include <net/route.h>
41 #include <net/if_dl.h>
42 #include <netinet/in.h>
43 #include <netinet/ip6.h>
44 #include <netinet6/ip6_var.h>
45 #include <netinet/icmp6.h>
46 
47 #include <arpa/inet.h>
48 
49 #include <time.h>
50 #include <unistd.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <err.h>
54 #include <errno.h>
55 #include <string.h>
56 #include <stdlib.h>
57 #include <syslog.h>
58 #include "rtadvd.h"
59 #include "rrenum.h"
60 #include "advcap.h"
61 #include "timer.h"
62 #include "if.h"
63 #include "config.h"
64 #include "dump.h"
65 
66 struct msghdr rcvmhdr;
67 static u_char *rcvcmsgbuf;
68 static size_t rcvcmsgbuflen;
69 static u_char *sndcmsgbuf = NULL;
70 static size_t sndcmsgbuflen;
71 static int do_dump;
72 struct msghdr sndmhdr;
73 struct iovec rcviov[2];
74 struct iovec sndiov[2];
75 struct sockaddr_in6 from;
76 struct sockaddr_in6 sin6_allnodes = {sizeof(sin6_allnodes), AF_INET6};
77 static char *dumpfilename = "/var/run/rtadvd.dump"; /* XXX: should be configurable */
78 static char *pidfilename = "/var/run/rtadvd.pid"; /* should be configurable */
79 int sock, rtsock;
80 #ifdef MIP6
81 int mobileip6 = 0;
82 #endif
83 int accept_rr = 0;
84 int dflag = 0, sflag = 0;
85 
86 u_char *conffile = NULL;
87 
88 struct rainfo *ralist = NULL;
89 struct nd_optlist {
90 	struct nd_optlist *next;
91 	struct nd_opt_hdr *opt;
92 };
93 union nd_opts {
94 	struct nd_opt_hdr *nd_opt_array[7];
95 	struct {
96 		struct nd_opt_hdr *zero;
97 		struct nd_opt_hdr *src_lladdr;
98 		struct nd_opt_hdr *tgt_lladdr;
99 		struct nd_opt_prefix_info *pi;
100 		struct nd_opt_rd_hdr *rh;
101 		struct nd_opt_mtu *mtu;
102 		struct nd_optlist *list;
103 	} nd_opt_each;
104 };
105 #define nd_opts_src_lladdr	nd_opt_each.src_lladdr
106 #define nd_opts_tgt_lladdr	nd_opt_each.tgt_lladdr
107 #define nd_opts_pi		nd_opt_each.pi
108 #define nd_opts_rh		nd_opt_each.rh
109 #define nd_opts_mtu		nd_opt_each.mtu
110 #define nd_opts_list		nd_opt_each.list
111 
112 #define NDOPT_FLAG_SRCLINKADDR 0x1
113 #define NDOPT_FLAG_TGTLINKADDR 0x2
114 #define NDOPT_FLAG_PREFIXINFO 0x4
115 #define NDOPT_FLAG_RDHDR 0x8
116 #define NDOPT_FLAG_MTU 0x10
117 
118 u_int32_t ndopt_flags[] = {
119 	0, NDOPT_FLAG_SRCLINKADDR, NDOPT_FLAG_TGTLINKADDR,
120 	NDOPT_FLAG_PREFIXINFO, NDOPT_FLAG_RDHDR, NDOPT_FLAG_MTU
121 };
122 
123 int main __P((int, char *[]));
124 static void die __P((int));
125 static void sock_open __P((void));
126 static void rtsock_open __P((void));
127 static void rtadvd_input __P((void));
128 static void rs_input __P((int, struct nd_router_solicit *,
129 			  struct in6_pktinfo *, struct sockaddr_in6 *));
130 static void ra_input __P((int, struct nd_router_advert *,
131 			  struct in6_pktinfo *, struct sockaddr_in6 *));
132 static int prefix_check __P((struct nd_opt_prefix_info *, struct rainfo *,
133 			     struct sockaddr_in6 *));
134 static int nd6_options __P((struct nd_opt_hdr *, int,
135 			    union nd_opts *, u_int32_t));
136 static void free_ndopts __P((union nd_opts *));
137 static struct rainfo *if_indextorainfo __P((int));
138 static void ra_output __P((struct rainfo *));
139 static void rtmsg_input __P((void));
140 static void rtadvd_set_dump_file __P((void));
141 
142 struct prefix *find_prefix __P((struct rainfo *, struct in6_addr *, int));
143 
144 int
145 main(argc, argv)
146 	int argc;
147 	char *argv[];
148 {
149 	fd_set fdset;
150 	int maxfd = 0;
151 	struct timeval *timeout;
152 	int i, ch;
153 	int fflag = 0;
154 	FILE *pidfp;
155 	pid_t pid;
156 
157 	openlog("rtadvd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
158 
159 	/* get command line options and arguments */
160 #ifdef MIP6
161 #define OPTIONS "c:dDfmRs"
162 #else
163 #define OPTIONS "c:dDfRs"
164 #endif
165 	while ((ch = getopt(argc, argv, OPTIONS)) != -1) {
166 #undef OPTIONS
167 		switch(ch) {
168 		 case 'c':
169 			 conffile = optarg;
170 			 break;
171 		 case 'd':
172 			 dflag = 1;
173 			 break;
174 		 case 'D':
175 			 dflag = 2;
176 			 break;
177 		 case 'f':
178 			 fflag = 1;
179 			 break;
180 #ifdef MIP6
181 		 case 'm':
182 			 mobileip6 = 1;
183 			 break;
184 #endif
185 		 case 'R':
186 			 accept_rr = 1;
187 			 break;
188 		 case 's':
189 			 sflag = 1;
190 			 break;
191 		}
192 	}
193 	argc -= optind;
194 	argv += optind;
195 	if (argc == 0) {
196 		fprintf(stderr,
197 #ifdef MIP6
198 			"usage: rtadvd [-dDfmRs] [-c conffile] "
199 #else
200 			"usage: rtadvd [-dDfRs] [-c conffile] "
201 #endif
202 			"interfaces...\n");
203 		exit(1);
204 	}
205 
206 	/* set log level */
207 	if (dflag == 0)
208 		(void)setlogmask(LOG_UPTO(LOG_ERR));
209 	if (dflag == 1)
210 		(void)setlogmask(LOG_UPTO(LOG_INFO));
211 
212 	/* timer initialization */
213 	rtadvd_timer_init();
214 
215 	/* random value initialization */
216 	srandom((u_long)time(NULL));
217 
218 	/* get iflist block from kernel */
219 	init_iflist();
220 
221 	while (argc--)
222 		getconfig(*argv++);
223 
224 	if (inet_pton(AF_INET6, ALLNODES, &sin6_allnodes.sin6_addr) != 1) {
225 		fprintf(stderr, "fatal: inet_pton failed\n");
226 		exit(1);
227 	}
228 	sock_open();
229 
230 	if (!fflag)
231 		daemon(1, 0);
232 
233 	/* record the current PID */
234 	pid = getpid();
235 	if ((pidfp = fopen(pidfilename, "w")) == NULL)
236 		syslog(LOG_ERR,
237 		       "<%s> failed to open a log file(%s), run anyway.",
238 		       __FUNCTION__, pidfilename);
239 	else {
240 		fprintf(pidfp, "%d\n", pid);
241 		fclose(pidfp);
242 	}
243 
244 	FD_ZERO(&fdset);
245 	FD_SET(sock, &fdset);
246 	maxfd = sock;
247 	rtsock_open();
248 	FD_SET(rtsock, &fdset);
249 	if (rtsock > sock)
250 			maxfd = rtsock;
251 
252 	signal(SIGTERM, (void *)die);
253 	signal(SIGUSR1, (void *)rtadvd_set_dump_file);
254 
255 	while (1) {
256 		struct fd_set select_fd = fdset; /* reinitialize */
257 
258 		if (do_dump) {	/* SIGUSR1 */
259 			do_dump = 0;
260 			rtadvd_dump_file(dumpfilename);
261 		}
262 
263 		/* timer expiration check and reset the timer */
264 		timeout = rtadvd_check_timer();
265 
266 		if (timeout != NULL) {
267 			syslog(LOG_DEBUG,
268 			       "<%s> set timer to %ld:%ld. waiting for "
269 			       "inputs or timeout",
270 			       __FUNCTION__,
271 			       (long int)timeout->tv_sec,
272 			       (long int)timeout->tv_usec);
273 		} else {
274 			syslog(LOG_DEBUG,
275 			       "<%s> there's no timer. waiting for inputs",
276 			       __FUNCTION__);
277 		}
278 
279 		if ((i = select(maxfd + 1, &select_fd,
280 				NULL, NULL, timeout)) < 0) {
281 			/* EINTR would occur upon SIGUSR1 for status dump */
282 			if (errno != EINTR)
283 				syslog(LOG_ERR, "<%s> select: %s",
284 				       __FUNCTION__, strerror(errno));
285 			continue;
286 		}
287 		if (i == 0)	/* timeout */
288 			continue;
289 		if (sflag == 0 && FD_ISSET(rtsock, &select_fd))
290 			rtmsg_input();
291 		if (FD_ISSET(sock, &select_fd))
292 			rtadvd_input();
293 	}
294 	exit(0);		/* NOTREACHED */
295 }
296 
297 static void
298 rtadvd_set_dump_file()
299 {
300 	do_dump = 1;
301 }
302 
303 static void
304 die(sig)
305 	int sig;
306 {
307 	struct rainfo *ra;
308 	int i;
309 	const int retrans = MAX_FINAL_RTR_ADVERTISEMENTS;
310 
311 	if (dflag > 1) {
312 		syslog(LOG_DEBUG, "<%s> cease to be an advertising router\n",
313 		    __FUNCTION__);
314 	}
315 
316 	for (ra = ralist; ra; ra = ra->next) {
317 		ra->lifetime = 0;
318 		make_packet(ra);
319 	}
320 	for (i = 0; i < retrans; i++) {
321 		for (ra = ralist; ra; ra = ra->next)
322 			ra_output(ra);
323 		sleep(MIN_DELAY_BETWEEN_RAS);
324 	}
325 	exit(0);
326 	/*NOTREACHED*/
327 }
328 
329 static void
330 rtmsg_input()
331 {
332 	int n, type, ifindex = 0, plen;
333 	size_t len;
334 	char msg[2048], *next, *lim;
335 	u_char ifname[16];
336 	struct prefix *prefix;
337 	struct rainfo *rai;
338 	struct in6_addr *addr;
339 	char addrbuf[INET6_ADDRSTRLEN];
340 
341 	n = read(rtsock, msg, 2048);
342 	if (dflag > 1) {
343 		syslog(LOG_DEBUG,
344 		       "<%s> received a routing message "
345 		       "(type = %d, len = %d)",
346 		       __FUNCTION__,
347 		       rtmsg_type(msg), n);
348 	}
349 	if (n > rtmsg_len(msg)) {
350 		/*
351 		 * This usually won't happen for messages received on
352 		 * a routing socket.
353 		 */
354 		if (dflag > 1)
355 			syslog(LOG_DEBUG,
356 			       "<%s> received data length is larger than"
357 			       "1st routing message len. multiple messages?"
358 			       " read %d bytes, but 1st msg len = %d",
359 			       __FUNCTION__, n, rtmsg_len(msg));
360 #if 0
361 		/* adjust length */
362 		n = rtmsg_len(msg);
363 #endif
364 	}
365 
366 	lim = msg + n;
367 	for (next = msg; next < lim; next += len) {
368 		int oldifflags;
369 
370 		next = get_next_msg(next, lim, 0, &len,
371 				    RTADV_TYPE2BITMASK(RTM_ADD) |
372 				    RTADV_TYPE2BITMASK(RTM_DELETE) |
373 				    RTADV_TYPE2BITMASK(RTM_NEWADDR) |
374 				    RTADV_TYPE2BITMASK(RTM_DELADDR) |
375 				    RTADV_TYPE2BITMASK(RTM_IFINFO));
376 		if (len == 0)
377 			break;
378 		type = rtmsg_type(next);
379 		switch (type) {
380 		case RTM_ADD:
381 		case RTM_DELETE:
382 			ifindex = get_rtm_ifindex(next);
383 			break;
384 		case RTM_NEWADDR:
385 		case RTM_DELADDR:
386 			ifindex = get_ifam_ifindex(next);
387 			break;
388 		case RTM_IFINFO:
389 			ifindex = get_ifm_ifindex(next);
390 			break;
391 		default:
392 			/* should not reach here */
393 			if (dflag > 1) {
394 				syslog(LOG_DEBUG,
395 				       "<%s:%d> unknown rtmsg %d on %s",
396 				       __FUNCTION__, __LINE__, type,
397 				       if_indextoname(ifindex, ifname));
398 			}
399 			continue;
400 		}
401 
402 		if ((rai = if_indextorainfo(ifindex)) == NULL) {
403 			if (dflag > 1) {
404 				syslog(LOG_DEBUG,
405 				       "<%s> route changed on "
406 				       "non advertising interface(%s)",
407 				       __FUNCTION__,
408 				       if_indextoname(ifindex, ifname));
409 			}
410 			continue;
411 		}
412 		oldifflags = iflist[ifindex]->ifm_flags;
413 
414 		switch(type) {
415 		 case RTM_ADD:
416 			 /* init ifflags because it may have changed */
417 			 iflist[ifindex]->ifm_flags =
418 			 	if_getflags(ifindex,
419 					    iflist[ifindex]->ifm_flags);
420 
421 			 if (sflag)
422 				 break;	/* we aren't interested in prefixes  */
423 
424 			 addr = get_addr(msg);
425 			 plen = get_prefixlen(msg);
426 			 /* sanity check for plen */
427 			 if (plen < 4 /* as RFC2373, prefixlen is at least 4 */
428 			     || plen > 127) {
429 				syslog(LOG_INFO, "<%s> new interface route's"
430 				       "plen %d is invalid for a prefix",
431 				       __FUNCTION__, plen);
432 				break;
433 			 }
434 			 prefix = find_prefix(rai, addr, plen);
435 			 if (prefix) {
436 				 if (dflag > 1) {
437 					 syslog(LOG_DEBUG,
438 						"<%s> new prefix(%s/%d) "
439 						"added on %s, "
440 						"but it was already in list",
441 						__FUNCTION__,
442 						inet_ntop(AF_INET6,
443 							  addr, (char *)addrbuf,
444 							  INET6_ADDRSTRLEN),
445 						plen,
446 						rai->ifname);
447 				 }
448 				 break;
449 			 }
450 			 make_prefix(rai, ifindex, addr, plen);
451 			 break;
452 		 case RTM_DELETE:
453 			 /* init ifflags because it may have changed */
454 			 iflist[ifindex]->ifm_flags =
455 			 	if_getflags(ifindex,
456 					    iflist[ifindex]->ifm_flags);
457 
458 			 if (sflag)
459 				 break;
460 
461 			 addr = get_addr(msg);
462 			 plen = get_prefixlen(msg);
463 			 /* sanity check for plen */
464 			 if (plen < 4 /* as RFC2373, prefixlen is at least 4 */
465 			     || plen > 127) {
466 				syslog(LOG_INFO, "<%s> deleted interface"
467 				       "route's"
468 				       "plen %d is invalid for a prefix",
469 				       __FUNCTION__, plen);
470 				break;
471 			 }
472 			 prefix = find_prefix(rai, addr, plen);
473 			 if (prefix == NULL) {
474 				 if (dflag > 1) {
475 					 syslog(LOG_DEBUG,
476 						"<%s> prefix(%s/%d) was "
477 						"deleted on %s, "
478 						"but it was not in list",
479 						__FUNCTION__,
480 						inet_ntop(AF_INET6,
481 							  addr, (char *)addrbuf,
482 							  INET6_ADDRSTRLEN),
483 						plen,
484 						rai->ifname);
485 				 }
486 				 break;
487 			 }
488 			 delete_prefix(rai, prefix);
489 			 break;
490 		case RTM_NEWADDR:
491 		case RTM_DELADDR:
492 			 /* init ifflags because it may have changed */
493 			 iflist[ifindex]->ifm_flags =
494 			 	if_getflags(ifindex,
495 					    iflist[ifindex]->ifm_flags);
496 			 break;
497 		case RTM_IFINFO:
498 			 iflist[ifindex]->ifm_flags = get_ifm_flags(next);
499 			 break;
500 		default:
501 			/* should not reach here */
502 			if (dflag > 1) {
503 				syslog(LOG_DEBUG,
504 				       "<%s:%d> unknown rtmsg %d on %s",
505 				       __FUNCTION__, __LINE__, type,
506 				       if_indextoname(ifindex, ifname));
507 			}
508 			return;
509 		}
510 
511 		/* check if an interface flag is changed */
512 		if ((oldifflags & IFF_UP) != 0 &&	/* UP to DOWN */
513 		    (iflist[ifindex]->ifm_flags & IFF_UP) == 0) {
514 			syslog(LOG_INFO,
515 			       "<%s> interface %s becomes down. stop timer.",
516 			       __FUNCTION__, rai->ifname);
517 			rtadvd_remove_timer(&rai->timer);
518 		}
519 		else if ((oldifflags & IFF_UP) == 0 &&	/* DOWN to UP */
520 			 (iflist[ifindex]->ifm_flags & IFF_UP) != 0) {
521 			syslog(LOG_INFO,
522 			       "<%s> interface %s becomes up. restart timer.",
523 			       __FUNCTION__, rai->ifname);
524 
525 			rai->initcounter = 0; /* reset the counter */
526 			rai->waiting = 0; /* XXX */
527 			rai->timer = rtadvd_add_timer(ra_timeout,
528 						      ra_timer_update,
529 						      rai, rai);
530 			ra_timer_update((void *)rai, &rai->timer->tm);
531 			rtadvd_set_timer(&rai->timer->tm, rai->timer);
532 		}
533 	}
534 
535 	return;
536 }
537 
538 void
539 rtadvd_input()
540 {
541 	int i;
542 	int *hlimp = NULL;
543 #ifdef OLDRAWSOCKET
544 	struct ip6_hdr *ip;
545 #endif
546 	struct icmp6_hdr *icp;
547 	int ifindex = 0;
548 	struct cmsghdr *cm;
549 	struct in6_pktinfo *pi = NULL;
550 	u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
551 	struct in6_addr dst = in6addr_any;
552 
553 	/*
554 	 * Get message. We reset msg_controllen since the field could
555 	 * be modified if we had received a message before setting
556 	 * receive options.
557 	 */
558 	rcvmhdr.msg_controllen = rcvcmsgbuflen;
559 	if ((i = recvmsg(sock, &rcvmhdr, 0)) < 0)
560 		return;
561 
562 	/* extract optional information via Advanced API */
563 	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmhdr);
564 	     cm;
565 	     cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvmhdr, cm)) {
566 		if (cm->cmsg_level == IPPROTO_IPV6 &&
567 		    cm->cmsg_type == IPV6_PKTINFO &&
568 		    cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) {
569 			pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
570 			ifindex = pi->ipi6_ifindex;
571 			dst = pi->ipi6_addr;
572 		}
573 		if (cm->cmsg_level == IPPROTO_IPV6 &&
574 		    cm->cmsg_type == IPV6_HOPLIMIT &&
575 		    cm->cmsg_len == CMSG_LEN(sizeof(int)))
576 			hlimp = (int *)CMSG_DATA(cm);
577 	}
578 	if (ifindex == 0) {
579 		syslog(LOG_ERR,
580 		       "<%s> failed to get receiving interface",
581 		       __FUNCTION__);
582 		return;
583 	}
584 	if (hlimp == NULL) {
585 		syslog(LOG_ERR,
586 		       "<%s> failed to get receiving hop limit",
587 		       __FUNCTION__);
588 		return;
589 	}
590 
591 	/*
592 	 * If we happen to receive data on an interface which is now down,
593 	 * just discard the data.
594 	 */
595 	if ((iflist[pi->ipi6_ifindex]->ifm_flags & IFF_UP) == 0) {
596 		syslog(LOG_INFO,
597 		       "<%s> received data on a disabled interface (%s)",
598 		       __FUNCTION__,
599 		       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
600 		return;
601 	}
602 
603 #ifdef OLDRAWSOCKET
604 	if (i < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)) {
605 		syslog(LOG_ERR,
606 		       "<%s> packet size(%d) is too short",
607 		       __FUNCTION__, i);
608 		return;
609 	}
610 
611 	ip = (struct ip6_hdr *)rcvmhdr.msg_iov[0].iov_base;
612 	icp = (struct icmp6_hdr *)(ip + 1); /* XXX: ext. hdr? */
613 #else
614 	if (i < sizeof(struct icmp6_hdr)) {
615 		syslog(LOG_ERR,
616 		       "<%s> packet size(%d) is too short",
617 		       __FUNCTION__, i);
618 		return;
619 	}
620 
621 	icp = (struct icmp6_hdr *)rcvmhdr.msg_iov[0].iov_base;
622 #endif
623 
624 	switch(icp->icmp6_type) {
625 	 case ND_ROUTER_SOLICIT:
626 		 /*
627 		  * Message verification - RFC-2461 6.1.1
628 		  * XXX: these checks must be done in the kernel as well,
629 		  *      but we can't completely rely on them.
630 		  */
631 		 if (*hlimp != 255) {
632 			 syslog(LOG_NOTICE,
633 				"<%s> RS with invalid hop limit(%d) "
634 				"received from %s on %s",
635 				__FUNCTION__, *hlimp,
636 				inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
637 					  INET6_ADDRSTRLEN),
638 				if_indextoname(pi->ipi6_ifindex, ifnamebuf));
639 			 return;
640 		 }
641 		 if (icp->icmp6_code) {
642 			 syslog(LOG_NOTICE,
643 				"<%s> RS with invalid ICMP6 code(%d) "
644 				"received from %s on %s",
645 				__FUNCTION__, icp->icmp6_code,
646 				inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
647 					  INET6_ADDRSTRLEN),
648 				if_indextoname(pi->ipi6_ifindex, ifnamebuf));
649 			 return;
650 		 }
651 		 if (i < sizeof(struct nd_router_solicit)) {
652 			 syslog(LOG_NOTICE,
653 				"<%s> RS from %s on %s does not have enough "
654 				"length (len = %d)",
655 				__FUNCTION__,
656 				inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
657 					  INET6_ADDRSTRLEN),
658 				if_indextoname(pi->ipi6_ifindex, ifnamebuf), i);
659 			 return;
660 		 }
661 		 rs_input(i, (struct nd_router_solicit *)icp, pi, &from);
662 		 break;
663 	 case ND_ROUTER_ADVERT:
664 		 /*
665 		  * Message verification - RFC-2461 6.1.2
666 		  * XXX: there's a same dilemma as above...
667 		  */
668 		 if (*hlimp != 255) {
669 			 syslog(LOG_NOTICE,
670 				"<%s> RA with invalid hop limit(%d) "
671 				"received from %s on %s",
672 				__FUNCTION__, *hlimp,
673 				inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
674 					  INET6_ADDRSTRLEN),
675 				if_indextoname(pi->ipi6_ifindex, ifnamebuf));
676 			 return;
677 		 }
678 		 if (icp->icmp6_code) {
679 			 syslog(LOG_NOTICE,
680 				"<%s> RA with invalid ICMP6 code(%d) "
681 				"received from %s on %s",
682 				__FUNCTION__, icp->icmp6_code,
683 				inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
684 					  INET6_ADDRSTRLEN),
685 				if_indextoname(pi->ipi6_ifindex, ifnamebuf));
686 			 return;
687 		 }
688 		 if (i < sizeof(struct nd_router_advert)) {
689 			 syslog(LOG_NOTICE,
690 				"<%s> RA from %s on %s does not have enough "
691 				"length (len = %d)",
692 				__FUNCTION__,
693 				inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
694 					  INET6_ADDRSTRLEN),
695 				if_indextoname(pi->ipi6_ifindex, ifnamebuf), i);
696 			 return;
697 		 }
698 		 ra_input(i, (struct nd_router_advert *)icp, pi, &from);
699 		 break;
700 	 case ICMP6_ROUTER_RENUMBERING:
701 		 if (accept_rr == 0) {
702 			 syslog(LOG_ERR,
703 				"<%s> received a router renumbering "
704 				"message, but not allowed to be accepted",
705 				__FUNCTION__);
706 			 break;
707 		 }
708 		 rr_input(i, (struct icmp6_router_renum *)icp, pi, &from,
709 			  &dst);
710 		 break;
711 	 default:
712 		 /*
713 		  * Note that this case is POSSIBLE, especially just
714 		  * after invocation of the daemon. This is because we
715 		  * could receive message after opening the socket and
716 		  * before setting ICMP6 type filter(see sock_open()).
717 		  */
718 		 syslog(LOG_ERR,
719 			"<%s> invalid icmp type(%d)",
720 			__FUNCTION__, icp->icmp6_type);
721 		 return;
722 	}
723 
724 	return;
725 }
726 
727 static void
728 rs_input(int len, struct nd_router_solicit *rs,
729 	 struct in6_pktinfo *pi, struct sockaddr_in6 *from)
730 {
731 	u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
732 	union nd_opts ndopts;
733 	struct rainfo *ra;
734 
735 	syslog(LOG_DEBUG,
736 	       "<%s> RS received from %s on %s",
737 	       __FUNCTION__,
738 	       inet_ntop(AF_INET6, &from->sin6_addr,
739 			 ntopbuf, INET6_ADDRSTRLEN),
740 	       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
741 
742 	/* ND option check */
743 	memset(&ndopts, 0, sizeof(ndopts));
744 	if (nd6_options((struct nd_opt_hdr *)(rs + 1),
745 			len - sizeof(struct nd_router_solicit),
746 			 &ndopts, NDOPT_FLAG_SRCLINKADDR)) {
747 		syslog(LOG_DEBUG,
748 		       "<%s> ND option check failed for an RS from %s on %s",
749 		       __FUNCTION__,
750 		       inet_ntop(AF_INET6, &from->sin6_addr,
751 				 ntopbuf, INET6_ADDRSTRLEN),
752 		       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
753 		return;
754 	}
755 
756 	/*
757 	 * If the IP source address is the unspecified address, there
758 	 * must be no source link-layer address option in the message.
759 	 * (RFC-2461 6.1.1)
760 	 */
761 	if (IN6_IS_ADDR_UNSPECIFIED(&from->sin6_addr) &&
762 	    ndopts.nd_opts_src_lladdr) {
763 		syslog(LOG_ERR,
764 		       "<%s> RS from unspecified src on %s has a link-layer"
765 		       " address option",
766 		       __FUNCTION__,
767 		       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
768 		goto done;
769 	}
770 
771 	ra = ralist;
772 	while (ra != NULL) {
773 		if (pi->ipi6_ifindex == ra->ifindex)
774 			break;
775 		ra = ra->next;
776 	}
777 	if (ra == NULL) {
778 		syslog(LOG_INFO,
779 		       "<%s> RS received on non advertising interface(%s)",
780 		       __FUNCTION__,
781 		       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
782 		goto done;
783 	}
784 
785 	ra->rsinput++;		/* increment statistics */
786 
787 	/*
788 	 * Decide whether to send RA according to the rate-limit
789 	 * consideration.
790 	 */
791 	{
792 		long delay;	/* must not be greater than 1000000 */
793 		struct timeval interval, now, min_delay, tm_tmp, *rest;
794 		struct soliciter *sol;
795 
796 		/*
797 		 * record sockaddr waiting for RA, if possible
798 		 */
799 		sol = (struct soliciter *)malloc(sizeof(*sol));
800 		if (sol) {
801 			sol->addr = *from;
802 			/*XXX RFC2553 need clarification on flowinfo */
803 			sol->addr.sin6_flowinfo = 0;
804 			sol->next = ra->soliciter;
805 			ra->soliciter = sol->next;
806 		}
807 
808 		/*
809 		 * If there is already a waiting RS packet, don't
810 		 * update the timer.
811 		 */
812 		if (ra->waiting++)
813 			goto done;
814 
815 		/*
816 		 * Compute a random delay. If the computed value
817 		 * corresponds to a time later than the time the next
818 		 * multicast RA is scheduled to be sent, ignore the random
819 		 * delay and send the advertisement at the
820 		 * already-scheduled time. RFC-2461 6.2.6
821 		 */
822 		delay = random() % MAX_RA_DELAY_TIME;
823 		interval.tv_sec = 0;
824 		interval.tv_usec = delay;
825 		rest = rtadvd_timer_rest(ra->timer);
826 		if (TIMEVAL_LT(*rest, interval)) {
827 			syslog(LOG_DEBUG,
828 			       "<%s> random delay is larger than "
829 			       "the rest of normal timer",
830 			       __FUNCTION__);
831 			interval = *rest;
832 		}
833 
834 		/*
835 		 * If we sent a multicast Router Advertisement within
836 		 * the last MIN_DELAY_BETWEEN_RAS seconds, schedule
837 		 * the advertisement to be sent at a time corresponding to
838 		 * MIN_DELAY_BETWEEN_RAS plus the random value after the
839 		 * previous advertisement was sent.
840 		 */
841 		gettimeofday(&now, NULL);
842 		TIMEVAL_SUB(&now, &ra->lastsent, &tm_tmp);
843 		min_delay.tv_sec = MIN_DELAY_BETWEEN_RAS;
844 		min_delay.tv_usec = 0;
845 		if (TIMEVAL_LT(tm_tmp, min_delay)) {
846 			TIMEVAL_SUB(&min_delay, &tm_tmp, &min_delay);
847 			TIMEVAL_ADD(&min_delay, &interval, &interval);
848 		}
849 		rtadvd_set_timer(&interval, ra->timer);
850 		goto done;
851 	}
852 
853   done:
854 	free_ndopts(&ndopts);
855 	return;
856 }
857 
858 static void
859 ra_input(int len, struct nd_router_advert *ra,
860 	 struct in6_pktinfo *pi, struct sockaddr_in6 *from)
861 {
862 	struct rainfo *rai;
863 	u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
864 	union nd_opts ndopts;
865 	char *on_off[] = {"OFF", "ON"};
866 	u_int32_t reachabletime, retranstimer, mtu;
867 	int inconsistent = 0;
868 
869 	syslog(LOG_DEBUG,
870 	       "<%s> RA received from %s on %s",
871 	       __FUNCTION__,
872 	       inet_ntop(AF_INET6, &from->sin6_addr,
873 			 ntopbuf, INET6_ADDRSTRLEN),
874 	       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
875 
876 	/* ND option check */
877 	memset(&ndopts, 0, sizeof(ndopts));
878 	if (nd6_options((struct nd_opt_hdr *)(ra + 1),
879 			len - sizeof(struct nd_router_advert),
880 			 &ndopts,
881 			NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU)) {
882 		syslog(LOG_ERR,
883 		       "<%s> ND option check failed for an RA from %s on %s",
884 		       __FUNCTION__,
885 		       inet_ntop(AF_INET6, &from->sin6_addr,
886 				 ntopbuf, INET6_ADDRSTRLEN),
887 		       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
888 		return;
889 	}
890 
891 	/*
892 	 * RA consistency check according to RFC-2461 6.2.7
893 	 */
894 	if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == 0) {
895 		syslog(LOG_INFO,
896 		       "<%s> received RA from %s on non-advertising"
897 		       " interface(%s)",
898 		       __FUNCTION__,
899 		       inet_ntop(AF_INET6, &from->sin6_addr,
900 				 ntopbuf, INET6_ADDRSTRLEN),
901 		       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
902 		goto done;
903 	}
904 	rai->rainput++;		/* increment statistics */
905 
906 	/* Cur Hop Limit value */
907 	if (ra->nd_ra_curhoplimit && rai->hoplimit &&
908 	    ra->nd_ra_curhoplimit != rai->hoplimit) {
909 		syslog(LOG_WARNING,
910 		       "<%s> CurHopLimit inconsistent on %s:"
911 		       " %d from %s, %d from us",
912 		       __FUNCTION__,
913 		       rai->ifname,
914 		       ra->nd_ra_curhoplimit,
915 		       inet_ntop(AF_INET6, &from->sin6_addr,
916 				 ntopbuf, INET6_ADDRSTRLEN),
917 		       rai->hoplimit);
918 		inconsistent++;
919 	}
920 	/* M flag */
921 	if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) !=
922 	    rai->managedflg) {
923 		syslog(LOG_WARNING,
924 		       "<%s> M flag inconsistent on %s:"
925 		       " %s from %s, %s from us",
926 		       __FUNCTION__,
927 		       rai->ifname,
928 		       on_off[!rai->managedflg],
929 		       inet_ntop(AF_INET6, &from->sin6_addr,
930 				 ntopbuf, INET6_ADDRSTRLEN),
931 		       on_off[rai->managedflg]);
932 		inconsistent++;
933 	}
934 	/* O flag */
935 	if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) !=
936 	    rai->otherflg) {
937 		syslog(LOG_WARNING,
938 		       "<%s> O flag inconsistent on %s:"
939 		       " %s from %s, %s from us",
940 		       __FUNCTION__,
941 		       rai->ifname,
942 		       on_off[!rai->otherflg],
943 		       inet_ntop(AF_INET6, &from->sin6_addr,
944 				 ntopbuf, INET6_ADDRSTRLEN),
945 		       on_off[rai->otherflg]);
946 		inconsistent++;
947 	}
948 	/* Reachable Time */
949 	reachabletime = ntohl(ra->nd_ra_reachable);
950 	if (reachabletime && rai->reachabletime &&
951 	    reachabletime != rai->reachabletime) {
952 		syslog(LOG_WARNING,
953 		       "<%s> ReachableTime inconsistent on %s:"
954 		       " %d from %s, %d from us",
955 		       __FUNCTION__,
956 		       rai->ifname,
957 		       reachabletime,
958 		       inet_ntop(AF_INET6, &from->sin6_addr,
959 				 ntopbuf, INET6_ADDRSTRLEN),
960 		       rai->reachabletime);
961 		inconsistent++;
962 	}
963 	/* Retrans Timer */
964 	retranstimer = ntohl(ra->nd_ra_retransmit);
965 	if (retranstimer && rai->retranstimer &&
966 	    retranstimer != rai->retranstimer) {
967 		syslog(LOG_WARNING,
968 		       "<%s> RetranceTimer inconsistent on %s:"
969 		       " %d from %s, %d from us",
970 		       __FUNCTION__,
971 		       rai->ifname,
972 		       retranstimer,
973 		       inet_ntop(AF_INET6, &from->sin6_addr,
974 				 ntopbuf, INET6_ADDRSTRLEN),
975 		       rai->retranstimer);
976 		inconsistent++;
977 	}
978 	/* Values in the MTU options */
979 	if (ndopts.nd_opts_mtu) {
980 		mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu);
981 		if (mtu && rai->linkmtu && mtu != rai->linkmtu) {
982 			syslog(LOG_WARNING,
983 			       "<%s> MTU option value inconsistent on %s:"
984 			       " %d from %s, %d from us",
985 			       __FUNCTION__,
986 			       rai->ifname, mtu,
987 			       inet_ntop(AF_INET6, &from->sin6_addr,
988 					 ntopbuf, INET6_ADDRSTRLEN),
989 			       rai->linkmtu);
990 			inconsistent++;
991 		}
992 	}
993 	/* Preferred and Valid Lifetimes for prefixes */
994 	{
995 		struct nd_optlist *optp = ndopts.nd_opts_list;
996 
997 		if (ndopts.nd_opts_pi) {
998 			if (prefix_check(ndopts.nd_opts_pi, rai, from))
999 				inconsistent++;
1000 		}
1001 		while (optp) {
1002 			if (prefix_check((struct nd_opt_prefix_info *)optp->opt,
1003 					 rai, from))
1004 				inconsistent++;
1005 			optp = optp->next;
1006 		}
1007 	}
1008 
1009 	if (inconsistent) {
1010 		printf("RA input %d inconsistents\n", inconsistent);
1011 		rai->rainconsistent++;
1012 	}
1013 
1014   done:
1015 	free_ndopts(&ndopts);
1016 	return;
1017 }
1018 
1019 /* return a non-zero value if the received prefix is inconsitent with ours */
1020 static int
1021 prefix_check(struct nd_opt_prefix_info *pinfo,
1022 	     struct rainfo *rai, struct sockaddr_in6 *from)
1023 {
1024 	u_int32_t preferred_time, valid_time;
1025 	struct prefix *pp;
1026 	int inconsistent = 0;
1027 	u_char ntopbuf[INET6_ADDRSTRLEN], prefixbuf[INET6_ADDRSTRLEN];
1028 
1029 #if 0				/* impossible */
1030 	if (pinfo->nd_opt_pi_type != ND_OPT_PREFIX_INFORMATION)
1031 		return(0);
1032 #endif
1033 
1034 	/*
1035 	 * log if the adveritsed prefix has link-local scope(sanity check?)
1036 	 */
1037 	if (IN6_IS_ADDR_LINKLOCAL(&pinfo->nd_opt_pi_prefix)) {
1038 		syslog(LOG_INFO,
1039 		       "<%s> link-local prefix %s/%d is advertised "
1040 		       "from %s on %s",
1041 		       __FUNCTION__,
1042 		       inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
1043 				 prefixbuf, INET6_ADDRSTRLEN),
1044 		       pinfo->nd_opt_pi_prefix_len,
1045 		       inet_ntop(AF_INET6, &from->sin6_addr,
1046 				 ntopbuf, INET6_ADDRSTRLEN),
1047 		       rai->ifname);
1048 	}
1049 
1050 	if ((pp = find_prefix(rai, &pinfo->nd_opt_pi_prefix,
1051 			      pinfo->nd_opt_pi_prefix_len)) == NULL) {
1052 		syslog(LOG_INFO,
1053 		       "<%s> prefix %s/%d from %s on %s is not in our list",
1054 		       __FUNCTION__,
1055 		       inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
1056 				 prefixbuf, INET6_ADDRSTRLEN),
1057 		       pinfo->nd_opt_pi_prefix_len,
1058 		       inet_ntop(AF_INET6, &from->sin6_addr,
1059 				 ntopbuf, INET6_ADDRSTRLEN),
1060 		       rai->ifname);
1061 		return(0);
1062 	}
1063 
1064 	preferred_time = ntohl(pinfo->nd_opt_pi_preferred_time);
1065 	if (preferred_time != pp->preflifetime) {
1066 		syslog(LOG_WARNING,
1067 		       "<%s> prefeerred lifetime for %s/%d"
1068 		       " inconsistent on %s:"
1069 		       " %d from %s, %d from us",
1070 		       __FUNCTION__,
1071 		       inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
1072 				 prefixbuf, INET6_ADDRSTRLEN),
1073 		       pinfo->nd_opt_pi_prefix_len,
1074 		       rai->ifname, preferred_time,
1075 		       inet_ntop(AF_INET6, &from->sin6_addr,
1076 				 ntopbuf, INET6_ADDRSTRLEN),
1077 		       pp->preflifetime);
1078 		inconsistent++;
1079 	}
1080 
1081 	valid_time = ntohl(pinfo->nd_opt_pi_valid_time);
1082 	if (valid_time != pp->validlifetime) {
1083 		syslog(LOG_WARNING,
1084 		       "<%s> valid lifetime for %s/%d"
1085 		       " inconsistent on %s:"
1086 		       " %d from %s, %d from us",
1087 		       __FUNCTION__,
1088 		       inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
1089 				 prefixbuf, INET6_ADDRSTRLEN),
1090 		       pinfo->nd_opt_pi_prefix_len,
1091 		       rai->ifname, valid_time,
1092 		       inet_ntop(AF_INET6, &from->sin6_addr,
1093 				 ntopbuf, INET6_ADDRSTRLEN),
1094 		       pp->validlifetime);
1095 		inconsistent++;
1096 	}
1097 
1098 	return(inconsistent);
1099 }
1100 
1101 struct prefix *
1102 find_prefix(struct rainfo *rai, struct in6_addr *prefix, int plen)
1103 {
1104 	struct prefix *pp;
1105 	int bytelen, bitlen;
1106 
1107 	for (pp = rai->prefix.next; pp != &rai->prefix; pp = pp->next) {
1108 		if (plen != pp->prefixlen)
1109 			continue;
1110 		bytelen = plen / 8;
1111 		bitlen = plen % 8;
1112 		if (memcmp((void *)prefix, (void *)&pp->prefix, bytelen))
1113 			continue;
1114 		if (prefix->s6_addr[bytelen] >> (8 - bitlen) ==
1115 		    pp->prefix.s6_addr[bytelen] >> (8 - bitlen))
1116 			return(pp);
1117 	}
1118 
1119 	return(NULL);
1120 }
1121 
1122 static int
1123 nd6_options(struct nd_opt_hdr *hdr, int limit,
1124 	    union nd_opts *ndopts, u_int32_t optflags)
1125 {
1126 	int optlen = 0;
1127 
1128 	for (; limit > 0; limit -= optlen) {
1129 		hdr = (struct nd_opt_hdr *)((caddr_t)hdr + optlen);
1130 		optlen = hdr->nd_opt_len << 3;
1131 		if (hdr->nd_opt_len == 0) {
1132 			syslog(LOG_ERR,
1133 			       "<%s> bad ND option length(0) (type = %d)",
1134 			       __FUNCTION__, hdr->nd_opt_type);
1135 			goto bad;
1136 		}
1137 
1138 		if (hdr->nd_opt_type > ND_OPT_MTU) {
1139 			syslog(LOG_INFO,
1140 			       "<%s> unknown ND option(type %d)",
1141 			       __FUNCTION__,
1142 			       hdr->nd_opt_type);
1143 			continue;
1144 		}
1145 
1146 		if ((ndopt_flags[hdr->nd_opt_type] & optflags) == 0) {
1147 			syslog(LOG_INFO,
1148 			       "<%s> unexpected ND option(type %d)",
1149 			       __FUNCTION__,
1150 			       hdr->nd_opt_type);
1151 			continue;
1152 		}
1153 
1154 		switch(hdr->nd_opt_type) {
1155 		 case ND_OPT_SOURCE_LINKADDR:
1156 		 case ND_OPT_TARGET_LINKADDR:
1157 		 case ND_OPT_REDIRECTED_HEADER:
1158 		 case ND_OPT_MTU:
1159 			 if (ndopts->nd_opt_array[hdr->nd_opt_type]) {
1160 				 syslog(LOG_INFO,
1161 					"<%s> duplicated ND option"
1162 					" (type = %d)",
1163 					__FUNCTION__,
1164 					hdr->nd_opt_type);
1165 			 }
1166 			 ndopts->nd_opt_array[hdr->nd_opt_type] = hdr;
1167 			 break;
1168 		 case ND_OPT_PREFIX_INFORMATION:
1169 		 {
1170 			 struct nd_optlist *pfxlist;
1171 
1172 			 if (ndopts->nd_opts_pi == 0) {
1173 				 ndopts->nd_opts_pi =
1174 					 (struct nd_opt_prefix_info *)hdr;
1175 				 continue;
1176 			 }
1177 			 if ((pfxlist = malloc(sizeof(*pfxlist))) == NULL) {
1178 				 syslog(LOG_ERR,
1179 					"<%s> can't allocate memory",
1180 					__FUNCTION__);
1181 				 goto bad;
1182 			 }
1183 			 pfxlist->next = ndopts->nd_opts_list;
1184 			 pfxlist->opt = hdr;
1185 			 ndopts->nd_opts_list = pfxlist;
1186 
1187 			 break;
1188 		 }
1189 		 default:	/* impossible */
1190 			 break;
1191 		}
1192 	}
1193 
1194 	return(0);
1195 
1196   bad:
1197 	free_ndopts(ndopts);
1198 
1199 	return(-1);
1200 }
1201 
1202 static void
1203 free_ndopts(union nd_opts *ndopts)
1204 {
1205 	struct nd_optlist *opt = ndopts->nd_opts_list, *next;
1206 
1207 	while(opt) {
1208 		next = opt->next;
1209 		free(opt);
1210 		opt = next;
1211 	}
1212 }
1213 
1214 void
1215 sock_open()
1216 {
1217 	struct icmp6_filter filt;
1218 	struct ipv6_mreq mreq;
1219 	struct rainfo *ra = ralist;
1220 	int on;
1221 	/* XXX: should be max MTU attached to the node */
1222 	static u_char answer[1500];
1223 
1224 	rcvcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
1225 				CMSG_SPACE(sizeof(int));
1226 	rcvcmsgbuf = (u_char *)malloc(rcvcmsgbuflen);
1227 	if (rcvcmsgbuf == NULL) {
1228 		syslog(LOG_ERR, "<%s> not enough core", __FUNCTION__);
1229 		exit(1);
1230 	}
1231 
1232 	sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
1233 				CMSG_SPACE(sizeof(int));
1234 	sndcmsgbuf = (u_char *)malloc(sndcmsgbuflen);
1235 	if (sndcmsgbuf == NULL) {
1236 		syslog(LOG_ERR, "<%s> not enough core", __FUNCTION__);
1237 		exit(1);
1238 	}
1239 
1240 	if ((sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
1241 		syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__,
1242 		       strerror(errno));
1243 		exit(1);
1244 	}
1245 
1246 	/* specify to tell receiving interface */
1247 	on = 1;
1248 #ifdef IPV6_RECVPKTINFO
1249 	if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
1250 		       sizeof(on)) < 0) {
1251 		syslog(LOG_ERR, "<%s> IPV6_RECVPKTINFO: %s",
1252 		       __FUNCTION__, strerror(errno));
1253 		exit(1);
1254 	}
1255 #else  /* old adv. API */
1256 	if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &on,
1257 		       sizeof(on)) < 0) {
1258 		syslog(LOG_ERR, "<%s> IPV6_PKTINFO: %s",
1259 		       __FUNCTION__, strerror(errno));
1260 		exit(1);
1261 	}
1262 #endif
1263 
1264 	on = 1;
1265 	/* specify to tell value of hoplimit field of received IP6 hdr */
1266 #ifdef IPV6_RECVHOPLIMIT
1267 	if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
1268 		       sizeof(on)) < 0) {
1269 		syslog(LOG_ERR, "<%s> IPV6_RECVHOPLIMIT: %s",
1270 		       __FUNCTION__, strerror(errno));
1271 		exit(1);
1272 	}
1273 #else  /* old adv. API */
1274 	if (setsockopt(sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
1275 		       sizeof(on)) < 0) {
1276 		syslog(LOG_ERR, "<%s> IPV6_HOPLIMIT: %s",
1277 		       __FUNCTION__, strerror(errno));
1278 		exit(1);
1279 	}
1280 #endif
1281 
1282 	ICMP6_FILTER_SETBLOCKALL(&filt);
1283 	ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt);
1284 	ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
1285 	if (accept_rr)
1286 		ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt);
1287 	if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
1288 		       sizeof(filt)) < 0) {
1289 		syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s",
1290 		       __FUNCTION__, strerror(errno));
1291 		exit(1);
1292 	}
1293 
1294 	/*
1295 	 * join all routers multicast address on each advertising interface.
1296 	 */
1297 	if (inet_pton(AF_INET6, ALLROUTERS, &mreq.ipv6mr_multiaddr.s6_addr)
1298 	    != 1) {
1299 		syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)",
1300 		       __FUNCTION__);
1301 		exit(1);
1302 	}
1303 	while(ra) {
1304 		mreq.ipv6mr_interface = ra->ifindex;
1305 		if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
1306 			       &mreq,
1307 			       sizeof(mreq)) < 0) {
1308 			syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP on %s: %s",
1309 			       __FUNCTION__, ra->ifname, strerror(errno));
1310 			exit(1);
1311 		}
1312 		ra = ra->next;
1313 	}
1314 
1315 	/* initialize msghdr for receiving packets */
1316 	rcviov[0].iov_base = (caddr_t)answer;
1317 	rcviov[0].iov_len = sizeof(answer);
1318 	rcvmhdr.msg_name = (caddr_t)&from;
1319 	rcvmhdr.msg_namelen = sizeof(from);
1320 	rcvmhdr.msg_iov = rcviov;
1321 	rcvmhdr.msg_iovlen = 1;
1322 	rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf;
1323 	rcvmhdr.msg_controllen = rcvcmsgbuflen;
1324 
1325 	/* initialize msghdr for sending packets */
1326 	sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
1327 	sndmhdr.msg_iov = sndiov;
1328 	sndmhdr.msg_iovlen = 1;
1329 	sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
1330 	sndmhdr.msg_controllen = sndcmsgbuflen;
1331 
1332 	return;
1333 }
1334 
1335 /* open a routing socket to watch the routing table */
1336 static void
1337 rtsock_open()
1338 {
1339 	if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
1340 		syslog(LOG_ERR,
1341 		       "<%s> socket: %s", __FUNCTION__, strerror(errno));
1342 		exit(1);
1343 	}
1344 }
1345 
1346 static struct rainfo *
1347 if_indextorainfo(int index)
1348 {
1349 	struct rainfo *rai = ralist;
1350 
1351 	for (rai = ralist; rai; rai = rai->next) {
1352 		if (rai->ifindex == index)
1353 			return(rai);
1354 	}
1355 
1356 	return(NULL);		/* search failed */
1357 }
1358 
1359 static void
1360 ra_output(rainfo)
1361 struct rainfo *rainfo;
1362 {
1363 	int i;
1364 	struct cmsghdr *cm;
1365 	struct in6_pktinfo *pi;
1366 	struct soliciter *sol, *nextsol;
1367 
1368 	if ((iflist[rainfo->ifindex]->ifm_flags & IFF_UP) == 0) {
1369 		syslog(LOG_DEBUG, "<%s> %s is not up, skip sending RA",
1370 		       __FUNCTION__, rainfo->ifname);
1371 		return;
1372 	}
1373 
1374 	sndmhdr.msg_name = (caddr_t)&sin6_allnodes;
1375 	sndmhdr.msg_iov[0].iov_base = (caddr_t)rainfo->ra_data;
1376 	sndmhdr.msg_iov[0].iov_len = rainfo->ra_datalen;
1377 
1378 	cm = CMSG_FIRSTHDR(&sndmhdr);
1379 	/* specify the outgoing interface */
1380 	cm->cmsg_level = IPPROTO_IPV6;
1381 	cm->cmsg_type = IPV6_PKTINFO;
1382 	cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
1383 	pi = (struct in6_pktinfo *)CMSG_DATA(cm);
1384 	memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr));	/*XXX*/
1385 	pi->ipi6_ifindex = rainfo->ifindex;
1386 
1387 	/* specify the hop limit of the packet */
1388 	{
1389 		int hoplimit = 255;
1390 
1391 		cm = CMSG_NXTHDR(&sndmhdr, cm);
1392 		cm->cmsg_level = IPPROTO_IPV6;
1393 		cm->cmsg_type = IPV6_HOPLIMIT;
1394 		cm->cmsg_len = CMSG_LEN(sizeof(int));
1395 		memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int));
1396 	}
1397 
1398 	syslog(LOG_DEBUG,
1399 	       "<%s> send RA on %s, # of waitings = %d",
1400 	       __FUNCTION__, rainfo->ifname, rainfo->waiting);
1401 
1402 	i = sendmsg(sock, &sndmhdr, 0);
1403 
1404 	if (i < 0 || i != rainfo->ra_datalen)  {
1405 		if (i < 0) {
1406 			syslog(LOG_ERR, "<%s> sendmsg on %s: %s",
1407 			       __FUNCTION__, rainfo->ifname,
1408 			       strerror(errno));
1409 		}
1410 	}
1411 
1412 	/*
1413 	 * unicast advertisements
1414 	 * XXX commented out.  reason: though spec does not forbit it, unicast
1415 	 * advert does not really help
1416 	 */
1417 	for (sol = rainfo->soliciter; sol; sol = nextsol) {
1418 		nextsol = sol->next;
1419 
1420 #if 0
1421 		sndmhdr.msg_name = (caddr_t)&sol->addr;
1422 		i = sendmsg(sock, &sndmhdr, 0);
1423 		if (i < 0 || i != rainfo->ra_datalen)  {
1424 			if (i < 0) {
1425 				syslog(LOG_ERR,
1426 				    "<%s> unicast sendmsg on %s: %s",
1427 				    __FUNCTION__, rainfo->ifname,
1428 				    strerror(errno));
1429 			}
1430 		}
1431 #endif
1432 
1433 		sol->next = NULL;
1434 		free(sol);
1435 	}
1436 	rainfo->soliciter = NULL;
1437 
1438 	/* update counter */
1439 	if (rainfo->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS)
1440 		rainfo->initcounter++;
1441 	rainfo->raoutput++;
1442 
1443 	/* update timestamp */
1444 	gettimeofday(&rainfo->lastsent, NULL);
1445 
1446 	/* reset waiting conter */
1447 	rainfo->waiting = 0;
1448 }
1449 
1450 /* process RA timer */
1451 void
1452 ra_timeout(void *data)
1453 {
1454 	struct rainfo *rai = (struct rainfo *)data;
1455 
1456 #ifdef notyet
1457 	/* if necessary, reconstruct the packet. */
1458 #endif
1459 
1460 	syslog(LOG_DEBUG,
1461 	       "<%s> RA timer on %s is expired",
1462 	       __FUNCTION__, rai->ifname);
1463 
1464 	ra_output(rai);
1465 }
1466 
1467 /* update RA timer */
1468 void
1469 ra_timer_update(void *data, struct timeval *tm)
1470 {
1471 	struct rainfo *rai = (struct rainfo *)data;
1472 	long interval;
1473 
1474 	/*
1475 	 * Whenever a multicast advertisement is sent from an interface,
1476 	 * the timer is reset to a uniformly-distributed random value
1477 	 * between the interface's configured MinRtrAdvInterval and
1478 	 * MaxRtrAdvInterval(discovery-v2-02 6.2.4).
1479 	 */
1480 	interval = rai->mininterval;
1481 	interval += random() % (rai->maxinterval - rai->mininterval);
1482 
1483 	/*
1484 	 * For the first few advertisements (up to
1485 	 * MAX_INITIAL_RTR_ADVERTISEMENTS), if the randomly chosen interval
1486 	 * is greater than MAX_INITIAL_RTR_ADVERT_INTERVAL, the timer
1487 	 * SHOULD be set to MAX_INITIAL_RTR_ADVERT_INTERVAL instead.
1488 	 * (RFC-2461 6.2.4)
1489 	 */
1490 	if (rai->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS &&
1491 	    interval > MAX_INITIAL_RTR_ADVERT_INTERVAL)
1492 		interval = MAX_INITIAL_RTR_ADVERT_INTERVAL;
1493 
1494 	tm->tv_sec = interval;
1495 	tm->tv_usec = 0;
1496 
1497 	syslog(LOG_DEBUG,
1498 	       "<%s> RA timer on %s is set to %ld:%ld",
1499 	       __FUNCTION__, rai->ifname,
1500 	       (long int)tm->tv_sec, (long int)tm->tv_usec);
1501 
1502 	return;
1503 }
1504