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