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