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