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