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