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