Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / usr.sbin / route6d / route6d.c
1 /*      $FreeBSD: src/usr.sbin/route6d/route6d.c,v 1.2.2.5 2001/07/03 11:02:09 ume Exp $        */
2 /*      $DragonFly: src/usr.sbin/route6d/route6d.c,v 1.2 2003/06/17 04:30:02 dillon Exp $       */
3 /*      $KAME: route6d.c,v 1.64 2001/05/08 04:36:37 itojun Exp $        */
4
5 /*
6  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7  * All rights reserved.
8  * 
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the project nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * $KAME: route6d.c,v 1.64 2001/05/08 04:36:37 itojun Exp $
34  */
35
36 #include <stdio.h>
37
38 #include <time.h>
39 #include <unistd.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <signal.h>
43 #ifdef __STDC__
44 #include <stdarg.h>
45 #else
46 #include <varargs.h>
47 #endif
48 #include <syslog.h>
49 #include <stddef.h>
50 #include <errno.h>
51 #include <err.h>
52
53 #include <sys/types.h>
54 #include <sys/param.h>
55 #include <sys/file.h>
56 #include <sys/socket.h>
57 #include <sys/ioctl.h>
58 #include <sys/sysctl.h>
59 #include <sys/uio.h>
60 #include <net/if.h>
61 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
62 #include <net/if_var.h>
63 #endif /* __FreeBSD__ >= 3 */
64 #define KERNEL  1
65 #define _KERNEL 1
66 #include <net/route.h>
67 #undef KERNEL
68 #undef _KERNEL
69 #include <netinet/in.h>
70 #include <netinet/in_var.h>
71 #include <netinet/ip6.h>
72 #include <netinet/udp.h>
73 #include <netdb.h>
74 #include <ifaddrs.h>
75
76 #include <arpa/inet.h>
77
78 #include "route6d.h"
79
80 #define MAXFILTER       40
81
82 #ifdef  DEBUG
83 #define INIT_INTERVAL6  6
84 #else
85 #define INIT_INTERVAL6  10      /* Wait to submit a initial riprequest */
86 #endif
87
88 /* alignment constraint for routing socket */
89 #define ROUNDUP(a) \
90         ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
91 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
92
93 /*
94  * Following two macros are highly depending on KAME Release
95  */
96 #define IN6_LINKLOCAL_IFINDEX(addr) \
97         ((addr).s6_addr[2] << 8 | (addr).s6_addr[3])
98
99 #define SET_IN6_LINKLOCAL_IFINDEX(addr, index) \
100         do { \
101                 (addr).s6_addr[2] = ((index) >> 8) & 0xff; \
102                 (addr).s6_addr[3] = (index) & 0xff; \
103         } while (0)
104
105 struct  ifc {                   /* Configuration of an interface */
106         char    *ifc_name;                      /* if name */
107         struct  ifc *ifc_next;
108         int     ifc_index;                      /* if index */
109         int     ifc_mtu;                        /* if mtu */
110         int     ifc_metric;                     /* if metric */
111         u_int   ifc_flags;                      /* flags */
112         short   ifc_cflags;                     /* IFC_XXX */
113         struct  in6_addr ifc_mylladdr;          /* my link-local address */
114         struct  sockaddr_in6 ifc_ripsin;        /* rip multicast address */
115         struct  iff *ifc_filter;                /* filter structure */
116         struct  ifac *ifc_addr;                 /* list of AF_INET6 addresses */
117         int     ifc_joined;                     /* joined to ff02::9 */
118 };
119
120 struct  ifac {                  /* Adddress associated to an interface */ 
121         struct  ifc *ifa_conf;          /* back pointer */
122         struct  ifac *ifa_next;
123         struct  in6_addr ifa_addr;      /* address */
124         struct  in6_addr ifa_raddr;     /* remote address, valid in p2p */
125         int     ifa_plen;               /* prefix length */
126 };
127
128 struct  iff {
129         int     iff_type;
130         struct  in6_addr iff_addr;
131         int     iff_plen;
132         struct  iff *iff_next;
133 };
134
135 struct  ifc *ifc;
136 int     nifc;           /* number of valid ifc's */
137 struct  ifc **index2ifc;
138 int     nindex2ifc;
139 struct  ifc *loopifcp = NULL;   /* pointing to loopback */
140 int     loopifindex = 0;        /* ditto */
141 fd_set  sockvec;        /* vector to select() for receiving */
142 int     rtsock;         /* the routing socket */
143 int     ripsock;        /* socket to send/receive RIP datagram */
144
145 struct  rip6 *ripbuf;   /* packet buffer for sending */
146
147 /*
148  * Maintain the routes in a linked list.  When the number of the routes
149  * grows, somebody would like to introduce a hash based or a radix tree
150  * based structure.  I believe the number of routes handled by RIP is
151  * limited and I don't have to manage a complex data structure, however.
152  *
153  * One of the major drawbacks of the linear linked list is the difficulty
154  * of representing the relationship between a couple of routes.  This may
155  * be a significant problem when we have to support route aggregation with
156  * supressing the specifices covered by the aggregate.
157  */
158
159 struct  riprt {
160         struct  riprt *rrt_next;        /* next destination */
161         struct  riprt *rrt_same;        /* same destination - future use */
162         struct  netinfo6 rrt_info;      /* network info */
163         struct  in6_addr rrt_gw;        /* gateway */
164         u_long  rrt_flags;              /* kernel routing table flags */
165         u_long  rrt_rflags;             /* route6d routing table flags */
166         time_t  rrt_t;                  /* when the route validated */
167         int     rrt_index;              /* ifindex from which this route got */
168 };
169
170 struct  riprt *riprt = 0;
171
172 int     dflag = 0;      /* debug flag */
173 int     qflag = 0;      /* quiet flag */
174 int     nflag = 0;      /* don't update kernel routing table */
175 int     aflag = 0;      /* age out even the statically defined routes */
176 int     hflag = 0;      /* don't split horizon */
177 int     lflag = 0;      /* exchange site local routes */
178 int     sflag = 0;      /* announce static routes w/ split horizon */
179 int     Sflag = 0;      /* announce static routes to every interface */
180 unsigned long routetag = 0;     /* route tag attached on originating case */
181
182 char    *filter[MAXFILTER];
183 int     filtertype[MAXFILTER];
184 int     nfilter = 0;
185
186 pid_t   pid;
187
188 struct  sockaddr_storage ripsin;
189
190 struct  rtentry rtentry;
191
192 int     interval = 1;
193 time_t  nextalarm = 0;
194 time_t  sup_trig_update = 0;
195
196 FILE    *rtlog = NULL;
197
198 int logopened = 0;
199
200 static  u_long  seq = 0;
201
202 volatile int signo;
203 volatile sig_atomic_t seenalrm;
204 volatile sig_atomic_t seenquit;
205 volatile sig_atomic_t seenusr1;
206
207 #define RRTF_AGGREGATE          0x08000000
208 #define RRTF_NOADVERTISE        0x10000000
209 #define RRTF_NH_NOT_LLADDR      0x20000000
210 #define RRTF_SENDANYWAY         0x40000000
211 #define RRTF_CHANGED            0x80000000
212
213 int main __P((int, char **));
214 void sighandler __P((int));
215 void ripalarm __P((void));
216 void riprecv __P((void));
217 void ripsend __P((struct ifc *, struct sockaddr_in6 *, int));
218 int out_filter __P((struct riprt *, struct ifc *));
219 void init __P((void));
220 void sockopt __P((struct ifc *));
221 void ifconfig __P((void));
222 void ifconfig1 __P((const char *, const struct sockaddr *, struct ifc *, int));
223 void rtrecv __P((void));
224 int rt_del __P((const struct sockaddr_in6 *, const struct sockaddr_in6 *,
225         const struct sockaddr_in6 *));
226 int rt_deladdr __P((struct ifc *, const struct sockaddr_in6 *,
227         const struct sockaddr_in6 *));
228 void filterconfig __P((void));
229 int getifmtu __P((int));
230 const char *rttypes __P((struct rt_msghdr *));
231 const char *rtflags __P((struct rt_msghdr *));
232 const char *ifflags __P((int));
233 int ifrt __P((struct ifc *, int));
234 void ifrt_p2p __P((struct ifc *, int));
235 void applymask __P((struct in6_addr *, struct in6_addr *));
236 void applyplen __P((struct in6_addr *, int));
237 void ifrtdump __P((int));
238 void ifdump __P((int));
239 void ifdump0 __P((FILE *, const struct ifc *));
240 void rtdump __P((int));
241 void rt_entry __P((struct rt_msghdr *, int));
242 void rtdexit __P((void));
243 void riprequest __P((struct ifc *, struct netinfo6 *, int,
244         struct sockaddr_in6 *));
245 void ripflush __P((struct ifc *, struct sockaddr_in6 *));
246 void sendrequest __P((struct ifc *));
247 int sin6mask2len __P((const struct sockaddr_in6 *));
248 int mask2len __P((const struct in6_addr *, int));
249 int sendpacket __P((struct sockaddr_in6 *, int));
250 int addroute __P((struct riprt *, const struct in6_addr *, struct ifc *));
251 int delroute __P((struct netinfo6 *, struct in6_addr *));
252 struct in6_addr *getroute __P((struct netinfo6 *, struct in6_addr *));
253 void krtread __P((int));
254 int tobeadv __P((struct riprt *, struct ifc *));
255 char *allocopy __P((char *));
256 char *hms __P((void));
257 const char *inet6_n2p __P((const struct in6_addr *));
258 struct ifac *ifa_match __P((const struct ifc *, const struct in6_addr *, int));
259 struct in6_addr *plen2mask __P((int));
260 struct riprt *rtsearch __P((struct netinfo6 *, struct riprt **));
261 int ripinterval __P((int));
262 time_t ripsuptrig __P((void));
263 void fatal __P((const char *, ...))
264         __attribute__((__format__(__printf__, 1, 2)));
265 void trace __P((int, const char *, ...))
266         __attribute__((__format__(__printf__, 2, 3)));
267 void tracet __P((int, const char *, ...))
268         __attribute__((__format__(__printf__, 2, 3)));
269 unsigned int if_maxindex __P((void));
270 struct ifc *ifc_find __P((char *));
271 struct iff *iff_find __P((struct ifc *, int));
272 void setindex2ifc __P((int, struct ifc *));
273
274 #define MALLOC(type)    ((type *)malloc(sizeof(type)))
275
276 int
277 main(argc, argv)
278         int     argc;
279         char    **argv;
280 {
281         int     ch;
282         int     error = 0;
283         struct  ifc *ifcp;
284         sigset_t mask, omask;
285         FILE    *pidfile;
286         char *progname;
287         char *ep;
288
289         progname = strrchr(*argv, '/');
290         if (progname)
291                 progname++;
292         else
293                 progname = *argv;
294
295         pid = getpid();
296         while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnqsS")) != -1) {
297                 switch (ch) {
298                 case 'A':
299                 case 'N':
300                 case 'O':
301                 case 'T':
302                 case 'L':
303                         if (nfilter >= MAXFILTER) {
304                                 fatal("Exceeds MAXFILTER");
305                                 /*NOTREACHED*/
306                         }
307                         filtertype[nfilter] = ch;
308                         filter[nfilter++] = allocopy(optarg);
309                         break;
310                 case 't':
311                         ep = NULL;
312                         routetag = strtoul(optarg, &ep, 0);
313                         if (!ep || *ep != '\0' || (routetag & ~0xffff) != 0) {
314                                 fatal("invalid route tag");
315                                 /*NOTREACHED*/
316                         }
317                         break;
318                 case 'R':
319                         if ((rtlog = fopen(optarg, "w")) == NULL) {
320                                 fatal("Can not write to routelog");
321                                 /*NOTREACHED*/
322                         }
323                         break;
324 #define FLAG(c, flag, n)        case c: do { flag = n; break; } while(0)
325                 FLAG('a', aflag, 1); break;
326                 FLAG('d', dflag, 1); break;
327                 FLAG('D', dflag, 2); break;
328                 FLAG('h', hflag, 1); break;
329                 FLAG('l', lflag, 1); break;
330                 FLAG('n', nflag, 1); break;
331                 FLAG('q', qflag, 1); break;
332                 FLAG('s', sflag, 1); break;
333                 FLAG('S', Sflag, 1); break;
334 #undef  FLAG
335                 default:
336                         fatal("Invalid option specified, terminating");
337                         /*NOTREACHED*/
338                 }
339         }
340         argc -= optind;
341         argv += optind;
342         if (argc > 0) {
343                 fatal("bogus extra arguments");
344                 /*NOTREACHED*/
345         }
346
347         if (geteuid()) {
348                 nflag = 1;
349                 fprintf(stderr, "No kernel update is allowed\n");
350         }
351         openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON);
352         logopened++;
353
354         if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL)
355                 fatal("malloc");
356         memset(ripbuf, 0, RIP6_MAXMTU);
357         ripbuf->rip6_cmd = RIP6_RESPONSE;
358         ripbuf->rip6_vers = RIP6_VERSION;
359         ripbuf->rip6_res1[0] = 0;
360         ripbuf->rip6_res1[1] = 0;
361
362         init();
363         ifconfig();
364         for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
365                 if (ifcp->ifc_index < 0) {
366                         fprintf(stderr,
367 "No ifindex found at %s (no link-local address?)\n",
368                                 ifcp->ifc_name);
369                         error++;
370                 }
371         }
372         if (error)
373                 exit(1);
374         if (loopifcp == NULL) {
375                 fatal("No loopback found");
376                 /*NOTREACHED*/
377         }
378         loopifindex = loopifcp->ifc_index;
379         for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next)
380                 ifrt(ifcp, 0);
381         filterconfig();
382         krtread(0);
383         if (dflag)
384                 ifrtdump(0);
385
386         if (dflag == 0) {
387 #if 1
388                 if (daemon(0, 0) < 0) {
389                         fatal("daemon");
390                         /*NOTREACHED*/
391                 }
392 #else
393                 if (fork())
394                         exit(0);
395                 if (setsid() < 0) {
396                         fatal("setid");
397                         /*NOTREACHED*/
398                 }
399 #endif
400         }
401         pid = getpid();
402         if ((pidfile = fopen(ROUTE6D_PID, "w")) != NULL) {
403                 fprintf(pidfile, "%d\n", pid);
404                 fclose(pidfile);
405         }
406
407         if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) {
408                 fatal("malloc");
409                 /*NOTREACHED*/
410         }
411         memset(ripbuf, 0, RIP6_MAXMTU);
412         ripbuf->rip6_cmd = RIP6_RESPONSE;
413         ripbuf->rip6_vers = RIP6_VERSION;
414         ripbuf->rip6_res1[0] = 0;
415         ripbuf->rip6_res1[1] = 0;
416
417         if (signal(SIGALRM, sighandler) == SIG_ERR ||
418             signal(SIGQUIT, sighandler) == SIG_ERR ||
419             signal(SIGTERM, sighandler) == SIG_ERR ||
420             signal(SIGUSR1, sighandler) == SIG_ERR ||
421             signal(SIGHUP, sighandler) == SIG_ERR ||
422             signal(SIGINT, sighandler) == SIG_ERR) {
423                 fatal("signal");
424                 /*NOTREACHED*/
425         }
426         /*
427          * To avoid rip packet congestion (not on a cable but in this
428          * process), wait for a moment to send the first RIP6_RESPONSE
429          * packets.
430          */
431         alarm(ripinterval(INIT_INTERVAL6));
432
433         for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
434                 if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP))
435                         sendrequest(ifcp);
436         }
437
438         syslog(LOG_INFO, "**** Started ****");
439         sigemptyset(&mask);
440         sigaddset(&mask, SIGALRM);
441         while (1) {
442                 fd_set  recvec;
443
444                 if (seenalrm) {
445                         ripalarm();
446                         seenalrm = 0;
447                         continue;
448                 }
449                 if (seenquit) {
450                         rtdexit();
451                         seenquit = 0;
452                         continue;
453                 }
454                 if (seenusr1) {
455                         ifrtdump(SIGUSR1);
456                         seenusr1 = 0;
457                         continue;
458                 }
459
460                 FD_COPY(&sockvec, &recvec);
461                 signo = 0;
462                 switch (select(FD_SETSIZE, &recvec, 0, 0, 0)) {
463                 case -1:
464                         if (errno != EINTR) {
465                                 fatal("select");
466                                 /*NOTREACHED*/
467                         }
468                         continue;
469                 case 0:
470                         continue;
471                 default:
472                         if (FD_ISSET(ripsock, &recvec)) {
473                                 sigprocmask(SIG_BLOCK, &mask, &omask);
474                                 riprecv();
475                                 sigprocmask(SIG_SETMASK, &omask, NULL);
476                         }
477                         if (FD_ISSET(rtsock, &recvec)) {
478                                 sigprocmask(SIG_BLOCK, &mask, &omask);
479                                 rtrecv();
480                                 sigprocmask(SIG_SETMASK, &omask, NULL);
481                         }
482                 }
483         }
484 }
485
486 void
487 sighandler(sig)
488         int sig;
489 {
490
491         signo = sig;
492         switch (signo) {
493         case SIGALRM:
494                 seenalrm++;
495                 break;
496         case SIGQUIT:
497         case SIGTERM:
498                 seenquit++;
499                 break;
500         case SIGUSR1:
501         case SIGHUP:
502         case SIGINT:
503                 seenusr1++;
504                 break;
505         }
506 }
507
508 /*
509  * gracefully exits after resetting sockopts.
510  */
511 /* ARGSUSED */
512 void
513 rtdexit()
514 {
515         struct  riprt *rrt;
516
517         alarm(0);
518         for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
519                 if (rrt->rrt_rflags & RRTF_AGGREGATE) {
520                         delroute(&rrt->rrt_info, &rrt->rrt_gw);
521                 }
522         }
523         close(ripsock);
524         close(rtsock);
525         syslog(LOG_INFO, "**** Terminated ****");
526         closelog();
527         exit(1);
528 }
529
530 /*
531  * Called periodically:
532  *      1. age out the learned route. remove it if necessary.
533  *      2. submit RIP6_RESPONSE packets.
534  * Invoked in every SUPPLY_INTERVAL6 (30) seconds.  I believe we don't have
535  * to invoke this function in every 1 or 5 or 10 seconds only to age the
536  * routes more precisely.
537  */
538 /* ARGSUSED */
539 void
540 ripalarm()
541 {
542         struct  ifc *ifcp;
543         struct  riprt *rrt, *rrt_prev, *rrt_next;
544         time_t  t_lifetime, t_holddown;
545
546         /* age the RIP routes */
547         rrt_prev = 0;
548         t_lifetime = time(NULL) - RIP_LIFETIME;
549         t_holddown = t_lifetime - RIP_HOLDDOWN;
550         for (rrt = riprt; rrt; rrt = rrt_next) {
551                 rrt_next = rrt->rrt_next;
552
553                 if (rrt->rrt_t == 0) {
554                         rrt_prev = rrt;
555                         continue;
556                 }
557                 if (rrt->rrt_t < t_holddown) {
558                         if (rrt_prev) {
559                                 rrt_prev->rrt_next = rrt->rrt_next;
560                         } else {
561                                 riprt = rrt->rrt_next;
562                         }
563                         delroute(&rrt->rrt_info, &rrt->rrt_gw);
564                         free(rrt);
565                         continue;
566                 }
567                 if (rrt->rrt_t < t_lifetime)
568                         rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
569                 rrt_prev = rrt;
570         }
571         /* Supply updates */
572         for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
573                 if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP))
574                         ripsend(ifcp, &ifcp->ifc_ripsin, 0);
575         }
576         alarm(ripinterval(SUPPLY_INTERVAL6));
577 }
578
579 void
580 init()
581 {
582         int     i, int0, int255, error;
583         struct  addrinfo hints, *res;
584         char    port[10];
585
586         ifc = (struct ifc *)NULL;
587         nifc = 0;
588         nindex2ifc = 0; /*initial guess*/
589         index2ifc = NULL;
590         snprintf(port, sizeof(port), "%d", RIP6_PORT);
591
592         memset(&hints, 0, sizeof(hints));
593         hints.ai_family = PF_INET6;
594         hints.ai_socktype = SOCK_DGRAM;
595         hints.ai_flags = AI_PASSIVE;
596         error = getaddrinfo(NULL, port, &hints, &res);
597         if (error) {
598                 fatal("%s", gai_strerror(error));
599                 /*NOTREACHED*/
600         }
601         if (res->ai_next) {
602                 fatal(":: resolved to multiple address");
603                 /*NOTREACHED*/
604         }
605
606         int0 = 0; int255 = 255;
607         ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
608         if (ripsock < 0) {
609                 fatal("rip socket");
610                 /*NOTREACHED*/
611         }
612         if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0) {
613                 fatal("rip bind");
614                 /*NOTREACHED*/
615         }
616         if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
617             &int255, sizeof(int255)) < 0) {
618                 fatal("rip IPV6_MULTICAST_HOPS");
619                 /*NOTREACHED*/
620         }
621         if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
622             &int0, sizeof(int0)) < 0) {
623                 fatal("rip IPV6_MULTICAST_LOOP");
624                 /*NOTREACHED*/
625         }
626
627         i = 1;
628 #ifdef IPV6_RECVPKTINFO
629         if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &i,
630             sizeof(i)) < 0) {
631                 fatal("rip IPV6_RECVPKTINFO");
632                 /*NOTREACHED*/
633         }
634 #else  /* old adv. API */
635         if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_PKTINFO, &i,
636             sizeof(i)) < 0) {
637                 fatal("rip IPV6_PKTINFO");
638                 /*NOTREACHED*/
639         }
640 #endif 
641
642         memset(&hints, 0, sizeof(hints));
643         hints.ai_family = PF_INET6;
644         hints.ai_socktype = SOCK_DGRAM;
645         error = getaddrinfo(RIP6_DEST, port, &hints, &res);
646         if (error) {
647                 fatal("%s", gai_strerror(error));
648                 /*NOTREACHED*/
649         }
650         if (res->ai_next) {
651                 fatal("%s resolved to multiple address", RIP6_DEST);
652                 /*NOTREACHED*/
653         }
654         memcpy(&ripsin, res->ai_addr, res->ai_addrlen);
655
656 #ifdef FD_ZERO
657         FD_ZERO(&sockvec);
658 #else
659         memset(&sockvec, 0, sizeof(sockvec));
660 #endif
661         FD_SET(ripsock, &sockvec);
662
663         if (nflag == 0) {
664                 if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
665                         fatal("route socket");
666                         /*NOTREACHED*/
667                 }
668                 FD_SET(rtsock, &sockvec);
669         } else
670                 rtsock = -1;    /*just for safety */
671 }
672
673 #define RIPSIZE(n) \
674         (sizeof(struct rip6) + ((n)-1) * sizeof(struct netinfo6))
675
676 /*
677  * ripflush flushes the rip datagram stored in the rip buffer
678  */
679 static int nrt;
680 static struct netinfo6 *np;
681
682 void
683 ripflush(ifcp, sin)
684         struct ifc *ifcp;
685         struct sockaddr_in6 *sin;
686 {
687         int i;
688         int error;
689
690         if (ifcp)
691                 tracet(1, "Send(%s): info(%d) to %s.%d\n",
692                         ifcp->ifc_name, nrt,
693                         inet6_n2p(&sin->sin6_addr), ntohs(sin->sin6_port));
694         else
695                 tracet(1, "Send: info(%d) to %s.%d\n",
696                         nrt, inet6_n2p(&sin->sin6_addr), ntohs(sin->sin6_port));
697         if (dflag >= 2) {
698                 np = ripbuf->rip6_nets;
699                 for (i = 0; i < nrt; i++, np++) {
700                         if (np->rip6_metric == NEXTHOP_METRIC) {
701                                 if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest))
702                                         trace(2, "    NextHop reset");
703                                 else {
704                                         trace(2, "    NextHop %s",
705                                                 inet6_n2p(&np->rip6_dest));
706                                 }
707                         } else {
708                                 trace(2, "    %s/%d[%d]",
709                                         inet6_n2p(&np->rip6_dest),
710                                         np->rip6_plen, np->rip6_metric);
711                         }
712                         if (np->rip6_tag) {
713                                 trace(2, "  tag=0x%04x",
714                                         ntohs(np->rip6_tag) & 0xffff);
715                         }
716                         trace(2, "\n");
717                 }
718         }
719         error = sendpacket(sin, RIPSIZE(nrt));
720         if (error == EAFNOSUPPORT) {
721                 /* Protocol not supported */
722                 tracet(1, "Could not send info to %s (%s): "
723                         "set IFF_UP to 0\n",
724                         ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
725                 ifcp->ifc_flags &= ~IFF_UP;     /* As if down for AF_INET6 */
726         }
727         nrt = 0; np = ripbuf->rip6_nets;
728 }
729
730 /*
731  * Generate RIP6_RESPONSE packets and send them.
732  */
733 void
734 ripsend(ifcp, sin, flag)
735         struct  ifc *ifcp;
736         struct  sockaddr_in6 *sin;
737         int flag;
738 {
739         struct  riprt *rrt;
740         struct  in6_addr *nh;   /* next hop */
741         int     maxrte;
742
743         if (ifcp == NULL) {
744                 /*
745                  * Request from non-link local address is not
746                  * a regular route6d update.
747                  */
748                 maxrte = (IFMINMTU - sizeof(struct ip6_hdr) - 
749                                 sizeof(struct udphdr) - 
750                                 sizeof(struct rip6) + sizeof(struct netinfo6)) /
751                                 sizeof(struct netinfo6);
752                 nrt = 0; np = ripbuf->rip6_nets; nh = NULL;
753                 for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
754                         if (rrt->rrt_rflags & RRTF_NOADVERTISE)
755                                 continue;
756                         /* Put the route to the buffer */
757                         *np = rrt->rrt_info;
758                         np++; nrt++;
759                         if (nrt == maxrte) {
760                                 ripflush(NULL, sin);
761                                 nh = NULL;
762                         }
763                 }
764                 if (nrt)        /* Send last packet */
765                         ripflush(NULL, sin);
766                 return;
767         }
768
769         if ((flag & RRTF_SENDANYWAY) == 0 &&
770             (qflag || (ifcp->ifc_flags & IFF_LOOPBACK)))
771                 return;
772
773         /* -N: no use */
774         if (iff_find(ifcp, 'N') != NULL)
775                 return;
776
777         /* -T: generate default route only */
778         if (iff_find(ifcp, 'T') != NULL) {
779                 struct netinfo6 rrt_info;
780                 memset(&rrt_info, 0, sizeof(struct netinfo6));
781                 rrt_info.rip6_dest = in6addr_any;
782                 rrt_info.rip6_plen = 0;
783                 rrt_info.rip6_metric = 1;
784                 rrt_info.rip6_metric += ifcp->ifc_metric;
785                 rrt_info.rip6_tag = htons(routetag & 0xffff);
786                 np = ripbuf->rip6_nets;
787                 *np = rrt_info;
788                 nrt = 1;
789                 ripflush(ifcp, sin);
790                 return;
791         }
792
793         maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) - 
794                         sizeof(struct udphdr) - 
795                         sizeof(struct rip6) + sizeof(struct netinfo6)) /
796                         sizeof(struct netinfo6);
797
798         nrt = 0; np = ripbuf->rip6_nets; nh = NULL;
799         for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
800                 if (rrt->rrt_rflags & RRTF_NOADVERTISE)
801                         continue;
802
803                 /* Need to check filter here */
804                 if (out_filter(rrt, ifcp) == 0)
805                         continue;
806
807                 /* Check split horizon and other conditions */
808                 if (tobeadv(rrt, ifcp) == 0)
809                         continue;
810
811                 /* Only considers the routes with flag if specified */
812                 if ((flag & RRTF_CHANGED) &&
813                     (rrt->rrt_rflags & RRTF_CHANGED) == 0)
814                         continue;
815
816                 /* Check nexthop */
817                 if (rrt->rrt_index == ifcp->ifc_index &&
818                     !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) &&
819                     (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) == 0) {
820                         if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) {
821                                 if (nrt == maxrte - 2)
822                                         ripflush(ifcp, sin);
823                                 np->rip6_dest = rrt->rrt_gw;
824                                 if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest))
825                                         SET_IN6_LINKLOCAL_IFINDEX(np->rip6_dest, 0);
826                                 np->rip6_plen = 0;
827                                 np->rip6_tag = 0;
828                                 np->rip6_metric = NEXTHOP_METRIC;
829                                 nh = &rrt->rrt_gw;
830                                 np++; nrt++;
831                         }
832                 } else if (nh && (rrt->rrt_index != ifcp->ifc_index ||
833                                   !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) ||
834                                   rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)) {
835                         /* Reset nexthop */
836                         if (nrt == maxrte - 2)
837                                 ripflush(ifcp, sin);
838                         memset(np, 0, sizeof(struct netinfo6));
839                         np->rip6_metric = NEXTHOP_METRIC;
840                         nh = NULL;
841                         np++; nrt++;
842                 }
843
844                 /* Put the route to the buffer */
845                 *np = rrt->rrt_info;
846                 np++; nrt++;
847                 if (nrt == maxrte) {
848                         ripflush(ifcp, sin);
849                         nh = NULL;
850                 }
851         }
852         if (nrt)        /* Send last packet */
853                 ripflush(ifcp, sin);
854 }
855
856 /*
857  * outbound filter logic, per-route/interface.
858  */
859 int
860 out_filter(rrt, ifcp)
861         struct riprt *rrt;
862         struct ifc *ifcp;
863 {
864         struct iff *iffp;
865         struct in6_addr ia;
866         int ok;
867
868         /*
869          * -A: filter out less specific routes, if we have aggregated
870          * route configured.
871          */ 
872         for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
873                 if (iffp->iff_type != 'A')
874                         continue;
875                 if (rrt->rrt_info.rip6_plen <= iffp->iff_plen)
876                         continue;
877                 ia = rrt->rrt_info.rip6_dest; 
878                 applyplen(&ia, iffp->iff_plen);
879                 if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr))
880                         return 0;
881         }
882
883         /*
884          * if it is an aggregated route, advertise it only to the
885          * interfaces specified on -A.
886          */
887         if ((rrt->rrt_rflags & RRTF_AGGREGATE) != 0) {
888                 ok = 0;
889                 for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
890                         if (iffp->iff_type != 'A')
891                                 continue;
892                         if (rrt->rrt_info.rip6_plen == iffp->iff_plen &&
893                             IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
894                             &iffp->iff_addr)) {
895                                 ok = 1;
896                                 break;
897                         }
898                 }
899                 if (!ok)
900                         return 0;
901         }
902
903         /*
904          * -O: advertise only if prefix matches the configured prefix.
905          */
906         if (iff_find(ifcp, 'O')) {
907                 ok = 0;
908                 for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
909                         if (iffp->iff_type != 'O')
910                                 continue;
911                         if (rrt->rrt_info.rip6_plen < iffp->iff_plen)
912                                 continue;
913                         ia = rrt->rrt_info.rip6_dest; 
914                         applyplen(&ia, iffp->iff_plen);
915                         if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) {
916                                 ok = 1;
917                                 break;
918                         }
919                 }
920                 if (!ok)
921                         return 0;
922         }
923
924         /* the prefix should be advertised */
925         return 1;
926 }
927
928 /*
929  * Determine if the route is to be advertised on the specified interface.
930  * It checks options specified in the arguments and the split horizon rule.
931  */
932 int
933 tobeadv(rrt, ifcp)
934         struct riprt *rrt;
935         struct ifc *ifcp;
936 {
937
938         /* Special care for static routes */
939         if (rrt->rrt_flags & RTF_STATIC) {
940                 /* XXX don't advertise reject/blackhole routes */
941                 if (rrt->rrt_flags & (RTF_REJECT | RTF_BLACKHOLE))
942                         return 0;
943
944                 if (Sflag)      /* Yes, advertise it anyway */
945                         return 1;
946                 if (sflag && rrt->rrt_index != ifcp->ifc_index)
947                         return 1;
948                 return 0;
949         }
950         /* Regular split horizon */
951         if (hflag == 0 && rrt->rrt_index == ifcp->ifc_index)
952                 return 0;
953         return 1;
954 }
955
956 /*
957  * Send a rip packet actually.
958  */
959 int
960 sendpacket(sin, len)
961         struct  sockaddr_in6 *sin;
962         int     len;
963 {
964         /*
965          * MSG_DONTROUTE should not be specified when it responds with a
966          * RIP6_REQUEST message.  SO_DONTROUTE has been specified to
967          * other sockets.
968          */
969         struct msghdr m;
970         struct cmsghdr *cm;
971         struct iovec iov[2];
972         u_char cmsgbuf[256];
973         struct in6_pktinfo *pi;
974         int idx;
975         struct sockaddr_in6 sincopy;
976
977         /* do not overwrite the given sin */
978         sincopy = *sin;
979         sin = &sincopy;
980
981         if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)
982          || IN6_IS_ADDR_MULTICAST(&sin->sin6_addr)) {
983                 idx = IN6_LINKLOCAL_IFINDEX(sin->sin6_addr);
984                 SET_IN6_LINKLOCAL_IFINDEX(sin->sin6_addr, 0);
985         } else
986                 idx = 0;
987
988         m.msg_name = (caddr_t)sin;
989         m.msg_namelen = sizeof(*sin);
990         iov[0].iov_base = (caddr_t)ripbuf;
991         iov[0].iov_len = len;
992         m.msg_iov = iov;
993         m.msg_iovlen = 1;
994         if (!idx) {
995                 m.msg_control = NULL;
996                 m.msg_controllen = 0;
997         } else {
998                 memset(cmsgbuf, 0, sizeof(cmsgbuf));
999                 cm = (struct cmsghdr *)cmsgbuf;
1000                 m.msg_control = (caddr_t)cm;
1001                 m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
1002
1003                 cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
1004                 cm->cmsg_level = IPPROTO_IPV6;
1005                 cm->cmsg_type = IPV6_PKTINFO;
1006                 pi = (struct in6_pktinfo *)CMSG_DATA(cm);
1007                 memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/
1008                 pi->ipi6_ifindex = idx;
1009         }
1010
1011         if (sendmsg(ripsock, &m, 0 /*MSG_DONTROUTE*/) < 0) {
1012                 trace(1, "sendmsg: %s\n", strerror(errno));
1013                 return errno;
1014         }
1015
1016         return 0;
1017 }
1018
1019 /*
1020  * Receive and process RIP packets.  Update the routes/kernel forwarding
1021  * table if necessary.
1022  */
1023 void
1024 riprecv()
1025 {
1026         struct  ifc *ifcp, *ic;
1027         struct  sockaddr_in6 fsock;
1028         struct  in6_addr nh;    /* next hop */
1029         struct  rip6 *rp;
1030         struct  netinfo6 *np, *nq;
1031         struct  riprt *rrt;
1032         int     len, nn, need_trigger, idx;
1033         char    buf[4 * RIP6_MAXMTU];
1034         time_t  t;
1035         struct msghdr m;
1036         struct cmsghdr *cm;
1037         struct iovec iov[2];
1038         u_char cmsgbuf[256];
1039         struct in6_pktinfo *pi;
1040         struct iff *iffp;
1041         struct in6_addr ia;
1042         int ok;
1043         time_t t_half_lifetime;
1044
1045         need_trigger = 0;
1046
1047         m.msg_name = (caddr_t)&fsock;
1048         m.msg_namelen = sizeof(fsock);
1049         iov[0].iov_base = (caddr_t)buf;
1050         iov[0].iov_len = sizeof(buf);
1051         m.msg_iov = iov;
1052         m.msg_iovlen = 1;
1053         cm = (struct cmsghdr *)cmsgbuf;
1054         m.msg_control = (caddr_t)cm;
1055         m.msg_controllen = sizeof(cmsgbuf);
1056         if ((len = recvmsg(ripsock, &m, 0)) < 0) {
1057                 fatal("recvmsg");
1058                 /*NOTREACHED*/
1059         }
1060         idx = 0;
1061         for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m);
1062              cm;
1063              cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) {
1064                 if (cm->cmsg_level == IPPROTO_IPV6 &&
1065                     cm->cmsg_type == IPV6_PKTINFO) {
1066                         pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
1067                         idx = pi->ipi6_ifindex;
1068                         break;
1069                 }
1070         }
1071         if (idx && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr))
1072                 SET_IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr, idx);
1073
1074         nh = fsock.sin6_addr;
1075         nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) /
1076                 sizeof(struct netinfo6);
1077         rp = (struct rip6 *)buf;
1078         np = rp->rip6_nets;
1079
1080         if (rp->rip6_vers !=  RIP6_VERSION) {
1081                 trace(1, "Incorrect RIP version %d\n", rp->rip6_vers);
1082                 return;
1083         }
1084         if (rp->rip6_cmd == RIP6_REQUEST) {
1085                 if (idx && idx < nindex2ifc) {
1086                         ifcp = index2ifc[idx];
1087                         riprequest(ifcp, np, nn, &fsock);
1088                 } else {
1089                         riprequest(NULL, np, nn, &fsock);
1090                 }
1091                 return; 
1092         } 
1093
1094         if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) {
1095                 trace(1, "Packets from non-ll addr: %s\n",
1096                     inet6_n2p(&fsock.sin6_addr));
1097                 return;         /* Ignore packets from non-link-local addr */
1098         }
1099         idx = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr);
1100         ifcp = (idx < nindex2ifc) ? index2ifc[idx] : NULL;
1101         if (!ifcp) {
1102                 trace(1, "Packets to unknown interface index %d\n", idx);
1103                 return;         /* Ignore it */
1104         }
1105         if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr))
1106                 return;         /* The packet is from me; ignore */
1107         if (rp->rip6_cmd != RIP6_RESPONSE) {
1108                 trace(1, "Invalid command %d\n", rp->rip6_cmd);
1109                 return; 
1110         }
1111
1112         /* -N: no use */
1113         if (iff_find(ifcp, 'N') != NULL)
1114                 return;
1115
1116         tracet(1, "Recv(%s): from %s.%d info(%d)\n",
1117             ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn);
1118
1119         t = time(NULL);
1120         t_half_lifetime = t - (RIP_LIFETIME/2);
1121         for (; nn; nn--, np++) {
1122                 if (np->rip6_metric == NEXTHOP_METRIC) {
1123                         /* modify neighbor address */
1124                         if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) {
1125                                 nh = np->rip6_dest;
1126                                 SET_IN6_LINKLOCAL_IFINDEX(nh, idx);
1127                                 trace(1, "\tNexthop: %s\n", inet6_n2p(&nh));
1128                         } else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) {
1129                                 nh = fsock.sin6_addr;
1130                                 trace(1, "\tNexthop: %s\n", inet6_n2p(&nh));
1131                         } else {
1132                                 nh = fsock.sin6_addr;
1133                                 trace(1, "\tInvalid Nexthop: %s\n",
1134                                     inet6_n2p(&np->rip6_dest));
1135                         }
1136                         continue;
1137                 }
1138                 if (IN6_IS_ADDR_MULTICAST(&np->rip6_dest)) {
1139                         trace(1, "\tMulticast netinfo6: %s/%d [%d]\n",
1140                                 inet6_n2p(&np->rip6_dest),
1141                                 np->rip6_plen, np->rip6_metric);
1142                         continue;
1143                 }
1144                 if (IN6_IS_ADDR_LOOPBACK(&np->rip6_dest)) {
1145                         trace(1, "\tLoopback netinfo6: %s/%d [%d]\n",
1146                                 inet6_n2p(&np->rip6_dest),
1147                                 np->rip6_plen, np->rip6_metric);
1148                         continue;
1149                 }
1150                 if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) {
1151                         trace(1, "\tLink Local netinfo6: %s/%d [%d]\n",
1152                                 inet6_n2p(&np->rip6_dest),
1153                                 np->rip6_plen, np->rip6_metric);
1154                         continue;
1155                 }
1156                 /* may need to pass sitelocal prefix in some case, however*/
1157                 if (IN6_IS_ADDR_SITELOCAL(&np->rip6_dest) && !lflag) {
1158                         trace(1, "\tSite Local netinfo6: %s/%d [%d]\n",
1159                                 inet6_n2p(&np->rip6_dest),
1160                                 np->rip6_plen, np->rip6_metric);
1161                         continue;
1162                 }
1163                 trace(2, "\tnetinfo6: %s/%d [%d]",
1164                         inet6_n2p(&np->rip6_dest),
1165                         np->rip6_plen, np->rip6_metric);
1166                 if (np->rip6_tag)
1167                         trace(2, "  tag=0x%04x", ntohs(np->rip6_tag) & 0xffff);
1168                 if (dflag >= 2) {
1169                         ia = np->rip6_dest;
1170                         applyplen(&ia, np->rip6_plen);
1171                         if (!IN6_ARE_ADDR_EQUAL(&ia, &np->rip6_dest))
1172                                 trace(2, " [junk outside prefix]");
1173                 }
1174
1175                 /*
1176                  * -L: listen only if the prefix matches the configuration
1177                  */
1178                 ok = 1;         /* if there's no L filter, it is ok */
1179                 for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
1180                         if (iffp->iff_type != 'L')
1181                                 continue;
1182                         ok = 0;
1183                         if (np->rip6_plen < iffp->iff_plen)
1184                                 continue;
1185                         /* special rule: ::/0 means default, not "in /0" */
1186                         if (iffp->iff_plen == 0 && np->rip6_plen > 0)
1187                                 continue;
1188                         ia = np->rip6_dest; 
1189                         applyplen(&ia, iffp->iff_plen);
1190                         if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) {
1191                                 ok = 1;
1192                                 break;
1193                         }
1194                 }
1195                 if (!ok) {
1196                         trace(2, "  (filtered)\n");
1197                         continue;
1198                 }
1199
1200                 trace(2, "\n");
1201                 np->rip6_metric++;
1202                 np->rip6_metric += ifcp->ifc_metric;
1203                 if (np->rip6_metric > HOPCNT_INFINITY6)
1204                         np->rip6_metric = HOPCNT_INFINITY6;
1205
1206                 applyplen(&np->rip6_dest, np->rip6_plen);
1207                 if ((rrt = rtsearch(np, NULL)) != NULL) {
1208                         if (rrt->rrt_t == 0)
1209                                 continue;       /* Intf route has priority */
1210                         nq = &rrt->rrt_info;
1211                         if (nq->rip6_metric > np->rip6_metric) {
1212                                 if (rrt->rrt_index == ifcp->ifc_index &&
1213                                     IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
1214                                         /* Small metric from the same gateway */
1215                                         nq->rip6_metric = np->rip6_metric;
1216                                 } else {
1217                                         /* Better route found */
1218                                         rrt->rrt_index = ifcp->ifc_index;
1219                                         /* Update routing table */
1220                                         delroute(nq, &rrt->rrt_gw);
1221                                         rrt->rrt_gw = nh;
1222                                         *nq = *np;
1223                                         addroute(rrt, &nh, ifcp);
1224                                 }
1225                                 rrt->rrt_rflags |= RRTF_CHANGED;
1226                                 rrt->rrt_t = t;
1227                                 need_trigger = 1;
1228                         } else if (nq->rip6_metric < np->rip6_metric &&
1229                                    rrt->rrt_index == ifcp->ifc_index &&
1230                                    IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
1231                                 /* Got worse route from same gw */
1232                                 nq->rip6_metric = np->rip6_metric;
1233                                 rrt->rrt_t = t;
1234                                 rrt->rrt_rflags |= RRTF_CHANGED;
1235                                 need_trigger = 1;
1236                         } else if (nq->rip6_metric == np->rip6_metric &&
1237                                    np->rip6_metric < HOPCNT_INFINITY6) {
1238                                 if (rrt->rrt_index == ifcp->ifc_index &&
1239                                    IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 
1240                                         /* same metric, same route from same gw */
1241                                         rrt->rrt_t = t;
1242                                 } else if (rrt->rrt_t < t_half_lifetime) {
1243                                         /* Better route found */
1244                                         rrt->rrt_index = ifcp->ifc_index;
1245                                         /* Update routing table */
1246                                         delroute(nq, &rrt->rrt_gw);
1247                                         rrt->rrt_gw = nh;
1248                                         *nq = *np;
1249                                         addroute(rrt, &nh, ifcp);
1250                                         rrt->rrt_rflags |= RRTF_CHANGED;
1251                                         rrt->rrt_t = t;
1252                                 }
1253                         }
1254                         /* 
1255                          * if nq->rip6_metric == HOPCNT_INFINITY6 then
1256                          * do not update age value.  Do nothing.
1257                          */
1258                 } else if (np->rip6_metric < HOPCNT_INFINITY6) {
1259                         /* Got a new valid route */
1260                         if ((rrt = MALLOC(struct riprt)) == NULL) {
1261                                 fatal("malloc: struct riprt");
1262                                 /*NOTREACHED*/
1263                         }
1264                         memset(rrt, 0, sizeof(*rrt));
1265                         nq = &rrt->rrt_info;
1266
1267                         rrt->rrt_same = NULL;
1268                         rrt->rrt_index = ifcp->ifc_index;
1269                         rrt->rrt_flags = RTF_UP|RTF_GATEWAY;
1270                         rrt->rrt_gw = nh;
1271                         *nq = *np;
1272                         applyplen(&nq->rip6_dest, nq->rip6_plen);
1273                         if (nq->rip6_plen == sizeof(struct in6_addr) * 8)
1274                                 rrt->rrt_flags |= RTF_HOST;
1275
1276                         /* Put the route to the list */
1277                         rrt->rrt_next = riprt;
1278                         riprt = rrt;
1279                         /* Update routing table */
1280                         addroute(rrt, &nh, ifcp);
1281                         rrt->rrt_rflags |= RRTF_CHANGED;
1282                         need_trigger = 1;
1283                         rrt->rrt_t = t;
1284                 }
1285         }
1286         /* XXX need to care the interval between triggered updates */
1287         if (need_trigger) {
1288                 if (nextalarm > time(NULL) + RIP_TRIG_INT6_MAX) {
1289                         for (ic = ifc; ic; ic = ic->ifc_next) {
1290                                 if (ifcp->ifc_index == ic->ifc_index)
1291                                         continue;
1292                                 if (ic->ifc_flags & IFF_UP)
1293                                         ripsend(ic, &ic->ifc_ripsin,
1294                                                 RRTF_CHANGED);
1295                         }
1296                 }
1297                 /* Reset the flag */
1298                 for (rrt = riprt; rrt; rrt = rrt->rrt_next)
1299                         rrt->rrt_rflags &= ~RRTF_CHANGED;
1300         }
1301 }
1302
1303 /*
1304  * Send all routes request packet to the specified interface.
1305  */
1306 void
1307 sendrequest(ifcp)
1308         struct ifc *ifcp;
1309 {
1310         struct netinfo6 *np;
1311         int error;
1312
1313         if (ifcp->ifc_flags & IFF_LOOPBACK)
1314                 return;
1315         ripbuf->rip6_cmd = RIP6_REQUEST;
1316         np = ripbuf->rip6_nets;
1317         memset(np, 0, sizeof(struct netinfo6));
1318         np->rip6_metric = HOPCNT_INFINITY6;
1319         tracet(1, "Send rtdump Request to %s (%s)\n",
1320                 ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
1321         error = sendpacket(&ifcp->ifc_ripsin, RIPSIZE(1));
1322         if (error == EAFNOSUPPORT) {
1323                 /* Protocol not supported */
1324                 tracet(1, "Could not send rtdump Request to %s (%s): "
1325                         "set IFF_UP to 0\n",
1326                         ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
1327                 ifcp->ifc_flags &= ~IFF_UP;     /* As if down for AF_INET6 */
1328         }
1329         ripbuf->rip6_cmd = RIP6_RESPONSE;
1330 }
1331
1332 /*
1333  * Process a RIP6_REQUEST packet.
1334  */
1335 void
1336 riprequest(ifcp, np, nn, sin)
1337         struct ifc *ifcp;
1338         struct netinfo6 *np;
1339         int nn;
1340         struct sockaddr_in6 *sin;
1341 {
1342         int i;
1343         struct riprt *rrt;
1344
1345         if (!(nn == 1 && IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest) &&
1346               np->rip6_plen == 0 && np->rip6_metric == HOPCNT_INFINITY6)) {
1347                 /* Specific response, don't split-horizon */
1348                 trace(1, "\tRIP Request\n");
1349                 for (i = 0; i < nn; i++, np++) {
1350                         rrt = rtsearch(np, NULL);
1351                         if (rrt)
1352                                 np->rip6_metric = rrt->rrt_info.rip6_metric;
1353                         else
1354                                 np->rip6_metric = HOPCNT_INFINITY6;
1355                 }
1356                 (void)sendpacket(sin, RIPSIZE(nn));
1357                 return;
1358         }
1359         /* Whole routing table dump */
1360         trace(1, "\tRIP Request -- whole routing table\n");
1361         ripsend(ifcp, sin, RRTF_SENDANYWAY);
1362 }
1363
1364 /*
1365  * Get information of each interface.
1366  */
1367 void
1368 ifconfig()
1369 {
1370         struct ifaddrs *ifap, *ifa;
1371         struct ifc *ifcp;
1372         struct ipv6_mreq mreq;
1373         int s;
1374
1375         if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1376                 fatal("socket");
1377                 /*NOTREACHED*/
1378         }
1379
1380         if (getifaddrs(&ifap) != 0) {
1381                 fatal("getifaddrs");
1382                 /*NOTREACHED*/
1383         }
1384
1385         for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1386                 if (ifa->ifa_addr->sa_family != AF_INET6)
1387                         continue;
1388                 ifcp = ifc_find(ifa->ifa_name);
1389                 /* we are interested in multicast-capable interfaces */
1390                 if ((ifa->ifa_flags & IFF_MULTICAST) == 0)
1391                         continue;
1392                 if (!ifcp) {
1393                         /* new interface */
1394                         if ((ifcp = MALLOC(struct ifc)) == NULL) {
1395                                 fatal("malloc: struct ifc");
1396                                 /*NOTREACHED*/
1397                         }
1398                         memset(ifcp, 0, sizeof(*ifcp));
1399                         ifcp->ifc_index = -1;
1400                         ifcp->ifc_next = ifc;
1401                         ifc = ifcp;
1402                         nifc++;
1403                         ifcp->ifc_name = allocopy(ifa->ifa_name);
1404                         ifcp->ifc_addr = 0;
1405                         ifcp->ifc_filter = 0;
1406                         ifcp->ifc_flags = ifa->ifa_flags;
1407                         trace(1, "newif %s <%s>\n", ifcp->ifc_name,
1408                                 ifflags(ifcp->ifc_flags));
1409                         if (!strcmp(ifcp->ifc_name, LOOPBACK_IF))
1410                                 loopifcp = ifcp;
1411                 } else {
1412                         /* update flag, this may be up again */
1413                         if (ifcp->ifc_flags != ifa->ifa_flags) {
1414                                 trace(1, "%s: <%s> -> ", ifcp->ifc_name,
1415                                         ifflags(ifcp->ifc_flags));
1416                                 trace(1, "<%s>\n", ifflags(ifa->ifa_flags));
1417                                 ifcp->ifc_cflags |= IFC_CHANGED;
1418                         }
1419                         ifcp->ifc_flags = ifa->ifa_flags;
1420                 }
1421                 ifconfig1(ifa->ifa_name, ifa->ifa_addr, ifcp, s);
1422                 if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP
1423                  && 0 < ifcp->ifc_index && !ifcp->ifc_joined) {
1424                         mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr;
1425                         mreq.ipv6mr_interface = ifcp->ifc_index;
1426                         if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
1427                             &mreq, sizeof(mreq)) < 0) {
1428                                 fatal("IPV6_JOIN_GROUP");
1429                                 /*NOTREACHED*/
1430                         }
1431                         trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST);
1432                         ifcp->ifc_joined++;
1433                 }
1434         }
1435         close(s);
1436         freeifaddrs(ifap);
1437 }
1438
1439 void
1440 ifconfig1(name, sa, ifcp, s)
1441         const char *name;
1442         const struct sockaddr *sa;
1443         struct  ifc *ifcp;
1444         int     s;
1445 {
1446         struct  in6_ifreq ifr;
1447         const struct sockaddr_in6 *sin;
1448         struct  ifac *ifa;
1449         int     plen;
1450         char    buf[BUFSIZ];
1451
1452         sin = (const struct sockaddr_in6 *)sa;
1453         ifr.ifr_addr = *sin;
1454         strcpy(ifr.ifr_name, name);
1455         if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0) {
1456                 fatal("ioctl: SIOCGIFNETMASK_IN6");
1457                 /*NOTREACHED*/
1458         }
1459         plen = sin6mask2len(&ifr.ifr_addr);
1460         if ((ifa = ifa_match(ifcp, &sin->sin6_addr, plen)) != NULL) {
1461                 /* same interface found */
1462                 /* need check if something changed */
1463                 /* XXX not yet implemented */
1464                 return;
1465         }
1466         /*
1467          * New address is found
1468          */
1469         if ((ifa = MALLOC(struct ifac)) == NULL) {
1470                 fatal("malloc: struct ifac");
1471                 /*NOTREACHED*/
1472         }
1473         memset(ifa, 0, sizeof(*ifa));
1474         ifa->ifa_conf = ifcp;
1475         ifa->ifa_next = ifcp->ifc_addr;
1476         ifcp->ifc_addr = ifa;
1477         ifa->ifa_addr = sin->sin6_addr;
1478         ifa->ifa_plen = plen;
1479         if (ifcp->ifc_flags & IFF_POINTOPOINT) {
1480                 ifr.ifr_addr = *sin;
1481                 if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0) {
1482                         fatal("ioctl: SIOCGIFDSTADDR_IN6");
1483                         /*NOTREACHED*/
1484                 }
1485                 ifa->ifa_raddr = ifr.ifr_dstaddr.sin6_addr;
1486                 inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, buf, sizeof(buf));
1487                 trace(1, "found address %s/%d -- %s\n",
1488                         inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen, buf);
1489         } else {
1490                 trace(1, "found address %s/%d\n",
1491                         inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen);
1492         }
1493         if (ifcp->ifc_index < 0 && IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) {
1494                 ifcp->ifc_mylladdr = ifa->ifa_addr;
1495                 ifcp->ifc_index = IN6_LINKLOCAL_IFINDEX(ifa->ifa_addr);
1496                 memcpy(&ifcp->ifc_ripsin, &ripsin, ripsin.ss_len);
1497                 SET_IN6_LINKLOCAL_IFINDEX(ifcp->ifc_ripsin.sin6_addr,
1498                         ifcp->ifc_index);
1499                 setindex2ifc(ifcp->ifc_index, ifcp);
1500                 ifcp->ifc_mtu = getifmtu(ifcp->ifc_index);
1501                 if (ifcp->ifc_mtu > RIP6_MAXMTU)
1502                         ifcp->ifc_mtu = RIP6_MAXMTU;
1503                 if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0) {
1504                         fatal("ioctl: SIOCGIFMETRIC");
1505                         /*NOTREACHED*/
1506                 }
1507                 ifcp->ifc_metric = ifr.ifr_metric;
1508                 trace(1, "\tindex: %d, mtu: %d, metric: %d\n",
1509                         ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric);
1510         } else
1511                 ifcp->ifc_cflags |= IFC_CHANGED;
1512 }
1513
1514 /*
1515  * Receive and process routing messages.
1516  * Update interface information as necesssary.
1517  */
1518 void
1519 rtrecv()
1520 {
1521         char buf[BUFSIZ];
1522         char *p, *q;
1523         struct rt_msghdr *rtm;
1524         struct ifa_msghdr *ifam;
1525         struct if_msghdr *ifm;
1526         int len;
1527         struct ifc *ifcp, *ic;
1528         int iface = 0, rtable = 0;
1529         struct sockaddr_in6 *rta[RTAX_MAX];
1530         struct sockaddr_in6 mask;
1531         int i, addrs;
1532         struct riprt *rrt;
1533
1534         if ((len = read(rtsock, buf, sizeof(buf))) < 0) {
1535                 perror("read from rtsock");
1536                 exit(1);
1537         }
1538         if (len < sizeof(*rtm)) {
1539                 trace(1, "short read from rtsock: %d (should be > %lu)\n",
1540                         len, (u_long)sizeof(*rtm));
1541                 return;
1542         }
1543
1544         for (p = buf; p - buf < len; p += ((struct rt_msghdr *)p)->rtm_msglen) {
1545                 /* safety against bogus message */
1546                 if (((struct rt_msghdr *)p)->rtm_msglen <= 0) {
1547                         trace(1, "bogus rtmsg: length=%d\n",
1548                                 ((struct rt_msghdr *)p)->rtm_msglen);
1549                         break;
1550                 }
1551                 rtm = NULL;
1552                 ifam = NULL;
1553                 ifm = NULL;
1554                 switch (((struct rt_msghdr *)p)->rtm_type) {
1555                 case RTM_NEWADDR:
1556                 case RTM_DELADDR:
1557                         ifam = (struct ifa_msghdr *)p;
1558                         addrs = ifam->ifam_addrs;
1559                         q = (char *)(ifam + 1);
1560                         break;
1561                 case RTM_IFINFO:
1562                         ifm = (struct if_msghdr *)p;
1563                         addrs = ifm->ifm_addrs;
1564                         q = (char *)(ifm + 1);
1565                         break;
1566                 default:
1567                         rtm = (struct rt_msghdr *)p;
1568                         addrs = rtm->rtm_addrs;
1569                         q = (char *)(rtm + 1);
1570                         if (rtm->rtm_version != RTM_VERSION) {
1571                                 trace(1, "unexpected rtmsg version %d "
1572                                         "(should be %d)\n",
1573                                         rtm->rtm_version, RTM_VERSION);
1574                                 continue;
1575                         }
1576                         if (rtm->rtm_pid == pid) {
1577 #if 0
1578                                 trace(1, "rtmsg looped back to me, ignored\n");
1579 #endif
1580                                 continue;
1581                         }
1582                         break;
1583                 }
1584                 memset(&rta, 0, sizeof(rta));
1585                 for (i = 0; i < RTAX_MAX; i++) {
1586                         if (addrs & (1 << i)) {
1587                                 rta[i] = (struct sockaddr_in6 *)q;
1588                                 q += ROUNDUP(rta[i]->sin6_len);
1589                         }
1590                 }
1591
1592                 trace(1, "rtsock: %s (addrs=%x)\n",
1593                         rttypes((struct rt_msghdr *)p), addrs);
1594                 if (dflag >= 2) {
1595                         for (i = 0;
1596                              i < ((struct rt_msghdr *)p)->rtm_msglen;
1597                              i++) {
1598                                 fprintf(stderr, "%02x ", p[i] & 0xff);
1599                                 if (i % 16 == 15) fprintf(stderr, "\n");
1600                         }
1601                         fprintf(stderr, "\n");
1602                 }
1603
1604                 /*
1605                  * Easy ones first.
1606                  *
1607                  * We may be able to optimize by using ifm->ifm_index or
1608                  * ifam->ifam_index.  For simplicity we don't do that here.
1609                  */
1610                 switch (((struct rt_msghdr *)p)->rtm_type) {
1611                 case RTM_NEWADDR:
1612                 case RTM_IFINFO:
1613                         iface++;
1614                         continue;
1615                 case RTM_ADD:
1616                         rtable++;
1617                         continue;
1618                 case RTM_LOSING:
1619                 case RTM_MISS:
1620                 case RTM_RESOLVE:
1621                 case RTM_GET:
1622                 case RTM_LOCK:
1623                         /* nothing to be done here */
1624                         trace(1, "\tnothing to be done, ignored\n");
1625                         continue;
1626                 }
1627
1628 #if 0
1629                 if (rta[RTAX_DST] == NULL) {
1630                         trace(1, "\tno destination, ignored\n");
1631                         continue;       
1632                 }
1633                 if (rta[RTAX_DST]->sin6_family != AF_INET6) {
1634                         trace(1, "\taf mismatch, ignored\n");
1635                         continue;
1636                 }
1637                 if (IN6_IS_ADDR_LINKLOCAL(&rta[RTAX_DST]->sin6_addr)) {
1638                         trace(1, "\tlinklocal destination, ignored\n");
1639                         continue;
1640                 }
1641                 if (IN6_ARE_ADDR_EQUAL(&rta[RTAX_DST]->sin6_addr, &in6addr_loopback)) {
1642                         trace(1, "\tloopback destination, ignored\n");
1643                         continue;               /* Loopback */
1644                 }
1645                 if (IN6_IS_ADDR_MULTICAST(&rta[RTAX_DST]->sin6_addr)) {
1646                         trace(1, "\tmulticast destination, ignored\n");
1647                         continue;
1648                 }
1649 #endif
1650
1651                 /* hard ones */
1652                 switch (((struct rt_msghdr *)p)->rtm_type) {
1653                 case RTM_NEWADDR:
1654                 case RTM_IFINFO:
1655                 case RTM_ADD:
1656                 case RTM_LOSING:
1657                 case RTM_MISS:
1658                 case RTM_RESOLVE:
1659                 case RTM_GET:
1660                 case RTM_LOCK:
1661                         /* should already be handled */
1662                         fatal("rtrecv: never reach here");
1663                         /*NOTREACHED*/
1664                 case RTM_DELETE:
1665                         if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY]) {
1666                                 trace(1, "\tsome of dst/gw/netamsk are "
1667                                     "unavailable, ignored\n");
1668                                 break;
1669                         }
1670                         if ((rtm->rtm_flags & RTF_HOST) != 0) {
1671                                 mask.sin6_len = sizeof(mask);
1672                                 memset(&mask.sin6_addr, 0xff,
1673                                     sizeof(mask.sin6_addr));
1674                                 rta[RTAX_NETMASK] = &mask;
1675                         } else if (!rta[RTAX_NETMASK]) {
1676                                 trace(1, "\tsome of dst/gw/netamsk are "
1677                                     "unavailable, ignored\n");
1678                                 break;
1679                         }
1680                         if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY],
1681                             rta[RTAX_NETMASK]) == 0) {
1682                                 rtable++;       /*just to be sure*/
1683                         }
1684                         break;
1685                 case RTM_CHANGE:
1686                 case RTM_REDIRECT:
1687                         trace(1, "\tnot supported yet, ignored\n");
1688                         break;
1689                 case RTM_DELADDR:
1690                         if (!rta[RTAX_NETMASK] || !rta[RTAX_IFA]) {
1691                                 trace(1, "\tno netmask or ifa given, ignored\n");
1692                                 break;
1693                         }
1694                         if (ifam->ifam_index < nindex2ifc)
1695                                 ifcp = index2ifc[ifam->ifam_index];
1696                         else
1697                                 ifcp = NULL;
1698                         if (!ifcp) {
1699                                 trace(1, "\tinvalid ifam_index %d, ignored\n",
1700                                         ifam->ifam_index);
1701                                 break;
1702                         }
1703                         if (!rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK]))
1704                                 iface++;
1705                         break;
1706                 case RTM_OLDADD:
1707                 case RTM_OLDDEL:
1708                         trace(1, "\tnot supported yet, ignored\n");
1709                         break;
1710                 }
1711
1712         }
1713
1714         if (iface) {
1715                 trace(1, "rtsock: reconfigure interfaces, refresh interface routes\n");
1716                 ifconfig();
1717                 for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next)
1718                         if (ifcp->ifc_cflags & IFC_CHANGED) {
1719                                 if (ifrt(ifcp, 1)) {
1720                                         for (ic = ifc; ic; ic = ic->ifc_next) {
1721                                                 if (ifcp->ifc_index == ic->ifc_index)
1722                                                         continue;
1723                                                 if (ic->ifc_flags & IFF_UP)
1724                                                         ripsend(ic, &ic->ifc_ripsin,
1725                                                         RRTF_CHANGED);
1726                                         }
1727                                         /* Reset the flag */
1728                                         for (rrt = riprt; rrt; rrt = rrt->rrt_next)
1729                                                 rrt->rrt_rflags &= ~RRTF_CHANGED;
1730                                 }
1731                                 ifcp->ifc_cflags &= ~IFC_CHANGED;
1732                         }
1733         }
1734         if (rtable) {
1735                 trace(1, "rtsock: read routing table again\n");
1736                 krtread(1);
1737         }
1738 }
1739
1740 /*
1741  * remove specified route from the internal routing table.
1742  */
1743 int
1744 rt_del(sdst, sgw, smask)
1745         const struct sockaddr_in6 *sdst;
1746         const struct sockaddr_in6 *sgw;
1747         const struct sockaddr_in6 *smask;
1748 {
1749         const struct in6_addr *dst = NULL;
1750         const struct in6_addr *gw = NULL;
1751         int prefix;
1752         struct netinfo6 ni6;
1753         struct riprt *rrt = NULL;
1754         time_t t_lifetime;
1755
1756         if (sdst->sin6_family != AF_INET6) {
1757                 trace(1, "\tother AF, ignored\n");
1758                 return -1;
1759         }
1760         if (IN6_IS_ADDR_LINKLOCAL(&sdst->sin6_addr)
1761          || IN6_ARE_ADDR_EQUAL(&sdst->sin6_addr, &in6addr_loopback)
1762          || IN6_IS_ADDR_MULTICAST(&sdst->sin6_addr)) {
1763                 trace(1, "\taddress %s not interesting, ignored\n",
1764                         inet6_n2p(&sdst->sin6_addr));
1765                 return -1;
1766         }
1767         dst = &sdst->sin6_addr;
1768         if (sgw->sin6_family == AF_INET6) {
1769                 /* easy case */
1770                 gw = &sgw->sin6_addr;
1771                 prefix = sin6mask2len(smask);
1772         } else if (sgw->sin6_family == AF_LINK) {
1773                 /*
1774                  * Interface route... a hard case.  We need to get the prefix
1775                  * length from the kernel, but we now are parsing rtmsg.
1776                  * We'll purge matching routes from my list, then get the
1777                  * fresh list.
1778                  */
1779                 struct riprt *longest;
1780                 trace(1, "\t%s is a interface route, guessing prefixlen\n",
1781                         inet6_n2p(dst));
1782                 longest = NULL;
1783                 for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
1784                         if (IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
1785                                         &sdst->sin6_addr)
1786                          && IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) {
1787                                 if (!longest
1788                                  || longest->rrt_info.rip6_plen <
1789                                                  rrt->rrt_info.rip6_plen) {
1790                                         longest = rrt;
1791                                 }
1792                         }
1793                 }
1794                 rrt = longest;
1795                 if (!rrt) {
1796                         trace(1, "\tno matching interface route found\n");
1797                         return -1;
1798                 }
1799                 gw = &in6addr_loopback;
1800                 prefix = rrt->rrt_info.rip6_plen;
1801         } else {
1802                 trace(1, "\tunsupported af: (gw=%d)\n", sgw->sin6_family);
1803                 return -1;
1804         }
1805
1806         trace(1, "\tdeleting %s/%d ", inet6_n2p(dst), prefix);
1807         trace(1, "gw %s\n", inet6_n2p(gw));
1808         t_lifetime = time(NULL) - RIP_LIFETIME;
1809         /* age route for interface address */
1810         memset(&ni6, 0, sizeof(ni6));
1811         ni6.rip6_dest = *dst;
1812         ni6.rip6_plen = prefix;
1813         applyplen(&ni6.rip6_dest, ni6.rip6_plen);       /*to be sure*/
1814         trace(1, "\tfind route %s/%d\n", inet6_n2p(&ni6.rip6_dest),
1815                 ni6.rip6_plen);
1816         if (!rrt && (rrt = rtsearch(&ni6, NULL)) == NULL) {
1817                 trace(1, "\tno route found\n");
1818                 return -1;
1819         }
1820 #if 0
1821         if ((rrt->rrt_flags & RTF_STATIC) == 0) {
1822                 trace(1, "\tyou can delete static routes only\n");
1823         } else
1824 #endif
1825         if (!IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, gw)) {
1826                 trace(1, "\tgw mismatch: %s <-> ",
1827                         inet6_n2p(&rrt->rrt_gw));
1828                 trace(1, "%s\n", inet6_n2p(gw));
1829         } else {
1830                 trace(1, "\troute found, age it\n");
1831                 if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
1832                         rrt->rrt_t = t_lifetime;
1833                         rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
1834                 }
1835         }
1836         return 0;
1837 }
1838
1839 /*
1840  * remove specified address from internal interface/routing table.
1841  */
1842 int
1843 rt_deladdr(ifcp, sifa, smask)
1844         struct ifc *ifcp;
1845         const struct sockaddr_in6 *sifa;
1846         const struct sockaddr_in6 *smask;
1847 {
1848         const struct in6_addr *addr = NULL;
1849         int prefix;
1850         struct ifac *ifa = NULL;
1851         struct netinfo6 ni6;
1852         struct riprt *rrt = NULL;
1853         time_t t_lifetime;
1854         int updated = 0;
1855
1856         if (sifa->sin6_family != AF_INET6) {
1857                 trace(1, "\tother AF, ignored\n");
1858                 return -1;
1859         }
1860         addr = &sifa->sin6_addr;
1861         prefix = sin6mask2len(smask);
1862
1863         trace(1, "\tdeleting %s/%d from %s\n",
1864                 inet6_n2p(addr), prefix, ifcp->ifc_name);
1865         ifa = ifa_match(ifcp, addr, prefix);
1866         if (!ifa) {
1867                 trace(1, "\tno matching ifa found for %s/%d on %s\n",
1868                         inet6_n2p(addr), prefix, ifcp->ifc_name);
1869                 return -1;
1870         }
1871         if (ifa->ifa_conf != ifcp) {
1872                 trace(1, "\taddress table corrupt: back pointer does not match "
1873                         "(%s != %s)\n",
1874                         ifcp->ifc_name, ifa->ifa_conf->ifc_name);
1875                 return -1;
1876         }
1877         /* remove ifa from interface */
1878         if (ifcp->ifc_addr == ifa)
1879                 ifcp->ifc_addr = ifa->ifa_next;
1880         else {
1881                 struct ifac *p;
1882                 for (p = ifcp->ifc_addr; p; p = p->ifa_next) {
1883                         if (p->ifa_next == ifa) {
1884                                 p->ifa_next = ifa->ifa_next;
1885                                 break;
1886                         }
1887                 }
1888         }
1889         ifa->ifa_next = NULL;
1890         ifa->ifa_conf = NULL;
1891         t_lifetime = time(NULL) - RIP_LIFETIME;
1892         /* age route for interface address */
1893         memset(&ni6, 0, sizeof(ni6));
1894         ni6.rip6_dest = ifa->ifa_addr;
1895         ni6.rip6_plen = ifa->ifa_plen;
1896         applyplen(&ni6.rip6_dest, ni6.rip6_plen);
1897         trace(1, "\tfind interface route %s/%d on %d\n",
1898                 inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index);
1899         if ((rrt = rtsearch(&ni6, NULL)) != NULL) {
1900                 struct in6_addr none;
1901                 memset(&none, 0, sizeof(none));
1902                 if (rrt->rrt_index == ifcp->ifc_index &&
1903                     (IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &none) ||
1904                      IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw))) {
1905                         trace(1, "\troute found, age it\n");
1906                         if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
1907                                 rrt->rrt_t = t_lifetime;
1908                                 rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
1909                         }
1910                         updated++;
1911                 } else {
1912                         trace(1, "\tnon-interface route found: %s/%d on %d\n",
1913                                 inet6_n2p(&rrt->rrt_info.rip6_dest),
1914                                 rrt->rrt_info.rip6_plen,
1915                                 rrt->rrt_index);
1916                 }
1917         } else
1918                 trace(1, "\tno interface route found\n");
1919         /* age route for p2p destination */
1920         if (ifcp->ifc_flags & IFF_POINTOPOINT) {
1921                 memset(&ni6, 0, sizeof(ni6));
1922                 ni6.rip6_dest = ifa->ifa_raddr;
1923                 ni6.rip6_plen = 128;
1924                 applyplen(&ni6.rip6_dest, ni6.rip6_plen);       /*to be sure*/
1925                 trace(1, "\tfind p2p route %s/%d on %d\n",
1926                         inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen,
1927                         ifcp->ifc_index);
1928                 if ((rrt = rtsearch(&ni6, NULL)) != NULL) {
1929                         if (rrt->rrt_index == ifcp->ifc_index &&
1930                             IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &ifa->ifa_addr)) {
1931                                 trace(1, "\troute found, age it\n");
1932                                 if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
1933                                         rrt->rrt_t = t_lifetime;
1934                                         rrt->rrt_info.rip6_metric =
1935                                             HOPCNT_INFINITY6;
1936                                         updated++;
1937                                 }
1938                         } else {
1939                                 trace(1, "\tnon-p2p route found: %s/%d on %d\n",
1940                                         inet6_n2p(&rrt->rrt_info.rip6_dest),
1941                                         rrt->rrt_info.rip6_plen,
1942                                         rrt->rrt_index);
1943                         }
1944                 } else
1945                         trace(1, "\tno p2p route found\n");
1946         }
1947         return updated ? 0 : -1;
1948 }
1949
1950 /*
1951  * Get each interface address and put those interface routes to the route
1952  * list.
1953  */
1954 int
1955 ifrt(ifcp, again)
1956         struct ifc *ifcp;
1957         int again;
1958 {
1959         struct ifac *ifa;
1960         struct riprt *rrt, *search_rrt, *prev_rrt, *loop_rrt;
1961         struct netinfo6 *np;
1962         time_t t_lifetime;
1963         int need_trigger = 0;
1964
1965         if (ifcp->ifc_flags & IFF_LOOPBACK)
1966                 return 0;                       /* ignore loopback */
1967         if (ifcp->ifc_flags & IFF_POINTOPOINT) {
1968                 ifrt_p2p(ifcp, again);
1969                 return 0;
1970         }
1971
1972         for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
1973                 if (IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) {
1974 #if 0
1975                         trace(1, "route: %s on %s: "
1976                             "skip linklocal interface address\n",
1977                             inet6_n2p(&ifa->ifa_addr), ifcp->ifc_name);
1978 #endif
1979                         continue;
1980                 }
1981                 if (IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_addr)) {
1982 #if 0
1983                         trace(1, "route: %s: skip unspec interface address\n",
1984                             ifcp->ifc_name);
1985 #endif
1986                         continue;
1987                 }
1988                 if (ifcp->ifc_flags & IFF_UP) {
1989                         if ((rrt = MALLOC(struct riprt)) == NULL)
1990                                 fatal("malloc: struct riprt");
1991                         memset(rrt, 0, sizeof(*rrt));
1992                         rrt->rrt_same = NULL;
1993                         rrt->rrt_index = ifcp->ifc_index;
1994                         rrt->rrt_t = 0; /* don't age */
1995                         rrt->rrt_info.rip6_dest = ifa->ifa_addr;
1996                         rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
1997                         rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric;
1998                         rrt->rrt_info.rip6_plen = ifa->ifa_plen;
1999                         rrt->rrt_flags = RTF_CLONING;
2000                         rrt->rrt_rflags |= RRTF_CHANGED;
2001                         applyplen(&rrt->rrt_info.rip6_dest, ifa->ifa_plen);
2002                         memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
2003 #if 0
2004                         /* XXX why gateway address == network adddress? */
2005                         rrt->rrt_gw = ifa->ifa_addr;
2006 #endif
2007                         np = &rrt->rrt_info;
2008                         search_rrt = rtsearch(np, &prev_rrt);
2009                         if (search_rrt != NULL) {
2010                                 if (search_rrt->rrt_info.rip6_metric >
2011                                     rrt->rrt_info.rip6_metric) {
2012                                         if (prev_rrt)
2013                                                 prev_rrt->rrt_next = rrt->rrt_next;
2014                                         else
2015                                                 riprt = rrt->rrt_next;
2016                                         delroute(&rrt->rrt_info, &rrt->rrt_gw);
2017                                         free(rrt);
2018                                 } else {
2019                                         /* Already have better route */
2020                                         if (!again) {
2021                                                 trace(1, "route: %s/%d: "
2022                                                     "already registered (%s)\n",
2023                                                     inet6_n2p(&np->rip6_dest), np->rip6_plen,
2024                                                     ifcp->ifc_name);
2025                                         }
2026                                         free(rrt);
2027                                         continue;
2028                                 }
2029                         }
2030                         /* Attach the route to the list */
2031                         trace(1, "route: %s/%d: register route (%s)\n",
2032                             inet6_n2p(&np->rip6_dest), np->rip6_plen,
2033                             ifcp->ifc_name);
2034                         rrt->rrt_next = riprt;
2035                         riprt = rrt;
2036                         addroute(rrt, &rrt->rrt_gw, ifcp);
2037                         sendrequest(ifcp);
2038                         ripsend(ifcp, &ifcp->ifc_ripsin, 0);
2039                         need_trigger = 1;
2040                 } else {
2041                         for (loop_rrt = riprt; loop_rrt; loop_rrt = loop_rrt->rrt_next) {
2042                                 if (loop_rrt->rrt_index == ifcp->ifc_index) {
2043                                         t_lifetime = time(NULL) - RIP_LIFETIME;
2044                                         if (loop_rrt->rrt_t == 0 || loop_rrt->rrt_t > t_lifetime) {
2045                                                 loop_rrt->rrt_t = t_lifetime;
2046                                                 loop_rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
2047                                                 loop_rrt->rrt_rflags |= RRTF_CHANGED;
2048                                                 need_trigger = 1;
2049                                         }
2050                                 }
2051                         }
2052                 }
2053         }
2054         return need_trigger;
2055 }
2056
2057 /*
2058  * there are couple of p2p interface routing models.  "behavior" lets
2059  * you pick one.  it looks that gated behavior fits best with BSDs,
2060  * since BSD kernels does not look at prefix length on p2p interfaces.
2061  */
2062 void
2063 ifrt_p2p(ifcp, again)
2064         struct ifc *ifcp;
2065         int again;
2066 {
2067         struct ifac *ifa;
2068         struct riprt *rrt, *orrt, *prevrrt;
2069         struct netinfo6 *np;
2070         struct in6_addr addr, dest;
2071         int advert, ignore, i;
2072 #define P2PADVERT_NETWORK       1
2073 #define P2PADVERT_ADDR          2
2074 #define P2PADVERT_DEST          4
2075 #define P2PADVERT_MAX           4
2076         const enum { CISCO, GATED, ROUTE6D } behavior = GATED;
2077         const char *category = "";
2078         const char *noadv;
2079
2080         for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
2081                 addr = ifa->ifa_addr;
2082                 dest = ifa->ifa_raddr;
2083                 applyplen(&addr, ifa->ifa_plen);
2084                 applyplen(&dest, ifa->ifa_plen);
2085                 advert = ignore = 0;
2086                 switch (behavior) {
2087                 case CISCO:
2088                         /*
2089                          * honor addr/plen, just like normal shared medium
2090                          * interface.  this may cause trouble if you reuse
2091                          * addr/plen on other interfaces.
2092                          *
2093                          * advertise addr/plen.
2094                          */
2095                         advert |= P2PADVERT_NETWORK;
2096                         break;
2097                 case GATED:
2098                         /*
2099                          * prefixlen on p2p interface is meaningless.
2100                          * advertise addr/128 and dest/128.
2101                          *
2102                          * do not install network route to route6d routing
2103                          * table (if we do, it would prevent route installation
2104                          * for other p2p interface that shares addr/plen).
2105                          *
2106                          * XXX what should we do if dest is ::?  it will not
2107                          * get announced anyways (see following filter),
2108                          * but we need to think.
2109                          */
2110                         advert |= P2PADVERT_ADDR;
2111                         advert |= P2PADVERT_DEST;
2112                         ignore |= P2PADVERT_NETWORK;
2113                         break;
2114                 case ROUTE6D:
2115                         /*
2116                          * just for testing.  actually the code is redundant
2117                          * given the current p2p interface address assignment
2118                          * rule for kame kernel.
2119                          *
2120                          * intent:
2121                          *      A/n -> announce A/n
2122                          *      A B/n, A and B share prefix -> A/n (= B/n)
2123                          *      A B/n, do not share prefix -> A/128 and B/128
2124                          * actually, A/64 and A B/128 are the only cases
2125                          * permitted by the kernel:
2126                          *      A/64 -> A/64
2127                          *      A B/128 -> A/128 and B/128
2128                          */
2129                         if (!IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_raddr)) {
2130                                 if (IN6_ARE_ADDR_EQUAL(&addr, &dest))
2131                                         advert |= P2PADVERT_NETWORK;
2132                                 else {
2133                                         advert |= P2PADVERT_ADDR;
2134                                         advert |= P2PADVERT_DEST;
2135                                         ignore |= P2PADVERT_NETWORK;
2136                                 }
2137                         } else
2138                                 advert |= P2PADVERT_NETWORK;
2139                         break;
2140                 }
2141
2142                 for (i = 1; i <= P2PADVERT_MAX; i *= 2) {
2143                         if ((ignore & i) != 0)
2144                                 continue;
2145                         if ((rrt = MALLOC(struct riprt)) == NULL) {
2146                                 fatal("malloc: struct riprt");
2147                                 /*NOTREACHED*/
2148                         }
2149                         memset(rrt, 0, sizeof(*rrt));
2150                         rrt->rrt_same = NULL;
2151                         rrt->rrt_index = ifcp->ifc_index;
2152                         rrt->rrt_t = 0; /* don't age */
2153                         switch (i) {
2154                         case P2PADVERT_NETWORK:
2155                                 rrt->rrt_info.rip6_dest = ifa->ifa_addr;
2156                                 rrt->rrt_info.rip6_plen = ifa->ifa_plen;
2157                                 applyplen(&rrt->rrt_info.rip6_dest,
2158                                     ifa->ifa_plen);
2159                                 category = "network";
2160                                 break;
2161                         case P2PADVERT_ADDR:
2162                                 rrt->rrt_info.rip6_dest = ifa->ifa_addr;
2163                                 rrt->rrt_info.rip6_plen = 128;
2164                                 rrt->rrt_gw = in6addr_loopback;
2165                                 category = "addr";
2166                                 break;
2167                         case P2PADVERT_DEST:
2168                                 rrt->rrt_info.rip6_dest = ifa->ifa_raddr;
2169                                 rrt->rrt_info.rip6_plen = 128;
2170                                 rrt->rrt_gw = ifa->ifa_addr;
2171                                 category = "dest";
2172                                 break;
2173                         }
2174                         if (IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_info.rip6_dest) ||
2175                             IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_info.rip6_dest)) {
2176 #if 0
2177                                 trace(1, "route: %s: skip unspec/linklocal "
2178                                     "(%s on %s)\n", category, ifcp->ifc_name);
2179 #endif
2180                                 free(rrt);
2181                                 continue;
2182                         }
2183                         if ((advert & i) == 0) {
2184                                 rrt->rrt_rflags |= RRTF_NOADVERTISE;
2185                                 noadv = ", NO-ADV";
2186                         } else
2187                                 noadv = "";
2188                         rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
2189                         rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric;
2190                         np = &rrt->rrt_info;
2191                         orrt = rtsearch(np, &prevrrt);
2192                         if (!orrt) {
2193                                 /* Attach the route to the list */
2194                                 trace(1, "route: %s/%d: register route "
2195                                     "(%s on %s%s)\n",
2196                                     inet6_n2p(&np->rip6_dest), np->rip6_plen,
2197                                     category, ifcp->ifc_name, noadv);
2198                                 rrt->rrt_next = riprt;
2199                                 riprt = rrt;
2200                         } else if (rrt->rrt_index != orrt->rrt_index ||
2201                             rrt->rrt_info.rip6_metric != orrt->rrt_info.rip6_metric) {
2202                                 /* swap route */
2203                                 rrt->rrt_next = orrt->rrt_next;
2204                                 if (prevrrt)
2205                                         prevrrt->rrt_next = rrt;
2206                                 else
2207                                         riprt = rrt;
2208                                 free(orrt);
2209
2210                                 trace(1, "route: %s/%d: update (%s on %s%s)\n",
2211                                     inet6_n2p(&np->rip6_dest), np->rip6_plen,
2212                                     category, ifcp->ifc_name, noadv);
2213                         } else {
2214                                 /* Already found */
2215                                 if (!again) {
2216                                         trace(1, "route: %s/%d: "
2217                                             "already registered (%s on %s%s)\n",
2218                                             inet6_n2p(&np->rip6_dest),
2219                                             np->rip6_plen, category,
2220                                             ifcp->ifc_name, noadv);
2221                                 }
2222                                 free(rrt);
2223                         }
2224                 }
2225         }
2226 #undef P2PADVERT_NETWORK
2227 #undef P2PADVERT_ADDR
2228 #undef P2PADVERT_DEST
2229 #undef P2PADVERT_MAX
2230 }
2231
2232 int
2233 getifmtu(ifindex)
2234         int     ifindex;
2235 {
2236         int     mib[6];
2237         char    *buf;
2238         size_t  msize;
2239         struct  if_msghdr *ifm;
2240         int     mtu;
2241
2242         mib[0] = CTL_NET;
2243         mib[1] = PF_ROUTE;
2244         mib[2] = 0;
2245         mib[3] = AF_INET6;
2246         mib[4] = NET_RT_IFLIST;
2247         mib[5] = ifindex;
2248         if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) {
2249                 fatal("sysctl estimate NET_RT_IFLIST");
2250                 /*NOTREACHED*/
2251         }
2252         if ((buf = malloc(msize)) == NULL) {
2253                 fatal("malloc");
2254                 /*NOTREACHED*/
2255         }
2256         if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) {
2257                 fatal("sysctl NET_RT_IFLIST");
2258                 /*NOTREACHED*/
2259         }
2260         ifm = (struct if_msghdr *)buf;
2261         mtu = ifm->ifm_data.ifi_mtu;
2262 #ifdef __FreeBSD__
2263         if (ifindex != ifm->ifm_index) {
2264                 fatal("ifindex does not match with ifm_index");
2265                 /*NOTREACHED*/
2266         }
2267 #endif
2268         free(buf);
2269         return mtu;
2270 }
2271
2272 const char *
2273 rttypes(rtm)
2274         struct rt_msghdr *rtm;
2275 {
2276 #define RTTYPE(s, f) \
2277 do { \
2278         if (rtm->rtm_type == (f)) \
2279                 return (s); \
2280 } while (0)
2281         RTTYPE("ADD", RTM_ADD);
2282         RTTYPE("DELETE", RTM_DELETE);
2283         RTTYPE("CHANGE", RTM_CHANGE);
2284         RTTYPE("GET", RTM_GET);
2285         RTTYPE("LOSING", RTM_LOSING);
2286         RTTYPE("REDIRECT", RTM_REDIRECT);
2287         RTTYPE("MISS", RTM_MISS);
2288         RTTYPE("LOCK", RTM_LOCK);
2289         RTTYPE("OLDADD", RTM_OLDADD);
2290         RTTYPE("OLDDEL", RTM_OLDDEL);
2291         RTTYPE("RESOLVE", RTM_RESOLVE);
2292         RTTYPE("NEWADDR", RTM_NEWADDR);
2293         RTTYPE("DELADDR", RTM_DELADDR);
2294         RTTYPE("IFINFO", RTM_IFINFO);
2295 #ifdef RTM_OLDADD
2296         RTTYPE("OLDADD", RTM_OLDADD);
2297 #endif
2298 #ifdef RTM_OLDDEL
2299         RTTYPE("OLDDEL", RTM_OLDDEL);
2300 #endif
2301 #ifdef RTM_OIFINFO
2302         RTTYPE("OIFINFO", RTM_OIFINFO);
2303 #endif
2304 #ifdef RTM_IFANNOUNCE
2305         RTTYPE("IFANNOUNCE", RTM_IFANNOUNCE);
2306 #endif
2307 #ifdef RTM_NEWMADDR
2308         RTTYPE("NEWMADDR", RTM_NEWMADDR);
2309 #endif
2310 #ifdef RTM_DELMADDR
2311         RTTYPE("DELMADDR", RTM_DELMADDR);
2312 #endif
2313 #undef RTTYPE
2314         return NULL;
2315 }
2316
2317 const char *
2318 rtflags(rtm)
2319         struct rt_msghdr *rtm;
2320 {
2321         static char buf[BUFSIZ];
2322
2323         /*
2324          * letter conflict should be okay.  painful when *BSD diverges...
2325          */
2326         strlcpy(buf, "", sizeof(buf));
2327 #define RTFLAG(s, f) \
2328 do { \
2329         if (rtm->rtm_flags & (f)) \
2330                 strlcat(buf, (s), sizeof(buf)); \
2331 } while (0)
2332         RTFLAG("U", RTF_UP);
2333         RTFLAG("G", RTF_GATEWAY);
2334         RTFLAG("H", RTF_HOST);
2335         RTFLAG("R", RTF_REJECT);
2336         RTFLAG("D", RTF_DYNAMIC);
2337         RTFLAG("M", RTF_MODIFIED);
2338         RTFLAG("d", RTF_DONE);
2339 #ifdef  RTF_MASK
2340         RTFLAG("m", RTF_MASK);
2341 #endif
2342         RTFLAG("C", RTF_CLONING);
2343 #ifdef RTF_CLONED
2344         RTFLAG("c", RTF_CLONED);
2345 #endif
2346 #ifdef RTF_PRCLONING
2347         RTFLAG("c", RTF_PRCLONING);
2348 #endif
2349 #ifdef RTF_WASCLONED
2350         RTFLAG("W", RTF_WASCLONED);
2351 #endif
2352         RTFLAG("X", RTF_XRESOLVE);
2353         RTFLAG("L", RTF_LLINFO);
2354         RTFLAG("S", RTF_STATIC);
2355         RTFLAG("B", RTF_BLACKHOLE);
2356 #ifdef RTF_PROTO3
2357         RTFLAG("3", RTF_PROTO3);
2358 #endif
2359         RTFLAG("2", RTF_PROTO2);
2360         RTFLAG("1", RTF_PROTO1);
2361 #ifdef RTF_BROADCAST
2362         RTFLAG("b", RTF_BROADCAST);
2363 #endif
2364 #ifdef RTF_DEFAULT
2365         RTFLAG("d", RTF_DEFAULT);
2366 #endif
2367 #ifdef RTF_ISAROUTER
2368         RTFLAG("r", RTF_ISAROUTER);
2369 #endif
2370 #ifdef RTF_TUNNEL
2371         RTFLAG("T", RTF_TUNNEL);
2372 #endif
2373 #ifdef RTF_AUTH
2374         RTFLAG("A", RTF_AUTH);
2375 #endif
2376 #ifdef RTF_CRYPT
2377         RTFLAG("E", RTF_CRYPT);
2378 #endif
2379 #undef RTFLAG
2380         return buf;
2381 }
2382
2383 const char *
2384 ifflags(flags)
2385         int flags;
2386 {
2387         static char buf[BUFSIZ];
2388
2389         strlcpy(buf, "", sizeof(buf));
2390 #define IFFLAG(s, f) \
2391 do { \
2392         if (flags & f) { \
2393                 if (buf[0]) \
2394                         strlcat(buf, ",", sizeof(buf)); \
2395                 strlcat(buf, s, sizeof(buf)); \
2396         } \
2397 } while (0)
2398         IFFLAG("UP", IFF_UP);
2399         IFFLAG("BROADCAST", IFF_BROADCAST);
2400         IFFLAG("DEBUG", IFF_DEBUG);
2401         IFFLAG("LOOPBACK", IFF_LOOPBACK);
2402         IFFLAG("POINTOPOINT", IFF_POINTOPOINT);
2403 #ifdef IFF_NOTRAILERS
2404         IFFLAG("NOTRAILERS", IFF_NOTRAILERS);
2405 #endif
2406 #ifdef IFF_SMART
2407         IFFLAG("SMART", IFF_SMART);
2408 #endif
2409         IFFLAG("RUNNING", IFF_RUNNING);
2410         IFFLAG("NOARP", IFF_NOARP);
2411         IFFLAG("PROMISC", IFF_PROMISC);
2412         IFFLAG("ALLMULTI", IFF_ALLMULTI);
2413         IFFLAG("OACTIVE", IFF_OACTIVE);
2414         IFFLAG("SIMPLEX", IFF_SIMPLEX);
2415         IFFLAG("LINK0", IFF_LINK0);
2416         IFFLAG("LINK1", IFF_LINK1);
2417         IFFLAG("LINK2", IFF_LINK2);
2418         IFFLAG("MULTICAST", IFF_MULTICAST);
2419 #undef IFFLAG
2420         return buf;
2421 }
2422
2423 void
2424 krtread(again)
2425         int again;
2426 {
2427         int mib[6];
2428         size_t msize;
2429         char *buf, *p, *lim;
2430         struct rt_msghdr *rtm;
2431         int retry;
2432         const char *errmsg;
2433
2434         retry = 0;
2435         buf = NULL;
2436         mib[0] = CTL_NET;
2437         mib[1] = PF_ROUTE;
2438         mib[2] = 0;
2439         mib[3] = AF_INET6;      /* Address family */
2440         mib[4] = NET_RT_DUMP;   /* Dump the kernel routing table */
2441         mib[5] = 0;             /* No flags */
2442         do {
2443                 retry++;
2444                 errmsg = NULL;
2445                 if (buf)
2446                         free(buf);
2447                 if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) {
2448                         errmsg = "sysctl estimate";
2449                         continue;
2450                 }
2451                 if ((buf = malloc(msize)) == NULL) {
2452                         errmsg = "malloc";
2453                         continue;
2454                 }
2455                 if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) {
2456                         errmsg = "sysctl NET_RT_DUMP";
2457                         continue;
2458                 }
2459         } while (retry < 5 && errmsg != NULL);
2460         if (errmsg) {
2461                 fatal("%s (with %d retries, msize=%lu)", errmsg, retry,
2462                     (u_long)msize);
2463                 /*NOTREACHED*/
2464         } else if (1 < retry)
2465                 syslog(LOG_INFO, "NET_RT_DUMP %d retires", retry);
2466
2467         lim = buf + msize;
2468         for (p = buf; p < lim; p += rtm->rtm_msglen) {
2469                 rtm = (struct rt_msghdr *)p;
2470                 rt_entry(rtm, again);
2471         }
2472         free(buf);
2473 }
2474
2475 void
2476 rt_entry(rtm, again)
2477         struct rt_msghdr *rtm;
2478         int again;
2479 {
2480         struct  sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask;
2481         struct  sockaddr_in6 *sin6_genmask, *sin6_ifp;
2482         char    *rtmp, *ifname = NULL;
2483         struct  riprt *rrt, *orrt;
2484         struct  netinfo6 *np;
2485         int     s;
2486
2487         sin6_dst = sin6_gw = sin6_mask = sin6_genmask = sin6_ifp = 0;
2488         if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags &
2489                 (RTF_CLONING|RTF_XRESOLVE|RTF_LLINFO|RTF_BLACKHOLE)) {
2490                 return;         /* not interested in the link route */
2491         }
2492         /* do not look at cloned routes */
2493 #ifdef RTF_WASCLONED
2494         if (rtm->rtm_flags & RTF_WASCLONED)
2495                 return;
2496 #endif
2497 #ifdef RTF_CLONED
2498         if (rtm->rtm_flags & RTF_CLONED)
2499                 return;
2500 #endif
2501         /*
2502          * do not look at dynamic routes.
2503          * netbsd/openbsd cloned routes have UGHD.
2504          */
2505         if (rtm->rtm_flags & RTF_DYNAMIC)
2506                 return;
2507         rtmp = (char *)(rtm + 1);
2508         /* Destination */
2509         if ((rtm->rtm_addrs & RTA_DST) == 0)
2510                 return;         /* ignore routes without destination address */
2511         sin6_dst = (struct sockaddr_in6 *)rtmp;
2512         rtmp += ROUNDUP(sin6_dst->sin6_len);
2513         if (rtm->rtm_addrs & RTA_GATEWAY) {
2514                 sin6_gw = (struct sockaddr_in6 *)rtmp;
2515                 rtmp += ROUNDUP(sin6_gw->sin6_len);
2516         }
2517         if (rtm->rtm_addrs & RTA_NETMASK) {
2518                 sin6_mask = (struct sockaddr_in6 *)rtmp;
2519                 rtmp += ROUNDUP(sin6_mask->sin6_len);
2520         }
2521         if (rtm->rtm_addrs & RTA_GENMASK) {
2522                 sin6_genmask = (struct sockaddr_in6 *)rtmp;
2523                 rtmp += ROUNDUP(sin6_genmask->sin6_len);
2524         }
2525         if (rtm->rtm_addrs & RTA_IFP) {
2526                 sin6_ifp = (struct sockaddr_in6 *)rtmp;
2527                 rtmp += ROUNDUP(sin6_ifp->sin6_len);
2528         }
2529
2530         /* Destination */
2531         if (sin6_dst->sin6_family != AF_INET6)
2532                 return;
2533         if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst->sin6_addr))
2534                 return;         /* Link-local */
2535         if (IN6_ARE_ADDR_EQUAL(&sin6_dst->sin6_addr, &in6addr_loopback))
2536                 return;         /* Loopback */
2537         if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr))
2538                 return;
2539
2540         if ((rrt = MALLOC(struct riprt)) == NULL) {
2541                 fatal("malloc: struct riprt");
2542                 /*NOTREACHED*/
2543         }
2544         memset(rrt, 0, sizeof(*rrt));
2545         np = &rrt->rrt_info;
2546         rrt->rrt_same = NULL;
2547         rrt->rrt_t = time(NULL);
2548         if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC))
2549                 rrt->rrt_t = 0; /* Don't age static routes */
2550 #if 0
2551         np->rip6_tag = htons(routetag & 0xffff);
2552 #else
2553         np->rip6_tag = 0;
2554 #endif
2555         np->rip6_metric = rtm->rtm_rmx.rmx_hopcount;
2556         if (np->rip6_metric < 1)
2557                 np->rip6_metric = 1;
2558         rrt->rrt_flags = rtm->rtm_flags;
2559         np->rip6_dest = sin6_dst->sin6_addr;
2560
2561         /* Mask or plen */
2562         if (rtm->rtm_flags & RTF_HOST)
2563                 np->rip6_plen = 128;    /* Host route */
2564         else if (sin6_mask)
2565                 np->rip6_plen = sin6mask2len(sin6_mask);
2566         else
2567                 np->rip6_plen = 0;
2568
2569         orrt = rtsearch(np, NULL);
2570         if (orrt && orrt->rrt_info.rip6_metric != HOPCNT_INFINITY6) {
2571                 /* Already found */
2572                 if (!again) {
2573                         trace(1, "route: %s/%d flags %s: already registered\n",
2574                                 inet6_n2p(&np->rip6_dest), np->rip6_plen,
2575                                 rtflags(rtm));
2576                 }
2577                 free(rrt);
2578                 return;
2579         }
2580         /* Gateway */
2581         if (!sin6_gw)
2582                 memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
2583         else {
2584                 if (sin6_gw->sin6_family == AF_INET6)
2585                         rrt->rrt_gw = sin6_gw->sin6_addr;
2586                 else if (sin6_gw->sin6_family == AF_LINK) {
2587                         /* XXX in case ppp link? */
2588                         rrt->rrt_gw = in6addr_loopback;
2589                 } else
2590                         memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
2591         }
2592         trace(1, "route: %s/%d flags %s",
2593                 inet6_n2p(&np->rip6_dest), np->rip6_plen, rtflags(rtm));
2594         trace(1, " gw %s", inet6_n2p(&rrt->rrt_gw));
2595
2596         /* Interface */
2597         s = rtm->rtm_index;
2598         if (s < nindex2ifc && index2ifc[s])
2599                 ifname = index2ifc[s]->ifc_name;
2600         else {
2601                 trace(1, " not configured\n");
2602                 free(rrt);
2603                 return;
2604         }
2605         trace(1, " if %s sock %d", ifname, s);
2606         rrt->rrt_index = s;
2607
2608         trace(1, "\n");
2609
2610         /* Check gateway */
2611         if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_gw) &&
2612             !IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)
2613 #ifdef __FreeBSD__
2614          && (rrt->rrt_flags & RTF_LOCAL) == 0
2615 #endif
2616             ) {
2617                 trace(0, "***** Gateway %s is not a link-local address.\n",
2618                         inet6_n2p(&rrt->rrt_gw));
2619                 trace(0, "*****     dest(%s) if(%s) -- Not optimized.\n",
2620                         inet6_n2p(&rrt->rrt_info.rip6_dest), ifname);
2621                 rrt->rrt_rflags |= RRTF_NH_NOT_LLADDR;
2622         }
2623
2624         /* Put it to the route list */
2625         if (orrt && orrt->rrt_info.rip6_metric == HOPCNT_INFINITY6) {
2626                 /* replace route list */
2627                 rrt->rrt_next = orrt->rrt_next;
2628                 *orrt = *rrt;
2629                 trace(1, "route: %s/%d flags %s: replace new route\n",
2630                     inet6_n2p(&np->rip6_dest), np->rip6_plen,
2631                     rtflags(rtm));
2632                 free(rrt);
2633         } else {
2634                 rrt->rrt_next = riprt;
2635                 riprt = rrt;
2636         }
2637 }
2638
2639 int
2640 addroute(rrt, gw, ifcp)
2641         struct riprt *rrt;
2642         const struct in6_addr *gw;
2643         struct ifc *ifcp;
2644 {
2645         struct  netinfo6 *np;
2646         u_char  buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ];
2647         struct  rt_msghdr       *rtm;
2648         struct  sockaddr_in6    *sin;
2649         int     len;
2650
2651         np = &rrt->rrt_info;
2652         inet_ntop(AF_INET6, (const void *)gw, (char *)buf1, sizeof(buf1));
2653         inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2));
2654         tracet(1, "ADD: %s/%d gw %s [%d] ifa %s\n",
2655                 inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1,
2656                 np->rip6_metric - 1, buf2);
2657         if (rtlog)
2658                 fprintf(rtlog, "%s: ADD: %s/%d gw %s [%d] ifa %s\n", hms(),
2659                         inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1,
2660                         np->rip6_metric - 1, buf2);
2661         if (nflag)
2662                 return 0;
2663
2664         memset(buf, 0, sizeof(buf));
2665         rtm = (struct rt_msghdr *)buf;
2666         rtm->rtm_type = RTM_ADD;
2667         rtm->rtm_version = RTM_VERSION;
2668         rtm->rtm_seq = ++seq;
2669         rtm->rtm_pid = pid;
2670         rtm->rtm_flags = rrt->rrt_flags;
2671         rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
2672         rtm->rtm_rmx.rmx_hopcount = np->rip6_metric - 1;
2673         rtm->rtm_inits = RTV_HOPCOUNT;
2674         sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
2675         /* Destination */
2676         sin->sin6_len = sizeof(struct sockaddr_in6);
2677         sin->sin6_family = AF_INET6;
2678         sin->sin6_addr = np->rip6_dest;
2679         sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
2680         /* Gateway */
2681         sin->sin6_len = sizeof(struct sockaddr_in6);
2682         sin->sin6_family = AF_INET6;
2683         sin->sin6_addr = *gw;
2684         sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
2685         /* Netmask */
2686         sin->sin6_len = sizeof(struct sockaddr_in6);
2687         sin->sin6_family = AF_INET6;
2688         sin->sin6_addr = *(plen2mask(np->rip6_plen));
2689         sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
2690
2691         len = (char *)sin - (char *)buf;
2692         rtm->rtm_msglen = len;
2693         if (write(rtsock, buf, len) > 0)
2694                 return 0;
2695
2696         if (errno == EEXIST) {
2697                 trace(0, "ADD: Route already exists %s/%d gw %s\n",
2698                         inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1);
2699                 if (rtlog)
2700                         fprintf(rtlog, "ADD: Route already exists %s/%d gw %s\n",
2701                                 inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1);
2702         } else {
2703                 trace(0, "Can not write to rtsock (addroute): %s\n",
2704                         strerror(errno));
2705                 if (rtlog)
2706                         fprintf(rtlog, "\tCan not write to rtsock: %s\n",
2707                                 strerror(errno));
2708         }
2709         return -1;
2710 }
2711
2712 int
2713 delroute(np, gw)
2714         struct netinfo6 *np;
2715         struct in6_addr *gw;
2716 {
2717         u_char  buf[BUFSIZ], buf2[BUFSIZ];
2718         struct  rt_msghdr       *rtm;
2719         struct  sockaddr_in6    *sin;
2720         int     len;
2721
2722         inet_ntop(AF_INET6, (void *)gw, (char *)buf2, sizeof(buf2));
2723         tracet(1, "DEL: %s/%d gw %s\n", inet6_n2p(&np->rip6_dest),
2724                 np->rip6_plen, buf2);
2725         if (rtlog)
2726                 fprintf(rtlog, "%s: DEL: %s/%d gw %s\n",
2727                         hms(), inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
2728         if (nflag)
2729                 return 0;
2730
2731         memset(buf, 0, sizeof(buf));
2732         rtm = (struct rt_msghdr *)buf;
2733         rtm->rtm_type = RTM_DELETE;
2734         rtm->rtm_version = RTM_VERSION;
2735         rtm->rtm_seq = ++seq;
2736         rtm->rtm_pid = pid;
2737         rtm->rtm_flags = RTF_UP | RTF_GATEWAY;
2738         if (np->rip6_plen == sizeof(struct in6_addr) * 8)
2739                 rtm->rtm_flags |= RTF_HOST;
2740         rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
2741         sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
2742         /* Destination */
2743         sin->sin6_len = sizeof(struct sockaddr_in6);
2744         sin->sin6_family = AF_INET6;
2745         sin->sin6_addr = np->rip6_dest;
2746         sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
2747         /* Gateway */
2748         sin->sin6_len = sizeof(struct sockaddr_in6);
2749         sin->sin6_family = AF_INET6;
2750         sin->sin6_addr = *gw;
2751         sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
2752         /* Netmask */
2753         sin->sin6_len = sizeof(struct sockaddr_in6);
2754         sin->sin6_family = AF_INET6;
2755         sin->sin6_addr = *(plen2mask(np->rip6_plen));
2756         sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
2757
2758         len = (char *)sin - (char *)buf;
2759         rtm->rtm_msglen = len;
2760         if (write(rtsock, buf, len) >= 0)
2761                 return 0;
2762
2763         if (errno == ESRCH) {
2764                 trace(0, "RTDEL: Route does not exist: %s/%d gw %s\n",
2765                         inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
2766                 if (rtlog)
2767                         fprintf(rtlog, "RTDEL: Route does not exist: %s/%d gw %s\n",
2768                                 inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
2769         } else {
2770                 trace(0, "Can not write to rtsock (delroute): %s\n",
2771                         strerror(errno));
2772                 if (rtlog)
2773                         fprintf(rtlog, "\tCan not write to rtsock: %s\n",
2774                                 strerror(errno));
2775         }
2776         return -1;
2777 }
2778
2779 struct in6_addr *
2780 getroute(np, gw)
2781         struct netinfo6 *np;
2782         struct in6_addr *gw;
2783 {
2784         u_char buf[BUFSIZ];
2785         u_long myseq;
2786         int len;
2787         struct rt_msghdr *rtm;
2788         struct sockaddr_in6 *sin;
2789
2790         rtm = (struct rt_msghdr *)buf;
2791         len = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6);
2792         memset(rtm, 0, len);
2793         rtm->rtm_type = RTM_GET;
2794         rtm->rtm_version = RTM_VERSION;
2795         myseq = ++seq;
2796         rtm->rtm_seq = myseq;
2797         rtm->rtm_addrs = RTA_DST;
2798         rtm->rtm_msglen = len;
2799         sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
2800         sin->sin6_len = sizeof(struct sockaddr_in6);
2801         sin->sin6_family = AF_INET6;
2802         sin->sin6_addr = np->rip6_dest;
2803         if (write(rtsock, buf, len) < 0) {
2804                 if (errno == ESRCH)     /* No such route found */
2805                         return NULL;
2806                 perror("write to rtsock");
2807                 exit(1);
2808         }
2809         do {
2810                 if ((len = read(rtsock, buf, sizeof(buf))) < 0) {
2811                         perror("read from rtsock");
2812                         exit(1);
2813                 }
2814                 rtm = (struct rt_msghdr *)buf;
2815         } while (rtm->rtm_seq != myseq || rtm->rtm_pid != pid);
2816         sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
2817         if (rtm->rtm_addrs & RTA_DST) {
2818                 sin = (struct sockaddr_in6 *)
2819                         ((char *)sin + ROUNDUP(sin->sin6_len));
2820         }
2821         if (rtm->rtm_addrs & RTA_GATEWAY) {
2822                 *gw = sin->sin6_addr;
2823                 return gw;
2824         }
2825         return NULL;
2826 }
2827
2828 const char *
2829 inet6_n2p(p)
2830         const struct in6_addr *p;
2831 {
2832         static char buf[BUFSIZ];
2833
2834         return inet_ntop(AF_INET6, (const void *)p, buf, sizeof(buf));
2835 }
2836
2837 void
2838 ifrtdump(sig)
2839         int sig;
2840 {
2841
2842         ifdump(sig);
2843         rtdump(sig);
2844 }
2845
2846 void
2847 ifdump(sig)
2848         int sig;
2849 {
2850         struct ifc *ifcp;
2851         FILE *dump;
2852         int i;
2853
2854         if (sig == 0)
2855                 dump = stderr;
2856         else
2857                 if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL)
2858                         dump = stderr;
2859
2860         fprintf(dump, "%s: Interface Table Dump\n", hms());
2861         fprintf(dump, "  Number of interfaces: %d\n", nifc);
2862         for (i = 0; i < 2; i++) {
2863                 fprintf(dump, "  %sadvertising interfaces:\n", i ? "non-" : "");
2864                 for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
2865                         if (i == 0) {
2866                                 if ((ifcp->ifc_flags & IFF_UP) == 0)
2867                                         continue;
2868                                 if (iff_find(ifcp, 'N') != NULL)
2869                                         continue;
2870                         } else {
2871                                 if (ifcp->ifc_flags & IFF_UP)
2872                                         continue;
2873                         }
2874                         ifdump0(dump, ifcp);
2875                 }
2876         }
2877         fprintf(dump, "\n");
2878         if (dump != stderr)
2879                 fclose(dump);
2880 }
2881
2882 void
2883 ifdump0(dump, ifcp)
2884         FILE *dump;
2885         const struct ifc *ifcp;
2886 {
2887         struct ifac *ifa;
2888         struct iff *iffp;
2889         char buf[BUFSIZ];
2890         const char *ft;
2891         int addr;
2892
2893         fprintf(dump, "    %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)\n",
2894                 ifcp->ifc_name, ifcp->ifc_index, ifflags(ifcp->ifc_flags),
2895                 inet6_n2p(&ifcp->ifc_mylladdr),
2896                 ifcp->ifc_mtu, ifcp->ifc_metric);
2897         for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
2898                 if (ifcp->ifc_flags & IFF_POINTOPOINT) {
2899                         inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr,
2900                                 buf, sizeof(buf));
2901                         fprintf(dump, "\t%s/%d -- %s\n",
2902                                 inet6_n2p(&ifa->ifa_addr),
2903                                 ifa->ifa_plen, buf);
2904                 } else {
2905                         fprintf(dump, "\t%s/%d\n",
2906                                 inet6_n2p(&ifa->ifa_addr),
2907                                 ifa->ifa_plen);
2908                 }
2909         }
2910         if (ifcp->ifc_filter) {
2911                 fprintf(dump, "\tFilter:");
2912                 for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
2913                         addr = 0;
2914                         switch (iffp->iff_type) {
2915                         case 'A':
2916                                 ft = "Aggregate"; addr++; break;
2917                         case 'N':
2918                                 ft = "No-use"; break;
2919                         case 'O':
2920                                 ft = "Advertise-only"; addr++; break;
2921                         case 'T':
2922                                 ft = "Default-only"; break;
2923                         case 'L':
2924                                 ft = "Listen-only"; addr++; break;
2925                         default:
2926                                 snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type);
2927                                 ft = buf;
2928                                 addr++;
2929                                 break;
2930                         }
2931                         fprintf(dump, " %s", ft);
2932                         if (addr) {
2933                                 fprintf(dump, "(%s/%d)", inet6_n2p(&iffp->iff_addr),
2934                                         iffp->iff_plen);
2935                         }
2936                 }
2937                 fprintf(dump, "\n");
2938         }
2939 }
2940
2941 void
2942 rtdump(sig)
2943         int sig;
2944 {
2945         struct  riprt *rrt;
2946         char    buf[BUFSIZ];
2947         FILE    *dump;
2948         time_t  t, age;
2949
2950         if (sig == 0)
2951                 dump = stderr;
2952         else
2953                 if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL)
2954                         dump = stderr;
2955
2956         t = time(NULL);
2957         fprintf(dump, "\n%s: Routing Table Dump\n", hms());
2958         for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
2959                 if (rrt->rrt_t == 0)
2960                         age = 0;
2961                 else
2962                         age = t - rrt->rrt_t;
2963                 inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest,
2964                         buf, sizeof(buf));
2965                 fprintf(dump, "    %s/%d if(%d:%s) gw(%s) [%d] age(%ld)",
2966                         buf, rrt->rrt_info.rip6_plen, rrt->rrt_index,
2967                         index2ifc[rrt->rrt_index]->ifc_name,
2968                         inet6_n2p(&rrt->rrt_gw),
2969                         rrt->rrt_info.rip6_metric, (long)age);
2970                 if (rrt->rrt_info.rip6_tag) {
2971                         fprintf(dump, " tag(0x%04x)",
2972                                 ntohs(rrt->rrt_info.rip6_tag) & 0xffff);
2973                 }
2974                 if (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)
2975                         fprintf(dump, " NOT-LL");
2976                 if (rrt->rrt_rflags & RRTF_NOADVERTISE)
2977                         fprintf(dump, " NO-ADV");
2978                 fprintf(dump, "\n");
2979         }
2980         fprintf(dump, "\n");
2981         if (dump != stderr)
2982                 fclose(dump);
2983 }
2984
2985 /*
2986  * Parse the -A (and -O) options and put corresponding filter object to the
2987  * specified interface structures.  Each of the -A/O option has the following
2988  * syntax:      -A 5f09:c400::/32,ef0,ef1  (aggregate)
2989  *              -O 5f09:c400::/32,ef0,ef1  (only when match)
2990  */
2991 void
2992 filterconfig()
2993 {
2994         int i;
2995         char *p, *ap, *iflp, *ifname;
2996         struct iff ftmp, *iff_obj;
2997         struct ifc *ifcp;
2998         struct riprt *rrt;
2999 #if 0
3000         struct in6_addr gw;
3001 #endif
3002
3003         for (i = 0; i < nfilter; i++) {
3004                 ap = filter[i];
3005                 iflp = NULL;
3006                 ifcp = NULL;
3007                 if (filtertype[i] == 'N' || filtertype[i] == 'T') {
3008                         iflp = ap;
3009                         goto ifonly;
3010                 }
3011                 if ((p = index(ap, ',')) != NULL) {
3012                         *p++ = '\0';
3013                         iflp = p;
3014                 }
3015                 if ((p = index(ap, '/')) == NULL) {
3016                         fatal("no prefixlen specified for '%s'", ap);
3017                         /*NOTREACHED*/
3018                 }
3019                 *p++ = '\0';
3020                 if (inet_pton(AF_INET6, ap, &ftmp.iff_addr) != 1) {
3021                         fatal("invalid prefix specified for '%s'", ap);
3022                         /*NOTREACHED*/
3023                 }
3024                 ftmp.iff_plen = atoi(p);
3025                 ftmp.iff_next = NULL;
3026                 applyplen(&ftmp.iff_addr, ftmp.iff_plen);
3027 ifonly:
3028                 ftmp.iff_type = filtertype[i];
3029                 if (iflp == NULL || *iflp == '\0') {
3030                         fatal("no interface specified for '%s'", ap);
3031                         /*NOTREACHED*/
3032                 }
3033                 /* parse the interface listing portion */
3034                 while (iflp) {
3035                         ifname = iflp;
3036                         if ((iflp = index(iflp, ',')) != NULL)
3037                                 *iflp++ = '\0';
3038                         ifcp = ifc_find(ifname);
3039                         if (ifcp == NULL) {
3040                                 fatal("no interface %s exists", ifname);
3041                                 /*NOTREACHED*/
3042                         }
3043                         iff_obj = (struct iff *)malloc(sizeof(struct iff));
3044                         if (iff_obj == NULL) {
3045                                 fatal("malloc of iff_obj");
3046                                 /*NOTREACHED*/
3047                         }
3048                         memcpy((void *)iff_obj, (void *)&ftmp,
3049                             sizeof(struct iff));
3050                         /* link it to the interface filter */
3051                         iff_obj->iff_next = ifcp->ifc_filter;
3052                         ifcp->ifc_filter = iff_obj;
3053                 }
3054
3055                 /*
3056                  * -A: aggregate configuration.
3057                  */
3058                 if (filtertype[i] != 'A')
3059                         continue;
3060                 /* put the aggregate to the kernel routing table */
3061                 rrt = (struct riprt *)malloc(sizeof(struct riprt));
3062                 if (rrt == NULL) {
3063                         fatal("malloc: rrt");
3064                         /*NOTREACHED*/
3065                 }
3066                 memset(rrt, 0, sizeof(struct riprt));
3067                 rrt->rrt_info.rip6_dest = ftmp.iff_addr;
3068                 rrt->rrt_info.rip6_plen = ftmp.iff_plen;
3069                 rrt->rrt_info.rip6_metric = 1;
3070                 rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
3071                 rrt->rrt_gw = in6addr_loopback;
3072                 rrt->rrt_flags = RTF_UP | RTF_REJECT;
3073                 rrt->rrt_rflags = RRTF_AGGREGATE;
3074                 rrt->rrt_t = 0;
3075                 rrt->rrt_index = loopifindex;
3076 #if 0
3077                 if (getroute(&rrt->rrt_info, &gw)) {
3078 #if 0
3079                         /*
3080                          * When the address has already been registered in the
3081                          * kernel routing table, it should be removed 
3082                          */
3083                         delroute(&rrt->rrt_info, &gw);
3084 #else
3085                         /* it is safer behavior */
3086                         errno = EINVAL;
3087                         fatal("%s/%u already in routing table, "
3088                             "cannot aggregate",
3089                             inet6_n2p(&rrt->rrt_info.rip6_dest),
3090                             rrt->rrt_info.rip6_plen);
3091                         /*NOTREACHED*/
3092 #endif
3093                 }
3094 #endif
3095                 /* Put the route to the list */
3096                 rrt->rrt_next = riprt;
3097                 riprt = rrt;
3098                 trace(1, "Aggregate: %s/%d for %s\n",
3099                         inet6_n2p(&ftmp.iff_addr), ftmp.iff_plen,
3100                         ifcp->ifc_name);
3101                 /* Add this route to the kernel */
3102                 if (nflag)      /* do not modify kernel routing table */
3103                         continue;
3104                 addroute(rrt, &in6addr_loopback, loopifcp);
3105         }
3106 }
3107
3108 /***************** utility functions *****************/
3109
3110 /*
3111  * Returns a pointer to ifac whose address and prefix length matches
3112  * with the address and prefix length specified in the arguments.
3113  */
3114 struct ifac *
3115 ifa_match(ifcp, ia, plen)
3116         const struct ifc *ifcp;
3117         const struct in6_addr *ia;
3118         int plen;
3119 {
3120         struct ifac *ifa;
3121
3122         for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
3123                 if (IN6_ARE_ADDR_EQUAL(&ifa->ifa_addr, ia) &&
3124                     ifa->ifa_plen == plen)
3125                         break;
3126         }
3127         return ifa;
3128 }
3129
3130 /*
3131  * Return a pointer to riprt structure whose address and prefix length
3132  * matches with the address and prefix length found in the argument.
3133  * Note: This is not a rtalloc().  Therefore exact match is necessary.
3134  */
3135 struct riprt *
3136 rtsearch(np, prev_rrt)
3137         struct  netinfo6 *np;
3138         struct  riprt **prev_rrt;
3139 {
3140         struct  riprt   *rrt;
3141
3142         if (prev_rrt)
3143                 *prev_rrt = NULL;
3144         for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
3145                 if (rrt->rrt_info.rip6_plen == np->rip6_plen &&
3146                     IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
3147                                        &np->rip6_dest))
3148                         return rrt;
3149                 if (prev_rrt)
3150                         *prev_rrt = rrt;
3151         }
3152         if (prev_rrt)
3153                 *prev_rrt = NULL;
3154         return 0;
3155 }
3156
3157 int
3158 sin6mask2len(sin6)
3159         const struct sockaddr_in6 *sin6;
3160 {
3161
3162         return mask2len(&sin6->sin6_addr,
3163             sin6->sin6_len - offsetof(struct sockaddr_in6, sin6_addr));
3164 }
3165
3166 int
3167 mask2len(addr, lenlim)
3168         const struct in6_addr *addr;
3169         int lenlim;
3170 {
3171         int i = 0, j;
3172         const u_char *p = (const u_char *)addr;
3173         
3174         for (j = 0; j < lenlim; j++, p++) {
3175                 if (*p != 0xff)
3176                         break;
3177                 i += 8;
3178         }
3179         if (j < lenlim) {
3180                 switch (*p) {
3181 #define MASKLEN(m, l)   case m: do { i += l; break; } while (0)
3182                 MASKLEN(0xfe, 7); break;
3183                 MASKLEN(0xfc, 6); break;
3184                 MASKLEN(0xf8, 5); break;
3185                 MASKLEN(0xf0, 4); break;
3186                 MASKLEN(0xe0, 3); break;
3187                 MASKLEN(0xc0, 2); break;
3188                 MASKLEN(0x80, 1); break;
3189 #undef  MASKLEN
3190                 }
3191         }
3192         return i;
3193 }
3194
3195 void
3196 applymask(addr, mask)
3197         struct in6_addr *addr, *mask;
3198 {
3199         int     i;
3200         u_long  *p, *q;
3201
3202         p = (u_long *)addr; q = (u_long *)mask;
3203         for (i = 0; i < 4; i++)
3204                 *p++ &= *q++;
3205 }
3206
3207 static const u_char plent[8] = {
3208         0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
3209 };
3210
3211 void
3212 applyplen(ia, plen)
3213         struct  in6_addr *ia;
3214         int     plen;
3215 {
3216         u_char  *p;
3217         int     i;
3218
3219         p = ia->s6_addr;
3220         for (i = 0; i < 16; i++) {
3221                 if (plen <= 0)
3222                         *p = 0;
3223                 else if (plen < 8)
3224                         *p &= plent[plen];
3225                 p++, plen -= 8;
3226         }
3227 }
3228
3229 static const int pl2m[9] = {
3230         0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
3231 };
3232
3233 struct in6_addr *
3234 plen2mask(n)
3235         int     n;
3236 {
3237         static struct in6_addr ia;
3238         u_char  *p;
3239         int     i;
3240
3241         memset(&ia, 0, sizeof(struct in6_addr));
3242         p = (u_char *)&ia;
3243         for (i = 0; i < 16; i++, p++, n -= 8) {
3244                 if (n >= 8) {
3245                         *p = 0xff;
3246                         continue;
3247                 }
3248                 *p = pl2m[n];
3249                 break;
3250         }
3251         return &ia;
3252 }
3253
3254 char *
3255 allocopy(p)
3256         char *p;
3257 {
3258         char *q = (char *)malloc(strlen(p) + 1);
3259
3260         strcpy(q, p);
3261         return q;
3262 }
3263
3264 char *
3265 hms()
3266 {
3267         static char buf[BUFSIZ];
3268         time_t t;
3269         struct  tm *tm;
3270
3271         t = time(NULL);
3272         if ((tm = localtime(&t)) == 0) {
3273                 fatal("localtime");
3274                 /*NOTREACHED*/
3275         }
3276         snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
3277             tm->tm_sec);
3278         return buf;
3279 }
3280
3281 #define RIPRANDDEV      1.0     /* 30 +- 15, max - min = 30 */
3282
3283 int
3284 ripinterval(timer)
3285         int timer;
3286 {
3287         double r = rand();
3288
3289         interval = (int)(timer + timer * RIPRANDDEV * (r / RAND_MAX - 0.5));
3290         nextalarm = time(NULL) + interval;
3291         return interval;
3292 }
3293
3294 time_t
3295 ripsuptrig()
3296 {
3297         time_t t;
3298
3299         double r = rand();
3300         t  = (int)(RIP_TRIG_INT6_MIN + 
3301                 (RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / RAND_MAX));
3302         sup_trig_update = time(NULL) + t;
3303         return t;
3304 }
3305
3306 void
3307 #ifdef __STDC__
3308 fatal(const char *fmt, ...)
3309 #else
3310 fatal(fmt, va_alist)
3311         char    *fmt;
3312         va_dcl
3313 #endif
3314 {
3315         va_list ap;
3316         char buf[1024];
3317
3318 #ifdef __STDC__
3319         va_start(ap, fmt);
3320 #else
3321         va_start(ap);
3322 #endif
3323         vsnprintf(buf, sizeof(buf), fmt, ap);
3324         perror(buf);
3325         syslog(LOG_ERR, "%s: %s", buf, strerror(errno));
3326         rtdexit();
3327         va_end(ap);
3328 }
3329
3330 void
3331 #ifdef __STDC__
3332 tracet(int level, const char *fmt, ...)
3333 #else
3334 tracet(level, fmt, va_alist)
3335         int level;
3336         char *fmt;
3337         va_dcl
3338 #endif
3339 {
3340         va_list ap;
3341
3342 #ifdef __STDC__
3343         va_start(ap, fmt);
3344 #else
3345         va_start(ap);
3346 #endif
3347         if (level <= dflag) {
3348                 fprintf(stderr, "%s: ", hms());
3349                 vfprintf(stderr, fmt, ap);
3350         }
3351         if (dflag) {
3352                 if (level > 0)
3353                         vsyslog(LOG_DEBUG, fmt, ap);
3354                 else
3355                         vsyslog(LOG_WARNING, fmt, ap);
3356         }
3357         va_end(ap);
3358 }
3359
3360 void
3361 #ifdef __STDC__
3362 trace(int level, const char *fmt, ...)
3363 #else
3364 trace(level, fmt, va_alist)
3365         int level;
3366         char *fmt;
3367         va_dcl
3368 #endif
3369 {
3370         va_list ap;
3371
3372 #ifdef __STDC__
3373         va_start(ap, fmt);
3374 #else
3375         va_start(ap);
3376 #endif
3377         if (level <= dflag)
3378                 vfprintf(stderr, fmt, ap);
3379         if (dflag) {
3380                 if (level > 0)
3381                         vsyslog(LOG_DEBUG, fmt, ap);
3382                 else
3383                         vsyslog(LOG_WARNING, fmt, ap);
3384         }
3385         va_end(ap);
3386 }
3387
3388 unsigned int
3389 if_maxindex()
3390 {
3391         struct if_nameindex *p, *p0;
3392         unsigned int max = 0;
3393
3394         p0 = if_nameindex();
3395         for (p = p0; p && p->if_index && p->if_name; p++) {
3396                 if (max < p->if_index)
3397                         max = p->if_index;
3398         }
3399         if_freenameindex(p0);
3400         return max;
3401 }
3402
3403 struct ifc *
3404 ifc_find(name)
3405         char *name;
3406 {
3407         struct ifc *ifcp;
3408
3409         for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
3410                 if (strcmp(name, ifcp->ifc_name) == 0)
3411                         return ifcp;
3412         }
3413         return (struct ifc *)NULL;
3414 }
3415
3416 struct iff *
3417 iff_find(ifcp, type)
3418         struct ifc *ifcp;
3419         int type;
3420 {
3421         struct iff *iffp;
3422
3423         for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
3424                 if (iffp->iff_type == type)
3425                         return iffp;
3426         }
3427         return NULL;
3428 }
3429
3430 void
3431 setindex2ifc(idx, ifcp)
3432         int idx;
3433         struct ifc *ifcp;
3434 {
3435         int n;
3436         struct ifc **p;
3437
3438         if (!index2ifc) {
3439                 nindex2ifc = 5; /*initial guess*/
3440                 index2ifc = (struct ifc **)
3441                         malloc(sizeof(*index2ifc) * nindex2ifc);
3442                 if (index2ifc == NULL) {
3443                         fatal("malloc");
3444                         /*NOTREACHED*/
3445                 }
3446                 memset(index2ifc, 0, sizeof(*index2ifc) * nindex2ifc);
3447         }
3448         n = nindex2ifc;
3449         while (nindex2ifc <= idx)
3450                 nindex2ifc *= 2;
3451         if (n != nindex2ifc) {
3452                 p = (struct ifc **)realloc(index2ifc,
3453                     sizeof(*index2ifc) * nindex2ifc);
3454                 if (p == NULL) {
3455                         fatal("realloc");
3456                         /*NOTREACHED*/
3457                 }
3458                 memset(p + n, 0, sizeof(*index2ifc) * (nindex2ifc - n));
3459                 index2ifc = p;
3460         }
3461         index2ifc[idx] = ifcp;
3462 }