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