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