route6d.c revision 119037
1274201Sdim/*	$FreeBSD: head/usr.sbin/route6d/route6d.c 119037 2003-08-17 17:29:54Z ume $	*/
2274201Sdim/*	$KAME: route6d.c,v 1.64 2001/05/08 04:36:37 itojun Exp $	*/
3274201Sdim
4274201Sdim/*
5274201Sdim * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6274201Sdim * All rights reserved.
7274201Sdim *
8274201Sdim * Redistribution and use in source and binary forms, with or without
9274201Sdim * modification, are permitted provided that the following conditions
10274201Sdim * are met:
11274201Sdim * 1. Redistributions of source code must retain the above copyright
12274201Sdim *    notice, this list of conditions and the following disclaimer.
13274201Sdim * 2. Redistributions in binary form must reproduce the above copyright
14274201Sdim *    notice, this list of conditions and the following disclaimer in the
15274201Sdim *    documentation and/or other materials provided with the distribution.
16274201Sdim * 3. Neither the name of the project nor the names of its contributors
17276789Sdim *    may be used to endorse or promote products derived from this software
18276789Sdim *    without specific prior written permission.
19276789Sdim *
20276789Sdim * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21274201Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22274201Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23274201Sdim * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24274201Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25276789Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26274201Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27276789Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28276789Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29274201Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30274201Sdim * SUCH DAMAGE.
31274201Sdim */
32274201Sdim
33274201Sdim#ifndef	lint
34274201Sdimstatic char _rcsid[] = "$KAME: route6d.c,v 1.64 2001/05/08 04:36:37 itojun Exp $";
35274201Sdim#endif
36274201Sdim
37274201Sdim#include <stdio.h>
38274201Sdim
39274201Sdim#include <time.h>
40274201Sdim#include <unistd.h>
41274201Sdim#include <stdlib.h>
42274201Sdim#include <string.h>
43274201Sdim#include <signal.h>
44274201Sdim#ifdef __STDC__
45274201Sdim#include <stdarg.h>
46274201Sdim#else
47274201Sdim#include <varargs.h>
48274201Sdim#endif
49274201Sdim#include <syslog.h>
50274201Sdim#include <stddef.h>
51274201Sdim#include <errno.h>
52274201Sdim#include <err.h>
53274201Sdim
54274201Sdim#include <sys/types.h>
55274201Sdim#include <sys/param.h>
56274201Sdim#include <sys/file.h>
57274201Sdim#include <sys/socket.h>
58274201Sdim#include <sys/ioctl.h>
59274201Sdim#include <sys/sysctl.h>
60274201Sdim#include <sys/uio.h>
61274201Sdim#include <net/if.h>
62274201Sdim#if defined(__FreeBSD__) && __FreeBSD__ >= 3
63274201Sdim#include <net/if_var.h>
64274201Sdim#endif /* __FreeBSD__ >= 3 */
65274201Sdim#define	KERNEL	1
66274201Sdim#define	_KERNEL	1
67274201Sdim#include <net/route.h>
68274201Sdim#undef KERNEL
69274201Sdim#undef _KERNEL
70274201Sdim#include <netinet/in.h>
71274201Sdim#include <netinet/in_var.h>
72274201Sdim#include <netinet/ip6.h>
73274201Sdim#include <netinet/udp.h>
74274201Sdim#include <netdb.h>
75274201Sdim#include <ifaddrs.h>
76274201Sdim
77274201Sdim#include <arpa/inet.h>
78274201Sdim
79274201Sdim#include "route6d.h"
80274201Sdim
81274201Sdim#define	MAXFILTER	40
82274201Sdim
83274201Sdim#ifdef	DEBUG
84274201Sdim#define	INIT_INTERVAL6	6
85274201Sdim#else
86274201Sdim#define	INIT_INTERVAL6	10	/* Wait to submit an initial riprequest. */
87274201Sdim#endif
88274201Sdim
89274201Sdim/* alignment constraint for routing socket */
90274201Sdim#define ROUNDUP(a) \
91274201Sdim	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
92274201Sdim#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
93274201Sdim
94274201Sdim/*
95274201Sdim * Following two macros are highly depending on KAME Release
96274201Sdim */
97274201Sdim#define	IN6_LINKLOCAL_IFINDEX(addr) \
98274201Sdim	((addr).s6_addr[2] << 8 | (addr).s6_addr[3])
99274201Sdim
100274201Sdim#define	SET_IN6_LINKLOCAL_IFINDEX(addr, index) \
101274201Sdim	do { \
102274201Sdim		(addr).s6_addr[2] = ((index) >> 8) & 0xff; \
103274201Sdim		(addr).s6_addr[3] = (index) & 0xff; \
104274201Sdim	} while (0)
105274201Sdim
106274201Sdimstruct	ifc {			/* Configuration of an interface */
107274201Sdim	char	*ifc_name;			/* if name */
108274201Sdim	struct	ifc *ifc_next;
109274201Sdim	int	ifc_index;			/* if index */
110274201Sdim	int	ifc_mtu;			/* if mtu */
111274201Sdim	int	ifc_metric;			/* if metric */
112274201Sdim	u_int	ifc_flags;			/* flags */
113274201Sdim	short	ifc_cflags;			/* IFC_XXX */
114274201Sdim	struct	in6_addr ifc_mylladdr;		/* my link-local address */
115274201Sdim	struct	sockaddr_in6 ifc_ripsin;	/* rip multicast address */
116274201Sdim	struct	iff *ifc_filter;		/* filter structure */
117274201Sdim	struct	ifac *ifc_addr;			/* list of AF_INET6 addresses */
118274201Sdim	int	ifc_joined;			/* joined to ff02::9 */
119274201Sdim};
120274201Sdim
121274201Sdimstruct	ifac {			/* Adddress associated to an interface */
122274201Sdim	struct	ifc *ifa_conf;		/* back pointer */
123274201Sdim	struct	ifac *ifa_next;
124274201Sdim	struct	in6_addr ifa_addr;	/* address */
125274201Sdim	struct	in6_addr ifa_raddr;	/* remote address, valid in p2p */
126274201Sdim	int	ifa_plen;		/* prefix length */
127274201Sdim};
128274201Sdim
129274201Sdimstruct	iff {
130274201Sdim	int	iff_type;
131274201Sdim	struct	in6_addr iff_addr;
132274201Sdim	int	iff_plen;
133274201Sdim	struct	iff *iff_next;
134274201Sdim};
135274201Sdim
136274201Sdimstruct	ifc *ifc;
137274201Sdimint	nifc;		/* number of valid ifc's */
138274201Sdimstruct	ifc **index2ifc;
139274201Sdimint	nindex2ifc;
140274201Sdimstruct	ifc *loopifcp = NULL;	/* pointing to loopback */
141274201Sdimint	loopifindex = 0;	/* ditto */
142274201Sdimfd_set	sockvec;	/* vector to select() for receiving */
143274201Sdimint	rtsock;		/* the routing socket */
144274201Sdimint	ripsock;	/* socket to send/receive RIP datagram */
145274201Sdim
146274201Sdimstruct	rip6 *ripbuf;	/* packet buffer for sending */
147274201Sdim
148274201Sdim/*
149274201Sdim * Maintain the routes in a linked list.  When the number of the routes
150274201Sdim * grows, somebody would like to introduce a hash based or a radix tree
151274201Sdim * based structure.  I believe the number of routes handled by RIP is
152274201Sdim * limited and I don't have to manage a complex data structure, however.
153274201Sdim *
154274201Sdim * One of the major drawbacks of the linear linked list is the difficulty
155274201Sdim * of representing the relationship between a couple of routes.  This may
156274201Sdim * be a significant problem when we have to support route aggregation with
157274201Sdim * supressing the specifices covered by the aggregate.
158274201Sdim */
159274201Sdim
160274201Sdimstruct	riprt {
161274201Sdim	struct	riprt *rrt_next;	/* next destination */
162274201Sdim	struct	riprt *rrt_same;	/* same destination - future use */
163274201Sdim	struct	netinfo6 rrt_info;	/* network info */
164274201Sdim	struct	in6_addr rrt_gw;	/* gateway */
165274201Sdim	u_long	rrt_flags;		/* kernel routing table flags */
166274201Sdim	u_long	rrt_rflags;		/* route6d routing table flags */
167274201Sdim	time_t	rrt_t;			/* when the route validated */
168274201Sdim	int	rrt_index;		/* ifindex from which this route got */
169274201Sdim};
170274201Sdim
171274201Sdimstruct	riprt *riprt = 0;
172274201Sdim
173274201Sdimint	dflag = 0;	/* debug flag */
174274201Sdimint	qflag = 0;	/* quiet flag */
175274201Sdimint	nflag = 0;	/* don't update kernel routing table */
176274201Sdimint	aflag = 0;	/* age out even the statically defined routes */
177274201Sdimint	hflag = 0;	/* don't split horizon */
178274201Sdimint	lflag = 0;	/* exchange site local routes */
179274201Sdimint	sflag = 0;	/* announce static routes w/ split horizon */
180274201Sdimint	Sflag = 0;	/* announce static routes to every interface */
181274201Sdimunsigned long routetag = 0;	/* route tag attached on originating case */
182274201Sdim
183274201Sdimchar	*filter[MAXFILTER];
184274201Sdimint	filtertype[MAXFILTER];
185274201Sdimint	nfilter = 0;
186274201Sdim
187274201Sdimpid_t	pid;
188274201Sdim
189274201Sdimstruct	sockaddr_storage ripsin;
190274201Sdim
191274201Sdimstruct	rtentry rtentry;
192274201Sdim
193274201Sdimint	interval = 1;
194274201Sdimtime_t	nextalarm = 0;
195274201Sdimtime_t	sup_trig_update = 0;
196274201Sdim
197274201SdimFILE	*rtlog = NULL;
198274201Sdim
199274201Sdimint logopened = 0;
200274201Sdim
201274201Sdimstatic	u_long	seq = 0;
202274201Sdim
203274201Sdimvolatile int signo;
204274201Sdimvolatile sig_atomic_t seenalrm;
205274201Sdimvolatile sig_atomic_t seenquit;
206274201Sdimvolatile sig_atomic_t seenusr1;
207274201Sdim
208274201Sdim#define	RRTF_AGGREGATE		0x08000000
209274201Sdim#define	RRTF_NOADVERTISE	0x10000000
210274201Sdim#define	RRTF_NH_NOT_LLADDR	0x20000000
211274201Sdim#define RRTF_SENDANYWAY		0x40000000
212274201Sdim#define	RRTF_CHANGED		0x80000000
213274201Sdim
214274201Sdimint main __P((int, char **));
215274201Sdimvoid sighandler __P((int));
216274201Sdimvoid ripalarm __P((void));
217274201Sdimvoid riprecv __P((void));
218274201Sdimvoid ripsend __P((struct ifc *, struct sockaddr_in6 *, int));
219274201Sdimint out_filter __P((struct riprt *, struct ifc *));
220274201Sdimvoid init __P((void));
221274201Sdimvoid sockopt __P((struct ifc *));
222274201Sdimvoid ifconfig __P((void));
223274201Sdimvoid ifconfig1 __P((const char *, const struct sockaddr *, struct ifc *, int));
224274201Sdimvoid rtrecv __P((void));
225274201Sdimint rt_del __P((const struct sockaddr_in6 *, const struct sockaddr_in6 *,
226274201Sdim	const struct sockaddr_in6 *));
227274201Sdimint rt_deladdr __P((struct ifc *, const struct sockaddr_in6 *,
228274201Sdim	const struct sockaddr_in6 *));
229274201Sdimvoid filterconfig __P((void));
230274201Sdimint getifmtu __P((int));
231274201Sdimconst char *rttypes __P((struct rt_msghdr *));
232274201Sdimconst char *rtflags __P((struct rt_msghdr *));
233274201Sdimconst char *ifflags __P((int));
234274201Sdimint ifrt __P((struct ifc *, int));
235274201Sdimvoid ifrt_p2p __P((struct ifc *, int));
236274201Sdimvoid applymask __P((struct in6_addr *, struct in6_addr *));
237274201Sdimvoid applyplen __P((struct in6_addr *, int));
238274201Sdimvoid ifrtdump __P((int));
239274201Sdimvoid ifdump __P((int));
240274201Sdimvoid ifdump0 __P((FILE *, const struct ifc *));
241274201Sdimvoid rtdump __P((int));
242274201Sdimvoid rt_entry __P((struct rt_msghdr *, int));
243274201Sdimvoid rtdexit __P((void));
244274201Sdimvoid riprequest __P((struct ifc *, struct netinfo6 *, int,
245274201Sdim	struct sockaddr_in6 *));
246274201Sdimvoid ripflush __P((struct ifc *, struct sockaddr_in6 *));
247274201Sdimvoid sendrequest __P((struct ifc *));
248274201Sdimint sin6mask2len __P((const struct sockaddr_in6 *));
249274201Sdimint mask2len __P((const struct in6_addr *, int));
250274201Sdimint sendpacket __P((struct sockaddr_in6 *, int));
251274201Sdimint addroute __P((struct riprt *, const struct in6_addr *, struct ifc *));
252274201Sdimint delroute __P((struct netinfo6 *, struct in6_addr *));
253274201Sdimstruct in6_addr *getroute __P((struct netinfo6 *, struct in6_addr *));
254274201Sdimvoid krtread __P((int));
255274201Sdimint tobeadv __P((struct riprt *, struct ifc *));
256274201Sdimchar *allocopy __P((char *));
257274201Sdimchar *hms __P((void));
258274201Sdimconst char *inet6_n2p __P((const struct in6_addr *));
259274201Sdimstruct ifac *ifa_match __P((const struct ifc *, const struct in6_addr *, int));
260274201Sdimstruct in6_addr *plen2mask __P((int));
261274201Sdimstruct riprt *rtsearch __P((struct netinfo6 *, struct riprt **));
262274201Sdimint ripinterval __P((int));
263274201Sdimtime_t ripsuptrig __P((void));
264274201Sdimvoid fatal __P((const char *, ...))
265274201Sdim	__attribute__((__format__(__printf__, 1, 2)));
266274201Sdimvoid trace __P((int, const char *, ...))
267274201Sdim	__attribute__((__format__(__printf__, 2, 3)));
268274201Sdimvoid tracet __P((int, const char *, ...))
269274201Sdim	__attribute__((__format__(__printf__, 2, 3)));
270274201Sdimunsigned int if_maxindex __P((void));
271274201Sdimstruct ifc *ifc_find __P((char *));
272274201Sdimstruct iff *iff_find __P((struct ifc *, int));
273274201Sdimvoid setindex2ifc __P((int, struct ifc *));
274274201Sdim
275274201Sdim#define	MALLOC(type)	((type *)malloc(sizeof(type)))
276274201Sdim
277274201Sdimint
278274201Sdimmain(argc, argv)
279274201Sdim	int	argc;
280274201Sdim	char	**argv;
281274201Sdim{
282274201Sdim	int	ch;
283274201Sdim	int	error = 0;
284274201Sdim	struct	ifc *ifcp;
285274201Sdim	sigset_t mask, omask;
286274201Sdim	FILE	*pidfile;
287274201Sdim	char *progname;
288274201Sdim	char *ep;
289274201Sdim
290274201Sdim	progname = strrchr(*argv, '/');
291274201Sdim	if (progname)
292274201Sdim		progname++;
293274201Sdim	else
294274201Sdim		progname = *argv;
295274201Sdim
296274201Sdim	pid = getpid();
297274201Sdim	while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnqsS")) != -1) {
298274201Sdim		switch (ch) {
299274201Sdim		case 'A':
300274201Sdim		case 'N':
301274201Sdim		case 'O':
302274201Sdim		case 'T':
303274201Sdim		case 'L':
304274201Sdim			if (nfilter >= MAXFILTER) {
305274201Sdim				fatal("Exceeds MAXFILTER");
306274201Sdim				/*NOTREACHED*/
307274201Sdim			}
308274201Sdim			filtertype[nfilter] = ch;
309274201Sdim			filter[nfilter++] = allocopy(optarg);
310274201Sdim			break;
311274201Sdim		case 't':
312274201Sdim			ep = NULL;
313274201Sdim			routetag = strtoul(optarg, &ep, 0);
314274201Sdim			if (!ep || *ep != '\0' || (routetag & ~0xffff) != 0) {
315274201Sdim				fatal("invalid route tag");
316274201Sdim				/*NOTREACHED*/
317274201Sdim			}
318274201Sdim			break;
319274201Sdim		case 'R':
320274201Sdim			if ((rtlog = fopen(optarg, "w")) == NULL) {
321274201Sdim				fatal("Can not write to routelog");
322274201Sdim				/*NOTREACHED*/
323274201Sdim			}
324274201Sdim			break;
325274201Sdim#define	FLAG(c, flag, n)	case c: do { flag = n; break; } while(0)
326274201Sdim		FLAG('a', aflag, 1); break;
327274201Sdim		FLAG('d', dflag, 1); break;
328274201Sdim		FLAG('D', dflag, 2); break;
329274201Sdim		FLAG('h', hflag, 1); break;
330274201Sdim		FLAG('l', lflag, 1); break;
331274201Sdim		FLAG('n', nflag, 1); break;
332274201Sdim		FLAG('q', qflag, 1); break;
333274201Sdim		FLAG('s', sflag, 1); break;
334274201Sdim		FLAG('S', Sflag, 1); break;
335274201Sdim#undef	FLAG
336274201Sdim		default:
337274201Sdim			fatal("Invalid option specified, terminating");
338274201Sdim			/*NOTREACHED*/
339274201Sdim		}
340274201Sdim	}
341274201Sdim	argc -= optind;
342274201Sdim	argv += optind;
343274201Sdim	if (argc > 0) {
344274201Sdim		fatal("bogus extra arguments");
345274201Sdim		/*NOTREACHED*/
346274201Sdim	}
347274201Sdim
348274201Sdim	if (geteuid()) {
349274201Sdim		nflag = 1;
350274201Sdim		fprintf(stderr, "No kernel update is allowed\n");
351274201Sdim	}
352274201Sdim
353274201Sdim	if (dflag == 0) {
354274201Sdim		if (daemon(0, 0) < 0) {
355274201Sdim			fatal("daemon");
356274201Sdim			/*NOTREACHED*/
357274201Sdim		}
358274201Sdim	}
359274201Sdim
360274201Sdim	openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON);
361274201Sdim	logopened++;
362274201Sdim
363274201Sdim	if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL)
364274201Sdim		fatal("malloc");
365274201Sdim	memset(ripbuf, 0, RIP6_MAXMTU);
366274201Sdim	ripbuf->rip6_cmd = RIP6_RESPONSE;
367274201Sdim	ripbuf->rip6_vers = RIP6_VERSION;
368274201Sdim	ripbuf->rip6_res1[0] = 0;
369274201Sdim	ripbuf->rip6_res1[1] = 0;
370274201Sdim
371274201Sdim	init();
372274201Sdim	ifconfig();
373274201Sdim	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
374274201Sdim		if (ifcp->ifc_index < 0) {
375274201Sdim			fprintf(stderr,
376274201Sdim"No ifindex found at %s (no link-local address?)\n",
377274201Sdim				ifcp->ifc_name);
378274201Sdim			error++;
379274201Sdim		}
380274201Sdim	}
381274201Sdim	if (error)
382274201Sdim		exit(1);
383274201Sdim	if (loopifcp == NULL) {
384274201Sdim		fatal("No loopback found");
385274201Sdim		/*NOTREACHED*/
386274201Sdim	}
387274201Sdim#ifdef __FreeBSD__
388274201Sdim	sranddev();
389274201Sdim#else
390274201Sdim	srand((unsigned)(time(NULL)^(pid<<16)));
391274201Sdim#endif
392274201Sdim	loopifindex = loopifcp->ifc_index;
393274201Sdim	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next)
394274201Sdim		ifrt(ifcp, 0);
395274201Sdim	filterconfig();
396274201Sdim	krtread(0);
397274201Sdim	if (dflag)
398274201Sdim		ifrtdump(0);
399274201Sdim
400274201Sdim	pid = getpid();
401274201Sdim	if ((pidfile = fopen(ROUTE6D_PID, "w")) != NULL) {
402274201Sdim		fprintf(pidfile, "%d\n", pid);
403274201Sdim		fclose(pidfile);
404274201Sdim	}
405274201Sdim
406274201Sdim	if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) {
407274201Sdim		fatal("malloc");
408274201Sdim		/*NOTREACHED*/
409274201Sdim	}
410274201Sdim	memset(ripbuf, 0, RIP6_MAXMTU);
411274201Sdim	ripbuf->rip6_cmd = RIP6_RESPONSE;
412274201Sdim	ripbuf->rip6_vers = RIP6_VERSION;
413274201Sdim	ripbuf->rip6_res1[0] = 0;
414274201Sdim	ripbuf->rip6_res1[1] = 0;
415274201Sdim
416274201Sdim	if (signal(SIGALRM, sighandler) == SIG_ERR ||
417274201Sdim	    signal(SIGQUIT, sighandler) == SIG_ERR ||
418274201Sdim	    signal(SIGTERM, sighandler) == SIG_ERR ||
419274201Sdim	    signal(SIGUSR1, sighandler) == SIG_ERR ||
420274201Sdim	    signal(SIGHUP, sighandler) == SIG_ERR ||
421274201Sdim	    signal(SIGINT, sighandler) == SIG_ERR) {
422274201Sdim		fatal("signal");
423274201Sdim		/*NOTREACHED*/
424274201Sdim	}
425274201Sdim	/*
426274201Sdim	 * To avoid rip packet congestion (not on a cable but in this
427274201Sdim	 * process), wait for a moment to send the first RIP6_RESPONSE
428274201Sdim	 * packets.
429274201Sdim	 */
430274201Sdim	alarm(ripinterval(INIT_INTERVAL6));
431274201Sdim
432274201Sdim	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
433274201Sdim		if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP))
434274201Sdim			sendrequest(ifcp);
435274201Sdim	}
436274201Sdim
437274201Sdim	syslog(LOG_INFO, "**** Started ****");
438274201Sdim	sigemptyset(&mask);
439274201Sdim	sigaddset(&mask, SIGALRM);
440274201Sdim	while (1) {
441274201Sdim		fd_set	recvec;
442274201Sdim
443274201Sdim		if (seenalrm) {
444274201Sdim			ripalarm();
445274201Sdim			seenalrm = 0;
446274201Sdim			continue;
447274201Sdim		}
448274201Sdim		if (seenquit) {
449274201Sdim			rtdexit();
450274201Sdim			seenquit = 0;
451274201Sdim			continue;
452274201Sdim		}
453274201Sdim		if (seenusr1) {
454274201Sdim			ifrtdump(SIGUSR1);
455274201Sdim			seenusr1 = 0;
456274201Sdim			continue;
457274201Sdim		}
458274201Sdim
459274201Sdim		FD_COPY(&sockvec, &recvec);
460274201Sdim		signo = 0;
461274201Sdim		switch (select(FD_SETSIZE, &recvec, 0, 0, 0)) {
462274201Sdim		case -1:
463274201Sdim			if (errno != EINTR) {
464274201Sdim				fatal("select");
465274201Sdim				/*NOTREACHED*/
466274201Sdim			}
467274201Sdim			continue;
468274201Sdim		case 0:
469274201Sdim			continue;
470274201Sdim		default:
471274201Sdim			if (FD_ISSET(ripsock, &recvec)) {
472274201Sdim				sigprocmask(SIG_BLOCK, &mask, &omask);
473274201Sdim				riprecv();
474274201Sdim				sigprocmask(SIG_SETMASK, &omask, NULL);
475274201Sdim			}
476274201Sdim			if (FD_ISSET(rtsock, &recvec)) {
477274201Sdim				sigprocmask(SIG_BLOCK, &mask, &omask);
478274201Sdim				rtrecv();
479274201Sdim				sigprocmask(SIG_SETMASK, &omask, NULL);
480274201Sdim			}
481274201Sdim		}
482274201Sdim	}
483274201Sdim}
484274201Sdim
485274201Sdimvoid
486274201Sdimsighandler(sig)
487274201Sdim	int sig;
488274201Sdim{
489274201Sdim
490274201Sdim	signo = sig;
491274201Sdim	switch (signo) {
492274201Sdim	case SIGALRM:
493274201Sdim		seenalrm++;
494274201Sdim		break;
495274201Sdim	case SIGQUIT:
496276789Sdim	case SIGTERM:
497276789Sdim		seenquit++;
498276789Sdim		break;
499276789Sdim	case SIGUSR1:
500274201Sdim	case SIGHUP:
501276789Sdim	case SIGINT:
502276789Sdim		seenusr1++;
503274201Sdim		break;
504276789Sdim	}
505274201Sdim}
506274201Sdim
507274201Sdim/*
508274201Sdim * gracefully exits after resetting sockopts.
509274201Sdim */
510274201Sdim/* ARGSUSED */
511274201Sdimvoid
512274201Sdimrtdexit()
513274201Sdim{
514274201Sdim	struct	riprt *rrt;
515274201Sdim
516274201Sdim	alarm(0);
517274201Sdim	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
518274201Sdim		if (rrt->rrt_rflags & RRTF_AGGREGATE) {
519274201Sdim			delroute(&rrt->rrt_info, &rrt->rrt_gw);
520274201Sdim		}
521274201Sdim	}
522274201Sdim	close(ripsock);
523296417Sdim	close(rtsock);
524274201Sdim	syslog(LOG_INFO, "**** Terminated ****");
525274201Sdim	closelog();
526276789Sdim	exit(1);
527276789Sdim}
528276789Sdim
529276789Sdim/*
530276789Sdim * Called periodically:
531276789Sdim *	1. age out the learned route. remove it if necessary.
532276789Sdim *	2. submit RIP6_RESPONSE packets.
533276789Sdim * Invoked in every SUPPLY_INTERVAL6 (30) seconds.  I believe we don't have
534276789Sdim * to invoke this function in every 1 or 5 or 10 seconds only to age the
535276789Sdim * routes more precisely.
536276789Sdim */
537276789Sdim/* ARGSUSED */
538276789Sdimvoid
539276789Sdimripalarm()
540276789Sdim{
541276789Sdim	struct	ifc *ifcp;
542276789Sdim	struct	riprt *rrt, *rrt_prev, *rrt_next;
543276789Sdim	time_t	t_lifetime, t_holddown;
544276789Sdim
545276789Sdim	/* age the RIP routes */
546276789Sdim	rrt_prev = 0;
547276789Sdim	t_lifetime = time(NULL) - RIP_LIFETIME;
548276789Sdim	t_holddown = t_lifetime - RIP_HOLDDOWN;
549276789Sdim	for (rrt = riprt; rrt; rrt = rrt_next) {
550276789Sdim		rrt_next = rrt->rrt_next;
551276789Sdim
552276789Sdim		if (rrt->rrt_t == 0) {
553276789Sdim			rrt_prev = rrt;
554276789Sdim			continue;
555276789Sdim		}
556276789Sdim		if (rrt->rrt_t < t_holddown) {
557274201Sdim			if (rrt_prev) {
558274201Sdim				rrt_prev->rrt_next = rrt->rrt_next;
559274201Sdim			} else {
560274201Sdim				riprt = rrt->rrt_next;
561274201Sdim			}
562274201Sdim			delroute(&rrt->rrt_info, &rrt->rrt_gw);
563276789Sdim			free(rrt);
564274201Sdim			continue;
565274201Sdim		}
566274201Sdim		if (rrt->rrt_t < t_lifetime)
567276789Sdim			rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
568276789Sdim		rrt_prev = rrt;
569274201Sdim	}
570296417Sdim	/* Supply updates */
571274201Sdim	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
572274201Sdim		if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP))
573274201Sdim			ripsend(ifcp, &ifcp->ifc_ripsin, 0);
574274201Sdim	}
575276789Sdim	alarm(ripinterval(SUPPLY_INTERVAL6));
576274201Sdim}
577274201Sdim
578274201Sdimvoid
579274201Sdiminit()
580274201Sdim{
581288943Sdim	int	error;
582288943Sdim	const int int0 = 0, int1 = 1, int255 = 255;
583288943Sdim	struct	addrinfo hints, *res;
584274201Sdim	char	port[10];
585274201Sdim
586274201Sdim	ifc = (struct ifc *)NULL;
587274201Sdim	nifc = 0;
588274201Sdim	nindex2ifc = 0;	/*initial guess*/
589276789Sdim	index2ifc = NULL;
590274201Sdim	snprintf(port, sizeof(port), "%d", RIP6_PORT);
591274201Sdim
592274201Sdim	memset(&hints, 0, sizeof(hints));
593274201Sdim	hints.ai_family = PF_INET6;
594274201Sdim	hints.ai_socktype = SOCK_DGRAM;
595274201Sdim	hints.ai_flags = AI_PASSIVE;
596288943Sdim	error = getaddrinfo(NULL, port, &hints, &res);
597288943Sdim	if (error) {
598288943Sdim		fatal("%s", gai_strerror(error));
599274201Sdim		/*NOTREACHED*/
600274201Sdim	}
601	if (res->ai_next) {
602		fatal(":: resolved to multiple address");
603		/*NOTREACHED*/
604	}
605
606	ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
607	if (ripsock < 0) {
608		fatal("rip socket");
609		/*NOTREACHED*/
610	}
611#ifdef IPV6_V6ONLY
612	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_V6ONLY,
613	    &int1, sizeof(int1)) < 0) {
614		fatal("rip IPV6_V6ONLY");
615		/*NOTREACHED*/
616	}
617#endif
618	if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0) {
619		fatal("rip bind");
620		/*NOTREACHED*/
621	}
622	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
623	    &int255, sizeof(int255)) < 0) {
624		fatal("rip IPV6_MULTICAST_HOPS");
625		/*NOTREACHED*/
626	}
627	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
628	    &int0, sizeof(int0)) < 0) {
629		fatal("rip IPV6_MULTICAST_LOOP");
630		/*NOTREACHED*/
631	}
632
633#ifdef IPV6_RECVPKTINFO
634	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
635	    &int1, sizeof(int1)) < 0) {
636		fatal("rip IPV6_RECVPKTINFO");
637		/*NOTREACHED*/
638	}
639#else  /* old adv. API */
640	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_PKTINFO,
641	    &int1, sizeof(int1)) < 0) {
642		fatal("rip IPV6_PKTINFO");
643		/*NOTREACHED*/
644	}
645#endif
646
647	memset(&hints, 0, sizeof(hints));
648	hints.ai_family = PF_INET6;
649	hints.ai_socktype = SOCK_DGRAM;
650	error = getaddrinfo(RIP6_DEST, port, &hints, &res);
651	if (error) {
652		fatal("%s", gai_strerror(error));
653		/*NOTREACHED*/
654	}
655	if (res->ai_next) {
656		fatal("%s resolved to multiple address", RIP6_DEST);
657		/*NOTREACHED*/
658	}
659	memcpy(&ripsin, res->ai_addr, res->ai_addrlen);
660
661#ifdef FD_ZERO
662	FD_ZERO(&sockvec);
663#else
664	memset(&sockvec, 0, sizeof(sockvec));
665#endif
666	FD_SET(ripsock, &sockvec);
667
668	if (nflag == 0) {
669		if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
670			fatal("route socket");
671			/*NOTREACHED*/
672		}
673		FD_SET(rtsock, &sockvec);
674	} else
675		rtsock = -1;	/*just for safety */
676}
677
678#define	RIPSIZE(n) \
679	(sizeof(struct rip6) + ((n)-1) * sizeof(struct netinfo6))
680
681/*
682 * ripflush flushes the rip datagram stored in the rip buffer
683 */
684static int nrt;
685static struct netinfo6 *np;
686
687void
688ripflush(ifcp, sin6)
689	struct ifc *ifcp;
690	struct sockaddr_in6 *sin6;
691{
692	int i;
693	int error;
694
695	if (ifcp)
696		tracet(1, "Send(%s): info(%d) to %s.%d\n",
697			ifcp->ifc_name, nrt,
698			inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port));
699	else
700		tracet(1, "Send: info(%d) to %s.%d\n",
701			nrt, inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port));
702	if (dflag >= 2) {
703		np = ripbuf->rip6_nets;
704		for (i = 0; i < nrt; i++, np++) {
705			if (np->rip6_metric == NEXTHOP_METRIC) {
706				if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest))
707					trace(2, "    NextHop reset");
708				else {
709					trace(2, "    NextHop %s",
710						inet6_n2p(&np->rip6_dest));
711				}
712			} else {
713				trace(2, "    %s/%d[%d]",
714					inet6_n2p(&np->rip6_dest),
715					np->rip6_plen, np->rip6_metric);
716			}
717			if (np->rip6_tag) {
718				trace(2, "  tag=0x%04x",
719					ntohs(np->rip6_tag) & 0xffff);
720			}
721			trace(2, "\n");
722		}
723	}
724	error = sendpacket(sin6, RIPSIZE(nrt));
725	if (error == EAFNOSUPPORT) {
726		/* Protocol not supported */
727		tracet(1, "Could not send info to %s (%s): "
728			"set IFF_UP to 0\n",
729			ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
730		ifcp->ifc_flags &= ~IFF_UP;	/* As if down for AF_INET6 */
731	}
732	nrt = 0; np = ripbuf->rip6_nets;
733}
734
735/*
736 * Generate RIP6_RESPONSE packets and send them.
737 */
738void
739ripsend(ifcp, sin6, flag)
740	struct	ifc *ifcp;
741	struct	sockaddr_in6 *sin6;
742	int flag;
743{
744	struct	riprt *rrt;
745	struct	in6_addr *nh;	/* next hop */
746	int	maxrte;
747
748	if (ifcp == NULL) {
749		/*
750		 * Request from non-link local address is not
751		 * a regular route6d update.
752		 */
753		maxrte = (IFMINMTU - sizeof(struct ip6_hdr) -
754				sizeof(struct udphdr) -
755				sizeof(struct rip6) + sizeof(struct netinfo6)) /
756				sizeof(struct netinfo6);
757		nrt = 0; np = ripbuf->rip6_nets; nh = NULL;
758		for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
759			if (rrt->rrt_rflags & RRTF_NOADVERTISE)
760				continue;
761			/* Put the route to the buffer */
762			*np = rrt->rrt_info;
763			np++; nrt++;
764			if (nrt == maxrte) {
765				ripflush(NULL, sin6);
766				nh = NULL;
767			}
768		}
769		if (nrt)	/* Send last packet */
770			ripflush(NULL, sin6);
771		return;
772	}
773
774	if ((flag & RRTF_SENDANYWAY) == 0 &&
775	    (qflag || (ifcp->ifc_flags & IFF_LOOPBACK)))
776		return;
777
778	/* -N: no use */
779	if (iff_find(ifcp, 'N') != NULL)
780		return;
781
782	/* -T: generate default route only */
783	if (iff_find(ifcp, 'T') != NULL) {
784		struct netinfo6 rrt_info;
785		memset(&rrt_info, 0, sizeof(struct netinfo6));
786		rrt_info.rip6_dest = in6addr_any;
787		rrt_info.rip6_plen = 0;
788		rrt_info.rip6_metric = 1;
789		rrt_info.rip6_metric += ifcp->ifc_metric;
790		rrt_info.rip6_tag = htons(routetag & 0xffff);
791		np = ripbuf->rip6_nets;
792		*np = rrt_info;
793		nrt = 1;
794		ripflush(ifcp, sin6);
795		return;
796	}
797
798	maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) -
799			sizeof(struct udphdr) -
800			sizeof(struct rip6) + sizeof(struct netinfo6)) /
801			sizeof(struct netinfo6);
802
803	nrt = 0; np = ripbuf->rip6_nets; nh = NULL;
804	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
805		if (rrt->rrt_rflags & RRTF_NOADVERTISE)
806			continue;
807
808		/* Need to check filter here */
809		if (out_filter(rrt, ifcp) == 0)
810			continue;
811
812		/* Check split horizon and other conditions */
813		if (tobeadv(rrt, ifcp) == 0)
814			continue;
815
816		/* Only considers the routes with flag if specified */
817		if ((flag & RRTF_CHANGED) &&
818		    (rrt->rrt_rflags & RRTF_CHANGED) == 0)
819			continue;
820
821		/* Check nexthop */
822		if (rrt->rrt_index == ifcp->ifc_index &&
823		    !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) &&
824		    (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) == 0) {
825			if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) {
826				if (nrt == maxrte - 2)
827					ripflush(ifcp, sin6);
828				np->rip6_dest = rrt->rrt_gw;
829				if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest))
830					SET_IN6_LINKLOCAL_IFINDEX(np->rip6_dest, 0);
831				np->rip6_plen = 0;
832				np->rip6_tag = 0;
833				np->rip6_metric = NEXTHOP_METRIC;
834				nh = &rrt->rrt_gw;
835				np++; nrt++;
836			}
837		} else if (nh && (rrt->rrt_index != ifcp->ifc_index ||
838			          !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) ||
839				  rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)) {
840			/* Reset nexthop */
841			if (nrt == maxrte - 2)
842				ripflush(ifcp, sin6);
843			memset(np, 0, sizeof(struct netinfo6));
844			np->rip6_metric = NEXTHOP_METRIC;
845			nh = NULL;
846			np++; nrt++;
847		}
848
849		/* Put the route to the buffer */
850		*np = rrt->rrt_info;
851		np++; nrt++;
852		if (nrt == maxrte) {
853			ripflush(ifcp, sin6);
854			nh = NULL;
855		}
856	}
857	if (nrt)	/* Send last packet */
858		ripflush(ifcp, sin6);
859}
860
861/*
862 * outbound filter logic, per-route/interface.
863 */
864int
865out_filter(rrt, ifcp)
866	struct riprt *rrt;
867	struct ifc *ifcp;
868{
869	struct iff *iffp;
870	struct in6_addr ia;
871	int ok;
872
873	/*
874	 * -A: filter out less specific routes, if we have aggregated
875	 * route configured.
876	 */
877	for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
878		if (iffp->iff_type != 'A')
879			continue;
880		if (rrt->rrt_info.rip6_plen <= iffp->iff_plen)
881			continue;
882		ia = rrt->rrt_info.rip6_dest;
883		applyplen(&ia, iffp->iff_plen);
884		if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr))
885			return 0;
886	}
887
888	/*
889	 * if it is an aggregated route, advertise it only to the
890	 * interfaces specified on -A.
891	 */
892	if ((rrt->rrt_rflags & RRTF_AGGREGATE) != 0) {
893		ok = 0;
894		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
895			if (iffp->iff_type != 'A')
896				continue;
897			if (rrt->rrt_info.rip6_plen == iffp->iff_plen &&
898			    IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
899			    &iffp->iff_addr)) {
900				ok = 1;
901				break;
902			}
903		}
904		if (!ok)
905			return 0;
906	}
907
908	/*
909	 * -O: advertise only if prefix matches the configured prefix.
910	 */
911	if (iff_find(ifcp, 'O')) {
912		ok = 0;
913		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
914			if (iffp->iff_type != 'O')
915				continue;
916			if (rrt->rrt_info.rip6_plen < iffp->iff_plen)
917				continue;
918			ia = rrt->rrt_info.rip6_dest;
919			applyplen(&ia, iffp->iff_plen);
920			if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) {
921				ok = 1;
922				break;
923			}
924		}
925		if (!ok)
926			return 0;
927	}
928
929	/* the prefix should be advertised */
930	return 1;
931}
932
933/*
934 * Determine if the route is to be advertised on the specified interface.
935 * It checks options specified in the arguments and the split horizon rule.
936 */
937int
938tobeadv(rrt, ifcp)
939	struct riprt *rrt;
940	struct ifc *ifcp;
941{
942
943	/* Special care for static routes */
944	if (rrt->rrt_flags & RTF_STATIC) {
945		/* XXX don't advertise reject/blackhole routes */
946		if (rrt->rrt_flags & (RTF_REJECT | RTF_BLACKHOLE))
947			return 0;
948
949		if (Sflag)	/* Yes, advertise it anyway */
950			return 1;
951		if (sflag && rrt->rrt_index != ifcp->ifc_index)
952			return 1;
953		return 0;
954	}
955	/* Regular split horizon */
956	if (hflag == 0 && rrt->rrt_index == ifcp->ifc_index)
957		return 0;
958	return 1;
959}
960
961/*
962 * Send a rip packet actually.
963 */
964int
965sendpacket(sin6, len)
966	struct	sockaddr_in6 *sin6;
967	int	len;
968{
969	/*
970	 * MSG_DONTROUTE should not be specified when it responds with a
971	 * RIP6_REQUEST message.  SO_DONTROUTE has been specified to
972	 * other sockets.
973	 */
974	struct msghdr m;
975	struct cmsghdr *cm;
976	struct iovec iov[2];
977	u_char cmsgbuf[256];
978	struct in6_pktinfo *pi;
979	int idx;
980	struct sockaddr_in6 sincopy;
981
982	/* do not overwrite the given sin */
983	sincopy = *sin6;
984	sin6 = &sincopy;
985
986	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
987	    IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
988		idx = IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr);
989		SET_IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr, 0);
990	} else
991		idx = 0;
992
993	m.msg_name = (caddr_t)sin6;
994	m.msg_namelen = sizeof(*sin6);
995	iov[0].iov_base = (caddr_t)ripbuf;
996	iov[0].iov_len = len;
997	m.msg_iov = iov;
998	m.msg_iovlen = 1;
999	if (!idx) {
1000		m.msg_control = NULL;
1001		m.msg_controllen = 0;
1002	} else {
1003		memset(cmsgbuf, 0, sizeof(cmsgbuf));
1004		cm = (struct cmsghdr *)cmsgbuf;
1005		m.msg_control = (caddr_t)cm;
1006		m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
1007
1008		cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
1009		cm->cmsg_level = IPPROTO_IPV6;
1010		cm->cmsg_type = IPV6_PKTINFO;
1011		pi = (struct in6_pktinfo *)CMSG_DATA(cm);
1012		memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/
1013		pi->ipi6_ifindex = idx;
1014	}
1015
1016	if (sendmsg(ripsock, &m, 0 /*MSG_DONTROUTE*/) < 0) {
1017		trace(1, "sendmsg: %s\n", strerror(errno));
1018		return errno;
1019	}
1020
1021	return 0;
1022}
1023
1024/*
1025 * Receive and process RIP packets.  Update the routes/kernel forwarding
1026 * table if necessary.
1027 */
1028void
1029riprecv()
1030{
1031	struct	ifc *ifcp, *ic;
1032	struct	sockaddr_in6 fsock;
1033	struct	in6_addr nh;	/* next hop */
1034	struct	rip6 *rp;
1035	struct	netinfo6 *np, *nq;
1036	struct	riprt *rrt;
1037	int	len, nn, need_trigger, idx;
1038	char	buf[4 * RIP6_MAXMTU];
1039	time_t	t;
1040	struct msghdr m;
1041	struct cmsghdr *cm;
1042	struct iovec iov[2];
1043	u_char cmsgbuf[256];
1044	struct in6_pktinfo *pi;
1045	struct iff *iffp;
1046	struct in6_addr ia;
1047	int ok;
1048	time_t t_half_lifetime;
1049
1050	need_trigger = 0;
1051
1052	m.msg_name = (caddr_t)&fsock;
1053	m.msg_namelen = sizeof(fsock);
1054	iov[0].iov_base = (caddr_t)buf;
1055	iov[0].iov_len = sizeof(buf);
1056	m.msg_iov = iov;
1057	m.msg_iovlen = 1;
1058	cm = (struct cmsghdr *)cmsgbuf;
1059	m.msg_control = (caddr_t)cm;
1060	m.msg_controllen = sizeof(cmsgbuf);
1061	if ((len = recvmsg(ripsock, &m, 0)) < 0) {
1062		fatal("recvmsg");
1063		/*NOTREACHED*/
1064	}
1065	idx = 0;
1066	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m);
1067	     cm;
1068	     cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) {
1069		if (cm->cmsg_level == IPPROTO_IPV6 &&
1070		    cm->cmsg_type == IPV6_PKTINFO) {
1071			pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
1072			idx = pi->ipi6_ifindex;
1073			break;
1074		}
1075	}
1076	if (idx && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr))
1077		SET_IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr, idx);
1078
1079	nh = fsock.sin6_addr;
1080	nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) /
1081		sizeof(struct netinfo6);
1082	rp = (struct rip6 *)buf;
1083	np = rp->rip6_nets;
1084
1085	if (rp->rip6_vers != RIP6_VERSION) {
1086		trace(1, "Incorrect RIP version %d\n", rp->rip6_vers);
1087		return;
1088	}
1089	if (rp->rip6_cmd == RIP6_REQUEST) {
1090		if (idx && idx < nindex2ifc) {
1091			ifcp = index2ifc[idx];
1092			riprequest(ifcp, np, nn, &fsock);
1093		} else {
1094			riprequest(NULL, np, nn, &fsock);
1095		}
1096		return;
1097	}
1098
1099	if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) {
1100		trace(1, "Packets from non-ll addr: %s\n",
1101		    inet6_n2p(&fsock.sin6_addr));
1102		return;		/* Ignore packets from non-link-local addr */
1103	}
1104	idx = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr);
1105	ifcp = (idx < nindex2ifc) ? index2ifc[idx] : NULL;
1106	if (!ifcp) {
1107		trace(1, "Packets to unknown interface index %d\n", idx);
1108		return;		/* Ignore it */
1109	}
1110	if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr))
1111		return;		/* The packet is from me; ignore */
1112	if (rp->rip6_cmd != RIP6_RESPONSE) {
1113		trace(1, "Invalid command %d\n", rp->rip6_cmd);
1114		return;
1115	}
1116
1117	/* -N: no use */
1118	if (iff_find(ifcp, 'N') != NULL)
1119		return;
1120
1121	tracet(1, "Recv(%s): from %s.%d info(%d)\n",
1122	    ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn);
1123
1124	t = time(NULL);
1125	t_half_lifetime = t - (RIP_LIFETIME/2);
1126	for (; nn; nn--, np++) {
1127		if (np->rip6_metric == NEXTHOP_METRIC) {
1128			/* modify neighbor address */
1129			if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) {
1130				nh = np->rip6_dest;
1131				SET_IN6_LINKLOCAL_IFINDEX(nh, idx);
1132				trace(1, "\tNexthop: %s\n", inet6_n2p(&nh));
1133			} else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) {
1134				nh = fsock.sin6_addr;
1135				trace(1, "\tNexthop: %s\n", inet6_n2p(&nh));
1136			} else {
1137				nh = fsock.sin6_addr;
1138				trace(1, "\tInvalid Nexthop: %s\n",
1139				    inet6_n2p(&np->rip6_dest));
1140			}
1141			continue;
1142		}
1143		if (IN6_IS_ADDR_MULTICAST(&np->rip6_dest)) {
1144			trace(1, "\tMulticast netinfo6: %s/%d [%d]\n",
1145				inet6_n2p(&np->rip6_dest),
1146				np->rip6_plen, np->rip6_metric);
1147			continue;
1148		}
1149		if (IN6_IS_ADDR_LOOPBACK(&np->rip6_dest)) {
1150			trace(1, "\tLoopback netinfo6: %s/%d [%d]\n",
1151				inet6_n2p(&np->rip6_dest),
1152				np->rip6_plen, np->rip6_metric);
1153			continue;
1154		}
1155		if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) {
1156			trace(1, "\tLink Local netinfo6: %s/%d [%d]\n",
1157				inet6_n2p(&np->rip6_dest),
1158				np->rip6_plen, np->rip6_metric);
1159			continue;
1160		}
1161		/* may need to pass sitelocal prefix in some case, however*/
1162		if (IN6_IS_ADDR_SITELOCAL(&np->rip6_dest) && !lflag) {
1163			trace(1, "\tSite Local netinfo6: %s/%d [%d]\n",
1164				inet6_n2p(&np->rip6_dest),
1165				np->rip6_plen, np->rip6_metric);
1166			continue;
1167		}
1168		trace(2, "\tnetinfo6: %s/%d [%d]",
1169			inet6_n2p(&np->rip6_dest),
1170			np->rip6_plen, np->rip6_metric);
1171		if (np->rip6_tag)
1172			trace(2, "  tag=0x%04x", ntohs(np->rip6_tag) & 0xffff);
1173		if (dflag >= 2) {
1174			ia = np->rip6_dest;
1175			applyplen(&ia, np->rip6_plen);
1176			if (!IN6_ARE_ADDR_EQUAL(&ia, &np->rip6_dest))
1177				trace(2, " [junk outside prefix]");
1178		}
1179
1180		/*
1181		 * -L: listen only if the prefix matches the configuration
1182		 */
1183		ok = 1;		/* if there's no L filter, it is ok */
1184		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
1185			if (iffp->iff_type != 'L')
1186				continue;
1187			ok = 0;
1188			if (np->rip6_plen < iffp->iff_plen)
1189				continue;
1190			/* special rule: ::/0 means default, not "in /0" */
1191			if (iffp->iff_plen == 0 && np->rip6_plen > 0)
1192				continue;
1193			ia = np->rip6_dest;
1194			applyplen(&ia, iffp->iff_plen);
1195			if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) {
1196				ok = 1;
1197				break;
1198			}
1199		}
1200		if (!ok) {
1201			trace(2, "  (filtered)\n");
1202			continue;
1203		}
1204
1205		trace(2, "\n");
1206		np->rip6_metric++;
1207		np->rip6_metric += ifcp->ifc_metric;
1208		if (np->rip6_metric > HOPCNT_INFINITY6)
1209			np->rip6_metric = HOPCNT_INFINITY6;
1210
1211		applyplen(&np->rip6_dest, np->rip6_plen);
1212		if ((rrt = rtsearch(np, NULL)) != NULL) {
1213			if (rrt->rrt_t == 0)
1214				continue;	/* Intf route has priority */
1215			nq = &rrt->rrt_info;
1216			if (nq->rip6_metric > np->rip6_metric) {
1217				if (rrt->rrt_index == ifcp->ifc_index &&
1218				    IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
1219					/* Small metric from the same gateway */
1220					nq->rip6_metric = np->rip6_metric;
1221				} else {
1222					/* Better route found */
1223					rrt->rrt_index = ifcp->ifc_index;
1224					/* Update routing table */
1225					delroute(nq, &rrt->rrt_gw);
1226					rrt->rrt_gw = nh;
1227					*nq = *np;
1228					addroute(rrt, &nh, ifcp);
1229				}
1230				rrt->rrt_rflags |= RRTF_CHANGED;
1231				rrt->rrt_t = t;
1232				need_trigger = 1;
1233			} else if (nq->rip6_metric < np->rip6_metric &&
1234				   rrt->rrt_index == ifcp->ifc_index &&
1235				   IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
1236				/* Got worse route from same gw */
1237				nq->rip6_metric = np->rip6_metric;
1238				rrt->rrt_t = t;
1239				rrt->rrt_rflags |= RRTF_CHANGED;
1240				need_trigger = 1;
1241			} else if (nq->rip6_metric == np->rip6_metric &&
1242				   np->rip6_metric < HOPCNT_INFINITY6) {
1243				if (rrt->rrt_index == ifcp->ifc_index &&
1244				   IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
1245					/* same metric, same route from same gw */
1246					rrt->rrt_t = t;
1247				} else if (rrt->rrt_t < t_half_lifetime) {
1248					/* Better route found */
1249					rrt->rrt_index = ifcp->ifc_index;
1250					/* Update routing table */
1251					delroute(nq, &rrt->rrt_gw);
1252					rrt->rrt_gw = nh;
1253					*nq = *np;
1254					addroute(rrt, &nh, ifcp);
1255					rrt->rrt_rflags |= RRTF_CHANGED;
1256					rrt->rrt_t = t;
1257				}
1258			}
1259			/*
1260			 * if nq->rip6_metric == HOPCNT_INFINITY6 then
1261			 * do not update age value.  Do nothing.
1262			 */
1263		} else if (np->rip6_metric < HOPCNT_INFINITY6) {
1264			/* Got a new valid route */
1265			if ((rrt = MALLOC(struct riprt)) == NULL) {
1266				fatal("malloc: struct riprt");
1267				/*NOTREACHED*/
1268			}
1269			memset(rrt, 0, sizeof(*rrt));
1270			nq = &rrt->rrt_info;
1271
1272			rrt->rrt_same = NULL;
1273			rrt->rrt_index = ifcp->ifc_index;
1274			rrt->rrt_flags = RTF_UP|RTF_GATEWAY;
1275			rrt->rrt_gw = nh;
1276			*nq = *np;
1277			applyplen(&nq->rip6_dest, nq->rip6_plen);
1278			if (nq->rip6_plen == sizeof(struct in6_addr) * 8)
1279				rrt->rrt_flags |= RTF_HOST;
1280
1281			/* Put the route to the list */
1282			rrt->rrt_next = riprt;
1283			riprt = rrt;
1284			/* Update routing table */
1285			addroute(rrt, &nh, ifcp);
1286			rrt->rrt_rflags |= RRTF_CHANGED;
1287			need_trigger = 1;
1288			rrt->rrt_t = t;
1289		}
1290	}
1291	/* XXX need to care the interval between triggered updates */
1292	if (need_trigger) {
1293		if (nextalarm > time(NULL) + RIP_TRIG_INT6_MAX) {
1294			for (ic = ifc; ic; ic = ic->ifc_next) {
1295				if (ifcp->ifc_index == ic->ifc_index)
1296					continue;
1297				if (ic->ifc_flags & IFF_UP)
1298					ripsend(ic, &ic->ifc_ripsin,
1299						RRTF_CHANGED);
1300			}
1301		}
1302		/* Reset the flag */
1303		for (rrt = riprt; rrt; rrt = rrt->rrt_next)
1304			rrt->rrt_rflags &= ~RRTF_CHANGED;
1305	}
1306}
1307
1308/*
1309 * Send all routes request packet to the specified interface.
1310 */
1311void
1312sendrequest(ifcp)
1313	struct ifc *ifcp;
1314{
1315	struct netinfo6 *np;
1316	int error;
1317
1318	if (ifcp->ifc_flags & IFF_LOOPBACK)
1319		return;
1320	ripbuf->rip6_cmd = RIP6_REQUEST;
1321	np = ripbuf->rip6_nets;
1322	memset(np, 0, sizeof(struct netinfo6));
1323	np->rip6_metric = HOPCNT_INFINITY6;
1324	tracet(1, "Send rtdump Request to %s (%s)\n",
1325		ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
1326	error = sendpacket(&ifcp->ifc_ripsin, RIPSIZE(1));
1327	if (error == EAFNOSUPPORT) {
1328		/* Protocol not supported */
1329		tracet(1, "Could not send rtdump Request to %s (%s): "
1330			"set IFF_UP to 0\n",
1331			ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
1332		ifcp->ifc_flags &= ~IFF_UP;	/* As if down for AF_INET6 */
1333	}
1334	ripbuf->rip6_cmd = RIP6_RESPONSE;
1335}
1336
1337/*
1338 * Process a RIP6_REQUEST packet.
1339 */
1340void
1341riprequest(ifcp, np, nn, sin6)
1342	struct ifc *ifcp;
1343	struct netinfo6 *np;
1344	int nn;
1345	struct sockaddr_in6 *sin6;
1346{
1347	int i;
1348	struct riprt *rrt;
1349
1350	if (!(nn == 1 && IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest) &&
1351	      np->rip6_plen == 0 && np->rip6_metric == HOPCNT_INFINITY6)) {
1352		/* Specific response, don't split-horizon */
1353		trace(1, "\tRIP Request\n");
1354		for (i = 0; i < nn; i++, np++) {
1355			rrt = rtsearch(np, NULL);
1356			if (rrt)
1357				np->rip6_metric = rrt->rrt_info.rip6_metric;
1358			else
1359				np->rip6_metric = HOPCNT_INFINITY6;
1360		}
1361		(void)sendpacket(sin6, RIPSIZE(nn));
1362		return;
1363	}
1364	/* Whole routing table dump */
1365	trace(1, "\tRIP Request -- whole routing table\n");
1366	ripsend(ifcp, sin6, RRTF_SENDANYWAY);
1367}
1368
1369/*
1370 * Get information of each interface.
1371 */
1372void
1373ifconfig()
1374{
1375	struct ifaddrs *ifap, *ifa;
1376	struct ifc *ifcp;
1377	struct ipv6_mreq mreq;
1378	int s;
1379
1380	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1381		fatal("socket");
1382		/*NOTREACHED*/
1383	}
1384
1385	if (getifaddrs(&ifap) != 0) {
1386		fatal("getifaddrs");
1387		/*NOTREACHED*/
1388	}
1389
1390	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1391		if (ifa->ifa_addr->sa_family != AF_INET6)
1392			continue;
1393		ifcp = ifc_find(ifa->ifa_name);
1394		/* we are interested in multicast-capable interfaces */
1395		if ((ifa->ifa_flags & IFF_MULTICAST) == 0)
1396			continue;
1397		if (!ifcp) {
1398			/* new interface */
1399			if ((ifcp = MALLOC(struct ifc)) == NULL) {
1400				fatal("malloc: struct ifc");
1401				/*NOTREACHED*/
1402			}
1403			memset(ifcp, 0, sizeof(*ifcp));
1404			ifcp->ifc_index = -1;
1405			ifcp->ifc_next = ifc;
1406			ifc = ifcp;
1407			nifc++;
1408			ifcp->ifc_name = allocopy(ifa->ifa_name);
1409			ifcp->ifc_addr = 0;
1410			ifcp->ifc_filter = 0;
1411			ifcp->ifc_flags = ifa->ifa_flags;
1412			trace(1, "newif %s <%s>\n", ifcp->ifc_name,
1413				ifflags(ifcp->ifc_flags));
1414			if (!strcmp(ifcp->ifc_name, LOOPBACK_IF))
1415				loopifcp = ifcp;
1416		} else {
1417			/* update flag, this may be up again */
1418			if (ifcp->ifc_flags != ifa->ifa_flags) {
1419				trace(1, "%s: <%s> -> ", ifcp->ifc_name,
1420					ifflags(ifcp->ifc_flags));
1421				trace(1, "<%s>\n", ifflags(ifa->ifa_flags));
1422				ifcp->ifc_cflags |= IFC_CHANGED;
1423			}
1424			ifcp->ifc_flags = ifa->ifa_flags;
1425		}
1426		ifconfig1(ifa->ifa_name, ifa->ifa_addr, ifcp, s);
1427		if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP
1428		 && 0 < ifcp->ifc_index && !ifcp->ifc_joined) {
1429			mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr;
1430			mreq.ipv6mr_interface = ifcp->ifc_index;
1431			if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
1432			    &mreq, sizeof(mreq)) < 0) {
1433				fatal("IPV6_JOIN_GROUP");
1434				/*NOTREACHED*/
1435			}
1436			trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST);
1437			ifcp->ifc_joined++;
1438		}
1439	}
1440	close(s);
1441	freeifaddrs(ifap);
1442}
1443
1444void
1445ifconfig1(name, sa, ifcp, s)
1446	const char *name;
1447	const struct sockaddr *sa;
1448	struct	ifc *ifcp;
1449	int	s;
1450{
1451	struct	in6_ifreq ifr;
1452	const struct sockaddr_in6 *sin6;
1453	struct	ifac *ifa;
1454	int	plen;
1455	char	buf[BUFSIZ];
1456
1457	sin6 = (const struct sockaddr_in6 *)sa;
1458	ifr.ifr_addr = *sin6;
1459	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1460	if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0) {
1461		fatal("ioctl: SIOCGIFNETMASK_IN6");
1462		/*NOTREACHED*/
1463	}
1464	plen = sin6mask2len(&ifr.ifr_addr);
1465	if ((ifa = ifa_match(ifcp, &sin6->sin6_addr, plen)) != NULL) {
1466		/* same interface found */
1467		/* need check if something changed */
1468		/* XXX not yet implemented */
1469		return;
1470	}
1471	/*
1472	 * New address is found
1473	 */
1474	if ((ifa = MALLOC(struct ifac)) == NULL) {
1475		fatal("malloc: struct ifac");
1476		/*NOTREACHED*/
1477	}
1478	memset(ifa, 0, sizeof(*ifa));
1479	ifa->ifa_conf = ifcp;
1480	ifa->ifa_next = ifcp->ifc_addr;
1481	ifcp->ifc_addr = ifa;
1482	ifa->ifa_addr = sin6->sin6_addr;
1483	ifa->ifa_plen = plen;
1484	if (ifcp->ifc_flags & IFF_POINTOPOINT) {
1485		ifr.ifr_addr = *sin6;
1486		if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0) {
1487			fatal("ioctl: SIOCGIFDSTADDR_IN6");
1488			/*NOTREACHED*/
1489		}
1490		ifa->ifa_raddr = ifr.ifr_dstaddr.sin6_addr;
1491		inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, buf, sizeof(buf));
1492		trace(1, "found address %s/%d -- %s\n",
1493			inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen, buf);
1494	} else {
1495		trace(1, "found address %s/%d\n",
1496			inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen);
1497	}
1498	if (ifcp->ifc_index < 0 && IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) {
1499		ifcp->ifc_mylladdr = ifa->ifa_addr;
1500		ifcp->ifc_index = IN6_LINKLOCAL_IFINDEX(ifa->ifa_addr);
1501		memcpy(&ifcp->ifc_ripsin, &ripsin, ripsin.ss_len);
1502		SET_IN6_LINKLOCAL_IFINDEX(ifcp->ifc_ripsin.sin6_addr,
1503			ifcp->ifc_index);
1504		setindex2ifc(ifcp->ifc_index, ifcp);
1505		ifcp->ifc_mtu = getifmtu(ifcp->ifc_index);
1506		if (ifcp->ifc_mtu > RIP6_MAXMTU)
1507			ifcp->ifc_mtu = RIP6_MAXMTU;
1508		if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0) {
1509			fatal("ioctl: SIOCGIFMETRIC");
1510			/*NOTREACHED*/
1511		}
1512		ifcp->ifc_metric = ifr.ifr_metric;
1513		trace(1, "\tindex: %d, mtu: %d, metric: %d\n",
1514			ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric);
1515	} else
1516		ifcp->ifc_cflags |= IFC_CHANGED;
1517}
1518
1519/*
1520 * Receive and process routing messages.
1521 * Update interface information as necesssary.
1522 */
1523void
1524rtrecv()
1525{
1526	char buf[BUFSIZ];
1527	char *p, *q;
1528	struct rt_msghdr *rtm;
1529	struct ifa_msghdr *ifam;
1530	struct if_msghdr *ifm;
1531	int len;
1532	struct ifc *ifcp, *ic;
1533	int iface = 0, rtable = 0;
1534	struct sockaddr_in6 *rta[RTAX_MAX];
1535	struct sockaddr_in6 mask;
1536	int i, addrs;
1537	struct riprt *rrt;
1538
1539	if ((len = read(rtsock, buf, sizeof(buf))) < 0) {
1540		perror("read from rtsock");
1541		exit(1);
1542	}
1543	if (len < sizeof(*rtm)) {
1544		trace(1, "short read from rtsock: %d (should be > %lu)\n",
1545			len, (u_long)sizeof(*rtm));
1546		return;
1547	}
1548
1549	for (p = buf; p - buf < len; p += ((struct rt_msghdr *)p)->rtm_msglen) {
1550		/* safety against bogus message */
1551		if (((struct rt_msghdr *)p)->rtm_msglen <= 0) {
1552			trace(1, "bogus rtmsg: length=%d\n",
1553				((struct rt_msghdr *)p)->rtm_msglen);
1554			break;
1555		}
1556		rtm = NULL;
1557		ifam = NULL;
1558		ifm = NULL;
1559		switch (((struct rt_msghdr *)p)->rtm_type) {
1560		case RTM_NEWADDR:
1561		case RTM_DELADDR:
1562			ifam = (struct ifa_msghdr *)p;
1563			addrs = ifam->ifam_addrs;
1564			q = (char *)(ifam + 1);
1565			break;
1566		case RTM_IFINFO:
1567			ifm = (struct if_msghdr *)p;
1568			addrs = ifm->ifm_addrs;
1569			q = (char *)(ifm + 1);
1570			break;
1571		default:
1572			rtm = (struct rt_msghdr *)p;
1573			addrs = rtm->rtm_addrs;
1574			q = (char *)(rtm + 1);
1575			if (rtm->rtm_version != RTM_VERSION) {
1576				trace(1, "unexpected rtmsg version %d "
1577					"(should be %d)\n",
1578					rtm->rtm_version, RTM_VERSION);
1579				continue;
1580			}
1581			if (rtm->rtm_pid == pid) {
1582#if 0
1583				trace(1, "rtmsg looped back to me, ignored\n");
1584#endif
1585				continue;
1586			}
1587			break;
1588		}
1589		memset(&rta, 0, sizeof(rta));
1590		for (i = 0; i < RTAX_MAX; i++) {
1591			if (addrs & (1 << i)) {
1592				rta[i] = (struct sockaddr_in6 *)q;
1593				q += ROUNDUP(rta[i]->sin6_len);
1594			}
1595		}
1596
1597		trace(1, "rtsock: %s (addrs=%x)\n",
1598			rttypes((struct rt_msghdr *)p), addrs);
1599		if (dflag >= 2) {
1600			for (i = 0;
1601			     i < ((struct rt_msghdr *)p)->rtm_msglen;
1602			     i++) {
1603				fprintf(stderr, "%02x ", p[i] & 0xff);
1604				if (i % 16 == 15) fprintf(stderr, "\n");
1605			}
1606			fprintf(stderr, "\n");
1607		}
1608
1609		/*
1610		 * Easy ones first.
1611		 *
1612		 * We may be able to optimize by using ifm->ifm_index or
1613		 * ifam->ifam_index.  For simplicity we don't do that here.
1614		 */
1615		switch (((struct rt_msghdr *)p)->rtm_type) {
1616		case RTM_NEWADDR:
1617		case RTM_IFINFO:
1618			iface++;
1619			continue;
1620		case RTM_ADD:
1621			rtable++;
1622			continue;
1623		case RTM_LOSING:
1624		case RTM_MISS:
1625		case RTM_RESOLVE:
1626		case RTM_GET:
1627		case RTM_LOCK:
1628			/* nothing to be done here */
1629			trace(1, "\tnothing to be done, ignored\n");
1630			continue;
1631		}
1632
1633#if 0
1634		if (rta[RTAX_DST] == NULL) {
1635			trace(1, "\tno destination, ignored\n");
1636			continue;
1637		}
1638		if (rta[RTAX_DST]->sin6_family != AF_INET6) {
1639			trace(1, "\taf mismatch, ignored\n");
1640			continue;
1641		}
1642		if (IN6_IS_ADDR_LINKLOCAL(&rta[RTAX_DST]->sin6_addr)) {
1643			trace(1, "\tlinklocal destination, ignored\n");
1644			continue;
1645		}
1646		if (IN6_ARE_ADDR_EQUAL(&rta[RTAX_DST]->sin6_addr, &in6addr_loopback)) {
1647			trace(1, "\tloopback destination, ignored\n");
1648			continue;		/* Loopback */
1649		}
1650		if (IN6_IS_ADDR_MULTICAST(&rta[RTAX_DST]->sin6_addr)) {
1651			trace(1, "\tmulticast destination, ignored\n");
1652			continue;
1653		}
1654#endif
1655
1656		/* hard ones */
1657		switch (((struct rt_msghdr *)p)->rtm_type) {
1658		case RTM_NEWADDR:
1659		case RTM_IFINFO:
1660		case RTM_ADD:
1661		case RTM_LOSING:
1662		case RTM_MISS:
1663		case RTM_RESOLVE:
1664		case RTM_GET:
1665		case RTM_LOCK:
1666			/* should already be handled */
1667			fatal("rtrecv: never reach here");
1668			/*NOTREACHED*/
1669		case RTM_DELETE:
1670			if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY]) {
1671				trace(1, "\tsome of dst/gw/netamsk are "
1672				    "unavailable, ignored\n");
1673				break;
1674			}
1675			if ((rtm->rtm_flags & RTF_HOST) != 0) {
1676				mask.sin6_len = sizeof(mask);
1677				memset(&mask.sin6_addr, 0xff,
1678				    sizeof(mask.sin6_addr));
1679				rta[RTAX_NETMASK] = &mask;
1680			} else if (!rta[RTAX_NETMASK]) {
1681				trace(1, "\tsome of dst/gw/netamsk are "
1682				    "unavailable, ignored\n");
1683				break;
1684			}
1685			if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY],
1686			    rta[RTAX_NETMASK]) == 0) {
1687				rtable++;	/*just to be sure*/
1688			}
1689			break;
1690		case RTM_CHANGE:
1691		case RTM_REDIRECT:
1692			trace(1, "\tnot supported yet, ignored\n");
1693			break;
1694		case RTM_DELADDR:
1695			if (!rta[RTAX_NETMASK] || !rta[RTAX_IFA]) {
1696				trace(1, "\tno netmask or ifa given, ignored\n");
1697				break;
1698			}
1699			if (ifam->ifam_index < nindex2ifc)
1700				ifcp = index2ifc[ifam->ifam_index];
1701			else
1702				ifcp = NULL;
1703			if (!ifcp) {
1704				trace(1, "\tinvalid ifam_index %d, ignored\n",
1705					ifam->ifam_index);
1706				break;
1707			}
1708			if (!rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK]))
1709				iface++;
1710			break;
1711		case RTM_OLDADD:
1712		case RTM_OLDDEL:
1713			trace(1, "\tnot supported yet, ignored\n");
1714			break;
1715		}
1716
1717	}
1718
1719	if (iface) {
1720		trace(1, "rtsock: reconfigure interfaces, refresh interface routes\n");
1721		ifconfig();
1722		for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next)
1723			if (ifcp->ifc_cflags & IFC_CHANGED) {
1724				if (ifrt(ifcp, 1)) {
1725					for (ic = ifc; ic; ic = ic->ifc_next) {
1726						if (ifcp->ifc_index == ic->ifc_index)
1727							continue;
1728						if (ic->ifc_flags & IFF_UP)
1729							ripsend(ic, &ic->ifc_ripsin,
1730							RRTF_CHANGED);
1731					}
1732					/* Reset the flag */
1733					for (rrt = riprt; rrt; rrt = rrt->rrt_next)
1734						rrt->rrt_rflags &= ~RRTF_CHANGED;
1735				}
1736				ifcp->ifc_cflags &= ~IFC_CHANGED;
1737			}
1738	}
1739	if (rtable) {
1740		trace(1, "rtsock: read routing table again\n");
1741		krtread(1);
1742	}
1743}
1744
1745/*
1746 * remove specified route from the internal routing table.
1747 */
1748int
1749rt_del(sdst, sgw, smask)
1750	const struct sockaddr_in6 *sdst;
1751	const struct sockaddr_in6 *sgw;
1752	const struct sockaddr_in6 *smask;
1753{
1754	const struct in6_addr *dst = NULL;
1755	const struct in6_addr *gw = NULL;
1756	int prefix;
1757	struct netinfo6 ni6;
1758	struct riprt *rrt = NULL;
1759	time_t t_lifetime;
1760
1761	if (sdst->sin6_family != AF_INET6) {
1762		trace(1, "\tother AF, ignored\n");
1763		return -1;
1764	}
1765	if (IN6_IS_ADDR_LINKLOCAL(&sdst->sin6_addr)
1766	 || IN6_ARE_ADDR_EQUAL(&sdst->sin6_addr, &in6addr_loopback)
1767	 || IN6_IS_ADDR_MULTICAST(&sdst->sin6_addr)) {
1768		trace(1, "\taddress %s not interesting, ignored\n",
1769			inet6_n2p(&sdst->sin6_addr));
1770		return -1;
1771	}
1772	dst = &sdst->sin6_addr;
1773	if (sgw->sin6_family == AF_INET6) {
1774		/* easy case */
1775		gw = &sgw->sin6_addr;
1776		prefix = sin6mask2len(smask);
1777	} else if (sgw->sin6_family == AF_LINK) {
1778		/*
1779		 * Interface route... a hard case.  We need to get the prefix
1780		 * length from the kernel, but we now are parsing rtmsg.
1781		 * We'll purge matching routes from my list, then get the
1782		 * fresh list.
1783		 */
1784		struct riprt *longest;
1785		trace(1, "\t%s is an interface route, guessing prefixlen\n",
1786			inet6_n2p(dst));
1787		longest = NULL;
1788		for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
1789			if (IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
1790					&sdst->sin6_addr)
1791			 && IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) {
1792				if (!longest
1793				 || longest->rrt_info.rip6_plen <
1794						 rrt->rrt_info.rip6_plen) {
1795					longest = rrt;
1796				}
1797			}
1798		}
1799		rrt = longest;
1800		if (!rrt) {
1801			trace(1, "\tno matching interface route found\n");
1802			return -1;
1803		}
1804		gw = &in6addr_loopback;
1805		prefix = rrt->rrt_info.rip6_plen;
1806	} else {
1807		trace(1, "\tunsupported af: (gw=%d)\n", sgw->sin6_family);
1808		return -1;
1809	}
1810
1811	trace(1, "\tdeleting %s/%d ", inet6_n2p(dst), prefix);
1812	trace(1, "gw %s\n", inet6_n2p(gw));
1813	t_lifetime = time(NULL) - RIP_LIFETIME;
1814	/* age route for interface address */
1815	memset(&ni6, 0, sizeof(ni6));
1816	ni6.rip6_dest = *dst;
1817	ni6.rip6_plen = prefix;
1818	applyplen(&ni6.rip6_dest, ni6.rip6_plen);	/*to be sure*/
1819	trace(1, "\tfind route %s/%d\n", inet6_n2p(&ni6.rip6_dest),
1820		ni6.rip6_plen);
1821	if (!rrt && (rrt = rtsearch(&ni6, NULL)) == NULL) {
1822		trace(1, "\tno route found\n");
1823		return -1;
1824	}
1825#if 0
1826	if ((rrt->rrt_flags & RTF_STATIC) == 0) {
1827		trace(1, "\tyou can delete static routes only\n");
1828	} else
1829#endif
1830	if (!IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, gw)) {
1831		trace(1, "\tgw mismatch: %s <-> ",
1832			inet6_n2p(&rrt->rrt_gw));
1833		trace(1, "%s\n", inet6_n2p(gw));
1834	} else {
1835		trace(1, "\troute found, age it\n");
1836		if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
1837			rrt->rrt_t = t_lifetime;
1838			rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
1839		}
1840	}
1841	return 0;
1842}
1843
1844/*
1845 * remove specified address from internal interface/routing table.
1846 */
1847int
1848rt_deladdr(ifcp, sifa, smask)
1849	struct ifc *ifcp;
1850	const struct sockaddr_in6 *sifa;
1851	const struct sockaddr_in6 *smask;
1852{
1853	const struct in6_addr *addr = NULL;
1854	int prefix;
1855	struct ifac *ifa = NULL;
1856	struct netinfo6 ni6;
1857	struct riprt *rrt = NULL;
1858	time_t t_lifetime;
1859	int updated = 0;
1860
1861	if (sifa->sin6_family != AF_INET6) {
1862		trace(1, "\tother AF, ignored\n");
1863		return -1;
1864	}
1865	addr = &sifa->sin6_addr;
1866	prefix = sin6mask2len(smask);
1867
1868	trace(1, "\tdeleting %s/%d from %s\n",
1869		inet6_n2p(addr), prefix, ifcp->ifc_name);
1870	ifa = ifa_match(ifcp, addr, prefix);
1871	if (!ifa) {
1872		trace(1, "\tno matching ifa found for %s/%d on %s\n",
1873			inet6_n2p(addr), prefix, ifcp->ifc_name);
1874		return -1;
1875	}
1876	if (ifa->ifa_conf != ifcp) {
1877		trace(1, "\taddress table corrupt: back pointer does not match "
1878			"(%s != %s)\n",
1879			ifcp->ifc_name, ifa->ifa_conf->ifc_name);
1880		return -1;
1881	}
1882	/* remove ifa from interface */
1883	if (ifcp->ifc_addr == ifa)
1884		ifcp->ifc_addr = ifa->ifa_next;
1885	else {
1886		struct ifac *p;
1887		for (p = ifcp->ifc_addr; p; p = p->ifa_next) {
1888			if (p->ifa_next == ifa) {
1889				p->ifa_next = ifa->ifa_next;
1890				break;
1891			}
1892		}
1893	}
1894	ifa->ifa_next = NULL;
1895	ifa->ifa_conf = NULL;
1896	t_lifetime = time(NULL) - RIP_LIFETIME;
1897	/* age route for interface address */
1898	memset(&ni6, 0, sizeof(ni6));
1899	ni6.rip6_dest = ifa->ifa_addr;
1900	ni6.rip6_plen = ifa->ifa_plen;
1901	applyplen(&ni6.rip6_dest, ni6.rip6_plen);
1902	trace(1, "\tfind interface route %s/%d on %d\n",
1903		inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index);
1904	if ((rrt = rtsearch(&ni6, NULL)) != NULL) {
1905		struct in6_addr none;
1906		memset(&none, 0, sizeof(none));
1907		if (rrt->rrt_index == ifcp->ifc_index &&
1908		    (IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &none) ||
1909		     IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw))) {
1910			trace(1, "\troute found, age it\n");
1911			if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
1912				rrt->rrt_t = t_lifetime;
1913				rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
1914			}
1915			updated++;
1916		} else {
1917			trace(1, "\tnon-interface route found: %s/%d on %d\n",
1918				inet6_n2p(&rrt->rrt_info.rip6_dest),
1919				rrt->rrt_info.rip6_plen,
1920				rrt->rrt_index);
1921		}
1922	} else
1923		trace(1, "\tno interface route found\n");
1924	/* age route for p2p destination */
1925	if (ifcp->ifc_flags & IFF_POINTOPOINT) {
1926		memset(&ni6, 0, sizeof(ni6));
1927		ni6.rip6_dest = ifa->ifa_raddr;
1928		ni6.rip6_plen = 128;
1929		applyplen(&ni6.rip6_dest, ni6.rip6_plen);	/*to be sure*/
1930		trace(1, "\tfind p2p route %s/%d on %d\n",
1931			inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen,
1932			ifcp->ifc_index);
1933		if ((rrt = rtsearch(&ni6, NULL)) != NULL) {
1934			if (rrt->rrt_index == ifcp->ifc_index &&
1935			    IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &ifa->ifa_addr)) {
1936				trace(1, "\troute found, age it\n");
1937				if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
1938					rrt->rrt_t = t_lifetime;
1939					rrt->rrt_info.rip6_metric =
1940					    HOPCNT_INFINITY6;
1941					updated++;
1942				}
1943			} else {
1944				trace(1, "\tnon-p2p route found: %s/%d on %d\n",
1945					inet6_n2p(&rrt->rrt_info.rip6_dest),
1946					rrt->rrt_info.rip6_plen,
1947					rrt->rrt_index);
1948			}
1949		} else
1950			trace(1, "\tno p2p route found\n");
1951	}
1952	return updated ? 0 : -1;
1953}
1954
1955/*
1956 * Get each interface address and put those interface routes to the route
1957 * list.
1958 */
1959int
1960ifrt(ifcp, again)
1961	struct ifc *ifcp;
1962	int again;
1963{
1964	struct ifac *ifa;
1965	struct riprt *rrt, *search_rrt, *prev_rrt, *loop_rrt;
1966	struct netinfo6 *np;
1967	time_t t_lifetime;
1968	int need_trigger = 0;
1969
1970	if (ifcp->ifc_flags & IFF_LOOPBACK)
1971		return 0;			/* ignore loopback */
1972	if (ifcp->ifc_flags & IFF_POINTOPOINT) {
1973		ifrt_p2p(ifcp, again);
1974		return 0;
1975	}
1976
1977	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
1978		if (IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) {
1979#if 0
1980			trace(1, "route: %s on %s: "
1981			    "skip linklocal interface address\n",
1982			    inet6_n2p(&ifa->ifa_addr), ifcp->ifc_name);
1983#endif
1984			continue;
1985		}
1986		if (IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_addr)) {
1987#if 0
1988			trace(1, "route: %s: skip unspec interface address\n",
1989			    ifcp->ifc_name);
1990#endif
1991			continue;
1992		}
1993		if (ifcp->ifc_flags & IFF_UP) {
1994			if ((rrt = MALLOC(struct riprt)) == NULL)
1995				fatal("malloc: struct riprt");
1996			memset(rrt, 0, sizeof(*rrt));
1997			rrt->rrt_same = NULL;
1998			rrt->rrt_index = ifcp->ifc_index;
1999			rrt->rrt_t = 0;	/* don't age */
2000			rrt->rrt_info.rip6_dest = ifa->ifa_addr;
2001			rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
2002			rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric;
2003			rrt->rrt_info.rip6_plen = ifa->ifa_plen;
2004			rrt->rrt_flags = RTF_CLONING;
2005			rrt->rrt_rflags |= RRTF_CHANGED;
2006			applyplen(&rrt->rrt_info.rip6_dest, ifa->ifa_plen);
2007			memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
2008#if 0
2009			/* XXX why gateway address == network adddress? */
2010			rrt->rrt_gw = ifa->ifa_addr;
2011#endif
2012			np = &rrt->rrt_info;
2013			search_rrt = rtsearch(np, &prev_rrt);
2014			if (search_rrt != NULL) {
2015				if (search_rrt->rrt_info.rip6_metric >
2016				    rrt->rrt_info.rip6_metric) {
2017					if (prev_rrt)
2018						prev_rrt->rrt_next = rrt->rrt_next;
2019					else
2020						riprt = rrt->rrt_next;
2021					delroute(&rrt->rrt_info, &rrt->rrt_gw);
2022					free(rrt);
2023				} else {
2024					/* Already have better route */
2025					if (!again) {
2026						trace(1, "route: %s/%d: "
2027						    "already registered (%s)\n",
2028						    inet6_n2p(&np->rip6_dest), np->rip6_plen,
2029						    ifcp->ifc_name);
2030					}
2031					free(rrt);
2032					continue;
2033				}
2034			}
2035			/* Attach the route to the list */
2036			trace(1, "route: %s/%d: register route (%s)\n",
2037			    inet6_n2p(&np->rip6_dest), np->rip6_plen,
2038			    ifcp->ifc_name);
2039			rrt->rrt_next = riprt;
2040			riprt = rrt;
2041			addroute(rrt, &rrt->rrt_gw, ifcp);
2042			sendrequest(ifcp);
2043			ripsend(ifcp, &ifcp->ifc_ripsin, 0);
2044			need_trigger = 1;
2045		} else {
2046			for (loop_rrt = riprt; loop_rrt; loop_rrt = loop_rrt->rrt_next) {
2047				if (loop_rrt->rrt_index == ifcp->ifc_index) {
2048					t_lifetime = time(NULL) - RIP_LIFETIME;
2049					if (loop_rrt->rrt_t == 0 || loop_rrt->rrt_t > t_lifetime) {
2050						loop_rrt->rrt_t = t_lifetime;
2051						loop_rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
2052						loop_rrt->rrt_rflags |= RRTF_CHANGED;
2053						need_trigger = 1;
2054					}
2055				}
2056			}
2057                }
2058	}
2059	return need_trigger;
2060}
2061
2062/*
2063 * there are couple of p2p interface routing models.  "behavior" lets
2064 * you pick one.  it looks that gated behavior fits best with BSDs,
2065 * since BSD kernels do not look at prefix length on p2p interfaces.
2066 */
2067void
2068ifrt_p2p(ifcp, again)
2069	struct ifc *ifcp;
2070	int again;
2071{
2072	struct ifac *ifa;
2073	struct riprt *rrt, *orrt, *prevrrt;
2074	struct netinfo6 *np;
2075	struct in6_addr addr, dest;
2076	int advert, ignore, i;
2077#define P2PADVERT_NETWORK	1
2078#define P2PADVERT_ADDR		2
2079#define P2PADVERT_DEST		4
2080#define P2PADVERT_MAX		4
2081	const enum { CISCO, GATED, ROUTE6D } behavior = GATED;
2082	const char *category = "";
2083	const char *noadv;
2084
2085	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
2086		addr = ifa->ifa_addr;
2087		dest = ifa->ifa_raddr;
2088		applyplen(&addr, ifa->ifa_plen);
2089		applyplen(&dest, ifa->ifa_plen);
2090		advert = ignore = 0;
2091		switch (behavior) {
2092		case CISCO:
2093			/*
2094			 * honor addr/plen, just like normal shared medium
2095			 * interface.  this may cause trouble if you reuse
2096			 * addr/plen on other interfaces.
2097			 *
2098			 * advertise addr/plen.
2099			 */
2100			advert |= P2PADVERT_NETWORK;
2101			break;
2102		case GATED:
2103			/*
2104			 * prefixlen on p2p interface is meaningless.
2105			 * advertise addr/128 and dest/128.
2106			 *
2107			 * do not install network route to route6d routing
2108			 * table (if we do, it would prevent route installation
2109			 * for other p2p interface that shares addr/plen).
2110			 *
2111			 * XXX what should we do if dest is ::?  it will not
2112			 * get announced anyways (see following filter),
2113			 * but we need to think.
2114			 */
2115			advert |= P2PADVERT_ADDR;
2116			advert |= P2PADVERT_DEST;
2117			ignore |= P2PADVERT_NETWORK;
2118			break;
2119		case ROUTE6D:
2120			/*
2121			 * just for testing.  actually the code is redundant
2122			 * given the current p2p interface address assignment
2123			 * rule for kame kernel.
2124			 *
2125			 * intent:
2126			 *	A/n -> announce A/n
2127			 *	A B/n, A and B share prefix -> A/n (= B/n)
2128			 *	A B/n, do not share prefix -> A/128 and B/128
2129			 * actually, A/64 and A B/128 are the only cases
2130			 * permitted by the kernel:
2131			 *	A/64 -> A/64
2132			 *	A B/128 -> A/128 and B/128
2133			 */
2134			if (!IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_raddr)) {
2135				if (IN6_ARE_ADDR_EQUAL(&addr, &dest))
2136					advert |= P2PADVERT_NETWORK;
2137				else {
2138					advert |= P2PADVERT_ADDR;
2139					advert |= P2PADVERT_DEST;
2140					ignore |= P2PADVERT_NETWORK;
2141				}
2142			} else
2143				advert |= P2PADVERT_NETWORK;
2144			break;
2145		}
2146
2147		for (i = 1; i <= P2PADVERT_MAX; i *= 2) {
2148			if ((ignore & i) != 0)
2149				continue;
2150			if ((rrt = MALLOC(struct riprt)) == NULL) {
2151				fatal("malloc: struct riprt");
2152				/*NOTREACHED*/
2153			}
2154			memset(rrt, 0, sizeof(*rrt));
2155			rrt->rrt_same = NULL;
2156			rrt->rrt_index = ifcp->ifc_index;
2157			rrt->rrt_t = 0;	/* don't age */
2158			switch (i) {
2159			case P2PADVERT_NETWORK:
2160				rrt->rrt_info.rip6_dest = ifa->ifa_addr;
2161				rrt->rrt_info.rip6_plen = ifa->ifa_plen;
2162				applyplen(&rrt->rrt_info.rip6_dest,
2163				    ifa->ifa_plen);
2164				category = "network";
2165				break;
2166			case P2PADVERT_ADDR:
2167				rrt->rrt_info.rip6_dest = ifa->ifa_addr;
2168				rrt->rrt_info.rip6_plen = 128;
2169				rrt->rrt_gw = in6addr_loopback;
2170				category = "addr";
2171				break;
2172			case P2PADVERT_DEST:
2173				rrt->rrt_info.rip6_dest = ifa->ifa_raddr;
2174				rrt->rrt_info.rip6_plen = 128;
2175				rrt->rrt_gw = ifa->ifa_addr;
2176				category = "dest";
2177				break;
2178			}
2179			if (IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_info.rip6_dest) ||
2180			    IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_info.rip6_dest)) {
2181#if 0
2182				trace(1, "route: %s: skip unspec/linklocal "
2183				    "(%s on %s)\n", category, ifcp->ifc_name);
2184#endif
2185				free(rrt);
2186				continue;
2187			}
2188			if ((advert & i) == 0) {
2189				rrt->rrt_rflags |= RRTF_NOADVERTISE;
2190				noadv = ", NO-ADV";
2191			} else
2192				noadv = "";
2193			rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
2194			rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric;
2195			np = &rrt->rrt_info;
2196			orrt = rtsearch(np, &prevrrt);
2197			if (!orrt) {
2198				/* Attach the route to the list */
2199				trace(1, "route: %s/%d: register route "
2200				    "(%s on %s%s)\n",
2201				    inet6_n2p(&np->rip6_dest), np->rip6_plen,
2202				    category, ifcp->ifc_name, noadv);
2203				rrt->rrt_next = riprt;
2204				riprt = rrt;
2205			} else if (rrt->rrt_index != orrt->rrt_index ||
2206			    rrt->rrt_info.rip6_metric != orrt->rrt_info.rip6_metric) {
2207				/* swap route */
2208				rrt->rrt_next = orrt->rrt_next;
2209				if (prevrrt)
2210					prevrrt->rrt_next = rrt;
2211				else
2212					riprt = rrt;
2213				free(orrt);
2214
2215				trace(1, "route: %s/%d: update (%s on %s%s)\n",
2216				    inet6_n2p(&np->rip6_dest), np->rip6_plen,
2217				    category, ifcp->ifc_name, noadv);
2218			} else {
2219				/* Already found */
2220				if (!again) {
2221					trace(1, "route: %s/%d: "
2222					    "already registered (%s on %s%s)\n",
2223					    inet6_n2p(&np->rip6_dest),
2224					    np->rip6_plen, category,
2225					    ifcp->ifc_name, noadv);
2226				}
2227				free(rrt);
2228			}
2229		}
2230	}
2231#undef P2PADVERT_NETWORK
2232#undef P2PADVERT_ADDR
2233#undef P2PADVERT_DEST
2234#undef P2PADVERT_MAX
2235}
2236
2237int
2238getifmtu(ifindex)
2239	int	ifindex;
2240{
2241	int	mib[6];
2242	char	*buf;
2243	size_t	msize;
2244	struct	if_msghdr *ifm;
2245	int	mtu;
2246
2247	mib[0] = CTL_NET;
2248	mib[1] = PF_ROUTE;
2249	mib[2] = 0;
2250	mib[3] = AF_INET6;
2251	mib[4] = NET_RT_IFLIST;
2252	mib[5] = ifindex;
2253	if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) {
2254		fatal("sysctl estimate NET_RT_IFLIST");
2255		/*NOTREACHED*/
2256	}
2257	if ((buf = malloc(msize)) == NULL) {
2258		fatal("malloc");
2259		/*NOTREACHED*/
2260	}
2261	if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) {
2262		fatal("sysctl NET_RT_IFLIST");
2263		/*NOTREACHED*/
2264	}
2265	ifm = (struct if_msghdr *)buf;
2266	mtu = ifm->ifm_data.ifi_mtu;
2267#ifdef __FreeBSD__
2268	if (ifindex != ifm->ifm_index) {
2269		fatal("ifindex does not match with ifm_index");
2270		/*NOTREACHED*/
2271	}
2272#endif
2273	free(buf);
2274	return mtu;
2275}
2276
2277const char *
2278rttypes(rtm)
2279	struct rt_msghdr *rtm;
2280{
2281#define	RTTYPE(s, f) \
2282do { \
2283	if (rtm->rtm_type == (f)) \
2284		return (s); \
2285} while (0)
2286	RTTYPE("ADD", RTM_ADD);
2287	RTTYPE("DELETE", RTM_DELETE);
2288	RTTYPE("CHANGE", RTM_CHANGE);
2289	RTTYPE("GET", RTM_GET);
2290	RTTYPE("LOSING", RTM_LOSING);
2291	RTTYPE("REDIRECT", RTM_REDIRECT);
2292	RTTYPE("MISS", RTM_MISS);
2293	RTTYPE("LOCK", RTM_LOCK);
2294	RTTYPE("OLDADD", RTM_OLDADD);
2295	RTTYPE("OLDDEL", RTM_OLDDEL);
2296	RTTYPE("RESOLVE", RTM_RESOLVE);
2297	RTTYPE("NEWADDR", RTM_NEWADDR);
2298	RTTYPE("DELADDR", RTM_DELADDR);
2299	RTTYPE("IFINFO", RTM_IFINFO);
2300#ifdef RTM_OLDADD
2301	RTTYPE("OLDADD", RTM_OLDADD);
2302#endif
2303#ifdef RTM_OLDDEL
2304	RTTYPE("OLDDEL", RTM_OLDDEL);
2305#endif
2306#ifdef RTM_OIFINFO
2307	RTTYPE("OIFINFO", RTM_OIFINFO);
2308#endif
2309#ifdef RTM_IFANNOUNCE
2310	RTTYPE("IFANNOUNCE", RTM_IFANNOUNCE);
2311#endif
2312#ifdef RTM_NEWMADDR
2313	RTTYPE("NEWMADDR", RTM_NEWMADDR);
2314#endif
2315#ifdef RTM_DELMADDR
2316	RTTYPE("DELMADDR", RTM_DELMADDR);
2317#endif
2318#undef RTTYPE
2319	return NULL;
2320}
2321
2322const char *
2323rtflags(rtm)
2324	struct rt_msghdr *rtm;
2325{
2326	static char buf[BUFSIZ];
2327
2328	/*
2329	 * letter conflict should be okay.  painful when *BSD diverges...
2330	 */
2331	strlcpy(buf, "", sizeof(buf));
2332#define	RTFLAG(s, f) \
2333do { \
2334	if (rtm->rtm_flags & (f)) \
2335		strlcat(buf, (s), sizeof(buf)); \
2336} while (0)
2337	RTFLAG("U", RTF_UP);
2338	RTFLAG("G", RTF_GATEWAY);
2339	RTFLAG("H", RTF_HOST);
2340	RTFLAG("R", RTF_REJECT);
2341	RTFLAG("D", RTF_DYNAMIC);
2342	RTFLAG("M", RTF_MODIFIED);
2343	RTFLAG("d", RTF_DONE);
2344#ifdef	RTF_MASK
2345	RTFLAG("m", RTF_MASK);
2346#endif
2347	RTFLAG("C", RTF_CLONING);
2348#ifdef RTF_CLONED
2349	RTFLAG("c", RTF_CLONED);
2350#endif
2351#ifdef RTF_PRCLONING
2352	RTFLAG("c", RTF_PRCLONING);
2353#endif
2354#ifdef RTF_WASCLONED
2355	RTFLAG("W", RTF_WASCLONED);
2356#endif
2357	RTFLAG("X", RTF_XRESOLVE);
2358	RTFLAG("L", RTF_LLINFO);
2359	RTFLAG("S", RTF_STATIC);
2360	RTFLAG("B", RTF_BLACKHOLE);
2361#ifdef RTF_PROTO3
2362	RTFLAG("3", RTF_PROTO3);
2363#endif
2364	RTFLAG("2", RTF_PROTO2);
2365	RTFLAG("1", RTF_PROTO1);
2366#ifdef RTF_BROADCAST
2367	RTFLAG("b", RTF_BROADCAST);
2368#endif
2369#ifdef RTF_DEFAULT
2370	RTFLAG("d", RTF_DEFAULT);
2371#endif
2372#ifdef RTF_ISAROUTER
2373	RTFLAG("r", RTF_ISAROUTER);
2374#endif
2375#ifdef RTF_TUNNEL
2376	RTFLAG("T", RTF_TUNNEL);
2377#endif
2378#ifdef RTF_AUTH
2379	RTFLAG("A", RTF_AUTH);
2380#endif
2381#ifdef RTF_CRYPT
2382	RTFLAG("E", RTF_CRYPT);
2383#endif
2384#undef RTFLAG
2385	return buf;
2386}
2387
2388const char *
2389ifflags(flags)
2390	int flags;
2391{
2392	static char buf[BUFSIZ];
2393
2394	strlcpy(buf, "", sizeof(buf));
2395#define	IFFLAG(s, f) \
2396do { \
2397	if (flags & f) { \
2398		if (buf[0]) \
2399			strlcat(buf, ",", sizeof(buf)); \
2400		strlcat(buf, s, sizeof(buf)); \
2401	} \
2402} while (0)
2403	IFFLAG("UP", IFF_UP);
2404	IFFLAG("BROADCAST", IFF_BROADCAST);
2405	IFFLAG("DEBUG", IFF_DEBUG);
2406	IFFLAG("LOOPBACK", IFF_LOOPBACK);
2407	IFFLAG("POINTOPOINT", IFF_POINTOPOINT);
2408#ifdef IFF_NOTRAILERS
2409	IFFLAG("NOTRAILERS", IFF_NOTRAILERS);
2410#endif
2411#ifdef IFF_SMART
2412	IFFLAG("SMART", IFF_SMART);
2413#endif
2414	IFFLAG("RUNNING", IFF_RUNNING);
2415	IFFLAG("NOARP", IFF_NOARP);
2416	IFFLAG("PROMISC", IFF_PROMISC);
2417	IFFLAG("ALLMULTI", IFF_ALLMULTI);
2418	IFFLAG("OACTIVE", IFF_OACTIVE);
2419	IFFLAG("SIMPLEX", IFF_SIMPLEX);
2420	IFFLAG("LINK0", IFF_LINK0);
2421	IFFLAG("LINK1", IFF_LINK1);
2422	IFFLAG("LINK2", IFF_LINK2);
2423	IFFLAG("MULTICAST", IFF_MULTICAST);
2424#undef IFFLAG
2425	return buf;
2426}
2427
2428void
2429krtread(again)
2430	int again;
2431{
2432	int mib[6];
2433	size_t msize;
2434	char *buf, *p, *lim;
2435	struct rt_msghdr *rtm;
2436	int retry;
2437	const char *errmsg;
2438
2439	retry = 0;
2440	buf = NULL;
2441	mib[0] = CTL_NET;
2442	mib[1] = PF_ROUTE;
2443	mib[2] = 0;
2444	mib[3] = AF_INET6;	/* Address family */
2445	mib[4] = NET_RT_DUMP;	/* Dump the kernel routing table */
2446	mib[5] = 0;		/* No flags */
2447	do {
2448		retry++;
2449		errmsg = NULL;
2450		if (buf)
2451			free(buf);
2452		if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) {
2453			errmsg = "sysctl estimate";
2454			continue;
2455		}
2456		if ((buf = malloc(msize)) == NULL) {
2457			errmsg = "malloc";
2458			continue;
2459		}
2460		if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) {
2461			errmsg = "sysctl NET_RT_DUMP";
2462			continue;
2463		}
2464	} while (retry < 5 && errmsg != NULL);
2465	if (errmsg) {
2466		fatal("%s (with %d retries, msize=%lu)", errmsg, retry,
2467		    (u_long)msize);
2468		/*NOTREACHED*/
2469	} else if (1 < retry)
2470		syslog(LOG_INFO, "NET_RT_DUMP %d retires", retry);
2471
2472	lim = buf + msize;
2473	for (p = buf; p < lim; p += rtm->rtm_msglen) {
2474		rtm = (struct rt_msghdr *)p;
2475		rt_entry(rtm, again);
2476	}
2477	free(buf);
2478}
2479
2480void
2481rt_entry(rtm, again)
2482	struct rt_msghdr *rtm;
2483	int again;
2484{
2485	struct	sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask;
2486	struct	sockaddr_in6 *sin6_genmask, *sin6_ifp;
2487	char	*rtmp, *ifname = NULL;
2488	struct	riprt *rrt, *orrt;
2489	struct	netinfo6 *np;
2490	int	s;
2491
2492	sin6_dst = sin6_gw = sin6_mask = sin6_genmask = sin6_ifp = 0;
2493	if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags &
2494		(RTF_CLONING|RTF_XRESOLVE|RTF_LLINFO|RTF_BLACKHOLE)) {
2495		return;		/* not interested in the link route */
2496	}
2497	/* do not look at cloned routes */
2498#ifdef RTF_WASCLONED
2499	if (rtm->rtm_flags & RTF_WASCLONED)
2500		return;
2501#endif
2502#ifdef RTF_CLONED
2503	if (rtm->rtm_flags & RTF_CLONED)
2504		return;
2505#endif
2506	/*
2507	 * do not look at dynamic routes.
2508	 * netbsd/openbsd cloned routes have UGHD.
2509	 */
2510	if (rtm->rtm_flags & RTF_DYNAMIC)
2511		return;
2512	rtmp = (char *)(rtm + 1);
2513	/* Destination */
2514	if ((rtm->rtm_addrs & RTA_DST) == 0)
2515		return;		/* ignore routes without destination address */
2516	sin6_dst = (struct sockaddr_in6 *)rtmp;
2517	rtmp += ROUNDUP(sin6_dst->sin6_len);
2518	if (rtm->rtm_addrs & RTA_GATEWAY) {
2519		sin6_gw = (struct sockaddr_in6 *)rtmp;
2520		rtmp += ROUNDUP(sin6_gw->sin6_len);
2521	}
2522	if (rtm->rtm_addrs & RTA_NETMASK) {
2523		sin6_mask = (struct sockaddr_in6 *)rtmp;
2524		rtmp += ROUNDUP(sin6_mask->sin6_len);
2525	}
2526	if (rtm->rtm_addrs & RTA_GENMASK) {
2527		sin6_genmask = (struct sockaddr_in6 *)rtmp;
2528		rtmp += ROUNDUP(sin6_genmask->sin6_len);
2529	}
2530	if (rtm->rtm_addrs & RTA_IFP) {
2531		sin6_ifp = (struct sockaddr_in6 *)rtmp;
2532		rtmp += ROUNDUP(sin6_ifp->sin6_len);
2533	}
2534
2535	/* Destination */
2536	if (sin6_dst->sin6_family != AF_INET6)
2537		return;
2538	if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst->sin6_addr))
2539		return;		/* Link-local */
2540	if (IN6_ARE_ADDR_EQUAL(&sin6_dst->sin6_addr, &in6addr_loopback))
2541		return;		/* Loopback */
2542	if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr))
2543		return;
2544
2545	if ((rrt = MALLOC(struct riprt)) == NULL) {
2546		fatal("malloc: struct riprt");
2547		/*NOTREACHED*/
2548	}
2549	memset(rrt, 0, sizeof(*rrt));
2550	np = &rrt->rrt_info;
2551	rrt->rrt_same = NULL;
2552	rrt->rrt_t = time(NULL);
2553	if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC))
2554		rrt->rrt_t = 0;	/* Don't age static routes */
2555	np->rip6_tag = 0;
2556	np->rip6_metric = rtm->rtm_rmx.rmx_hopcount;
2557	if (np->rip6_metric < 1)
2558		np->rip6_metric = 1;
2559	rrt->rrt_flags = rtm->rtm_flags;
2560	np->rip6_dest = sin6_dst->sin6_addr;
2561
2562	/* Mask or plen */
2563	if (rtm->rtm_flags & RTF_HOST)
2564		np->rip6_plen = 128;	/* Host route */
2565	else if (sin6_mask)
2566		np->rip6_plen = sin6mask2len(sin6_mask);
2567	else
2568		np->rip6_plen = 0;
2569
2570	orrt = rtsearch(np, NULL);
2571	if (orrt && orrt->rrt_info.rip6_metric != HOPCNT_INFINITY6) {
2572		/* Already found */
2573		if (!again) {
2574			trace(1, "route: %s/%d flags %s: already registered\n",
2575				inet6_n2p(&np->rip6_dest), np->rip6_plen,
2576				rtflags(rtm));
2577		}
2578		free(rrt);
2579		return;
2580	}
2581	/* Gateway */
2582	if (!sin6_gw)
2583		memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
2584	else {
2585		if (sin6_gw->sin6_family == AF_INET6)
2586			rrt->rrt_gw = sin6_gw->sin6_addr;
2587		else if (sin6_gw->sin6_family == AF_LINK) {
2588			/* XXX in case ppp link? */
2589			rrt->rrt_gw = in6addr_loopback;
2590		} else
2591			memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
2592	}
2593	trace(1, "route: %s/%d flags %s",
2594		inet6_n2p(&np->rip6_dest), np->rip6_plen, rtflags(rtm));
2595	trace(1, " gw %s", inet6_n2p(&rrt->rrt_gw));
2596
2597	/* Interface */
2598	s = rtm->rtm_index;
2599	if (s < nindex2ifc && index2ifc[s])
2600		ifname = index2ifc[s]->ifc_name;
2601	else {
2602		trace(1, " not configured\n");
2603		free(rrt);
2604		return;
2605	}
2606	trace(1, " if %s sock %d", ifname, s);
2607	rrt->rrt_index = s;
2608
2609	trace(1, "\n");
2610
2611	/* Check gateway */
2612	if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_gw) &&
2613	    !IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)
2614#ifdef __FreeBSD__
2615	 && (rrt->rrt_flags & RTF_LOCAL) == 0
2616#endif
2617	    ) {
2618		trace(0, "***** Gateway %s is not a link-local address.\n",
2619			inet6_n2p(&rrt->rrt_gw));
2620		trace(0, "*****     dest(%s) if(%s) -- Not optimized.\n",
2621			inet6_n2p(&rrt->rrt_info.rip6_dest), ifname);
2622		rrt->rrt_rflags |= RRTF_NH_NOT_LLADDR;
2623	}
2624
2625	/* Put it to the route list */
2626	if (orrt && orrt->rrt_info.rip6_metric == HOPCNT_INFINITY6) {
2627		/* replace route list */
2628		rrt->rrt_next = orrt->rrt_next;
2629		*orrt = *rrt;
2630		trace(1, "route: %s/%d flags %s: replace new route\n",
2631		    inet6_n2p(&np->rip6_dest), np->rip6_plen,
2632		    rtflags(rtm));
2633		free(rrt);
2634	} else {
2635		rrt->rrt_next = riprt;
2636		riprt = rrt;
2637	}
2638}
2639
2640int
2641addroute(rrt, gw, ifcp)
2642	struct riprt *rrt;
2643	const struct in6_addr *gw;
2644	struct ifc *ifcp;
2645{
2646	struct	netinfo6 *np;
2647	u_char	buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ];
2648	struct	rt_msghdr	*rtm;
2649	struct	sockaddr_in6	*sin6;
2650	int	len;
2651
2652	np = &rrt->rrt_info;
2653	inet_ntop(AF_INET6, (const void *)gw, (char *)buf1, sizeof(buf1));
2654	inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2));
2655	tracet(1, "ADD: %s/%d gw %s [%d] ifa %s\n",
2656		inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1,
2657		np->rip6_metric - 1, buf2);
2658	if (rtlog)
2659		fprintf(rtlog, "%s: ADD: %s/%d gw %s [%d] ifa %s\n", hms(),
2660			inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1,
2661			np->rip6_metric - 1, buf2);
2662	if (nflag)
2663		return 0;
2664
2665	memset(buf, 0, sizeof(buf));
2666	rtm = (struct rt_msghdr *)buf;
2667	rtm->rtm_type = RTM_ADD;
2668	rtm->rtm_version = RTM_VERSION;
2669	rtm->rtm_seq = ++seq;
2670	rtm->rtm_pid = pid;
2671	rtm->rtm_flags = rrt->rrt_flags;
2672	rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
2673	rtm->rtm_rmx.rmx_hopcount = np->rip6_metric - 1;
2674	rtm->rtm_inits = RTV_HOPCOUNT;
2675	sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
2676	/* Destination */
2677	sin6->sin6_len = sizeof(struct sockaddr_in6);
2678	sin6->sin6_family = AF_INET6;
2679	sin6->sin6_addr = np->rip6_dest;
2680	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
2681	/* Gateway */
2682	sin6->sin6_len = sizeof(struct sockaddr_in6);
2683	sin6->sin6_family = AF_INET6;
2684	sin6->sin6_addr = *gw;
2685	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
2686	/* Netmask */
2687	sin6->sin6_len = sizeof(struct sockaddr_in6);
2688	sin6->sin6_family = AF_INET6;
2689	sin6->sin6_addr = *(plen2mask(np->rip6_plen));
2690	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
2691
2692	len = (char *)sin6 - (char *)buf;
2693	rtm->rtm_msglen = len;
2694	if (write(rtsock, buf, len) > 0)
2695		return 0;
2696
2697	if (errno == EEXIST) {
2698		trace(0, "ADD: Route already exists %s/%d gw %s\n",
2699		    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1);
2700		if (rtlog)
2701			fprintf(rtlog, "ADD: Route already exists %s/%d gw %s\n",
2702			    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1);
2703	} else {
2704		trace(0, "Can not write to rtsock (addroute): %s\n",
2705		    strerror(errno));
2706		if (rtlog)
2707			fprintf(rtlog, "\tCan not write to rtsock: %s\n",
2708			    strerror(errno));
2709	}
2710	return -1;
2711}
2712
2713int
2714delroute(np, gw)
2715	struct netinfo6 *np;
2716	struct in6_addr *gw;
2717{
2718	u_char	buf[BUFSIZ], buf2[BUFSIZ];
2719	struct	rt_msghdr	*rtm;
2720	struct	sockaddr_in6	*sin6;
2721	int	len;
2722
2723	inet_ntop(AF_INET6, (void *)gw, (char *)buf2, sizeof(buf2));
2724	tracet(1, "DEL: %s/%d gw %s\n", inet6_n2p(&np->rip6_dest),
2725		np->rip6_plen, buf2);
2726	if (rtlog)
2727		fprintf(rtlog, "%s: DEL: %s/%d gw %s\n",
2728			hms(), inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
2729	if (nflag)
2730		return 0;
2731
2732	memset(buf, 0, sizeof(buf));
2733	rtm = (struct rt_msghdr *)buf;
2734	rtm->rtm_type = RTM_DELETE;
2735	rtm->rtm_version = RTM_VERSION;
2736	rtm->rtm_seq = ++seq;
2737	rtm->rtm_pid = pid;
2738	rtm->rtm_flags = RTF_UP | RTF_GATEWAY;
2739	if (np->rip6_plen == sizeof(struct in6_addr) * 8)
2740		rtm->rtm_flags |= RTF_HOST;
2741	rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
2742	sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
2743	/* Destination */
2744	sin6->sin6_len = sizeof(struct sockaddr_in6);
2745	sin6->sin6_family = AF_INET6;
2746	sin6->sin6_addr = np->rip6_dest;
2747	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
2748	/* Gateway */
2749	sin6->sin6_len = sizeof(struct sockaddr_in6);
2750	sin6->sin6_family = AF_INET6;
2751	sin6->sin6_addr = *gw;
2752	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
2753	/* Netmask */
2754	sin6->sin6_len = sizeof(struct sockaddr_in6);
2755	sin6->sin6_family = AF_INET6;
2756	sin6->sin6_addr = *(plen2mask(np->rip6_plen));
2757	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
2758
2759	len = (char *)sin6 - (char *)buf;
2760	rtm->rtm_msglen = len;
2761	if (write(rtsock, buf, len) >= 0)
2762		return 0;
2763
2764	if (errno == ESRCH) {
2765		trace(0, "RTDEL: Route does not exist: %s/%d gw %s\n",
2766		    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
2767		if (rtlog)
2768			fprintf(rtlog, "RTDEL: Route does not exist: %s/%d gw %s\n",
2769			    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
2770	} else {
2771		trace(0, "Can not write to rtsock (delroute): %s\n",
2772		    strerror(errno));
2773		if (rtlog)
2774			fprintf(rtlog, "\tCan not write to rtsock: %s\n",
2775			    strerror(errno));
2776	}
2777	return -1;
2778}
2779
2780struct in6_addr *
2781getroute(np, gw)
2782	struct netinfo6 *np;
2783	struct in6_addr *gw;
2784{
2785	u_char buf[BUFSIZ];
2786	u_long myseq;
2787	int len;
2788	struct rt_msghdr *rtm;
2789	struct sockaddr_in6 *sin6;
2790
2791	rtm = (struct rt_msghdr *)buf;
2792	len = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6);
2793	memset(rtm, 0, len);
2794	rtm->rtm_type = RTM_GET;
2795	rtm->rtm_version = RTM_VERSION;
2796	myseq = ++seq;
2797	rtm->rtm_seq = myseq;
2798	rtm->rtm_addrs = RTA_DST;
2799	rtm->rtm_msglen = len;
2800	sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
2801	sin6->sin6_len = sizeof(struct sockaddr_in6);
2802	sin6->sin6_family = AF_INET6;
2803	sin6->sin6_addr = np->rip6_dest;
2804	if (write(rtsock, buf, len) < 0) {
2805		if (errno == ESRCH)	/* No such route found */
2806			return NULL;
2807		perror("write to rtsock");
2808		exit(1);
2809	}
2810	do {
2811		if ((len = read(rtsock, buf, sizeof(buf))) < 0) {
2812			perror("read from rtsock");
2813			exit(1);
2814		}
2815		rtm = (struct rt_msghdr *)buf;
2816	} while (rtm->rtm_seq != myseq || rtm->rtm_pid != pid);
2817	sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
2818	if (rtm->rtm_addrs & RTA_DST) {
2819		sin6 = (struct sockaddr_in6 *)
2820			((char *)sin6 + ROUNDUP(sin6->sin6_len));
2821	}
2822	if (rtm->rtm_addrs & RTA_GATEWAY) {
2823		*gw = sin6->sin6_addr;
2824		return gw;
2825	}
2826	return NULL;
2827}
2828
2829const char *
2830inet6_n2p(p)
2831	const struct in6_addr *p;
2832{
2833	static char buf[BUFSIZ];
2834
2835	return inet_ntop(AF_INET6, (const void *)p, buf, sizeof(buf));
2836}
2837
2838void
2839ifrtdump(sig)
2840	int sig;
2841{
2842
2843	ifdump(sig);
2844	rtdump(sig);
2845}
2846
2847void
2848ifdump(sig)
2849	int sig;
2850{
2851	struct ifc *ifcp;
2852	FILE *dump;
2853	int i;
2854
2855	if (sig == 0)
2856		dump = stderr;
2857	else
2858		if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL)
2859			dump = stderr;
2860
2861	fprintf(dump, "%s: Interface Table Dump\n", hms());
2862	fprintf(dump, "  Number of interfaces: %d\n", nifc);
2863	for (i = 0; i < 2; i++) {
2864		fprintf(dump, "  %sadvertising interfaces:\n", i ? "non-" : "");
2865		for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
2866			if (i == 0) {
2867				if ((ifcp->ifc_flags & IFF_UP) == 0)
2868					continue;
2869				if (iff_find(ifcp, 'N') != NULL)
2870					continue;
2871			} else {
2872				if (ifcp->ifc_flags & IFF_UP)
2873					continue;
2874			}
2875			ifdump0(dump, ifcp);
2876		}
2877	}
2878	fprintf(dump, "\n");
2879	if (dump != stderr)
2880		fclose(dump);
2881}
2882
2883void
2884ifdump0(dump, ifcp)
2885	FILE *dump;
2886	const struct ifc *ifcp;
2887{
2888	struct ifac *ifa;
2889	struct iff *iffp;
2890	char buf[BUFSIZ];
2891	const char *ft;
2892	int addr;
2893
2894	fprintf(dump, "    %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)\n",
2895		ifcp->ifc_name, ifcp->ifc_index, ifflags(ifcp->ifc_flags),
2896		inet6_n2p(&ifcp->ifc_mylladdr),
2897		ifcp->ifc_mtu, ifcp->ifc_metric);
2898	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
2899		if (ifcp->ifc_flags & IFF_POINTOPOINT) {
2900			inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr,
2901				buf, sizeof(buf));
2902			fprintf(dump, "\t%s/%d -- %s\n",
2903				inet6_n2p(&ifa->ifa_addr),
2904				ifa->ifa_plen, buf);
2905		} else {
2906			fprintf(dump, "\t%s/%d\n",
2907				inet6_n2p(&ifa->ifa_addr),
2908				ifa->ifa_plen);
2909		}
2910	}
2911	if (ifcp->ifc_filter) {
2912		fprintf(dump, "\tFilter:");
2913		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
2914			addr = 0;
2915			switch (iffp->iff_type) {
2916			case 'A':
2917				ft = "Aggregate"; addr++; break;
2918			case 'N':
2919				ft = "No-use"; break;
2920			case 'O':
2921				ft = "Advertise-only"; addr++; break;
2922			case 'T':
2923				ft = "Default-only"; break;
2924			case 'L':
2925				ft = "Listen-only"; addr++; break;
2926			default:
2927				snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type);
2928				ft = buf;
2929				addr++;
2930				break;
2931			}
2932			fprintf(dump, " %s", ft);
2933			if (addr) {
2934				fprintf(dump, "(%s/%d)", inet6_n2p(&iffp->iff_addr),
2935					iffp->iff_plen);
2936			}
2937		}
2938		fprintf(dump, "\n");
2939	}
2940}
2941
2942void
2943rtdump(sig)
2944	int sig;
2945{
2946	struct	riprt *rrt;
2947	char	buf[BUFSIZ];
2948	FILE	*dump;
2949	time_t	t, age;
2950
2951	if (sig == 0)
2952		dump = stderr;
2953	else
2954		if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL)
2955			dump = stderr;
2956
2957	t = time(NULL);
2958	fprintf(dump, "\n%s: Routing Table Dump\n", hms());
2959	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
2960		if (rrt->rrt_t == 0)
2961			age = 0;
2962		else
2963			age = t - rrt->rrt_t;
2964		inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest,
2965			buf, sizeof(buf));
2966		fprintf(dump, "    %s/%d if(%d:%s) gw(%s) [%d] age(%ld)",
2967			buf, rrt->rrt_info.rip6_plen, rrt->rrt_index,
2968			index2ifc[rrt->rrt_index]->ifc_name,
2969			inet6_n2p(&rrt->rrt_gw),
2970			rrt->rrt_info.rip6_metric, (long)age);
2971		if (rrt->rrt_info.rip6_tag) {
2972			fprintf(dump, " tag(0x%04x)",
2973				ntohs(rrt->rrt_info.rip6_tag) & 0xffff);
2974		}
2975		if (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)
2976			fprintf(dump, " NOT-LL");
2977		if (rrt->rrt_rflags & RRTF_NOADVERTISE)
2978			fprintf(dump, " NO-ADV");
2979		fprintf(dump, "\n");
2980	}
2981	fprintf(dump, "\n");
2982	if (dump != stderr)
2983		fclose(dump);
2984}
2985
2986/*
2987 * Parse the -A (and -O) options and put corresponding filter object to the
2988 * specified interface structures.  Each of the -A/O option has the following
2989 * syntax:	-A 5f09:c400::/32,ef0,ef1  (aggregate)
2990 * 		-O 5f09:c400::/32,ef0,ef1  (only when match)
2991 */
2992void
2993filterconfig()
2994{
2995	int i;
2996	char *p, *ap, *iflp, *ifname;
2997	struct iff ftmp, *iff_obj;
2998	struct ifc *ifcp;
2999	struct riprt *rrt;
3000#if 0
3001	struct in6_addr gw;
3002#endif
3003
3004	for (i = 0; i < nfilter; i++) {
3005		ap = filter[i];
3006		iflp = NULL;
3007		ifcp = NULL;
3008		if (filtertype[i] == 'N' || filtertype[i] == 'T') {
3009			iflp = ap;
3010			goto ifonly;
3011		}
3012		if ((p = index(ap, ',')) != NULL) {
3013			*p++ = '\0';
3014			iflp = p;
3015		}
3016		if ((p = index(ap, '/')) == NULL) {
3017			fatal("no prefixlen specified for '%s'", ap);
3018			/*NOTREACHED*/
3019		}
3020		*p++ = '\0';
3021		if (inet_pton(AF_INET6, ap, &ftmp.iff_addr) != 1) {
3022			fatal("invalid prefix specified for '%s'", ap);
3023			/*NOTREACHED*/
3024		}
3025		ftmp.iff_plen = atoi(p);
3026		ftmp.iff_next = NULL;
3027		applyplen(&ftmp.iff_addr, ftmp.iff_plen);
3028ifonly:
3029		ftmp.iff_type = filtertype[i];
3030		if (iflp == NULL || *iflp == '\0') {
3031			fatal("no interface specified for '%s'", ap);
3032			/*NOTREACHED*/
3033		}
3034		/* parse the interface listing portion */
3035		while (iflp) {
3036			ifname = iflp;
3037			if ((iflp = index(iflp, ',')) != NULL)
3038				*iflp++ = '\0';
3039			ifcp = ifc_find(ifname);
3040			if (ifcp == NULL) {
3041				fatal("no interface %s exists", ifname);
3042				/*NOTREACHED*/
3043			}
3044			iff_obj = (struct iff *)malloc(sizeof(struct iff));
3045			if (iff_obj == NULL) {
3046				fatal("malloc of iff_obj");
3047				/*NOTREACHED*/
3048			}
3049			memcpy((void *)iff_obj, (void *)&ftmp,
3050			    sizeof(struct iff));
3051			/* link it to the interface filter */
3052			iff_obj->iff_next = ifcp->ifc_filter;
3053			ifcp->ifc_filter = iff_obj;
3054		}
3055
3056		/*
3057		 * -A: aggregate configuration.
3058		 */
3059		if (filtertype[i] != 'A')
3060			continue;
3061		/* put the aggregate to the kernel routing table */
3062		rrt = (struct riprt *)malloc(sizeof(struct riprt));
3063		if (rrt == NULL) {
3064			fatal("malloc: rrt");
3065			/*NOTREACHED*/
3066		}
3067		memset(rrt, 0, sizeof(struct riprt));
3068		rrt->rrt_info.rip6_dest = ftmp.iff_addr;
3069		rrt->rrt_info.rip6_plen = ftmp.iff_plen;
3070		rrt->rrt_info.rip6_metric = 1;
3071		rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
3072		rrt->rrt_gw = in6addr_loopback;
3073		rrt->rrt_flags = RTF_UP | RTF_REJECT;
3074		rrt->rrt_rflags = RRTF_AGGREGATE;
3075		rrt->rrt_t = 0;
3076		rrt->rrt_index = loopifindex;
3077#if 0
3078		if (getroute(&rrt->rrt_info, &gw)) {
3079#if 0
3080			/*
3081			 * When the address has already been registered in the
3082			 * kernel routing table, it should be removed
3083			 */
3084			delroute(&rrt->rrt_info, &gw);
3085#else
3086			/* it is safer behavior */
3087			errno = EINVAL;
3088			fatal("%s/%u already in routing table, "
3089			    "cannot aggregate",
3090			    inet6_n2p(&rrt->rrt_info.rip6_dest),
3091			    rrt->rrt_info.rip6_plen);
3092			/*NOTREACHED*/
3093#endif
3094		}
3095#endif
3096		/* Put the route to the list */
3097		rrt->rrt_next = riprt;
3098		riprt = rrt;
3099		trace(1, "Aggregate: %s/%d for %s\n",
3100			inet6_n2p(&ftmp.iff_addr), ftmp.iff_plen,
3101			ifcp->ifc_name);
3102		/* Add this route to the kernel */
3103		if (nflag) 	/* do not modify kernel routing table */
3104			continue;
3105		addroute(rrt, &in6addr_loopback, loopifcp);
3106	}
3107}
3108
3109/***************** utility functions *****************/
3110
3111/*
3112 * Returns a pointer to ifac whose address and prefix length matches
3113 * with the address and prefix length specified in the arguments.
3114 */
3115struct ifac *
3116ifa_match(ifcp, ia, plen)
3117	const struct ifc *ifcp;
3118	const struct in6_addr *ia;
3119	int plen;
3120{
3121	struct ifac *ifa;
3122
3123	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
3124		if (IN6_ARE_ADDR_EQUAL(&ifa->ifa_addr, ia) &&
3125		    ifa->ifa_plen == plen)
3126			break;
3127	}
3128	return ifa;
3129}
3130
3131/*
3132 * Return a pointer to riprt structure whose address and prefix length
3133 * matches with the address and prefix length found in the argument.
3134 * Note: This is not a rtalloc().  Therefore exact match is necessary.
3135 */
3136struct riprt *
3137rtsearch(np, prev_rrt)
3138	struct	netinfo6 *np;
3139	struct	riprt **prev_rrt;
3140{
3141	struct	riprt	*rrt;
3142
3143	if (prev_rrt)
3144		*prev_rrt = NULL;
3145	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
3146		if (rrt->rrt_info.rip6_plen == np->rip6_plen &&
3147		    IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
3148				       &np->rip6_dest))
3149			return rrt;
3150		if (prev_rrt)
3151			*prev_rrt = rrt;
3152	}
3153	if (prev_rrt)
3154		*prev_rrt = NULL;
3155	return 0;
3156}
3157
3158int
3159sin6mask2len(sin6)
3160	const struct sockaddr_in6 *sin6;
3161{
3162
3163	return mask2len(&sin6->sin6_addr,
3164	    sin6->sin6_len - offsetof(struct sockaddr_in6, sin6_addr));
3165}
3166
3167int
3168mask2len(addr, lenlim)
3169	const struct in6_addr *addr;
3170	int lenlim;
3171{
3172	int i = 0, j;
3173	const u_char *p = (const u_char *)addr;
3174
3175	for (j = 0; j < lenlim; j++, p++) {
3176		if (*p != 0xff)
3177			break;
3178		i += 8;
3179	}
3180	if (j < lenlim) {
3181		switch (*p) {
3182#define	MASKLEN(m, l)	case m: do { i += l; break; } while (0)
3183		MASKLEN(0xfe, 7); break;
3184		MASKLEN(0xfc, 6); break;
3185		MASKLEN(0xf8, 5); break;
3186		MASKLEN(0xf0, 4); break;
3187		MASKLEN(0xe0, 3); break;
3188		MASKLEN(0xc0, 2); break;
3189		MASKLEN(0x80, 1); break;
3190#undef	MASKLEN
3191		}
3192	}
3193	return i;
3194}
3195
3196void
3197applymask(addr, mask)
3198	struct in6_addr *addr, *mask;
3199{
3200	int	i;
3201	u_long	*p, *q;
3202
3203	p = (u_long *)addr; q = (u_long *)mask;
3204	for (i = 0; i < 4; i++)
3205		*p++ &= *q++;
3206}
3207
3208static const u_char plent[8] = {
3209	0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
3210};
3211
3212void
3213applyplen(ia, plen)
3214	struct	in6_addr *ia;
3215	int	plen;
3216{
3217	u_char	*p;
3218	int	i;
3219
3220	p = ia->s6_addr;
3221	for (i = 0; i < 16; i++) {
3222		if (plen <= 0)
3223			*p = 0;
3224		else if (plen < 8)
3225			*p &= plent[plen];
3226		p++, plen -= 8;
3227	}
3228}
3229
3230static const int pl2m[9] = {
3231	0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
3232};
3233
3234struct in6_addr *
3235plen2mask(n)
3236	int	n;
3237{
3238	static struct in6_addr ia;
3239	u_char	*p;
3240	int	i;
3241
3242	memset(&ia, 0, sizeof(struct in6_addr));
3243	p = (u_char *)&ia;
3244	for (i = 0; i < 16; i++, p++, n -= 8) {
3245		if (n >= 8) {
3246			*p = 0xff;
3247			continue;
3248		}
3249		*p = pl2m[n];
3250		break;
3251	}
3252	return &ia;
3253}
3254
3255char *
3256allocopy(p)
3257	char *p;
3258{
3259	int len = strlen(p) + 1;
3260	char *q = (char *)malloc(len);
3261
3262	if (!q) {
3263		fatal("malloc");
3264		/*NOTREACHED*/
3265	}
3266
3267	strlcpy(q, p, len);
3268	return q;
3269}
3270
3271char *
3272hms()
3273{
3274	static char buf[BUFSIZ];
3275	time_t t;
3276	struct	tm *tm;
3277
3278	t = time(NULL);
3279	if ((tm = localtime(&t)) == 0) {
3280		fatal("localtime");
3281		/*NOTREACHED*/
3282	}
3283	snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
3284	    tm->tm_sec);
3285	return buf;
3286}
3287
3288#define	RIPRANDDEV	1.0	/* 30 +- 15, max - min = 30 */
3289
3290int
3291ripinterval(timer)
3292	int timer;
3293{
3294	double r = rand();
3295
3296	interval = (int)(timer + timer * RIPRANDDEV * (r / RAND_MAX - 0.5));
3297	nextalarm = time(NULL) + interval;
3298	return interval;
3299}
3300
3301time_t
3302ripsuptrig()
3303{
3304	time_t t;
3305
3306	double r = rand();
3307	t  = (int)(RIP_TRIG_INT6_MIN +
3308		(RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / RAND_MAX));
3309	sup_trig_update = time(NULL) + t;
3310	return t;
3311}
3312
3313void
3314#ifdef __STDC__
3315fatal(const char *fmt, ...)
3316#else
3317fatal(fmt, va_alist)
3318	char	*fmt;
3319	va_dcl
3320#endif
3321{
3322	va_list ap;
3323	char buf[1024];
3324
3325#ifdef __STDC__
3326	va_start(ap, fmt);
3327#else
3328	va_start(ap);
3329#endif
3330	vsnprintf(buf, sizeof(buf), fmt, ap);
3331	perror(buf);
3332	syslog(LOG_ERR, "%s: %s", buf, strerror(errno));
3333	rtdexit();
3334	va_end(ap);
3335}
3336
3337void
3338#ifdef __STDC__
3339tracet(int level, const char *fmt, ...)
3340#else
3341tracet(level, fmt, va_alist)
3342	int level;
3343	char *fmt;
3344	va_dcl
3345#endif
3346{
3347	va_list ap;
3348
3349#ifdef __STDC__
3350	va_start(ap, fmt);
3351#else
3352	va_start(ap);
3353#endif
3354	if (level <= dflag) {
3355		fprintf(stderr, "%s: ", hms());
3356		vfprintf(stderr, fmt, ap);
3357	}
3358	if (dflag) {
3359		if (level > 0)
3360			vsyslog(LOG_DEBUG, fmt, ap);
3361		else
3362			vsyslog(LOG_WARNING, fmt, ap);
3363	}
3364	va_end(ap);
3365}
3366
3367void
3368#ifdef __STDC__
3369trace(int level, const char *fmt, ...)
3370#else
3371trace(level, fmt, va_alist)
3372	int level;
3373	char *fmt;
3374	va_dcl
3375#endif
3376{
3377	va_list ap;
3378
3379#ifdef __STDC__
3380	va_start(ap, fmt);
3381#else
3382	va_start(ap);
3383#endif
3384	if (level <= dflag)
3385		vfprintf(stderr, fmt, ap);
3386	if (dflag) {
3387		if (level > 0)
3388			vsyslog(LOG_DEBUG, fmt, ap);
3389		else
3390			vsyslog(LOG_WARNING, fmt, ap);
3391	}
3392	va_end(ap);
3393}
3394
3395unsigned int
3396if_maxindex()
3397{
3398	struct if_nameindex *p, *p0;
3399	unsigned int max = 0;
3400
3401	p0 = if_nameindex();
3402	for (p = p0; p && p->if_index && p->if_name; p++) {
3403		if (max < p->if_index)
3404			max = p->if_index;
3405	}
3406	if_freenameindex(p0);
3407	return max;
3408}
3409
3410struct ifc *
3411ifc_find(name)
3412	char *name;
3413{
3414	struct ifc *ifcp;
3415
3416	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
3417		if (strcmp(name, ifcp->ifc_name) == 0)
3418			return ifcp;
3419	}
3420	return (struct ifc *)NULL;
3421}
3422
3423struct iff *
3424iff_find(ifcp, type)
3425	struct ifc *ifcp;
3426	int type;
3427{
3428	struct iff *iffp;
3429
3430	for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
3431		if (iffp->iff_type == type)
3432			return iffp;
3433	}
3434	return NULL;
3435}
3436
3437void
3438setindex2ifc(idx, ifcp)
3439	int idx;
3440	struct ifc *ifcp;
3441{
3442	int n;
3443	struct ifc **p;
3444
3445	if (!index2ifc) {
3446		nindex2ifc = 5;	/*initial guess*/
3447		index2ifc = (struct ifc **)
3448			malloc(sizeof(*index2ifc) * nindex2ifc);
3449		if (index2ifc == NULL) {
3450			fatal("malloc");
3451			/*NOTREACHED*/
3452		}
3453		memset(index2ifc, 0, sizeof(*index2ifc) * nindex2ifc);
3454	}
3455	n = nindex2ifc;
3456	while (nindex2ifc <= idx)
3457		nindex2ifc *= 2;
3458	if (n != nindex2ifc) {
3459		p = (struct ifc **)realloc(index2ifc,
3460		    sizeof(*index2ifc) * nindex2ifc);
3461		if (p == NULL) {
3462			fatal("realloc");
3463			/*NOTREACHED*/
3464		}
3465		memset(p + n, 0, sizeof(*index2ifc) * (nindex2ifc - n));
3466		index2ifc = p;
3467	}
3468	index2ifc[idx] = ifcp;
3469}
3470