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