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