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