route6d.c revision 122677
162607Sitojun/*	$FreeBSD: head/usr.sbin/route6d/route6d.c 122677 2003-11-14 17:16:50Z ume $	*/
2122677Sume/*	$KAME: route6d.c,v 1.104 2003/10/31 00:30:20 itojun Exp $	*/
355163Sshin
455163Sshin/*
555163Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
655163Sshin * All rights reserved.
762607Sitojun *
855163Sshin * Redistribution and use in source and binary forms, with or without
955163Sshin * modification, are permitted provided that the following conditions
1055163Sshin * are met:
1155163Sshin * 1. Redistributions of source code must retain the above copyright
1255163Sshin *    notice, this list of conditions and the following disclaimer.
1355163Sshin * 2. Redistributions in binary form must reproduce the above copyright
1455163Sshin *    notice, this list of conditions and the following disclaimer in the
1555163Sshin *    documentation and/or other materials provided with the distribution.
1655163Sshin * 3. Neither the name of the project nor the names of its contributors
1755163Sshin *    may be used to endorse or promote products derived from this software
1855163Sshin *    without specific prior written permission.
1962607Sitojun *
2055163Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2155163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2255163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2355163Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2455163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2555163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2655163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2755163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2855163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2955163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3055163Sshin * SUCH DAMAGE.
3155163Sshin */
3255163Sshin
3355163Sshin#ifndef	lint
34122677Sumestatic char _rcsid[] = "$KAME: route6d.c,v 1.104 2003/10/31 00:30:20 itojun Exp $";
3555163Sshin#endif
3655163Sshin
3755163Sshin#include <stdio.h>
3855163Sshin
3955163Sshin#include <time.h>
4055163Sshin#include <unistd.h>
4155163Sshin#include <stdlib.h>
4255163Sshin#include <string.h>
4355163Sshin#include <signal.h>
4455163Sshin#ifdef __STDC__
4555163Sshin#include <stdarg.h>
4655163Sshin#else
4755163Sshin#include <varargs.h>
4855163Sshin#endif
4955163Sshin#include <syslog.h>
5055163Sshin#include <stddef.h>
5162607Sitojun#include <errno.h>
5255163Sshin#include <err.h>
53119076Sume#ifdef HAVE_POLL_H
54119076Sume#include <poll.h>
55119076Sume#endif
5655163Sshin
5755163Sshin#include <sys/types.h>
5855163Sshin#include <sys/param.h>
5955163Sshin#include <sys/file.h>
6055163Sshin#include <sys/socket.h>
6155163Sshin#include <sys/ioctl.h>
6255163Sshin#include <sys/sysctl.h>
6355163Sshin#include <sys/uio.h>
6455163Sshin#include <net/if.h>
6555163Sshin#include <net/if_var.h>
6662607Sitojun#define	_KERNEL	1
6755163Sshin#include <net/route.h>
6862607Sitojun#undef _KERNEL
6955163Sshin#include <netinet/in.h>
7055163Sshin#include <netinet/in_var.h>
7155163Sshin#include <netinet/ip6.h>
7255163Sshin#include <netinet/udp.h>
7355163Sshin#include <netdb.h>
7462607Sitojun#include <ifaddrs.h>
7555163Sshin
7655163Sshin#include <arpa/inet.h>
7755163Sshin
7855163Sshin#include "route6d.h"
7955163Sshin
8055163Sshin#define	MAXFILTER	40
8155163Sshin
8255163Sshin#ifdef	DEBUG
8355163Sshin#define	INIT_INTERVAL6	6
8455163Sshin#else
85119039Sume#define	INIT_INTERVAL6	10	/* Wait to submit an initial riprequest */
8655163Sshin#endif
8755163Sshin
8855163Sshin/* alignment constraint for routing socket */
8962607Sitojun#define ROUNDUP(a) \
9055163Sshin	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
9162607Sitojun#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
9255163Sshin
9355163Sshin/*
9455163Sshin * Following two macros are highly depending on KAME Release
9555163Sshin */
9655163Sshin#define	IN6_LINKLOCAL_IFINDEX(addr) \
9755163Sshin	((addr).s6_addr[2] << 8 | (addr).s6_addr[3])
9855163Sshin
9955163Sshin#define	SET_IN6_LINKLOCAL_IFINDEX(addr, index) \
10055163Sshin	do { \
10155163Sshin		(addr).s6_addr[2] = ((index) >> 8) & 0xff; \
10255163Sshin		(addr).s6_addr[3] = (index) & 0xff; \
10355163Sshin	} while (0)
10455163Sshin
10555163Sshinstruct	ifc {			/* Configuration of an interface */
10655163Sshin	char	*ifc_name;			/* if name */
10755163Sshin	struct	ifc *ifc_next;
10855163Sshin	int	ifc_index;			/* if index */
10955163Sshin	int	ifc_mtu;			/* if mtu */
11055163Sshin	int	ifc_metric;			/* if metric */
11178064Sume	u_int	ifc_flags;			/* flags */
11278064Sume	short	ifc_cflags;			/* IFC_XXX */
11355163Sshin	struct	in6_addr ifc_mylladdr;		/* my link-local address */
11455163Sshin	struct	sockaddr_in6 ifc_ripsin;	/* rip multicast address */
11555163Sshin	struct	iff *ifc_filter;		/* filter structure */
11655163Sshin	struct	ifac *ifc_addr;			/* list of AF_INET6 addresses */
11755163Sshin	int	ifc_joined;			/* joined to ff02::9 */
11855163Sshin};
11955163Sshin
12062607Sitojunstruct	ifac {			/* Adddress associated to an interface */
12155163Sshin	struct	ifc *ifa_conf;		/* back pointer */
12255163Sshin	struct	ifac *ifa_next;
12355163Sshin	struct	in6_addr ifa_addr;	/* address */
12455163Sshin	struct	in6_addr ifa_raddr;	/* remote address, valid in p2p */
12555163Sshin	int	ifa_plen;		/* prefix length */
12655163Sshin};
12755163Sshin
12855163Sshinstruct	iff {
12955163Sshin	int	iff_type;
13055163Sshin	struct	in6_addr iff_addr;
13155163Sshin	int	iff_plen;
13255163Sshin	struct	iff *iff_next;
13355163Sshin};
13455163Sshin
13555163Sshinstruct	ifc *ifc;
13655163Sshinint	nifc;		/* number of valid ifc's */
13755163Sshinstruct	ifc **index2ifc;
13855163Sshinint	nindex2ifc;
13955163Sshinstruct	ifc *loopifcp = NULL;	/* pointing to loopback */
140119076Sume#ifdef HAVE_POLL_H
141119076Sumestruct	pollfd set[2];
142119076Sume#else
143119070Sumefd_set	*sockvecp;	/* vector to select() for receiving */
144119070Sumefd_set	*recvecp;
145119070Sumeint	fdmasks;
146119070Sumeint	maxfd;		/* maximum fd for select() */
147119076Sume#endif
14855163Sshinint	rtsock;		/* the routing socket */
14955163Sshinint	ripsock;	/* socket to send/receive RIP datagram */
15055163Sshin
15155163Sshinstruct	rip6 *ripbuf;	/* packet buffer for sending */
15255163Sshin
15355163Sshin/*
15478064Sume * Maintain the routes in a linked list.  When the number of the routes
15555163Sshin * grows, somebody would like to introduce a hash based or a radix tree
15678064Sume * based structure.  I believe the number of routes handled by RIP is
15755163Sshin * limited and I don't have to manage a complex data structure, however.
15855163Sshin *
15955163Sshin * One of the major drawbacks of the linear linked list is the difficulty
16078064Sume * of representing the relationship between a couple of routes.  This may
16155163Sshin * be a significant problem when we have to support route aggregation with
16255163Sshin * supressing the specifices covered by the aggregate.
16355163Sshin */
16455163Sshin
16555163Sshinstruct	riprt {
16655163Sshin	struct	riprt *rrt_next;	/* next destination */
16755163Sshin	struct	riprt *rrt_same;	/* same destination - future use */
16855163Sshin	struct	netinfo6 rrt_info;	/* network info */
16955163Sshin	struct	in6_addr rrt_gw;	/* gateway */
17062607Sitojun	u_long	rrt_flags;		/* kernel routing table flags */
17162607Sitojun	u_long	rrt_rflags;		/* route6d routing table flags */
17255163Sshin	time_t	rrt_t;			/* when the route validated */
17355163Sshin	int	rrt_index;		/* ifindex from which this route got */
17455163Sshin};
17555163Sshin
17655163Sshinstruct	riprt *riprt = 0;
17755163Sshin
17855163Sshinint	dflag = 0;	/* debug flag */
17955163Sshinint	qflag = 0;	/* quiet flag */
18055163Sshinint	nflag = 0;	/* don't update kernel routing table */
18155163Sshinint	aflag = 0;	/* age out even the statically defined routes */
18255163Sshinint	hflag = 0;	/* don't split horizon */
18355163Sshinint	lflag = 0;	/* exchange site local routes */
18455163Sshinint	sflag = 0;	/* announce static routes w/ split horizon */
18555163Sshinint	Sflag = 0;	/* announce static routes to every interface */
18662607Sitojununsigned long routetag = 0;	/* route tag attached on originating case */
18755163Sshin
18855163Sshinchar	*filter[MAXFILTER];
18955163Sshinint	filtertype[MAXFILTER];
19055163Sshinint	nfilter = 0;
19155163Sshin
19255163Sshinpid_t	pid;
19355163Sshin
19455163Sshinstruct	sockaddr_storage ripsin;
19555163Sshin
19655163Sshinint	interval = 1;
19755163Sshintime_t	nextalarm = 0;
19855163Sshintime_t	sup_trig_update = 0;
19955163Sshin
20055163SshinFILE	*rtlog = NULL;
20155163Sshin
20255163Sshinint logopened = 0;
20355163Sshin
204119085Sumestatic	int	seq = 0;
20555163Sshin
20678064Sumevolatile sig_atomic_t seenalrm;
20778064Sumevolatile sig_atomic_t seenquit;
20878064Sumevolatile sig_atomic_t seenusr1;
20978064Sume
21062607Sitojun#define	RRTF_AGGREGATE		0x08000000
21162607Sitojun#define	RRTF_NOADVERTISE	0x10000000
21262607Sitojun#define	RRTF_NH_NOT_LLADDR	0x20000000
21362607Sitojun#define RRTF_SENDANYWAY		0x40000000
21462607Sitojun#define	RRTF_CHANGED		0x80000000
21555163Sshin
21655163Sshinint main __P((int, char **));
21778064Sumevoid sighandler __P((int));
21878064Sumevoid ripalarm __P((void));
21955163Sshinvoid riprecv __P((void));
22055163Sshinvoid ripsend __P((struct ifc *, struct sockaddr_in6 *, int));
22178064Sumeint out_filter __P((struct riprt *, struct ifc *));
22255163Sshinvoid init __P((void));
22355163Sshinvoid sockopt __P((struct ifc *));
22455163Sshinvoid ifconfig __P((void));
22562607Sitojunvoid ifconfig1 __P((const char *, const struct sockaddr *, struct ifc *, int));
22655163Sshinvoid rtrecv __P((void));
22755163Sshinint rt_del __P((const struct sockaddr_in6 *, const struct sockaddr_in6 *,
22855163Sshin	const struct sockaddr_in6 *));
22955163Sshinint rt_deladdr __P((struct ifc *, const struct sockaddr_in6 *,
23055163Sshin	const struct sockaddr_in6 *));
23155163Sshinvoid filterconfig __P((void));
23255163Sshinint getifmtu __P((int));
23378064Sumeconst char *rttypes __P((struct rt_msghdr *));
23478064Sumeconst char *rtflags __P((struct rt_msghdr *));
23578064Sumeconst char *ifflags __P((int));
23678064Sumeint ifrt __P((struct ifc *, int));
23762607Sitojunvoid ifrt_p2p __P((struct ifc *, int));
23855163Sshinvoid applymask __P((struct in6_addr *, struct in6_addr *));
23955163Sshinvoid applyplen __P((struct in6_addr *, int));
24055163Sshinvoid ifrtdump __P((int));
24155163Sshinvoid ifdump __P((int));
24255163Sshinvoid ifdump0 __P((FILE *, const struct ifc *));
24355163Sshinvoid rtdump __P((int));
24455163Sshinvoid rt_entry __P((struct rt_msghdr *, int));
24578064Sumevoid rtdexit __P((void));
24678064Sumevoid riprequest __P((struct ifc *, struct netinfo6 *, int,
24778064Sume	struct sockaddr_in6 *));
24855163Sshinvoid ripflush __P((struct ifc *, struct sockaddr_in6 *));
24955163Sshinvoid sendrequest __P((struct ifc *));
25078064Sumeint sin6mask2len __P((const struct sockaddr_in6 *));
25155163Sshinint mask2len __P((const struct in6_addr *, int));
25255163Sshinint sendpacket __P((struct sockaddr_in6 *, int));
25355163Sshinint addroute __P((struct riprt *, const struct in6_addr *, struct ifc *));
25455163Sshinint delroute __P((struct netinfo6 *, struct in6_addr *));
25555163Sshinstruct in6_addr *getroute __P((struct netinfo6 *, struct in6_addr *));
25655163Sshinvoid krtread __P((int));
25755163Sshinint tobeadv __P((struct riprt *, struct ifc *));
25855163Sshinchar *allocopy __P((char *));
25955163Sshinchar *hms __P((void));
26055163Sshinconst char *inet6_n2p __P((const struct in6_addr *));
26155163Sshinstruct ifac *ifa_match __P((const struct ifc *, const struct in6_addr *, int));
26255163Sshinstruct in6_addr *plen2mask __P((int));
26378064Sumestruct riprt *rtsearch __P((struct netinfo6 *, struct riprt **));
26455163Sshinint ripinterval __P((int));
26555163Sshintime_t ripsuptrig __P((void));
26666807Skrisvoid fatal __P((const char *, ...))
26766807Skris	__attribute__((__format__(__printf__, 1, 2)));
26866807Skrisvoid trace __P((int, const char *, ...))
26966807Skris	__attribute__((__format__(__printf__, 2, 3)));
27066807Skrisvoid tracet __P((int, const char *, ...))
27166807Skris	__attribute__((__format__(__printf__, 2, 3)));
27255163Sshinunsigned int if_maxindex __P((void));
27355163Sshinstruct ifc *ifc_find __P((char *));
27455163Sshinstruct iff *iff_find __P((struct ifc *, int));
27555163Sshinvoid setindex2ifc __P((int, struct ifc *));
27655163Sshin
27755163Sshin#define	MALLOC(type)	((type *)malloc(sizeof(type)))
27855163Sshin
27955163Sshinint
28055163Sshinmain(argc, argv)
28155163Sshin	int	argc;
28255163Sshin	char	**argv;
28355163Sshin{
28455163Sshin	int	ch;
28555163Sshin	int	error = 0;
28655163Sshin	struct	ifc *ifcp;
28755163Sshin	sigset_t mask, omask;
28855163Sshin	FILE	*pidfile;
28955163Sshin	char *progname;
29062607Sitojun	char *ep;
29155163Sshin
29255163Sshin	progname = strrchr(*argv, '/');
29355163Sshin	if (progname)
29455163Sshin		progname++;
29555163Sshin	else
29655163Sshin		progname = *argv;
29755163Sshin
29855163Sshin	pid = getpid();
29978064Sume	while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnqsS")) != -1) {
30055163Sshin		switch (ch) {
30155163Sshin		case 'A':
30255163Sshin		case 'N':
30355163Sshin		case 'O':
30455163Sshin		case 'T':
30555163Sshin		case 'L':
30662607Sitojun			if (nfilter >= MAXFILTER) {
30755163Sshin				fatal("Exceeds MAXFILTER");
30862607Sitojun				/*NOTREACHED*/
30962607Sitojun			}
31055163Sshin			filtertype[nfilter] = ch;
31155163Sshin			filter[nfilter++] = allocopy(optarg);
31255163Sshin			break;
31355163Sshin		case 't':
31462607Sitojun			ep = NULL;
31562607Sitojun			routetag = strtoul(optarg, &ep, 0);
31662607Sitojun			if (!ep || *ep != '\0' || (routetag & ~0xffff) != 0) {
31755163Sshin				fatal("invalid route tag");
31855163Sshin				/*NOTREACHED*/
31955163Sshin			}
32055163Sshin			break;
32155163Sshin		case 'R':
32262607Sitojun			if ((rtlog = fopen(optarg, "w")) == NULL) {
32355163Sshin				fatal("Can not write to routelog");
32462607Sitojun				/*NOTREACHED*/
32562607Sitojun			}
32655163Sshin			break;
32762607Sitojun#define	FLAG(c, flag, n)	case c: do { flag = n; break; } while(0)
32862607Sitojun		FLAG('a', aflag, 1); break;
32962607Sitojun		FLAG('d', dflag, 1); break;
33062607Sitojun		FLAG('D', dflag, 2); break;
33162607Sitojun		FLAG('h', hflag, 1); break;
33262607Sitojun		FLAG('l', lflag, 1); break;
33362607Sitojun		FLAG('n', nflag, 1); break;
33462607Sitojun		FLAG('q', qflag, 1); break;
33562607Sitojun		FLAG('s', sflag, 1); break;
33662607Sitojun		FLAG('S', Sflag, 1); break;
33755163Sshin#undef	FLAG
33855163Sshin		default:
33955163Sshin			fatal("Invalid option specified, terminating");
34062607Sitojun			/*NOTREACHED*/
34155163Sshin		}
34255163Sshin	}
34355163Sshin	argc -= optind;
34455163Sshin	argv += optind;
34578064Sume	if (argc > 0) {
34655163Sshin		fatal("bogus extra arguments");
34778064Sume		/*NOTREACHED*/
34878064Sume	}
34955163Sshin
35055163Sshin	if (geteuid()) {
35155163Sshin		nflag = 1;
35255163Sshin		fprintf(stderr, "No kernel update is allowed\n");
35355163Sshin	}
354119037Sume
355119037Sume	if (dflag == 0) {
356119037Sume		if (daemon(0, 0) < 0) {
357119037Sume			fatal("daemon");
358119037Sume			/*NOTREACHED*/
359119037Sume		}
360119037Sume	}
361119037Sume
36255163Sshin	openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON);
36355163Sshin	logopened++;
36478064Sume
36578064Sume	if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL)
36678064Sume		fatal("malloc");
36778064Sume	memset(ripbuf, 0, RIP6_MAXMTU);
36878064Sume	ripbuf->rip6_cmd = RIP6_RESPONSE;
36978064Sume	ripbuf->rip6_vers = RIP6_VERSION;
37078064Sume	ripbuf->rip6_res1[0] = 0;
37178064Sume	ripbuf->rip6_res1[1] = 0;
37278064Sume
37355163Sshin	init();
37455163Sshin	ifconfig();
37555163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
37655163Sshin		if (ifcp->ifc_index < 0) {
37755163Sshin			fprintf(stderr,
37855163Sshin"No ifindex found at %s (no link-local address?)\n",
37955163Sshin				ifcp->ifc_name);
38055163Sshin			error++;
38155163Sshin		}
38255163Sshin	}
38355163Sshin	if (error)
38455163Sshin		exit(1);
38578064Sume	if (loopifcp == NULL) {
38655163Sshin		fatal("No loopback found");
38778064Sume		/*NOTREACHED*/
38878064Sume	}
38955163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next)
39055163Sshin		ifrt(ifcp, 0);
39155163Sshin	filterconfig();
39255163Sshin	krtread(0);
39355163Sshin	if (dflag)
39455163Sshin		ifrtdump(0);
39555163Sshin
396122677Sume#if 1
39755163Sshin	pid = getpid();
39855163Sshin	if ((pidfile = fopen(ROUTE6D_PID, "w")) != NULL) {
39955163Sshin		fprintf(pidfile, "%d\n", pid);
40055163Sshin		fclose(pidfile);
40155163Sshin	}
402122677Sume#endif
40355163Sshin
40478064Sume	if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) {
40555163Sshin		fatal("malloc");
40678064Sume		/*NOTREACHED*/
40778064Sume	}
40862607Sitojun	memset(ripbuf, 0, RIP6_MAXMTU);
40955163Sshin	ripbuf->rip6_cmd = RIP6_RESPONSE;
41055163Sshin	ripbuf->rip6_vers = RIP6_VERSION;
41155163Sshin	ripbuf->rip6_res1[0] = 0;
41255163Sshin	ripbuf->rip6_res1[1] = 0;
41355163Sshin
41478064Sume	if (signal(SIGALRM, sighandler) == SIG_ERR ||
41578064Sume	    signal(SIGQUIT, sighandler) == SIG_ERR ||
41678064Sume	    signal(SIGTERM, sighandler) == SIG_ERR ||
41778064Sume	    signal(SIGUSR1, sighandler) == SIG_ERR ||
41878064Sume	    signal(SIGHUP, sighandler) == SIG_ERR ||
41978064Sume	    signal(SIGINT, sighandler) == SIG_ERR) {
42078064Sume		fatal("signal");
42178064Sume		/*NOTREACHED*/
42278064Sume	}
42355163Sshin	/*
42455163Sshin	 * To avoid rip packet congestion (not on a cable but in this
42555163Sshin	 * process), wait for a moment to send the first RIP6_RESPONSE
42655163Sshin	 * packets.
42755163Sshin	 */
42855163Sshin	alarm(ripinterval(INIT_INTERVAL6));
42955163Sshin
43055163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
431119041Sume		if (iff_find(ifcp, 'N'))
432119041Sume			continue;
43355163Sshin		if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP))
43455163Sshin			sendrequest(ifcp);
43555163Sshin	}
43655163Sshin
43755163Sshin	syslog(LOG_INFO, "**** Started ****");
43855163Sshin	sigemptyset(&mask);
43955163Sshin	sigaddset(&mask, SIGALRM);
44055163Sshin	while (1) {
44178064Sume		if (seenalrm) {
44278064Sume			ripalarm();
44378064Sume			seenalrm = 0;
44478064Sume			continue;
44578064Sume		}
44678064Sume		if (seenquit) {
44778064Sume			rtdexit();
44878064Sume			seenquit = 0;
44978064Sume			continue;
45078064Sume		}
45178064Sume		if (seenusr1) {
45278064Sume			ifrtdump(SIGUSR1);
45378064Sume			seenusr1 = 0;
45478064Sume			continue;
45578064Sume		}
45678064Sume
457119076Sume#ifdef HAVE_POLL_H
458119076Sume		switch (poll(set, 2, INFTIM))
459119076Sume#else
460119070Sume		memcpy(recvecp, sockvecp, fdmasks);
461119076Sume		switch (select(maxfd + 1, recvecp, 0, 0, 0))
462119076Sume#endif
463119076Sume		{
46455163Sshin		case -1:
46578064Sume			if (errno != EINTR) {
46678064Sume				fatal("select");
46778064Sume				/*NOTREACHED*/
46878064Sume			}
46978064Sume			continue;
47055163Sshin		case 0:
47155163Sshin			continue;
47255163Sshin		default:
473119076Sume#ifdef HAVE_POLL_H
474119076Sume			if (set[0].revents & POLLIN)
475119076Sume#else
476119076Sume			if (FD_ISSET(ripsock, recvecp))
477119076Sume#endif
478119076Sume			{
47955163Sshin				sigprocmask(SIG_BLOCK, &mask, &omask);
48055163Sshin				riprecv();
48155163Sshin				sigprocmask(SIG_SETMASK, &omask, NULL);
48255163Sshin			}
483119076Sume#ifdef HAVE_POLL_H
484119076Sume			if (set[1].revents & POLLIN)
485119076Sume#else
486119076Sume			if (FD_ISSET(rtsock, recvecp))
487119076Sume#endif
488119076Sume			{
48955163Sshin				sigprocmask(SIG_BLOCK, &mask, &omask);
49055163Sshin				rtrecv();
49155163Sshin				sigprocmask(SIG_SETMASK, &omask, NULL);
49255163Sshin			}
49355163Sshin		}
49455163Sshin	}
49555163Sshin}
49655163Sshin
49778064Sumevoid
498119079Sumesighandler(signo)
499119079Sume	int signo;
50078064Sume{
50178064Sume
50278064Sume	switch (signo) {
50378064Sume	case SIGALRM:
50478064Sume		seenalrm++;
50578064Sume		break;
50678064Sume	case SIGQUIT:
50778064Sume	case SIGTERM:
50878064Sume		seenquit++;
50978064Sume		break;
51078064Sume	case SIGUSR1:
51178064Sume	case SIGHUP:
51278064Sume	case SIGINT:
51378064Sume		seenusr1++;
51478064Sume		break;
51578064Sume	}
51678064Sume}
51778064Sume
51855163Sshin/*
51955163Sshin * gracefully exits after resetting sockopts.
52055163Sshin */
52155163Sshin/* ARGSUSED */
52255163Sshinvoid
52378064Sumertdexit()
52455163Sshin{
52555163Sshin	struct	riprt *rrt;
52655163Sshin
52755163Sshin	alarm(0);
52855163Sshin	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
52962607Sitojun		if (rrt->rrt_rflags & RRTF_AGGREGATE) {
53055163Sshin			delroute(&rrt->rrt_info, &rrt->rrt_gw);
53155163Sshin		}
53255163Sshin	}
53355163Sshin	close(ripsock);
53455163Sshin	close(rtsock);
53555163Sshin	syslog(LOG_INFO, "**** Terminated ****");
53655163Sshin	closelog();
53755163Sshin	exit(1);
53855163Sshin}
53955163Sshin
54055163Sshin/*
54155163Sshin * Called periodically:
54255163Sshin *	1. age out the learned route. remove it if necessary.
54355163Sshin *	2. submit RIP6_RESPONSE packets.
54478064Sume * Invoked in every SUPPLY_INTERVAL6 (30) seconds.  I believe we don't have
54555163Sshin * to invoke this function in every 1 or 5 or 10 seconds only to age the
54655163Sshin * routes more precisely.
54755163Sshin */
54855163Sshin/* ARGSUSED */
54955163Sshinvoid
55078064Sumeripalarm()
55155163Sshin{
55255163Sshin	struct	ifc *ifcp;
55355163Sshin	struct	riprt *rrt, *rrt_prev, *rrt_next;
55455163Sshin	time_t	t_lifetime, t_holddown;
55555163Sshin
55655163Sshin	/* age the RIP routes */
55755163Sshin	rrt_prev = 0;
55855163Sshin	t_lifetime = time(NULL) - RIP_LIFETIME;
55955163Sshin	t_holddown = t_lifetime - RIP_HOLDDOWN;
56055163Sshin	for (rrt = riprt; rrt; rrt = rrt_next) {
56155163Sshin		rrt_next = rrt->rrt_next;
56255163Sshin
56355163Sshin		if (rrt->rrt_t == 0) {
56455163Sshin			rrt_prev = rrt;
56555163Sshin			continue;
56655163Sshin		}
56755163Sshin		if (rrt->rrt_t < t_holddown) {
56855163Sshin			if (rrt_prev) {
56955163Sshin				rrt_prev->rrt_next = rrt->rrt_next;
57055163Sshin			} else {
57155163Sshin				riprt = rrt->rrt_next;
57255163Sshin			}
57355163Sshin			delroute(&rrt->rrt_info, &rrt->rrt_gw);
57455163Sshin			free(rrt);
57555163Sshin			continue;
57655163Sshin		}
57755163Sshin		if (rrt->rrt_t < t_lifetime)
57855163Sshin			rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
57955163Sshin		rrt_prev = rrt;
58055163Sshin	}
58155163Sshin	/* Supply updates */
58255163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
58355163Sshin		if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP))
58455163Sshin			ripsend(ifcp, &ifcp->ifc_ripsin, 0);
58555163Sshin	}
58655163Sshin	alarm(ripinterval(SUPPLY_INTERVAL6));
58755163Sshin}
58855163Sshin
58955163Sshinvoid
59055163Sshininit()
59155163Sshin{
592119034Sume	int	error;
593119034Sume	const int int0 = 0, int1 = 1, int255 = 255;
59455163Sshin	struct	addrinfo hints, *res;
595119081Sume	char	port[NI_MAXSERV];
59655163Sshin
59755163Sshin	ifc = (struct ifc *)NULL;
59855163Sshin	nifc = 0;
59955163Sshin	nindex2ifc = 0;	/*initial guess*/
60055163Sshin	index2ifc = NULL;
601119081Sume	snprintf(port, sizeof(port), "%u", RIP6_PORT);
60255163Sshin
60355163Sshin	memset(&hints, 0, sizeof(hints));
60455163Sshin	hints.ai_family = PF_INET6;
60555163Sshin	hints.ai_socktype = SOCK_DGRAM;
606119080Sume	hints.ai_protocol = IPPROTO_UDP;
60755163Sshin	hints.ai_flags = AI_PASSIVE;
60855163Sshin	error = getaddrinfo(NULL, port, &hints, &res);
60978064Sume	if (error) {
61066807Skris		fatal("%s", gai_strerror(error));
61178064Sume		/*NOTREACHED*/
61278064Sume	}
61378064Sume	if (res->ai_next) {
61455163Sshin		fatal(":: resolved to multiple address");
61578064Sume		/*NOTREACHED*/
61678064Sume	}
61755163Sshin
61855163Sshin	ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
61978064Sume	if (ripsock < 0) {
62055163Sshin		fatal("rip socket");
62178064Sume		/*NOTREACHED*/
62278064Sume	}
623119034Sume#ifdef IPV6_V6ONLY
624119034Sume	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_V6ONLY,
625119034Sume	    &int1, sizeof(int1)) < 0) {
626119034Sume		fatal("rip IPV6_V6ONLY");
627119034Sume		/*NOTREACHED*/
628119034Sume	}
629119034Sume#endif
63078064Sume	if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0) {
63155163Sshin		fatal("rip bind");
63278064Sume		/*NOTREACHED*/
63378064Sume	}
63455163Sshin	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
63578064Sume	    &int255, sizeof(int255)) < 0) {
63655163Sshin		fatal("rip IPV6_MULTICAST_HOPS");
63778064Sume		/*NOTREACHED*/
63878064Sume	}
63955163Sshin	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
64078064Sume	    &int0, sizeof(int0)) < 0) {
64155163Sshin		fatal("rip IPV6_MULTICAST_LOOP");
64278064Sume		/*NOTREACHED*/
64378064Sume	}
64462921Sume
64562607Sitojun#ifdef IPV6_RECVPKTINFO
646119034Sume	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
647119034Sume	    &int1, sizeof(int1)) < 0) {
64862607Sitojun		fatal("rip IPV6_RECVPKTINFO");
64978064Sume		/*NOTREACHED*/
65078064Sume	}
65162607Sitojun#else  /* old adv. API */
652119034Sume	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_PKTINFO,
653119034Sume	    &int1, sizeof(int1)) < 0) {
65455163Sshin		fatal("rip IPV6_PKTINFO");
65578064Sume		/*NOTREACHED*/
65678064Sume	}
65762607Sitojun#endif
65855163Sshin
65955163Sshin	memset(&hints, 0, sizeof(hints));
66055163Sshin	hints.ai_family = PF_INET6;
66155163Sshin	hints.ai_socktype = SOCK_DGRAM;
662119080Sume	hints.ai_protocol = IPPROTO_UDP;
66355163Sshin	error = getaddrinfo(RIP6_DEST, port, &hints, &res);
66478064Sume	if (error) {
66566807Skris		fatal("%s", gai_strerror(error));
66678064Sume		/*NOTREACHED*/
66778064Sume	}
66878064Sume	if (res->ai_next) {
66955163Sshin		fatal("%s resolved to multiple address", RIP6_DEST);
67078064Sume		/*NOTREACHED*/
67178064Sume	}
67255163Sshin	memcpy(&ripsin, res->ai_addr, res->ai_addrlen);
67355163Sshin
674119076Sume#ifdef HAVE_POLL_H
675119076Sume	set[0].fd = ripsock;
676119076Sume	set[0].events = POLLIN;
677119076Sume#else
678119070Sume	maxfd = ripsock;
679119076Sume#endif
68055163Sshin
68155163Sshin	if (nflag == 0) {
68278064Sume		if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
68355163Sshin			fatal("route socket");
68478064Sume			/*NOTREACHED*/
68578064Sume		}
686119076Sume#ifdef HAVE_POLL_H
687119076Sume		set[1].fd = rtsock;
688119076Sume		set[1].events = POLLIN;
689119076Sume#else
690119070Sume		if (rtsock > maxfd)
691119070Sume			maxfd = rtsock;
692119076Sume#endif
693119076Sume	} else {
694119076Sume#ifdef HAVE_POLL_H
695119076Sume		set[1].fd = -1;
696119076Sume#else
69755163Sshin		rtsock = -1;	/*just for safety */
698119076Sume#endif
699119076Sume	}
700119070Sume
701119076Sume#ifndef HAVE_POLL_H
702119070Sume	fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask);
703119070Sume	if ((sockvecp = malloc(fdmasks)) == NULL) {
704119070Sume		fatal("malloc");
705119070Sume		/*NOTREACHED*/
706119070Sume	}
707119070Sume	if ((recvecp = malloc(fdmasks)) == NULL) {
708119070Sume		fatal("malloc");
709119070Sume		/*NOTREACHED*/
710119070Sume	}
711119070Sume	memset(sockvecp, 0, fdmasks);
712119070Sume	FD_SET(ripsock, sockvecp);
713119070Sume	if (rtsock >= 0)
714119070Sume		FD_SET(rtsock, sockvecp);
715119076Sume#endif
71655163Sshin}
71755163Sshin
71862607Sitojun#define	RIPSIZE(n) \
71962607Sitojun	(sizeof(struct rip6) + ((n)-1) * sizeof(struct netinfo6))
72055163Sshin
72155163Sshin/*
72255163Sshin * ripflush flushes the rip datagram stored in the rip buffer
72355163Sshin */
72455163Sshinstatic int nrt;
72555163Sshinstatic struct netinfo6 *np;
72655163Sshin
72755163Sshinvoid
728119031Sumeripflush(ifcp, sin6)
72955163Sshin	struct ifc *ifcp;
730119031Sume	struct sockaddr_in6 *sin6;
73155163Sshin{
73255163Sshin	int i;
73355163Sshin	int error;
73455163Sshin
73555163Sshin	if (ifcp)
73655163Sshin		tracet(1, "Send(%s): info(%d) to %s.%d\n",
73755163Sshin			ifcp->ifc_name, nrt,
738119031Sume			inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port));
73955163Sshin	else
74055163Sshin		tracet(1, "Send: info(%d) to %s.%d\n",
741119031Sume			nrt, inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port));
74255163Sshin	if (dflag >= 2) {
74355163Sshin		np = ripbuf->rip6_nets;
74455163Sshin		for (i = 0; i < nrt; i++, np++) {
74555163Sshin			if (np->rip6_metric == NEXTHOP_METRIC) {
74655163Sshin				if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest))
74762607Sitojun					trace(2, "    NextHop reset");
74855163Sshin				else {
74955163Sshin					trace(2, "    NextHop %s",
75055163Sshin						inet6_n2p(&np->rip6_dest));
75155163Sshin				}
75255163Sshin			} else {
75355163Sshin				trace(2, "    %s/%d[%d]",
75455163Sshin					inet6_n2p(&np->rip6_dest),
75555163Sshin					np->rip6_plen, np->rip6_metric);
75655163Sshin			}
75755163Sshin			if (np->rip6_tag) {
75855163Sshin				trace(2, "  tag=0x%04x",
75955163Sshin					ntohs(np->rip6_tag) & 0xffff);
76055163Sshin			}
76155163Sshin			trace(2, "\n");
76255163Sshin		}
76355163Sshin	}
764119031Sume	error = sendpacket(sin6, RIPSIZE(nrt));
76555163Sshin	if (error == EAFNOSUPPORT) {
76655163Sshin		/* Protocol not supported */
76755163Sshin		tracet(1, "Could not send info to %s (%s): "
76855163Sshin			"set IFF_UP to 0\n",
76955163Sshin			ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
77055163Sshin		ifcp->ifc_flags &= ~IFF_UP;	/* As if down for AF_INET6 */
77155163Sshin	}
77255163Sshin	nrt = 0; np = ripbuf->rip6_nets;
77355163Sshin}
77455163Sshin
77555163Sshin/*
77655163Sshin * Generate RIP6_RESPONSE packets and send them.
77755163Sshin */
77855163Sshinvoid
779119031Sumeripsend(ifcp, sin6, flag)
78055163Sshin	struct	ifc *ifcp;
781119031Sume	struct	sockaddr_in6 *sin6;
78255163Sshin	int flag;
78355163Sshin{
78455163Sshin	struct	riprt *rrt;
78555163Sshin	struct	in6_addr *nh;	/* next hop */
78678064Sume	int	maxrte;
78755163Sshin
788119084Sume	if (qflag)
789119084Sume		return;
790119084Sume
79155163Sshin	if (ifcp == NULL) {
79255163Sshin		/*
79355163Sshin		 * Request from non-link local address is not
79455163Sshin		 * a regular route6d update.
79555163Sshin		 */
79662607Sitojun		maxrte = (IFMINMTU - sizeof(struct ip6_hdr) -
79762607Sitojun				sizeof(struct udphdr) -
79855163Sshin				sizeof(struct rip6) + sizeof(struct netinfo6)) /
79955163Sshin				sizeof(struct netinfo6);
80055163Sshin		nrt = 0; np = ripbuf->rip6_nets; nh = NULL;
80155163Sshin		for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
80262607Sitojun			if (rrt->rrt_rflags & RRTF_NOADVERTISE)
80355163Sshin				continue;
80455163Sshin			/* Put the route to the buffer */
80555163Sshin			*np = rrt->rrt_info;
80655163Sshin			np++; nrt++;
80755163Sshin			if (nrt == maxrte) {
808119031Sume				ripflush(NULL, sin6);
80955163Sshin				nh = NULL;
81055163Sshin			}
81155163Sshin		}
81255163Sshin		if (nrt)	/* Send last packet */
813119031Sume			ripflush(NULL, sin6);
81455163Sshin		return;
81555163Sshin	}
81655163Sshin
81762607Sitojun	if ((flag & RRTF_SENDANYWAY) == 0 &&
81855163Sshin	    (qflag || (ifcp->ifc_flags & IFF_LOOPBACK)))
81955163Sshin		return;
82078064Sume
82178064Sume	/* -N: no use */
82255163Sshin	if (iff_find(ifcp, 'N') != NULL)
82355163Sshin		return;
82478064Sume
82578064Sume	/* -T: generate default route only */
82655163Sshin	if (iff_find(ifcp, 'T') != NULL) {
82755163Sshin		struct netinfo6 rrt_info;
82855163Sshin		memset(&rrt_info, 0, sizeof(struct netinfo6));
82955163Sshin		rrt_info.rip6_dest = in6addr_any;
83055163Sshin		rrt_info.rip6_plen = 0;
83155163Sshin		rrt_info.rip6_metric = 1;
83278064Sume		rrt_info.rip6_metric += ifcp->ifc_metric;
83355163Sshin		rrt_info.rip6_tag = htons(routetag & 0xffff);
83455163Sshin		np = ripbuf->rip6_nets;
83555163Sshin		*np = rrt_info;
83655163Sshin		nrt = 1;
837119031Sume		ripflush(ifcp, sin6);
83855163Sshin		return;
83955163Sshin	}
84078064Sume
84162607Sitojun	maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) -
84262607Sitojun			sizeof(struct udphdr) -
84355163Sshin			sizeof(struct rip6) + sizeof(struct netinfo6)) /
84455163Sshin			sizeof(struct netinfo6);
84578064Sume
84655163Sshin	nrt = 0; np = ripbuf->rip6_nets; nh = NULL;
84755163Sshin	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
84862607Sitojun		if (rrt->rrt_rflags & RRTF_NOADVERTISE)
84955163Sshin			continue;
85078064Sume
85178064Sume		/* Need to check filter here */
85278064Sume		if (out_filter(rrt, ifcp) == 0)
85355163Sshin			continue;
85478064Sume
85555163Sshin		/* Check split horizon and other conditions */
85655163Sshin		if (tobeadv(rrt, ifcp) == 0)
85755163Sshin			continue;
85878064Sume
85955163Sshin		/* Only considers the routes with flag if specified */
86062607Sitojun		if ((flag & RRTF_CHANGED) &&
86162607Sitojun		    (rrt->rrt_rflags & RRTF_CHANGED) == 0)
86255163Sshin			continue;
86378064Sume
86455163Sshin		/* Check nexthop */
86555163Sshin		if (rrt->rrt_index == ifcp->ifc_index &&
86655163Sshin		    !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) &&
86762607Sitojun		    (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) == 0) {
86855163Sshin			if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) {
86955163Sshin				if (nrt == maxrte - 2)
870119031Sume					ripflush(ifcp, sin6);
87155163Sshin				np->rip6_dest = rrt->rrt_gw;
87255163Sshin				if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest))
87355163Sshin					SET_IN6_LINKLOCAL_IFINDEX(np->rip6_dest, 0);
87455163Sshin				np->rip6_plen = 0;
87555163Sshin				np->rip6_tag = 0;
87655163Sshin				np->rip6_metric = NEXTHOP_METRIC;
87755163Sshin				nh = &rrt->rrt_gw;
87855163Sshin				np++; nrt++;
87955163Sshin			}
88055163Sshin		} else if (nh && (rrt->rrt_index != ifcp->ifc_index ||
88155163Sshin			          !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) ||
88262607Sitojun				  rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)) {
88355163Sshin			/* Reset nexthop */
88455163Sshin			if (nrt == maxrte - 2)
885119031Sume				ripflush(ifcp, sin6);
88655163Sshin			memset(np, 0, sizeof(struct netinfo6));
88755163Sshin			np->rip6_metric = NEXTHOP_METRIC;
88855163Sshin			nh = NULL;
88955163Sshin			np++; nrt++;
89055163Sshin		}
89178064Sume
89255163Sshin		/* Put the route to the buffer */
89355163Sshin		*np = rrt->rrt_info;
89455163Sshin		np++; nrt++;
89555163Sshin		if (nrt == maxrte) {
896119031Sume			ripflush(ifcp, sin6);
89755163Sshin			nh = NULL;
89855163Sshin		}
89955163Sshin	}
90055163Sshin	if (nrt)	/* Send last packet */
901119031Sume		ripflush(ifcp, sin6);
90255163Sshin}
90355163Sshin
90455163Sshin/*
90578064Sume * outbound filter logic, per-route/interface.
90678064Sume */
90778064Sumeint
90878064Sumeout_filter(rrt, ifcp)
90978064Sume	struct riprt *rrt;
91078064Sume	struct ifc *ifcp;
91178064Sume{
91278064Sume	struct iff *iffp;
91378064Sume	struct in6_addr ia;
91478064Sume	int ok;
91578064Sume
91678064Sume	/*
91778064Sume	 * -A: filter out less specific routes, if we have aggregated
91878064Sume	 * route configured.
91978064Sume	 */
92078064Sume	for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
92178064Sume		if (iffp->iff_type != 'A')
92278064Sume			continue;
92378064Sume		if (rrt->rrt_info.rip6_plen <= iffp->iff_plen)
92478064Sume			continue;
92578064Sume		ia = rrt->rrt_info.rip6_dest;
92678064Sume		applyplen(&ia, iffp->iff_plen);
92778064Sume		if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr))
92878064Sume			return 0;
92978064Sume	}
93078064Sume
93178064Sume	/*
93278064Sume	 * if it is an aggregated route, advertise it only to the
93378064Sume	 * interfaces specified on -A.
93478064Sume	 */
93578064Sume	if ((rrt->rrt_rflags & RRTF_AGGREGATE) != 0) {
93678064Sume		ok = 0;
93778064Sume		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
93878064Sume			if (iffp->iff_type != 'A')
93978064Sume				continue;
94078064Sume			if (rrt->rrt_info.rip6_plen == iffp->iff_plen &&
94178064Sume			    IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
94278064Sume			    &iffp->iff_addr)) {
94378064Sume				ok = 1;
94478064Sume				break;
94578064Sume			}
94678064Sume		}
94778064Sume		if (!ok)
94878064Sume			return 0;
94978064Sume	}
95078064Sume
95178064Sume	/*
95278064Sume	 * -O: advertise only if prefix matches the configured prefix.
95378064Sume	 */
95478064Sume	if (iff_find(ifcp, 'O')) {
95578064Sume		ok = 0;
95678064Sume		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
95778064Sume			if (iffp->iff_type != 'O')
95878064Sume				continue;
95978064Sume			if (rrt->rrt_info.rip6_plen < iffp->iff_plen)
96078064Sume				continue;
96178064Sume			ia = rrt->rrt_info.rip6_dest;
96278064Sume			applyplen(&ia, iffp->iff_plen);
96378064Sume			if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) {
96478064Sume				ok = 1;
96578064Sume				break;
96678064Sume			}
96778064Sume		}
96878064Sume		if (!ok)
96978064Sume			return 0;
97078064Sume	}
97178064Sume
97278064Sume	/* the prefix should be advertised */
97378064Sume	return 1;
97478064Sume}
97578064Sume
97678064Sume/*
97755163Sshin * Determine if the route is to be advertised on the specified interface.
97855163Sshin * It checks options specified in the arguments and the split horizon rule.
97955163Sshin */
98055163Sshinint
98155163Sshintobeadv(rrt, ifcp)
98255163Sshin	struct riprt *rrt;
98355163Sshin	struct ifc *ifcp;
98455163Sshin{
98555163Sshin
98655163Sshin	/* Special care for static routes */
98755163Sshin	if (rrt->rrt_flags & RTF_STATIC) {
98862607Sitojun		/* XXX don't advertise reject/blackhole routes */
98962607Sitojun		if (rrt->rrt_flags & (RTF_REJECT | RTF_BLACKHOLE))
99062607Sitojun			return 0;
99162607Sitojun
99255163Sshin		if (Sflag)	/* Yes, advertise it anyway */
99355163Sshin			return 1;
99455163Sshin		if (sflag && rrt->rrt_index != ifcp->ifc_index)
99555163Sshin			return 1;
99655163Sshin		return 0;
99755163Sshin	}
99855163Sshin	/* Regular split horizon */
99955163Sshin	if (hflag == 0 && rrt->rrt_index == ifcp->ifc_index)
100055163Sshin		return 0;
100155163Sshin	return 1;
100255163Sshin}
100355163Sshin
100455163Sshin/*
100555163Sshin * Send a rip packet actually.
100655163Sshin */
100755163Sshinint
1008119031Sumesendpacket(sin6, len)
1009119031Sume	struct	sockaddr_in6 *sin6;
101055163Sshin	int	len;
101155163Sshin{
101255163Sshin	struct msghdr m;
101355163Sshin	struct cmsghdr *cm;
101455163Sshin	struct iovec iov[2];
101555163Sshin	u_char cmsgbuf[256];
101655163Sshin	struct in6_pktinfo *pi;
101778064Sume	int idx;
101855163Sshin	struct sockaddr_in6 sincopy;
101955163Sshin
102055163Sshin	/* do not overwrite the given sin */
1021119031Sume	sincopy = *sin6;
1022119031Sume	sin6 = &sincopy;
102355163Sshin
1024119035Sume	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
1025119035Sume	    IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
1026122677Sume		/* XXX: do not mix the interface index and link index */
1027119031Sume		idx = IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr);
1028119031Sume		SET_IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr, 0);
1029122677Sume		sin6->sin6_scope_id = idx;
103055163Sshin	} else
103178064Sume		idx = 0;
103255163Sshin
1033119031Sume	m.msg_name = (caddr_t)sin6;
1034119031Sume	m.msg_namelen = sizeof(*sin6);
103555163Sshin	iov[0].iov_base = (caddr_t)ripbuf;
103655163Sshin	iov[0].iov_len = len;
103755163Sshin	m.msg_iov = iov;
103855163Sshin	m.msg_iovlen = 1;
103978064Sume	if (!idx) {
104055163Sshin		m.msg_control = NULL;
104155163Sshin		m.msg_controllen = 0;
104255163Sshin	} else {
104355163Sshin		memset(cmsgbuf, 0, sizeof(cmsgbuf));
104455163Sshin		cm = (struct cmsghdr *)cmsgbuf;
104555163Sshin		m.msg_control = (caddr_t)cm;
104655163Sshin		m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
104755163Sshin
104855163Sshin		cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
104955163Sshin		cm->cmsg_level = IPPROTO_IPV6;
105055163Sshin		cm->cmsg_type = IPV6_PKTINFO;
105155163Sshin		pi = (struct in6_pktinfo *)CMSG_DATA(cm);
105255163Sshin		memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/
105378064Sume		pi->ipi6_ifindex = idx;
105455163Sshin	}
105555163Sshin
105655163Sshin	if (sendmsg(ripsock, &m, 0 /*MSG_DONTROUTE*/) < 0) {
105755163Sshin		trace(1, "sendmsg: %s\n", strerror(errno));
105855163Sshin		return errno;
105955163Sshin	}
106062921Sume
106155163Sshin	return 0;
106255163Sshin}
106355163Sshin
106455163Sshin/*
106578064Sume * Receive and process RIP packets.  Update the routes/kernel forwarding
106655163Sshin * table if necessary.
106755163Sshin */
106855163Sshinvoid
106955163Sshinriprecv()
107055163Sshin{
107155163Sshin	struct	ifc *ifcp, *ic;
107255163Sshin	struct	sockaddr_in6 fsock;
107355163Sshin	struct	in6_addr nh;	/* next hop */
107455163Sshin	struct	rip6 *rp;
107555163Sshin	struct	netinfo6 *np, *nq;
107655163Sshin	struct	riprt *rrt;
1077122677Sume	ssize_t	len, nn;
1078122677Sume	unsigned int need_trigger, idx;
107955163Sshin	char	buf[4 * RIP6_MAXMTU];
108055163Sshin	time_t	t;
108155163Sshin	struct msghdr m;
108255163Sshin	struct cmsghdr *cm;
108355163Sshin	struct iovec iov[2];
108455163Sshin	u_char cmsgbuf[256];
108555163Sshin	struct in6_pktinfo *pi;
108655163Sshin	struct iff *iffp;
108755163Sshin	struct in6_addr ia;
108855163Sshin	int ok;
108978064Sume	time_t t_half_lifetime;
109055163Sshin
109155163Sshin	need_trigger = 0;
109262921Sume
109355163Sshin	m.msg_name = (caddr_t)&fsock;
109455163Sshin	m.msg_namelen = sizeof(fsock);
109555163Sshin	iov[0].iov_base = (caddr_t)buf;
109655163Sshin	iov[0].iov_len = sizeof(buf);
109755163Sshin	m.msg_iov = iov;
109855163Sshin	m.msg_iovlen = 1;
109955163Sshin	cm = (struct cmsghdr *)cmsgbuf;
110055163Sshin	m.msg_control = (caddr_t)cm;
110155163Sshin	m.msg_controllen = sizeof(cmsgbuf);
110278064Sume	if ((len = recvmsg(ripsock, &m, 0)) < 0) {
110355163Sshin		fatal("recvmsg");
110478064Sume		/*NOTREACHED*/
110578064Sume	}
110678064Sume	idx = 0;
110755163Sshin	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m);
110855163Sshin	     cm;
110955163Sshin	     cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) {
111078064Sume		if (cm->cmsg_level == IPPROTO_IPV6 &&
111178064Sume		    cm->cmsg_type == IPV6_PKTINFO) {
111255163Sshin			pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
111378064Sume			idx = pi->ipi6_ifindex;
111455163Sshin			break;
111555163Sshin		}
111655163Sshin	}
111778064Sume	if (idx && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr))
111878064Sume		SET_IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr, idx);
111955163Sshin
1120121779Ssuz	if (len < sizeof(struct rip6)) {
1121121779Ssuz		trace(1, "Packet too short\n");
1122121779Ssuz		return;
1123121779Ssuz	}
1124121779Ssuz
112555163Sshin	nh = fsock.sin6_addr;
112655163Sshin	nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) /
112755163Sshin		sizeof(struct netinfo6);
112855163Sshin	rp = (struct rip6 *)buf;
112955163Sshin	np = rp->rip6_nets;
113055163Sshin
1131119035Sume	if (rp->rip6_vers != RIP6_VERSION) {
113255163Sshin		trace(1, "Incorrect RIP version %d\n", rp->rip6_vers);
113355163Sshin		return;
113455163Sshin	}
113555163Sshin	if (rp->rip6_cmd == RIP6_REQUEST) {
113678064Sume		if (idx && idx < nindex2ifc) {
113778064Sume			ifcp = index2ifc[idx];
113855163Sshin			riprequest(ifcp, np, nn, &fsock);
113955163Sshin		} else {
114055163Sshin			riprequest(NULL, np, nn, &fsock);
114155163Sshin		}
114262607Sitojun		return;
114362607Sitojun	}
114455163Sshin
114555163Sshin	if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) {
114655163Sshin		trace(1, "Packets from non-ll addr: %s\n",
114778064Sume		    inet6_n2p(&fsock.sin6_addr));
114855163Sshin		return;		/* Ignore packets from non-link-local addr */
114955163Sshin	}
115078064Sume	idx = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr);
115178064Sume	ifcp = (idx < nindex2ifc) ? index2ifc[idx] : NULL;
115255163Sshin	if (!ifcp) {
115378064Sume		trace(1, "Packets to unknown interface index %d\n", idx);
115455163Sshin		return;		/* Ignore it */
115555163Sshin	}
115655163Sshin	if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr))
115755163Sshin		return;		/* The packet is from me; ignore */
115855163Sshin	if (rp->rip6_cmd != RIP6_RESPONSE) {
115955163Sshin		trace(1, "Invalid command %d\n", rp->rip6_cmd);
116062607Sitojun		return;
116155163Sshin	}
116278064Sume
116378064Sume	/* -N: no use */
116455163Sshin	if (iff_find(ifcp, 'N') != NULL)
116555163Sshin		return;
116678064Sume
116755163Sshin	tracet(1, "Recv(%s): from %s.%d info(%d)\n",
116878064Sume	    ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn);
116955163Sshin
117055163Sshin	t = time(NULL);
117178064Sume	t_half_lifetime = t - (RIP_LIFETIME/2);
117255163Sshin	for (; nn; nn--, np++) {
117355163Sshin		if (np->rip6_metric == NEXTHOP_METRIC) {
117455163Sshin			/* modify neighbor address */
117555163Sshin			if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) {
117655163Sshin				nh = np->rip6_dest;
117778064Sume				SET_IN6_LINKLOCAL_IFINDEX(nh, idx);
117855163Sshin				trace(1, "\tNexthop: %s\n", inet6_n2p(&nh));
117955163Sshin			} else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) {
118055163Sshin				nh = fsock.sin6_addr;
118155163Sshin				trace(1, "\tNexthop: %s\n", inet6_n2p(&nh));
118255163Sshin			} else {
118355163Sshin				nh = fsock.sin6_addr;
118455163Sshin				trace(1, "\tInvalid Nexthop: %s\n",
118578064Sume				    inet6_n2p(&np->rip6_dest));
118655163Sshin			}
118755163Sshin			continue;
118855163Sshin		}
118955163Sshin		if (IN6_IS_ADDR_MULTICAST(&np->rip6_dest)) {
119055163Sshin			trace(1, "\tMulticast netinfo6: %s/%d [%d]\n",
119155163Sshin				inet6_n2p(&np->rip6_dest),
119255163Sshin				np->rip6_plen, np->rip6_metric);
119355163Sshin			continue;
119455163Sshin		}
119555163Sshin		if (IN6_IS_ADDR_LOOPBACK(&np->rip6_dest)) {
119655163Sshin			trace(1, "\tLoopback netinfo6: %s/%d [%d]\n",
119755163Sshin				inet6_n2p(&np->rip6_dest),
119855163Sshin				np->rip6_plen, np->rip6_metric);
119955163Sshin			continue;
120055163Sshin		}
120155163Sshin		if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) {
120255163Sshin			trace(1, "\tLink Local netinfo6: %s/%d [%d]\n",
120355163Sshin				inet6_n2p(&np->rip6_dest),
120455163Sshin				np->rip6_plen, np->rip6_metric);
120555163Sshin			continue;
120655163Sshin		}
120755163Sshin		/* may need to pass sitelocal prefix in some case, however*/
120855163Sshin		if (IN6_IS_ADDR_SITELOCAL(&np->rip6_dest) && !lflag) {
120955163Sshin			trace(1, "\tSite Local netinfo6: %s/%d [%d]\n",
121055163Sshin				inet6_n2p(&np->rip6_dest),
121155163Sshin				np->rip6_plen, np->rip6_metric);
121255163Sshin			continue;
121355163Sshin		}
121455163Sshin		trace(2, "\tnetinfo6: %s/%d [%d]",
121555163Sshin			inet6_n2p(&np->rip6_dest),
121655163Sshin			np->rip6_plen, np->rip6_metric);
121755163Sshin		if (np->rip6_tag)
121855163Sshin			trace(2, "  tag=0x%04x", ntohs(np->rip6_tag) & 0xffff);
121962607Sitojun		if (dflag >= 2) {
122062607Sitojun			ia = np->rip6_dest;
122162607Sitojun			applyplen(&ia, np->rip6_plen);
122262607Sitojun			if (!IN6_ARE_ADDR_EQUAL(&ia, &np->rip6_dest))
122362607Sitojun				trace(2, " [junk outside prefix]");
122462607Sitojun		}
122555163Sshin
122678064Sume		/*
122778064Sume		 * -L: listen only if the prefix matches the configuration
122878064Sume		 */
122955163Sshin		ok = 1;		/* if there's no L filter, it is ok */
123055163Sshin		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
123155163Sshin			if (iffp->iff_type != 'L')
123255163Sshin				continue;
123355163Sshin			ok = 0;
123455163Sshin			if (np->rip6_plen < iffp->iff_plen)
123555163Sshin				continue;
123655163Sshin			/* special rule: ::/0 means default, not "in /0" */
123755163Sshin			if (iffp->iff_plen == 0 && np->rip6_plen > 0)
123855163Sshin				continue;
123962607Sitojun			ia = np->rip6_dest;
124055163Sshin			applyplen(&ia, iffp->iff_plen);
124155163Sshin			if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) {
124255163Sshin				ok = 1;
124355163Sshin				break;
124455163Sshin			}
124555163Sshin		}
124655163Sshin		if (!ok) {
124755163Sshin			trace(2, "  (filtered)\n");
124855163Sshin			continue;
124955163Sshin		}
125055163Sshin
125155163Sshin		trace(2, "\n");
125255163Sshin		np->rip6_metric++;
125355163Sshin		np->rip6_metric += ifcp->ifc_metric;
125455163Sshin		if (np->rip6_metric > HOPCNT_INFINITY6)
125555163Sshin			np->rip6_metric = HOPCNT_INFINITY6;
125655163Sshin
125755163Sshin		applyplen(&np->rip6_dest, np->rip6_plen);
125878064Sume		if ((rrt = rtsearch(np, NULL)) != NULL) {
125955163Sshin			if (rrt->rrt_t == 0)
126055163Sshin				continue;	/* Intf route has priority */
126155163Sshin			nq = &rrt->rrt_info;
126255163Sshin			if (nq->rip6_metric > np->rip6_metric) {
126355163Sshin				if (rrt->rrt_index == ifcp->ifc_index &&
126455163Sshin				    IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
126555163Sshin					/* Small metric from the same gateway */
126655163Sshin					nq->rip6_metric = np->rip6_metric;
126755163Sshin				} else {
126855163Sshin					/* Better route found */
126955163Sshin					rrt->rrt_index = ifcp->ifc_index;
127055163Sshin					/* Update routing table */
127155163Sshin					delroute(nq, &rrt->rrt_gw);
127255163Sshin					rrt->rrt_gw = nh;
127355163Sshin					*nq = *np;
127455163Sshin					addroute(rrt, &nh, ifcp);
127555163Sshin				}
127662607Sitojun				rrt->rrt_rflags |= RRTF_CHANGED;
127755163Sshin				rrt->rrt_t = t;
127855163Sshin				need_trigger = 1;
127955163Sshin			} else if (nq->rip6_metric < np->rip6_metric &&
128055163Sshin				   rrt->rrt_index == ifcp->ifc_index &&
128155163Sshin				   IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
128255163Sshin				/* Got worse route from same gw */
128355163Sshin				nq->rip6_metric = np->rip6_metric;
128455163Sshin				rrt->rrt_t = t;
128562607Sitojun				rrt->rrt_rflags |= RRTF_CHANGED;
128655163Sshin				need_trigger = 1;
128755163Sshin			} else if (nq->rip6_metric == np->rip6_metric &&
128855163Sshin				   np->rip6_metric < HOPCNT_INFINITY6) {
128978064Sume				if (rrt->rrt_index == ifcp->ifc_index &&
129078064Sume				   IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
129178064Sume					/* same metric, same route from same gw */
129278064Sume					rrt->rrt_t = t;
129378064Sume				} else if (rrt->rrt_t < t_half_lifetime) {
129478064Sume					/* Better route found */
129578064Sume					rrt->rrt_index = ifcp->ifc_index;
129678064Sume					/* Update routing table */
129778064Sume					delroute(nq, &rrt->rrt_gw);
129878064Sume					rrt->rrt_gw = nh;
129978064Sume					*nq = *np;
130078064Sume					addroute(rrt, &nh, ifcp);
130178064Sume					rrt->rrt_rflags |= RRTF_CHANGED;
130278064Sume					rrt->rrt_t = t;
130378064Sume				}
130455163Sshin			}
130562607Sitojun			/*
130655163Sshin			 * if nq->rip6_metric == HOPCNT_INFINITY6 then
130778064Sume			 * do not update age value.  Do nothing.
130855163Sshin			 */
130955163Sshin		} else if (np->rip6_metric < HOPCNT_INFINITY6) {
131055163Sshin			/* Got a new valid route */
131178064Sume			if ((rrt = MALLOC(struct riprt)) == NULL) {
131255163Sshin				fatal("malloc: struct riprt");
131378064Sume				/*NOTREACHED*/
131478064Sume			}
131562607Sitojun			memset(rrt, 0, sizeof(*rrt));
131655163Sshin			nq = &rrt->rrt_info;
131755163Sshin
131855163Sshin			rrt->rrt_same = NULL;
131955163Sshin			rrt->rrt_index = ifcp->ifc_index;
132055163Sshin			rrt->rrt_flags = RTF_UP|RTF_GATEWAY;
132155163Sshin			rrt->rrt_gw = nh;
132255163Sshin			*nq = *np;
132355163Sshin			applyplen(&nq->rip6_dest, nq->rip6_plen);
132455163Sshin			if (nq->rip6_plen == sizeof(struct in6_addr) * 8)
132555163Sshin				rrt->rrt_flags |= RTF_HOST;
132655163Sshin
132755163Sshin			/* Put the route to the list */
132855163Sshin			rrt->rrt_next = riprt;
132955163Sshin			riprt = rrt;
133055163Sshin			/* Update routing table */
133155163Sshin			addroute(rrt, &nh, ifcp);
133262607Sitojun			rrt->rrt_rflags |= RRTF_CHANGED;
133355163Sshin			need_trigger = 1;
133455163Sshin			rrt->rrt_t = t;
133555163Sshin		}
133655163Sshin	}
133755163Sshin	/* XXX need to care the interval between triggered updates */
133855163Sshin	if (need_trigger) {
133955163Sshin		if (nextalarm > time(NULL) + RIP_TRIG_INT6_MAX) {
134055163Sshin			for (ic = ifc; ic; ic = ic->ifc_next) {
134155163Sshin				if (ifcp->ifc_index == ic->ifc_index)
134255163Sshin					continue;
134355163Sshin				if (ic->ifc_flags & IFF_UP)
134455163Sshin					ripsend(ic, &ic->ifc_ripsin,
134562607Sitojun						RRTF_CHANGED);
134655163Sshin			}
134755163Sshin		}
134855163Sshin		/* Reset the flag */
134955163Sshin		for (rrt = riprt; rrt; rrt = rrt->rrt_next)
135062607Sitojun			rrt->rrt_rflags &= ~RRTF_CHANGED;
135155163Sshin	}
135255163Sshin}
135355163Sshin
135455163Sshin/*
135555163Sshin * Send all routes request packet to the specified interface.
135655163Sshin */
135755163Sshinvoid
135855163Sshinsendrequest(ifcp)
135955163Sshin	struct ifc *ifcp;
136055163Sshin{
136155163Sshin	struct netinfo6 *np;
136255163Sshin	int error;
136355163Sshin
136455163Sshin	if (ifcp->ifc_flags & IFF_LOOPBACK)
136555163Sshin		return;
136655163Sshin	ripbuf->rip6_cmd = RIP6_REQUEST;
136755163Sshin	np = ripbuf->rip6_nets;
136855163Sshin	memset(np, 0, sizeof(struct netinfo6));
136955163Sshin	np->rip6_metric = HOPCNT_INFINITY6;
137055163Sshin	tracet(1, "Send rtdump Request to %s (%s)\n",
137155163Sshin		ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
137255163Sshin	error = sendpacket(&ifcp->ifc_ripsin, RIPSIZE(1));
137355163Sshin	if (error == EAFNOSUPPORT) {
137455163Sshin		/* Protocol not supported */
137555163Sshin		tracet(1, "Could not send rtdump Request to %s (%s): "
137655163Sshin			"set IFF_UP to 0\n",
137755163Sshin			ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
137855163Sshin		ifcp->ifc_flags &= ~IFF_UP;	/* As if down for AF_INET6 */
137955163Sshin	}
138055163Sshin	ripbuf->rip6_cmd = RIP6_RESPONSE;
138155163Sshin}
138255163Sshin
138355163Sshin/*
138455163Sshin * Process a RIP6_REQUEST packet.
138555163Sshin */
138655163Sshinvoid
1387119031Sumeriprequest(ifcp, np, nn, sin6)
138855163Sshin	struct ifc *ifcp;
138955163Sshin	struct netinfo6 *np;
139055163Sshin	int nn;
1391119031Sume	struct sockaddr_in6 *sin6;
139255163Sshin{
139355163Sshin	int i;
139455163Sshin	struct riprt *rrt;
139555163Sshin
139655163Sshin	if (!(nn == 1 && IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest) &&
139755163Sshin	      np->rip6_plen == 0 && np->rip6_metric == HOPCNT_INFINITY6)) {
139855163Sshin		/* Specific response, don't split-horizon */
139955163Sshin		trace(1, "\tRIP Request\n");
140055163Sshin		for (i = 0; i < nn; i++, np++) {
140178064Sume			rrt = rtsearch(np, NULL);
140255163Sshin			if (rrt)
140355163Sshin				np->rip6_metric = rrt->rrt_info.rip6_metric;
140455163Sshin			else
140555163Sshin				np->rip6_metric = HOPCNT_INFINITY6;
140655163Sshin		}
1407119031Sume		(void)sendpacket(sin6, RIPSIZE(nn));
140855163Sshin		return;
140955163Sshin	}
141055163Sshin	/* Whole routing table dump */
141155163Sshin	trace(1, "\tRIP Request -- whole routing table\n");
1412119031Sume	ripsend(ifcp, sin6, RRTF_SENDANYWAY);
141355163Sshin}
141455163Sshin
141555163Sshin/*
141655163Sshin * Get information of each interface.
141755163Sshin */
141855163Sshinvoid
141955163Sshinifconfig()
142055163Sshin{
142162607Sitojun	struct ifaddrs *ifap, *ifa;
142262607Sitojun	struct ifc *ifcp;
142362607Sitojun	struct ipv6_mreq mreq;
142462607Sitojun	int s;
142562607Sitojun
142678064Sume	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
142762607Sitojun		fatal("socket");
142878064Sume		/*NOTREACHED*/
142978064Sume	}
143062607Sitojun
143178064Sume	if (getifaddrs(&ifap) != 0) {
143262607Sitojun		fatal("getifaddrs");
143378064Sume		/*NOTREACHED*/
143478064Sume	}
143562607Sitojun
143662607Sitojun	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
143762607Sitojun		if (ifa->ifa_addr->sa_family != AF_INET6)
143862607Sitojun			continue;
143962607Sitojun		ifcp = ifc_find(ifa->ifa_name);
144062607Sitojun		/* we are interested in multicast-capable interfaces */
144162607Sitojun		if ((ifa->ifa_flags & IFF_MULTICAST) == 0)
144262607Sitojun			continue;
144362607Sitojun		if (!ifcp) {
144462607Sitojun			/* new interface */
144578064Sume			if ((ifcp = MALLOC(struct ifc)) == NULL) {
144662607Sitojun				fatal("malloc: struct ifc");
144778064Sume				/*NOTREACHED*/
144878064Sume			}
144962607Sitojun			memset(ifcp, 0, sizeof(*ifcp));
145062607Sitojun			ifcp->ifc_index = -1;
145162607Sitojun			ifcp->ifc_next = ifc;
145262607Sitojun			ifc = ifcp;
145362607Sitojun			nifc++;
145462607Sitojun			ifcp->ifc_name = allocopy(ifa->ifa_name);
145562607Sitojun			ifcp->ifc_addr = 0;
145662607Sitojun			ifcp->ifc_filter = 0;
145762607Sitojun			ifcp->ifc_flags = ifa->ifa_flags;
145862607Sitojun			trace(1, "newif %s <%s>\n", ifcp->ifc_name,
145962607Sitojun				ifflags(ifcp->ifc_flags));
146062607Sitojun			if (!strcmp(ifcp->ifc_name, LOOPBACK_IF))
146162607Sitojun				loopifcp = ifcp;
146262607Sitojun		} else {
146362607Sitojun			/* update flag, this may be up again */
146462607Sitojun			if (ifcp->ifc_flags != ifa->ifa_flags) {
146562607Sitojun				trace(1, "%s: <%s> -> ", ifcp->ifc_name,
146662607Sitojun					ifflags(ifcp->ifc_flags));
146762607Sitojun				trace(1, "<%s>\n", ifflags(ifa->ifa_flags));
146878064Sume				ifcp->ifc_cflags |= IFC_CHANGED;
146962607Sitojun			}
147062607Sitojun			ifcp->ifc_flags = ifa->ifa_flags;
147162607Sitojun		}
147262607Sitojun		ifconfig1(ifa->ifa_name, ifa->ifa_addr, ifcp, s);
147362607Sitojun		if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP
147462607Sitojun		 && 0 < ifcp->ifc_index && !ifcp->ifc_joined) {
147562607Sitojun			mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr;
147662607Sitojun			mreq.ipv6mr_interface = ifcp->ifc_index;
147778064Sume			if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
147878064Sume			    &mreq, sizeof(mreq)) < 0) {
147962607Sitojun				fatal("IPV6_JOIN_GROUP");
148078064Sume				/*NOTREACHED*/
148178064Sume			}
148262607Sitojun			trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST);
148362607Sitojun			ifcp->ifc_joined++;
148462607Sitojun		}
148562607Sitojun	}
148662607Sitojun	close(s);
148762607Sitojun	freeifaddrs(ifap);
148855163Sshin}
148955163Sshin
149055163Sshinvoid
149162607Sitojunifconfig1(name, sa, ifcp, s)
149262607Sitojun	const char *name;
149362607Sitojun	const struct sockaddr *sa;
149455163Sshin	struct	ifc *ifcp;
149555163Sshin	int	s;
149655163Sshin{
149755163Sshin	struct	in6_ifreq ifr;
1498119031Sume	const struct sockaddr_in6 *sin6;
149955163Sshin	struct	ifac *ifa;
150055163Sshin	int	plen;
150155163Sshin	char	buf[BUFSIZ];
150255163Sshin
1503119031Sume	sin6 = (const struct sockaddr_in6 *)sa;
1504122677Sume	if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) && !lflag)
1505122677Sume		return;
1506119031Sume	ifr.ifr_addr = *sin6;
1507119032Sume	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
150878064Sume	if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0) {
150955163Sshin		fatal("ioctl: SIOCGIFNETMASK_IN6");
151078064Sume		/*NOTREACHED*/
151178064Sume	}
151278064Sume	plen = sin6mask2len(&ifr.ifr_addr);
1513119031Sume	if ((ifa = ifa_match(ifcp, &sin6->sin6_addr, plen)) != NULL) {
151455163Sshin		/* same interface found */
151555163Sshin		/* need check if something changed */
151655163Sshin		/* XXX not yet implemented */
151755163Sshin		return;
151855163Sshin	}
151955163Sshin	/*
152055163Sshin	 * New address is found
152155163Sshin	 */
152278064Sume	if ((ifa = MALLOC(struct ifac)) == NULL) {
152355163Sshin		fatal("malloc: struct ifac");
152478064Sume		/*NOTREACHED*/
152578064Sume	}
152662607Sitojun	memset(ifa, 0, sizeof(*ifa));
152755163Sshin	ifa->ifa_conf = ifcp;
152855163Sshin	ifa->ifa_next = ifcp->ifc_addr;
152955163Sshin	ifcp->ifc_addr = ifa;
1530119031Sume	ifa->ifa_addr = sin6->sin6_addr;
153155163Sshin	ifa->ifa_plen = plen;
153255163Sshin	if (ifcp->ifc_flags & IFF_POINTOPOINT) {
1533119031Sume		ifr.ifr_addr = *sin6;
153478064Sume		if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0) {
153555163Sshin			fatal("ioctl: SIOCGIFDSTADDR_IN6");
153678064Sume			/*NOTREACHED*/
153778064Sume		}
153855163Sshin		ifa->ifa_raddr = ifr.ifr_dstaddr.sin6_addr;
153955163Sshin		inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, buf, sizeof(buf));
154055163Sshin		trace(1, "found address %s/%d -- %s\n",
154155163Sshin			inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen, buf);
154255163Sshin	} else {
154355163Sshin		trace(1, "found address %s/%d\n",
154455163Sshin			inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen);
154555163Sshin	}
154655163Sshin	if (ifcp->ifc_index < 0 && IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) {
154755163Sshin		ifcp->ifc_mylladdr = ifa->ifa_addr;
154855163Sshin		ifcp->ifc_index = IN6_LINKLOCAL_IFINDEX(ifa->ifa_addr);
154955163Sshin		memcpy(&ifcp->ifc_ripsin, &ripsin, ripsin.ss_len);
155055163Sshin		SET_IN6_LINKLOCAL_IFINDEX(ifcp->ifc_ripsin.sin6_addr,
155155163Sshin			ifcp->ifc_index);
155255163Sshin		setindex2ifc(ifcp->ifc_index, ifcp);
155355163Sshin		ifcp->ifc_mtu = getifmtu(ifcp->ifc_index);
155455163Sshin		if (ifcp->ifc_mtu > RIP6_MAXMTU)
155555163Sshin			ifcp->ifc_mtu = RIP6_MAXMTU;
155678064Sume		if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0) {
155755163Sshin			fatal("ioctl: SIOCGIFMETRIC");
155878064Sume			/*NOTREACHED*/
155978064Sume		}
156055163Sshin		ifcp->ifc_metric = ifr.ifr_metric;
156155163Sshin		trace(1, "\tindex: %d, mtu: %d, metric: %d\n",
156255163Sshin			ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric);
156378064Sume	} else
156478064Sume		ifcp->ifc_cflags |= IFC_CHANGED;
156555163Sshin}
156655163Sshin
156755163Sshin/*
156855163Sshin * Receive and process routing messages.
156955163Sshin * Update interface information as necesssary.
157055163Sshin */
157155163Sshinvoid
157255163Sshinrtrecv()
157355163Sshin{
157455163Sshin	char buf[BUFSIZ];
157555163Sshin	char *p, *q;
157655163Sshin	struct rt_msghdr *rtm;
157755163Sshin	struct ifa_msghdr *ifam;
157855163Sshin	struct if_msghdr *ifm;
157955163Sshin	int len;
158078064Sume	struct ifc *ifcp, *ic;
158155163Sshin	int iface = 0, rtable = 0;
158255163Sshin	struct sockaddr_in6 *rta[RTAX_MAX];
158378064Sume	struct sockaddr_in6 mask;
158455163Sshin	int i, addrs;
158578064Sume	struct riprt *rrt;
158655163Sshin
158755163Sshin	if ((len = read(rtsock, buf, sizeof(buf))) < 0) {
158855163Sshin		perror("read from rtsock");
158978064Sume		exit(1);
159055163Sshin	}
159155163Sshin	if (len < sizeof(*rtm)) {
159269279Sume		trace(1, "short read from rtsock: %d (should be > %lu)\n",
159369279Sume			len, (u_long)sizeof(*rtm));
159455163Sshin		return;
159555163Sshin	}
1596119042Sume	if (dflag >= 2) {
1597119042Sume		fprintf(stderr, "rtmsg:\n");
1598119042Sume		for (i = 0; i < len; i++) {
1599119042Sume			fprintf(stderr, "%02x ", buf[i] & 0xff);
1600119042Sume			if (i % 16 == 15) fprintf(stderr, "\n");
1601119042Sume		}
1602119042Sume		fprintf(stderr, "\n");
1603119042Sume	}
160455163Sshin
160555163Sshin	for (p = buf; p - buf < len; p += ((struct rt_msghdr *)p)->rtm_msglen) {
160655163Sshin		/* safety against bogus message */
160755163Sshin		if (((struct rt_msghdr *)p)->rtm_msglen <= 0) {
160855163Sshin			trace(1, "bogus rtmsg: length=%d\n",
160955163Sshin				((struct rt_msghdr *)p)->rtm_msglen);
161055163Sshin			break;
161155163Sshin		}
161255163Sshin		rtm = NULL;
161355163Sshin		ifam = NULL;
161455163Sshin		ifm = NULL;
161555163Sshin		switch (((struct rt_msghdr *)p)->rtm_type) {
161655163Sshin		case RTM_NEWADDR:
161755163Sshin		case RTM_DELADDR:
161855163Sshin			ifam = (struct ifa_msghdr *)p;
161955163Sshin			addrs = ifam->ifam_addrs;
162055163Sshin			q = (char *)(ifam + 1);
162155163Sshin			break;
162255163Sshin		case RTM_IFINFO:
162355163Sshin			ifm = (struct if_msghdr *)p;
162455163Sshin			addrs = ifm->ifm_addrs;
162555163Sshin			q = (char *)(ifm + 1);
162655163Sshin			break;
162755163Sshin		default:
162855163Sshin			rtm = (struct rt_msghdr *)p;
162955163Sshin			addrs = rtm->rtm_addrs;
163055163Sshin			q = (char *)(rtm + 1);
163155163Sshin			if (rtm->rtm_version != RTM_VERSION) {
163255163Sshin				trace(1, "unexpected rtmsg version %d "
163355163Sshin					"(should be %d)\n",
163455163Sshin					rtm->rtm_version, RTM_VERSION);
163555163Sshin				continue;
163655163Sshin			}
163755163Sshin			if (rtm->rtm_pid == pid) {
163855163Sshin#if 0
163955163Sshin				trace(1, "rtmsg looped back to me, ignored\n");
164055163Sshin#endif
164155163Sshin				continue;
164255163Sshin			}
164355163Sshin			break;
164455163Sshin		}
164555163Sshin		memset(&rta, 0, sizeof(rta));
164655163Sshin		for (i = 0; i < RTAX_MAX; i++) {
164755163Sshin			if (addrs & (1 << i)) {
164855163Sshin				rta[i] = (struct sockaddr_in6 *)q;
164955163Sshin				q += ROUNDUP(rta[i]->sin6_len);
165055163Sshin			}
165155163Sshin		}
165255163Sshin
165355163Sshin		trace(1, "rtsock: %s (addrs=%x)\n",
165455163Sshin			rttypes((struct rt_msghdr *)p), addrs);
165555163Sshin		if (dflag >= 2) {
165655163Sshin			for (i = 0;
165755163Sshin			     i < ((struct rt_msghdr *)p)->rtm_msglen;
165855163Sshin			     i++) {
165955163Sshin				fprintf(stderr, "%02x ", p[i] & 0xff);
166055163Sshin				if (i % 16 == 15) fprintf(stderr, "\n");
166155163Sshin			}
166255163Sshin			fprintf(stderr, "\n");
166355163Sshin		}
166455163Sshin
166555163Sshin		/*
166655163Sshin		 * Easy ones first.
166755163Sshin		 *
166855163Sshin		 * We may be able to optimize by using ifm->ifm_index or
166955163Sshin		 * ifam->ifam_index.  For simplicity we don't do that here.
167055163Sshin		 */
167155163Sshin		switch (((struct rt_msghdr *)p)->rtm_type) {
167255163Sshin		case RTM_NEWADDR:
167355163Sshin		case RTM_IFINFO:
167455163Sshin			iface++;
167555163Sshin			continue;
167655163Sshin		case RTM_ADD:
167755163Sshin			rtable++;
167855163Sshin			continue;
167955163Sshin		case RTM_LOSING:
168055163Sshin		case RTM_MISS:
168155163Sshin		case RTM_RESOLVE:
168255163Sshin		case RTM_GET:
168355163Sshin		case RTM_LOCK:
168455163Sshin			/* nothing to be done here */
168555163Sshin			trace(1, "\tnothing to be done, ignored\n");
168655163Sshin			continue;
168755163Sshin		}
168855163Sshin
168955163Sshin#if 0
169055163Sshin		if (rta[RTAX_DST] == NULL) {
169155163Sshin			trace(1, "\tno destination, ignored\n");
169262607Sitojun			continue;
169355163Sshin		}
169455163Sshin		if (rta[RTAX_DST]->sin6_family != AF_INET6) {
169555163Sshin			trace(1, "\taf mismatch, ignored\n");
169655163Sshin			continue;
169755163Sshin		}
169855163Sshin		if (IN6_IS_ADDR_LINKLOCAL(&rta[RTAX_DST]->sin6_addr)) {
169955163Sshin			trace(1, "\tlinklocal destination, ignored\n");
170055163Sshin			continue;
170155163Sshin		}
170255163Sshin		if (IN6_ARE_ADDR_EQUAL(&rta[RTAX_DST]->sin6_addr, &in6addr_loopback)) {
170355163Sshin			trace(1, "\tloopback destination, ignored\n");
170455163Sshin			continue;		/* Loopback */
170555163Sshin		}
170655163Sshin		if (IN6_IS_ADDR_MULTICAST(&rta[RTAX_DST]->sin6_addr)) {
170755163Sshin			trace(1, "\tmulticast destination, ignored\n");
170855163Sshin			continue;
170955163Sshin		}
171055163Sshin#endif
171155163Sshin
171255163Sshin		/* hard ones */
171355163Sshin		switch (((struct rt_msghdr *)p)->rtm_type) {
171455163Sshin		case RTM_NEWADDR:
171555163Sshin		case RTM_IFINFO:
171655163Sshin		case RTM_ADD:
171755163Sshin		case RTM_LOSING:
171855163Sshin		case RTM_MISS:
171955163Sshin		case RTM_RESOLVE:
172055163Sshin		case RTM_GET:
172155163Sshin		case RTM_LOCK:
172255163Sshin			/* should already be handled */
172355163Sshin			fatal("rtrecv: never reach here");
172478064Sume			/*NOTREACHED*/
172555163Sshin		case RTM_DELETE:
172678064Sume			if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY]) {
172778064Sume				trace(1, "\tsome of dst/gw/netamsk are "
172878064Sume				    "unavailable, ignored\n");
172955163Sshin				break;
173055163Sshin			}
173178064Sume			if ((rtm->rtm_flags & RTF_HOST) != 0) {
173278064Sume				mask.sin6_len = sizeof(mask);
173378064Sume				memset(&mask.sin6_addr, 0xff,
173478064Sume				    sizeof(mask.sin6_addr));
173578064Sume				rta[RTAX_NETMASK] = &mask;
173678064Sume			} else if (!rta[RTAX_NETMASK]) {
173778064Sume				trace(1, "\tsome of dst/gw/netamsk are "
173878064Sume				    "unavailable, ignored\n");
173978064Sume				break;
174078064Sume			}
174178064Sume			if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY],
174278064Sume			    rta[RTAX_NETMASK]) == 0) {
174355163Sshin				rtable++;	/*just to be sure*/
174455163Sshin			}
174555163Sshin			break;
174655163Sshin		case RTM_CHANGE:
174755163Sshin		case RTM_REDIRECT:
174855163Sshin			trace(1, "\tnot supported yet, ignored\n");
174955163Sshin			break;
175055163Sshin		case RTM_DELADDR:
175155163Sshin			if (!rta[RTAX_NETMASK] || !rta[RTAX_IFA]) {
175255163Sshin				trace(1, "\tno netmask or ifa given, ignored\n");
175355163Sshin				break;
175455163Sshin			}
175555163Sshin			if (ifam->ifam_index < nindex2ifc)
175655163Sshin				ifcp = index2ifc[ifam->ifam_index];
175755163Sshin			else
175855163Sshin				ifcp = NULL;
175955163Sshin			if (!ifcp) {
176055163Sshin				trace(1, "\tinvalid ifam_index %d, ignored\n",
176155163Sshin					ifam->ifam_index);
176255163Sshin				break;
176355163Sshin			}
176478064Sume			if (!rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK]))
176578064Sume				iface++;
176655163Sshin			break;
176755163Sshin		case RTM_OLDADD:
176855163Sshin		case RTM_OLDDEL:
176955163Sshin			trace(1, "\tnot supported yet, ignored\n");
177055163Sshin			break;
177155163Sshin		}
177255163Sshin
177355163Sshin	}
177455163Sshin
177555163Sshin	if (iface) {
177655163Sshin		trace(1, "rtsock: reconfigure interfaces, refresh interface routes\n");
177755163Sshin		ifconfig();
177855163Sshin		for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next)
177978064Sume			if (ifcp->ifc_cflags & IFC_CHANGED) {
178078064Sume				if (ifrt(ifcp, 1)) {
178178064Sume					for (ic = ifc; ic; ic = ic->ifc_next) {
178278064Sume						if (ifcp->ifc_index == ic->ifc_index)
178378064Sume							continue;
178478064Sume						if (ic->ifc_flags & IFF_UP)
178578064Sume							ripsend(ic, &ic->ifc_ripsin,
178678064Sume							RRTF_CHANGED);
178778064Sume					}
178878064Sume					/* Reset the flag */
178978064Sume					for (rrt = riprt; rrt; rrt = rrt->rrt_next)
179078064Sume						rrt->rrt_rflags &= ~RRTF_CHANGED;
179178064Sume				}
179278064Sume				ifcp->ifc_cflags &= ~IFC_CHANGED;
179378064Sume			}
179455163Sshin	}
179555163Sshin	if (rtable) {
179655163Sshin		trace(1, "rtsock: read routing table again\n");
179755163Sshin		krtread(1);
179855163Sshin	}
179955163Sshin}
180055163Sshin
180155163Sshin/*
180255163Sshin * remove specified route from the internal routing table.
180355163Sshin */
180455163Sshinint
180555163Sshinrt_del(sdst, sgw, smask)
180655163Sshin	const struct sockaddr_in6 *sdst;
180755163Sshin	const struct sockaddr_in6 *sgw;
180855163Sshin	const struct sockaddr_in6 *smask;
180955163Sshin{
181055163Sshin	const struct in6_addr *dst = NULL;
181155163Sshin	const struct in6_addr *gw = NULL;
181255163Sshin	int prefix;
181355163Sshin	struct netinfo6 ni6;
181455163Sshin	struct riprt *rrt = NULL;
181555163Sshin	time_t t_lifetime;
181655163Sshin
181755163Sshin	if (sdst->sin6_family != AF_INET6) {
181855163Sshin		trace(1, "\tother AF, ignored\n");
181955163Sshin		return -1;
182055163Sshin	}
182155163Sshin	if (IN6_IS_ADDR_LINKLOCAL(&sdst->sin6_addr)
182255163Sshin	 || IN6_ARE_ADDR_EQUAL(&sdst->sin6_addr, &in6addr_loopback)
182355163Sshin	 || IN6_IS_ADDR_MULTICAST(&sdst->sin6_addr)) {
182455163Sshin		trace(1, "\taddress %s not interesting, ignored\n",
182555163Sshin			inet6_n2p(&sdst->sin6_addr));
182655163Sshin		return -1;
182755163Sshin	}
182855163Sshin	dst = &sdst->sin6_addr;
182978064Sume	if (sgw->sin6_family == AF_INET6) {
183055163Sshin		/* easy case */
183155163Sshin		gw = &sgw->sin6_addr;
183278064Sume		prefix = sin6mask2len(smask);
183355163Sshin	} else if (sgw->sin6_family == AF_LINK) {
183455163Sshin		/*
183555163Sshin		 * Interface route... a hard case.  We need to get the prefix
183655163Sshin		 * length from the kernel, but we now are parsing rtmsg.
183755163Sshin		 * We'll purge matching routes from my list, then get the
183855163Sshin		 * fresh list.
183955163Sshin		 */
184055163Sshin		struct riprt *longest;
1841108533Sschweikh		trace(1, "\t%s is an interface route, guessing prefixlen\n",
184255163Sshin			inet6_n2p(dst));
184355163Sshin		longest = NULL;
184455163Sshin		for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
184555163Sshin			if (IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
184655163Sshin					&sdst->sin6_addr)
184755163Sshin			 && IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) {
184855163Sshin				if (!longest
184955163Sshin				 || longest->rrt_info.rip6_plen <
185055163Sshin						 rrt->rrt_info.rip6_plen) {
185155163Sshin					longest = rrt;
185255163Sshin				}
185355163Sshin			}
185455163Sshin		}
185555163Sshin		rrt = longest;
185655163Sshin		if (!rrt) {
185755163Sshin			trace(1, "\tno matching interface route found\n");
185855163Sshin			return -1;
185955163Sshin		}
186055163Sshin		gw = &in6addr_loopback;
186155163Sshin		prefix = rrt->rrt_info.rip6_plen;
186255163Sshin	} else {
186378064Sume		trace(1, "\tunsupported af: (gw=%d)\n", sgw->sin6_family);
186455163Sshin		return -1;
186555163Sshin	}
186655163Sshin
186755163Sshin	trace(1, "\tdeleting %s/%d ", inet6_n2p(dst), prefix);
186855163Sshin	trace(1, "gw %s\n", inet6_n2p(gw));
186955163Sshin	t_lifetime = time(NULL) - RIP_LIFETIME;
187055163Sshin	/* age route for interface address */
187155163Sshin	memset(&ni6, 0, sizeof(ni6));
187255163Sshin	ni6.rip6_dest = *dst;
187355163Sshin	ni6.rip6_plen = prefix;
187455163Sshin	applyplen(&ni6.rip6_dest, ni6.rip6_plen);	/*to be sure*/
187555163Sshin	trace(1, "\tfind route %s/%d\n", inet6_n2p(&ni6.rip6_dest),
187655163Sshin		ni6.rip6_plen);
187778064Sume	if (!rrt && (rrt = rtsearch(&ni6, NULL)) == NULL) {
187855163Sshin		trace(1, "\tno route found\n");
187955163Sshin		return -1;
188055163Sshin	}
188178064Sume#if 0
188255163Sshin	if ((rrt->rrt_flags & RTF_STATIC) == 0) {
188355163Sshin		trace(1, "\tyou can delete static routes only\n");
188478064Sume	} else
188578064Sume#endif
188678064Sume	if (!IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, gw)) {
188755163Sshin		trace(1, "\tgw mismatch: %s <-> ",
188855163Sshin			inet6_n2p(&rrt->rrt_gw));
188955163Sshin		trace(1, "%s\n", inet6_n2p(gw));
189055163Sshin	} else {
189155163Sshin		trace(1, "\troute found, age it\n");
189255163Sshin		if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
189355163Sshin			rrt->rrt_t = t_lifetime;
189455163Sshin			rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
189555163Sshin		}
189655163Sshin	}
189755163Sshin	return 0;
189855163Sshin}
189955163Sshin
190055163Sshin/*
190155163Sshin * remove specified address from internal interface/routing table.
190255163Sshin */
190355163Sshinint
190455163Sshinrt_deladdr(ifcp, sifa, smask)
190555163Sshin	struct ifc *ifcp;
190655163Sshin	const struct sockaddr_in6 *sifa;
190755163Sshin	const struct sockaddr_in6 *smask;
190855163Sshin{
190955163Sshin	const struct in6_addr *addr = NULL;
191055163Sshin	int prefix;
191155163Sshin	struct ifac *ifa = NULL;
191255163Sshin	struct netinfo6 ni6;
191355163Sshin	struct riprt *rrt = NULL;
191455163Sshin	time_t t_lifetime;
191555163Sshin	int updated = 0;
191655163Sshin
191778064Sume	if (sifa->sin6_family != AF_INET6) {
191855163Sshin		trace(1, "\tother AF, ignored\n");
191955163Sshin		return -1;
192055163Sshin	}
192155163Sshin	addr = &sifa->sin6_addr;
192278064Sume	prefix = sin6mask2len(smask);
192355163Sshin
192455163Sshin	trace(1, "\tdeleting %s/%d from %s\n",
192555163Sshin		inet6_n2p(addr), prefix, ifcp->ifc_name);
192655163Sshin	ifa = ifa_match(ifcp, addr, prefix);
192755163Sshin	if (!ifa) {
192855163Sshin		trace(1, "\tno matching ifa found for %s/%d on %s\n",
192955163Sshin			inet6_n2p(addr), prefix, ifcp->ifc_name);
193055163Sshin		return -1;
193155163Sshin	}
193255163Sshin	if (ifa->ifa_conf != ifcp) {
193355163Sshin		trace(1, "\taddress table corrupt: back pointer does not match "
193455163Sshin			"(%s != %s)\n",
193555163Sshin			ifcp->ifc_name, ifa->ifa_conf->ifc_name);
193655163Sshin		return -1;
193755163Sshin	}
193855163Sshin	/* remove ifa from interface */
193955163Sshin	if (ifcp->ifc_addr == ifa)
194055163Sshin		ifcp->ifc_addr = ifa->ifa_next;
194155163Sshin	else {
194255163Sshin		struct ifac *p;
194355163Sshin		for (p = ifcp->ifc_addr; p; p = p->ifa_next) {
194455163Sshin			if (p->ifa_next == ifa) {
194555163Sshin				p->ifa_next = ifa->ifa_next;
194655163Sshin				break;
194755163Sshin			}
194855163Sshin		}
194955163Sshin	}
195055163Sshin	ifa->ifa_next = NULL;
195155163Sshin	ifa->ifa_conf = NULL;
195255163Sshin	t_lifetime = time(NULL) - RIP_LIFETIME;
195355163Sshin	/* age route for interface address */
195455163Sshin	memset(&ni6, 0, sizeof(ni6));
195555163Sshin	ni6.rip6_dest = ifa->ifa_addr;
195655163Sshin	ni6.rip6_plen = ifa->ifa_plen;
195755163Sshin	applyplen(&ni6.rip6_dest, ni6.rip6_plen);
195855163Sshin	trace(1, "\tfind interface route %s/%d on %d\n",
195955163Sshin		inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index);
196078064Sume	if ((rrt = rtsearch(&ni6, NULL)) != NULL) {
196155163Sshin		struct in6_addr none;
196255163Sshin		memset(&none, 0, sizeof(none));
196378064Sume		if (rrt->rrt_index == ifcp->ifc_index &&
196478064Sume		    (IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &none) ||
196578064Sume		     IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw))) {
196655163Sshin			trace(1, "\troute found, age it\n");
196755163Sshin			if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
196855163Sshin				rrt->rrt_t = t_lifetime;
196955163Sshin				rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
197055163Sshin			}
197155163Sshin			updated++;
197255163Sshin		} else {
197355163Sshin			trace(1, "\tnon-interface route found: %s/%d on %d\n",
197455163Sshin				inet6_n2p(&rrt->rrt_info.rip6_dest),
197555163Sshin				rrt->rrt_info.rip6_plen,
197655163Sshin				rrt->rrt_index);
197755163Sshin		}
197855163Sshin	} else
197955163Sshin		trace(1, "\tno interface route found\n");
198055163Sshin	/* age route for p2p destination */
198155163Sshin	if (ifcp->ifc_flags & IFF_POINTOPOINT) {
198255163Sshin		memset(&ni6, 0, sizeof(ni6));
198355163Sshin		ni6.rip6_dest = ifa->ifa_raddr;
198455163Sshin		ni6.rip6_plen = 128;
198555163Sshin		applyplen(&ni6.rip6_dest, ni6.rip6_plen);	/*to be sure*/
198655163Sshin		trace(1, "\tfind p2p route %s/%d on %d\n",
198755163Sshin			inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen,
198855163Sshin			ifcp->ifc_index);
198978064Sume		if ((rrt = rtsearch(&ni6, NULL)) != NULL) {
199078064Sume			if (rrt->rrt_index == ifcp->ifc_index &&
199178064Sume			    IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &ifa->ifa_addr)) {
199255163Sshin				trace(1, "\troute found, age it\n");
199355163Sshin				if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
199455163Sshin					rrt->rrt_t = t_lifetime;
199555163Sshin					rrt->rrt_info.rip6_metric =
199678064Sume					    HOPCNT_INFINITY6;
199755163Sshin					updated++;
199855163Sshin				}
199955163Sshin			} else {
200055163Sshin				trace(1, "\tnon-p2p route found: %s/%d on %d\n",
200155163Sshin					inet6_n2p(&rrt->rrt_info.rip6_dest),
200255163Sshin					rrt->rrt_info.rip6_plen,
200355163Sshin					rrt->rrt_index);
200455163Sshin			}
200555163Sshin		} else
200655163Sshin			trace(1, "\tno p2p route found\n");
200755163Sshin	}
200855163Sshin	return updated ? 0 : -1;
200955163Sshin}
201055163Sshin
201155163Sshin/*
201255163Sshin * Get each interface address and put those interface routes to the route
201355163Sshin * list.
201455163Sshin */
201578064Sumeint
201655163Sshinifrt(ifcp, again)
201762607Sitojun	struct ifc *ifcp;
201855163Sshin	int again;
201955163Sshin{
202062607Sitojun	struct ifac *ifa;
2021119042Sume	struct riprt *rrt = NULL, *search_rrt, *prev_rrt, *loop_rrt;
202262607Sitojun	struct netinfo6 *np;
202378064Sume	time_t t_lifetime;
202478064Sume	int need_trigger = 0;
202555163Sshin
2026122677Sume#if 0
202755163Sshin	if (ifcp->ifc_flags & IFF_LOOPBACK)
202878064Sume		return 0;			/* ignore loopback */
2029122677Sume#endif
2030122677Sume
203162607Sitojun	if (ifcp->ifc_flags & IFF_POINTOPOINT) {
203262607Sitojun		ifrt_p2p(ifcp, again);
203378064Sume		return 0;
203462607Sitojun	}
203562607Sitojun
203655163Sshin	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
203762607Sitojun		if (IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) {
203862607Sitojun#if 0
203962607Sitojun			trace(1, "route: %s on %s: "
204062607Sitojun			    "skip linklocal interface address\n",
204162607Sitojun			    inet6_n2p(&ifa->ifa_addr), ifcp->ifc_name);
204262607Sitojun#endif
204362607Sitojun			continue;
204462607Sitojun		}
204562607Sitojun		if (IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_addr)) {
204662607Sitojun#if 0
204762607Sitojun			trace(1, "route: %s: skip unspec interface address\n",
204862607Sitojun			    ifcp->ifc_name);
204962607Sitojun#endif
205062607Sitojun			continue;
205162607Sitojun		}
2052122677Sume		if (IN6_IS_ADDR_LOOPBACK(&ifa->ifa_addr)) {
2053122677Sume#if 0
2054122677Sume			trace(1, "route: %s: skip loopback address\n",
2055122677Sume			    ifcp->ifc_name);
2056122677Sume#endif
2057122677Sume			continue;
2058122677Sume		}
205978064Sume		if (ifcp->ifc_flags & IFF_UP) {
206078064Sume			if ((rrt = MALLOC(struct riprt)) == NULL)
206178064Sume				fatal("malloc: struct riprt");
206278064Sume			memset(rrt, 0, sizeof(*rrt));
206378064Sume			rrt->rrt_same = NULL;
206478064Sume			rrt->rrt_index = ifcp->ifc_index;
206578064Sume			rrt->rrt_t = 0;	/* don't age */
206678064Sume			rrt->rrt_info.rip6_dest = ifa->ifa_addr;
206778064Sume			rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
206878064Sume			rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric;
206978064Sume			rrt->rrt_info.rip6_plen = ifa->ifa_plen;
2070122677Sume			if (ifa->ifa_plen == 128)
2071122677Sume				rrt->rrt_flags = RTF_HOST;
2072122677Sume			else
2073122677Sume				rrt->rrt_flags = RTF_CLONING;
207478064Sume			rrt->rrt_rflags |= RRTF_CHANGED;
207578064Sume			applyplen(&rrt->rrt_info.rip6_dest, ifa->ifa_plen);
207678064Sume			memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
207778064Sume			rrt->rrt_gw = ifa->ifa_addr;
207878064Sume			np = &rrt->rrt_info;
207978064Sume			search_rrt = rtsearch(np, &prev_rrt);
208078064Sume			if (search_rrt != NULL) {
2081119042Sume				if (search_rrt->rrt_info.rip6_metric <=
208278064Sume				    rrt->rrt_info.rip6_metric) {
208378064Sume					/* Already have better route */
208478064Sume					if (!again) {
208578064Sume						trace(1, "route: %s/%d: "
208678064Sume						    "already registered (%s)\n",
208778064Sume						    inet6_n2p(&np->rip6_dest), np->rip6_plen,
208878064Sume						    ifcp->ifc_name);
208978064Sume					}
2090119042Sume					goto next;
209178064Sume				}
2092119042Sume
2093119042Sume				if (prev_rrt)
2094119042Sume					prev_rrt->rrt_next = rrt->rrt_next;
2095119042Sume				else
2096119042Sume					riprt = rrt->rrt_next;
2097119042Sume				delroute(&rrt->rrt_info, &rrt->rrt_gw);
209878064Sume			}
209955163Sshin			/* Attach the route to the list */
210062607Sitojun			trace(1, "route: %s/%d: register route (%s)\n",
210162607Sitojun			    inet6_n2p(&np->rip6_dest), np->rip6_plen,
210262607Sitojun			    ifcp->ifc_name);
210355163Sshin			rrt->rrt_next = riprt;
210455163Sshin			riprt = rrt;
210578064Sume			addroute(rrt, &rrt->rrt_gw, ifcp);
2106119042Sume			rrt = NULL;
210778064Sume			sendrequest(ifcp);
210878064Sume			ripsend(ifcp, &ifcp->ifc_ripsin, 0);
210978064Sume			need_trigger = 1;
211055163Sshin		} else {
211178064Sume			for (loop_rrt = riprt; loop_rrt; loop_rrt = loop_rrt->rrt_next) {
211278064Sume				if (loop_rrt->rrt_index == ifcp->ifc_index) {
211378064Sume					t_lifetime = time(NULL) - RIP_LIFETIME;
211478064Sume					if (loop_rrt->rrt_t == 0 || loop_rrt->rrt_t > t_lifetime) {
211578064Sume						loop_rrt->rrt_t = t_lifetime;
211678064Sume						loop_rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
211778064Sume						loop_rrt->rrt_rflags |= RRTF_CHANGED;
211878064Sume						need_trigger = 1;
211978064Sume					}
212078064Sume				}
212155163Sshin			}
212278064Sume                }
2123119042Sume	next:
2124119042Sume		if (rrt)
2125119042Sume			free(rrt);
212662607Sitojun	}
212778064Sume	return need_trigger;
212862607Sitojun}
212955163Sshin
213062607Sitojun/*
213162607Sitojun * there are couple of p2p interface routing models.  "behavior" lets
213262607Sitojun * you pick one.  it looks that gated behavior fits best with BSDs,
2133119035Sume * since BSD kernels do not look at prefix length on p2p interfaces.
213462607Sitojun */
213562607Sitojunvoid
213662607Sitojunifrt_p2p(ifcp, again)
213762607Sitojun	struct ifc *ifcp;
213862607Sitojun	int again;
213962607Sitojun{
214062607Sitojun	struct ifac *ifa;
214178064Sume	struct riprt *rrt, *orrt, *prevrrt;
214262607Sitojun	struct netinfo6 *np;
214362607Sitojun	struct in6_addr addr, dest;
214462607Sitojun	int advert, ignore, i;
214562607Sitojun#define P2PADVERT_NETWORK	1
214662607Sitojun#define P2PADVERT_ADDR		2
214762607Sitojun#define P2PADVERT_DEST		4
214862607Sitojun#define P2PADVERT_MAX		4
214962607Sitojun	const enum { CISCO, GATED, ROUTE6D } behavior = GATED;
215078064Sume	const char *category = "";
215162607Sitojun	const char *noadv;
215262607Sitojun
215362607Sitojun	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
215462607Sitojun		addr = ifa->ifa_addr;
215562607Sitojun		dest = ifa->ifa_raddr;
215662607Sitojun		applyplen(&addr, ifa->ifa_plen);
215762607Sitojun		applyplen(&dest, ifa->ifa_plen);
215862607Sitojun		advert = ignore = 0;
215962607Sitojun		switch (behavior) {
216062607Sitojun		case CISCO:
216162607Sitojun			/*
216262607Sitojun			 * honor addr/plen, just like normal shared medium
216362607Sitojun			 * interface.  this may cause trouble if you reuse
216462607Sitojun			 * addr/plen on other interfaces.
216562607Sitojun			 *
216662607Sitojun			 * advertise addr/plen.
216762607Sitojun			 */
216862607Sitojun			advert |= P2PADVERT_NETWORK;
216962607Sitojun			break;
217062607Sitojun		case GATED:
217162607Sitojun			/*
217262607Sitojun			 * prefixlen on p2p interface is meaningless.
217362607Sitojun			 * advertise addr/128 and dest/128.
217462607Sitojun			 *
217562607Sitojun			 * do not install network route to route6d routing
217662607Sitojun			 * table (if we do, it would prevent route installation
217762607Sitojun			 * for other p2p interface that shares addr/plen).
217878064Sume			 *
217978064Sume			 * XXX what should we do if dest is ::?  it will not
218078064Sume			 * get announced anyways (see following filter),
218178064Sume			 * but we need to think.
218262607Sitojun			 */
218362607Sitojun			advert |= P2PADVERT_ADDR;
218462607Sitojun			advert |= P2PADVERT_DEST;
218562607Sitojun			ignore |= P2PADVERT_NETWORK;
218662607Sitojun			break;
218762607Sitojun		case ROUTE6D:
218862607Sitojun			/*
218978064Sume			 * just for testing.  actually the code is redundant
219078064Sume			 * given the current p2p interface address assignment
219178064Sume			 * rule for kame kernel.
219278064Sume			 *
219378064Sume			 * intent:
219478064Sume			 *	A/n -> announce A/n
219578064Sume			 *	A B/n, A and B share prefix -> A/n (= B/n)
219678064Sume			 *	A B/n, do not share prefix -> A/128 and B/128
219778064Sume			 * actually, A/64 and A B/128 are the only cases
219878064Sume			 * permitted by the kernel:
219978064Sume			 *	A/64 -> A/64
220078064Sume			 *	A B/128 -> A/128 and B/128
220162607Sitojun			 */
220278064Sume			if (!IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_raddr)) {
220378064Sume				if (IN6_ARE_ADDR_EQUAL(&addr, &dest))
220478064Sume					advert |= P2PADVERT_NETWORK;
220578064Sume				else {
220678064Sume					advert |= P2PADVERT_ADDR;
220778064Sume					advert |= P2PADVERT_DEST;
220878064Sume					ignore |= P2PADVERT_NETWORK;
220978064Sume				}
221078064Sume			} else
221162607Sitojun				advert |= P2PADVERT_NETWORK;
221262607Sitojun			break;
221362607Sitojun		}
221462607Sitojun
221562607Sitojun		for (i = 1; i <= P2PADVERT_MAX; i *= 2) {
221662607Sitojun			if ((ignore & i) != 0)
221762607Sitojun				continue;
221878064Sume			if ((rrt = MALLOC(struct riprt)) == NULL) {
221955163Sshin				fatal("malloc: struct riprt");
222078064Sume				/*NOTREACHED*/
222178064Sume			}
222262607Sitojun			memset(rrt, 0, sizeof(*rrt));
222355163Sshin			rrt->rrt_same = NULL;
222455163Sshin			rrt->rrt_index = ifcp->ifc_index;
222562607Sitojun			rrt->rrt_t = 0;	/* don't age */
222662607Sitojun			switch (i) {
222762607Sitojun			case P2PADVERT_NETWORK:
222862607Sitojun				rrt->rrt_info.rip6_dest = ifa->ifa_addr;
222962607Sitojun				rrt->rrt_info.rip6_plen = ifa->ifa_plen;
223062607Sitojun				applyplen(&rrt->rrt_info.rip6_dest,
223162607Sitojun				    ifa->ifa_plen);
223262607Sitojun				category = "network";
223362607Sitojun				break;
223462607Sitojun			case P2PADVERT_ADDR:
223562607Sitojun				rrt->rrt_info.rip6_dest = ifa->ifa_addr;
223662607Sitojun				rrt->rrt_info.rip6_plen = 128;
223778064Sume				rrt->rrt_gw = in6addr_loopback;
223862607Sitojun				category = "addr";
223962607Sitojun				break;
224062607Sitojun			case P2PADVERT_DEST:
224162607Sitojun				rrt->rrt_info.rip6_dest = ifa->ifa_raddr;
224262607Sitojun				rrt->rrt_info.rip6_plen = 128;
224378064Sume				rrt->rrt_gw = ifa->ifa_addr;
224462607Sitojun				category = "dest";
224562607Sitojun				break;
224662607Sitojun			}
224762607Sitojun			if (IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_info.rip6_dest) ||
224862607Sitojun			    IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_info.rip6_dest)) {
224962607Sitojun#if 0
225062607Sitojun				trace(1, "route: %s: skip unspec/linklocal "
225162607Sitojun				    "(%s on %s)\n", category, ifcp->ifc_name);
225262607Sitojun#endif
225362607Sitojun				free(rrt);
225462607Sitojun				continue;
225562607Sitojun			}
225662607Sitojun			if ((advert & i) == 0) {
225762607Sitojun				rrt->rrt_rflags |= RRTF_NOADVERTISE;
225862607Sitojun				noadv = ", NO-ADV";
225962607Sitojun			} else
226062607Sitojun				noadv = "";
226155163Sshin			rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
226262607Sitojun			rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric;
226355163Sshin			np = &rrt->rrt_info;
226478064Sume			orrt = rtsearch(np, &prevrrt);
226578064Sume			if (!orrt) {
226655163Sshin				/* Attach the route to the list */
226762607Sitojun				trace(1, "route: %s/%d: register route "
226862607Sitojun				    "(%s on %s%s)\n",
226962607Sitojun				    inet6_n2p(&np->rip6_dest), np->rip6_plen,
227062607Sitojun				    category, ifcp->ifc_name, noadv);
227155163Sshin				rrt->rrt_next = riprt;
227255163Sshin				riprt = rrt;
227378064Sume			} else if (rrt->rrt_index != orrt->rrt_index ||
227478064Sume			    rrt->rrt_info.rip6_metric != orrt->rrt_info.rip6_metric) {
227578064Sume				/* swap route */
227678064Sume				rrt->rrt_next = orrt->rrt_next;
227778064Sume				if (prevrrt)
227878064Sume					prevrrt->rrt_next = rrt;
227978064Sume				else
228078064Sume					riprt = rrt;
228178064Sume				free(orrt);
228278064Sume
228378064Sume				trace(1, "route: %s/%d: update (%s on %s%s)\n",
228478064Sume				    inet6_n2p(&np->rip6_dest), np->rip6_plen,
228578064Sume				    category, ifcp->ifc_name, noadv);
228655163Sshin			} else {
228755163Sshin				/* Already found */
228855163Sshin				if (!again) {
228962607Sitojun					trace(1, "route: %s/%d: "
229062607Sitojun					    "already registered (%s on %s%s)\n",
229162607Sitojun					    inet6_n2p(&np->rip6_dest),
229262607Sitojun					    np->rip6_plen, category,
229362607Sitojun					    ifcp->ifc_name, noadv);
229455163Sshin				}
229555163Sshin				free(rrt);
229655163Sshin			}
229755163Sshin		}
229855163Sshin	}
229962607Sitojun#undef P2PADVERT_NETWORK
230062607Sitojun#undef P2PADVERT_ADDR
230162607Sitojun#undef P2PADVERT_DEST
230262607Sitojun#undef P2PADVERT_MAX
230355163Sshin}
230455163Sshin
230555163Sshinint
230655163Sshingetifmtu(ifindex)
230755163Sshin	int	ifindex;
230855163Sshin{
230955163Sshin	int	mib[6];
231055163Sshin	char	*buf;
231155163Sshin	size_t	msize;
231255163Sshin	struct	if_msghdr *ifm;
231355163Sshin	int	mtu;
231455163Sshin
231555163Sshin	mib[0] = CTL_NET;
231655163Sshin	mib[1] = PF_ROUTE;
231755163Sshin	mib[2] = 0;
231855163Sshin	mib[3] = AF_INET6;
231955163Sshin	mib[4] = NET_RT_IFLIST;
232055163Sshin	mib[5] = ifindex;
232178064Sume	if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) {
232255163Sshin		fatal("sysctl estimate NET_RT_IFLIST");
232378064Sume		/*NOTREACHED*/
232478064Sume	}
232578064Sume	if ((buf = malloc(msize)) == NULL) {
232655163Sshin		fatal("malloc");
232778064Sume		/*NOTREACHED*/
232878064Sume	}
232978064Sume	if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) {
233055163Sshin		fatal("sysctl NET_RT_IFLIST");
233178064Sume		/*NOTREACHED*/
233278064Sume	}
233355163Sshin	ifm = (struct if_msghdr *)buf;
233455163Sshin	mtu = ifm->ifm_data.ifi_mtu;
233578064Sume	if (ifindex != ifm->ifm_index) {
233655163Sshin		fatal("ifindex does not match with ifm_index");
233778064Sume		/*NOTREACHED*/
233878064Sume	}
233955163Sshin	free(buf);
234055163Sshin	return mtu;
234155163Sshin}
234255163Sshin
234355163Sshinconst char *
234455163Sshinrttypes(rtm)
234555163Sshin	struct rt_msghdr *rtm;
234655163Sshin{
234762607Sitojun#define	RTTYPE(s, f) \
234862607Sitojundo { \
234962607Sitojun	if (rtm->rtm_type == (f)) \
235062607Sitojun		return (s); \
235162607Sitojun} while (0)
235255163Sshin	RTTYPE("ADD", RTM_ADD);
235355163Sshin	RTTYPE("DELETE", RTM_DELETE);
235455163Sshin	RTTYPE("CHANGE", RTM_CHANGE);
235555163Sshin	RTTYPE("GET", RTM_GET);
235655163Sshin	RTTYPE("LOSING", RTM_LOSING);
235755163Sshin	RTTYPE("REDIRECT", RTM_REDIRECT);
235855163Sshin	RTTYPE("MISS", RTM_MISS);
235955163Sshin	RTTYPE("LOCK", RTM_LOCK);
236055163Sshin	RTTYPE("OLDADD", RTM_OLDADD);
236155163Sshin	RTTYPE("OLDDEL", RTM_OLDDEL);
236255163Sshin	RTTYPE("RESOLVE", RTM_RESOLVE);
236355163Sshin	RTTYPE("NEWADDR", RTM_NEWADDR);
236455163Sshin	RTTYPE("DELADDR", RTM_DELADDR);
236555163Sshin	RTTYPE("IFINFO", RTM_IFINFO);
236678064Sume#ifdef RTM_OLDADD
236778064Sume	RTTYPE("OLDADD", RTM_OLDADD);
236878064Sume#endif
236978064Sume#ifdef RTM_OLDDEL
237078064Sume	RTTYPE("OLDDEL", RTM_OLDDEL);
237178064Sume#endif
237278064Sume#ifdef RTM_OIFINFO
237378064Sume	RTTYPE("OIFINFO", RTM_OIFINFO);
237478064Sume#endif
237578064Sume#ifdef RTM_IFANNOUNCE
237678064Sume	RTTYPE("IFANNOUNCE", RTM_IFANNOUNCE);
237778064Sume#endif
237878064Sume#ifdef RTM_NEWMADDR
237978064Sume	RTTYPE("NEWMADDR", RTM_NEWMADDR);
238078064Sume#endif
238178064Sume#ifdef RTM_DELMADDR
238278064Sume	RTTYPE("DELMADDR", RTM_DELMADDR);
238378064Sume#endif
238455163Sshin#undef RTTYPE
238555163Sshin	return NULL;
238655163Sshin}
238755163Sshin
238855163Sshinconst char *
238955163Sshinrtflags(rtm)
239055163Sshin	struct rt_msghdr *rtm;
239155163Sshin{
239255163Sshin	static char buf[BUFSIZ];
239355163Sshin
239478064Sume	/*
239578064Sume	 * letter conflict should be okay.  painful when *BSD diverges...
239678064Sume	 */
239778064Sume	strlcpy(buf, "", sizeof(buf));
239862607Sitojun#define	RTFLAG(s, f) \
239962607Sitojundo { \
240062607Sitojun	if (rtm->rtm_flags & (f)) \
240178064Sume		strlcat(buf, (s), sizeof(buf)); \
240262607Sitojun} while (0)
240355163Sshin	RTFLAG("U", RTF_UP);
240455163Sshin	RTFLAG("G", RTF_GATEWAY);
240555163Sshin	RTFLAG("H", RTF_HOST);
240655163Sshin	RTFLAG("R", RTF_REJECT);
240755163Sshin	RTFLAG("D", RTF_DYNAMIC);
240855163Sshin	RTFLAG("M", RTF_MODIFIED);
240955163Sshin	RTFLAG("d", RTF_DONE);
241055163Sshin#ifdef	RTF_MASK
241155163Sshin	RTFLAG("m", RTF_MASK);
241255163Sshin#endif
241355163Sshin	RTFLAG("C", RTF_CLONING);
241478064Sume#ifdef RTF_CLONED
241578064Sume	RTFLAG("c", RTF_CLONED);
241678064Sume#endif
241778064Sume#ifdef RTF_PRCLONING
241878064Sume	RTFLAG("c", RTF_PRCLONING);
241978064Sume#endif
242078064Sume#ifdef RTF_WASCLONED
242178064Sume	RTFLAG("W", RTF_WASCLONED);
242278064Sume#endif
242355163Sshin	RTFLAG("X", RTF_XRESOLVE);
242455163Sshin	RTFLAG("L", RTF_LLINFO);
242555163Sshin	RTFLAG("S", RTF_STATIC);
242655163Sshin	RTFLAG("B", RTF_BLACKHOLE);
242778064Sume#ifdef RTF_PROTO3
242878064Sume	RTFLAG("3", RTF_PROTO3);
242978064Sume#endif
243055163Sshin	RTFLAG("2", RTF_PROTO2);
243155163Sshin	RTFLAG("1", RTF_PROTO1);
243278064Sume#ifdef RTF_BROADCAST
243378064Sume	RTFLAG("b", RTF_BROADCAST);
243478064Sume#endif
243578064Sume#ifdef RTF_DEFAULT
243678064Sume	RTFLAG("d", RTF_DEFAULT);
243778064Sume#endif
243878064Sume#ifdef RTF_ISAROUTER
243978064Sume	RTFLAG("r", RTF_ISAROUTER);
244078064Sume#endif
244178064Sume#ifdef RTF_TUNNEL
244278064Sume	RTFLAG("T", RTF_TUNNEL);
244378064Sume#endif
244478064Sume#ifdef RTF_AUTH
244578064Sume	RTFLAG("A", RTF_AUTH);
244678064Sume#endif
244778064Sume#ifdef RTF_CRYPT
244878064Sume	RTFLAG("E", RTF_CRYPT);
244978064Sume#endif
245055163Sshin#undef RTFLAG
245155163Sshin	return buf;
245255163Sshin}
245355163Sshin
245455163Sshinconst char *
245555163Sshinifflags(flags)
245655163Sshin	int flags;
245755163Sshin{
245855163Sshin	static char buf[BUFSIZ];
245955163Sshin
246078064Sume	strlcpy(buf, "", sizeof(buf));
246162607Sitojun#define	IFFLAG(s, f) \
246262607Sitojundo { \
2463119040Sume	if (flags & (f)) { \
246462607Sitojun		if (buf[0]) \
246578064Sume			strlcat(buf, ",", sizeof(buf)); \
2466119040Sume		strlcat(buf, (s), sizeof(buf)); \
246762607Sitojun	} \
246862607Sitojun} while (0)
246955163Sshin	IFFLAG("UP", IFF_UP);
247055163Sshin	IFFLAG("BROADCAST", IFF_BROADCAST);
247155163Sshin	IFFLAG("DEBUG", IFF_DEBUG);
247255163Sshin	IFFLAG("LOOPBACK", IFF_LOOPBACK);
247355163Sshin	IFFLAG("POINTOPOINT", IFF_POINTOPOINT);
247455163Sshin#ifdef IFF_NOTRAILERS
247555163Sshin	IFFLAG("NOTRAILERS", IFF_NOTRAILERS);
247655163Sshin#endif
247778064Sume#ifdef IFF_SMART
247878064Sume	IFFLAG("SMART", IFF_SMART);
247978064Sume#endif
248055163Sshin	IFFLAG("RUNNING", IFF_RUNNING);
248155163Sshin	IFFLAG("NOARP", IFF_NOARP);
248255163Sshin	IFFLAG("PROMISC", IFF_PROMISC);
248355163Sshin	IFFLAG("ALLMULTI", IFF_ALLMULTI);
248455163Sshin	IFFLAG("OACTIVE", IFF_OACTIVE);
248555163Sshin	IFFLAG("SIMPLEX", IFF_SIMPLEX);
248655163Sshin	IFFLAG("LINK0", IFF_LINK0);
248755163Sshin	IFFLAG("LINK1", IFF_LINK1);
248855163Sshin	IFFLAG("LINK2", IFF_LINK2);
248955163Sshin	IFFLAG("MULTICAST", IFF_MULTICAST);
249055163Sshin#undef IFFLAG
249155163Sshin	return buf;
249255163Sshin}
249355163Sshin
249455163Sshinvoid
249555163Sshinkrtread(again)
249655163Sshin	int again;
249755163Sshin{
249855163Sshin	int mib[6];
249955163Sshin	size_t msize;
250055163Sshin	char *buf, *p, *lim;
250155163Sshin	struct rt_msghdr *rtm;
250255163Sshin	int retry;
250355163Sshin	const char *errmsg;
250455163Sshin
250555163Sshin	retry = 0;
250655163Sshin	buf = NULL;
250755163Sshin	mib[0] = CTL_NET;
250855163Sshin	mib[1] = PF_ROUTE;
250955163Sshin	mib[2] = 0;
251055163Sshin	mib[3] = AF_INET6;	/* Address family */
251155163Sshin	mib[4] = NET_RT_DUMP;	/* Dump the kernel routing table */
251255163Sshin	mib[5] = 0;		/* No flags */
251355163Sshin	do {
251455163Sshin		retry++;
251555163Sshin		errmsg = NULL;
251655163Sshin		if (buf)
251755163Sshin			free(buf);
251855163Sshin		if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) {
251955163Sshin			errmsg = "sysctl estimate";
252055163Sshin			continue;
252155163Sshin		}
252255163Sshin		if ((buf = malloc(msize)) == NULL) {
252355163Sshin			errmsg = "malloc";
252455163Sshin			continue;
252555163Sshin		}
252655163Sshin		if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) {
252755163Sshin			errmsg = "sysctl NET_RT_DUMP";
252855163Sshin			continue;
252955163Sshin		}
253055163Sshin	} while (retry < 5 && errmsg != NULL);
253178064Sume	if (errmsg) {
253269279Sume		fatal("%s (with %d retries, msize=%lu)", errmsg, retry,
253369279Sume		    (u_long)msize);
253478064Sume		/*NOTREACHED*/
253578064Sume	} else if (1 < retry)
253655163Sshin		syslog(LOG_INFO, "NET_RT_DUMP %d retires", retry);
253755163Sshin
253855163Sshin	lim = buf + msize;
253955163Sshin	for (p = buf; p < lim; p += rtm->rtm_msglen) {
254055163Sshin		rtm = (struct rt_msghdr *)p;
254155163Sshin		rt_entry(rtm, again);
254255163Sshin	}
254355163Sshin	free(buf);
254455163Sshin}
254555163Sshin
254655163Sshinvoid
254755163Sshinrt_entry(rtm, again)
254855163Sshin	struct rt_msghdr *rtm;
254955163Sshin	int again;
255055163Sshin{
255155163Sshin	struct	sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask;
255255163Sshin	struct	sockaddr_in6 *sin6_genmask, *sin6_ifp;
255355163Sshin	char	*rtmp, *ifname = NULL;
255478064Sume	struct	riprt *rrt, *orrt;
255555163Sshin	struct	netinfo6 *np;
255655163Sshin	int	s;
255755163Sshin
255855163Sshin	sin6_dst = sin6_gw = sin6_mask = sin6_genmask = sin6_ifp = 0;
255955163Sshin	if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags &
256062607Sitojun		(RTF_CLONING|RTF_XRESOLVE|RTF_LLINFO|RTF_BLACKHOLE)) {
256155163Sshin		return;		/* not interested in the link route */
256262607Sitojun	}
256369279Sume	/* do not look at cloned routes */
256469279Sume#ifdef RTF_WASCLONED
256569279Sume	if (rtm->rtm_flags & RTF_WASCLONED)
256669279Sume		return;
256769279Sume#endif
256869279Sume#ifdef RTF_CLONED
256969279Sume	if (rtm->rtm_flags & RTF_CLONED)
257069279Sume		return;
257169279Sume#endif
257269279Sume	/*
257369279Sume	 * do not look at dynamic routes.
257469279Sume	 * netbsd/openbsd cloned routes have UGHD.
257569279Sume	 */
257669279Sume	if (rtm->rtm_flags & RTF_DYNAMIC)
257769279Sume		return;
257855163Sshin	rtmp = (char *)(rtm + 1);
257955163Sshin	/* Destination */
258055163Sshin	if ((rtm->rtm_addrs & RTA_DST) == 0)
258155163Sshin		return;		/* ignore routes without destination address */
258255163Sshin	sin6_dst = (struct sockaddr_in6 *)rtmp;
258364631Sitojun	rtmp += ROUNDUP(sin6_dst->sin6_len);
258455163Sshin	if (rtm->rtm_addrs & RTA_GATEWAY) {
258555163Sshin		sin6_gw = (struct sockaddr_in6 *)rtmp;
258655163Sshin		rtmp += ROUNDUP(sin6_gw->sin6_len);
258755163Sshin	}
258855163Sshin	if (rtm->rtm_addrs & RTA_NETMASK) {
258955163Sshin		sin6_mask = (struct sockaddr_in6 *)rtmp;
259055163Sshin		rtmp += ROUNDUP(sin6_mask->sin6_len);
259155163Sshin	}
259255163Sshin	if (rtm->rtm_addrs & RTA_GENMASK) {
259355163Sshin		sin6_genmask = (struct sockaddr_in6 *)rtmp;
259455163Sshin		rtmp += ROUNDUP(sin6_genmask->sin6_len);
259555163Sshin	}
259655163Sshin	if (rtm->rtm_addrs & RTA_IFP) {
259755163Sshin		sin6_ifp = (struct sockaddr_in6 *)rtmp;
259855163Sshin		rtmp += ROUNDUP(sin6_ifp->sin6_len);
259955163Sshin	}
260055163Sshin
260155163Sshin	/* Destination */
260255163Sshin	if (sin6_dst->sin6_family != AF_INET6)
260355163Sshin		return;
260455163Sshin	if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst->sin6_addr))
260555163Sshin		return;		/* Link-local */
260655163Sshin	if (IN6_ARE_ADDR_EQUAL(&sin6_dst->sin6_addr, &in6addr_loopback))
260755163Sshin		return;		/* Loopback */
260855163Sshin	if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr))
260955163Sshin		return;
261055163Sshin
261178064Sume	if ((rrt = MALLOC(struct riprt)) == NULL) {
261255163Sshin		fatal("malloc: struct riprt");
261378064Sume		/*NOTREACHED*/
261478064Sume	}
261562607Sitojun	memset(rrt, 0, sizeof(*rrt));
261655163Sshin	np = &rrt->rrt_info;
261755163Sshin	rrt->rrt_same = NULL;
261855163Sshin	rrt->rrt_t = time(NULL);
261955163Sshin	if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC))
262055163Sshin		rrt->rrt_t = 0;	/* Don't age static routes */
2621122677Sume	if ((rtm->rtm_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST)
2622122677Sume		rrt->rrt_t = 0;	/* Don't age non-gateway host routes */
262355163Sshin	np->rip6_tag = 0;
262455163Sshin	np->rip6_metric = rtm->rtm_rmx.rmx_hopcount;
262555163Sshin	if (np->rip6_metric < 1)
262655163Sshin		np->rip6_metric = 1;
262755163Sshin	rrt->rrt_flags = rtm->rtm_flags;
262855163Sshin	np->rip6_dest = sin6_dst->sin6_addr;
262955163Sshin
263055163Sshin	/* Mask or plen */
263155163Sshin	if (rtm->rtm_flags & RTF_HOST)
263255163Sshin		np->rip6_plen = 128;	/* Host route */
263378064Sume	else if (sin6_mask)
263478064Sume		np->rip6_plen = sin6mask2len(sin6_mask);
263578064Sume	else
263655163Sshin		np->rip6_plen = 0;
263755163Sshin
263878064Sume	orrt = rtsearch(np, NULL);
263978064Sume	if (orrt && orrt->rrt_info.rip6_metric != HOPCNT_INFINITY6) {
264055163Sshin		/* Already found */
264155163Sshin		if (!again) {
264255163Sshin			trace(1, "route: %s/%d flags %s: already registered\n",
264355163Sshin				inet6_n2p(&np->rip6_dest), np->rip6_plen,
264455163Sshin				rtflags(rtm));
264555163Sshin		}
264655163Sshin		free(rrt);
264755163Sshin		return;
264855163Sshin	}
264955163Sshin	/* Gateway */
265055163Sshin	if (!sin6_gw)
265155163Sshin		memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
265255163Sshin	else {
265355163Sshin		if (sin6_gw->sin6_family == AF_INET6)
265455163Sshin			rrt->rrt_gw = sin6_gw->sin6_addr;
265555163Sshin		else if (sin6_gw->sin6_family == AF_LINK) {
265655163Sshin			/* XXX in case ppp link? */
265755163Sshin			rrt->rrt_gw = in6addr_loopback;
265855163Sshin		} else
265955163Sshin			memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
266055163Sshin	}
266155163Sshin	trace(1, "route: %s/%d flags %s",
266255163Sshin		inet6_n2p(&np->rip6_dest), np->rip6_plen, rtflags(rtm));
266355163Sshin	trace(1, " gw %s", inet6_n2p(&rrt->rrt_gw));
266455163Sshin
266555163Sshin	/* Interface */
266655163Sshin	s = rtm->rtm_index;
266755163Sshin	if (s < nindex2ifc && index2ifc[s])
266855163Sshin		ifname = index2ifc[s]->ifc_name;
266958070Sshin	else {
267058070Sshin		trace(1, " not configured\n");
267162607Sitojun		free(rrt);
267258070Sshin		return;
267358070Sshin	}
267462607Sitojun	trace(1, " if %s sock %d", ifname, s);
267555163Sshin	rrt->rrt_index = s;
267655163Sshin
267762607Sitojun	trace(1, "\n");
267862607Sitojun
267955163Sshin	/* Check gateway */
268055163Sshin	if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_gw) &&
2681122677Sume	    !IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw) &&
2682122677Sume	    (rrt->rrt_flags & RTF_LOCAL) == 0) {
268355163Sshin		trace(0, "***** Gateway %s is not a link-local address.\n",
268455163Sshin			inet6_n2p(&rrt->rrt_gw));
268555163Sshin		trace(0, "*****     dest(%s) if(%s) -- Not optimized.\n",
268662607Sitojun			inet6_n2p(&rrt->rrt_info.rip6_dest), ifname);
268762607Sitojun		rrt->rrt_rflags |= RRTF_NH_NOT_LLADDR;
268855163Sshin	}
268955163Sshin
269055163Sshin	/* Put it to the route list */
269178064Sume	if (orrt && orrt->rrt_info.rip6_metric == HOPCNT_INFINITY6) {
269278064Sume		/* replace route list */
269378064Sume		rrt->rrt_next = orrt->rrt_next;
269478064Sume		*orrt = *rrt;
269578064Sume		trace(1, "route: %s/%d flags %s: replace new route\n",
269678064Sume		    inet6_n2p(&np->rip6_dest), np->rip6_plen,
269778064Sume		    rtflags(rtm));
269878064Sume		free(rrt);
269978064Sume	} else {
270078064Sume		rrt->rrt_next = riprt;
270178064Sume		riprt = rrt;
270278064Sume	}
270355163Sshin}
270455163Sshin
270555163Sshinint
270655163Sshinaddroute(rrt, gw, ifcp)
270755163Sshin	struct riprt *rrt;
270855163Sshin	const struct in6_addr *gw;
270955163Sshin	struct ifc *ifcp;
271055163Sshin{
271155163Sshin	struct	netinfo6 *np;
271255163Sshin	u_char	buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ];
271355163Sshin	struct	rt_msghdr	*rtm;
2714119031Sume	struct	sockaddr_in6	*sin6;
271555163Sshin	int	len;
271655163Sshin
271755163Sshin	np = &rrt->rrt_info;
271878064Sume	inet_ntop(AF_INET6, (const void *)gw, (char *)buf1, sizeof(buf1));
271955163Sshin	inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2));
272055163Sshin	tracet(1, "ADD: %s/%d gw %s [%d] ifa %s\n",
272155163Sshin		inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1,
272255163Sshin		np->rip6_metric - 1, buf2);
272355163Sshin	if (rtlog)
272455163Sshin		fprintf(rtlog, "%s: ADD: %s/%d gw %s [%d] ifa %s\n", hms(),
272555163Sshin			inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1,
272655163Sshin			np->rip6_metric - 1, buf2);
272755163Sshin	if (nflag)
272855163Sshin		return 0;
272955163Sshin
273055163Sshin	memset(buf, 0, sizeof(buf));
273155163Sshin	rtm = (struct rt_msghdr *)buf;
273255163Sshin	rtm->rtm_type = RTM_ADD;
273355163Sshin	rtm->rtm_version = RTM_VERSION;
273455163Sshin	rtm->rtm_seq = ++seq;
273555163Sshin	rtm->rtm_pid = pid;
273662607Sitojun	rtm->rtm_flags = rrt->rrt_flags;
273755163Sshin	rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
273855163Sshin	rtm->rtm_rmx.rmx_hopcount = np->rip6_metric - 1;
273955163Sshin	rtm->rtm_inits = RTV_HOPCOUNT;
2740119031Sume	sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
274155163Sshin	/* Destination */
2742119031Sume	sin6->sin6_len = sizeof(struct sockaddr_in6);
2743119031Sume	sin6->sin6_family = AF_INET6;
2744119031Sume	sin6->sin6_addr = np->rip6_dest;
2745119031Sume	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
274655163Sshin	/* Gateway */
2747119031Sume	sin6->sin6_len = sizeof(struct sockaddr_in6);
2748119031Sume	sin6->sin6_family = AF_INET6;
2749119031Sume	sin6->sin6_addr = *gw;
2750119031Sume	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
275155163Sshin	/* Netmask */
2752119031Sume	sin6->sin6_len = sizeof(struct sockaddr_in6);
2753119031Sume	sin6->sin6_family = AF_INET6;
2754119031Sume	sin6->sin6_addr = *(plen2mask(np->rip6_plen));
2755119031Sume	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
275655163Sshin
2757119031Sume	len = (char *)sin6 - (char *)buf;
275855163Sshin	rtm->rtm_msglen = len;
275955163Sshin	if (write(rtsock, buf, len) > 0)
276055163Sshin		return 0;
276155163Sshin
276255163Sshin	if (errno == EEXIST) {
276355163Sshin		trace(0, "ADD: Route already exists %s/%d gw %s\n",
2764119035Sume		    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1);
276555163Sshin		if (rtlog)
276655163Sshin			fprintf(rtlog, "ADD: Route already exists %s/%d gw %s\n",
2767119035Sume			    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1);
276855163Sshin	} else {
276955163Sshin		trace(0, "Can not write to rtsock (addroute): %s\n",
2770119035Sume		    strerror(errno));
277155163Sshin		if (rtlog)
277255163Sshin			fprintf(rtlog, "\tCan not write to rtsock: %s\n",
2773119035Sume			    strerror(errno));
277455163Sshin	}
277555163Sshin	return -1;
277655163Sshin}
277755163Sshin
277855163Sshinint
277955163Sshindelroute(np, gw)
278055163Sshin	struct netinfo6 *np;
278155163Sshin	struct in6_addr *gw;
278255163Sshin{
278355163Sshin	u_char	buf[BUFSIZ], buf2[BUFSIZ];
278455163Sshin	struct	rt_msghdr	*rtm;
2785119031Sume	struct	sockaddr_in6	*sin6;
278655163Sshin	int	len;
278755163Sshin
278855163Sshin	inet_ntop(AF_INET6, (void *)gw, (char *)buf2, sizeof(buf2));
278955163Sshin	tracet(1, "DEL: %s/%d gw %s\n", inet6_n2p(&np->rip6_dest),
279055163Sshin		np->rip6_plen, buf2);
279155163Sshin	if (rtlog)
279255163Sshin		fprintf(rtlog, "%s: DEL: %s/%d gw %s\n",
279355163Sshin			hms(), inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
279455163Sshin	if (nflag)
279555163Sshin		return 0;
279655163Sshin
279755163Sshin	memset(buf, 0, sizeof(buf));
279855163Sshin	rtm = (struct rt_msghdr *)buf;
279955163Sshin	rtm->rtm_type = RTM_DELETE;
280055163Sshin	rtm->rtm_version = RTM_VERSION;
280155163Sshin	rtm->rtm_seq = ++seq;
280255163Sshin	rtm->rtm_pid = pid;
280355163Sshin	rtm->rtm_flags = RTF_UP | RTF_GATEWAY;
280478064Sume	if (np->rip6_plen == sizeof(struct in6_addr) * 8)
280578064Sume		rtm->rtm_flags |= RTF_HOST;
280655163Sshin	rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
2807119031Sume	sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
280855163Sshin	/* Destination */
2809119031Sume	sin6->sin6_len = sizeof(struct sockaddr_in6);
2810119031Sume	sin6->sin6_family = AF_INET6;
2811119031Sume	sin6->sin6_addr = np->rip6_dest;
2812119031Sume	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
281355163Sshin	/* Gateway */
2814119031Sume	sin6->sin6_len = sizeof(struct sockaddr_in6);
2815119031Sume	sin6->sin6_family = AF_INET6;
2816119031Sume	sin6->sin6_addr = *gw;
2817119031Sume	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
281855163Sshin	/* Netmask */
2819119031Sume	sin6->sin6_len = sizeof(struct sockaddr_in6);
2820119031Sume	sin6->sin6_family = AF_INET6;
2821119031Sume	sin6->sin6_addr = *(plen2mask(np->rip6_plen));
2822119031Sume	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
282355163Sshin
2824119031Sume	len = (char *)sin6 - (char *)buf;
282555163Sshin	rtm->rtm_msglen = len;
282655163Sshin	if (write(rtsock, buf, len) >= 0)
282755163Sshin		return 0;
282855163Sshin
282955163Sshin	if (errno == ESRCH) {
283055163Sshin		trace(0, "RTDEL: Route does not exist: %s/%d gw %s\n",
2831119035Sume		    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
283255163Sshin		if (rtlog)
283355163Sshin			fprintf(rtlog, "RTDEL: Route does not exist: %s/%d gw %s\n",
2834119035Sume			    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
283555163Sshin	} else {
283655163Sshin		trace(0, "Can not write to rtsock (delroute): %s\n",
2837119035Sume		    strerror(errno));
283855163Sshin		if (rtlog)
283955163Sshin			fprintf(rtlog, "\tCan not write to rtsock: %s\n",
2840119035Sume			    strerror(errno));
284155163Sshin	}
284255163Sshin	return -1;
284355163Sshin}
284455163Sshin
284555163Sshinstruct in6_addr *
284655163Sshingetroute(np, gw)
284755163Sshin	struct netinfo6 *np;
284855163Sshin	struct in6_addr *gw;
284955163Sshin{
285055163Sshin	u_char buf[BUFSIZ];
2851119085Sume	int myseq;
285255163Sshin	int len;
285355163Sshin	struct rt_msghdr *rtm;
2854119031Sume	struct sockaddr_in6 *sin6;
285555163Sshin
285655163Sshin	rtm = (struct rt_msghdr *)buf;
285755163Sshin	len = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6);
285855163Sshin	memset(rtm, 0, len);
285955163Sshin	rtm->rtm_type = RTM_GET;
286055163Sshin	rtm->rtm_version = RTM_VERSION;
286155163Sshin	myseq = ++seq;
286255163Sshin	rtm->rtm_seq = myseq;
286355163Sshin	rtm->rtm_addrs = RTA_DST;
286455163Sshin	rtm->rtm_msglen = len;
2865119031Sume	sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
2866119031Sume	sin6->sin6_len = sizeof(struct sockaddr_in6);
2867119031Sume	sin6->sin6_family = AF_INET6;
2868119031Sume	sin6->sin6_addr = np->rip6_dest;
286955163Sshin	if (write(rtsock, buf, len) < 0) {
287055163Sshin		if (errno == ESRCH)	/* No such route found */
287155163Sshin			return NULL;
287255163Sshin		perror("write to rtsock");
287378064Sume		exit(1);
287455163Sshin	}
287555163Sshin	do {
287655163Sshin		if ((len = read(rtsock, buf, sizeof(buf))) < 0) {
287755163Sshin			perror("read from rtsock");
287878064Sume			exit(1);
287955163Sshin		}
288055163Sshin		rtm = (struct rt_msghdr *)buf;
288155163Sshin	} while (rtm->rtm_seq != myseq || rtm->rtm_pid != pid);
2882119031Sume	sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
288355163Sshin	if (rtm->rtm_addrs & RTA_DST) {
2884119031Sume		sin6 = (struct sockaddr_in6 *)
2885119031Sume			((char *)sin6 + ROUNDUP(sin6->sin6_len));
288655163Sshin	}
288755163Sshin	if (rtm->rtm_addrs & RTA_GATEWAY) {
2888119031Sume		*gw = sin6->sin6_addr;
288955163Sshin		return gw;
289055163Sshin	}
289155163Sshin	return NULL;
289255163Sshin}
289355163Sshin
289455163Sshinconst char *
289555163Sshininet6_n2p(p)
289655163Sshin	const struct in6_addr *p;
289755163Sshin{
289855163Sshin	static char buf[BUFSIZ];
289955163Sshin
290078064Sume	return inet_ntop(AF_INET6, (const void *)p, buf, sizeof(buf));
290155163Sshin}
290255163Sshin
290355163Sshinvoid
290455163Sshinifrtdump(sig)
290555163Sshin	int sig;
290655163Sshin{
290755163Sshin
290855163Sshin	ifdump(sig);
290955163Sshin	rtdump(sig);
291055163Sshin}
291155163Sshin
291255163Sshinvoid
291355163Sshinifdump(sig)
291455163Sshin	int sig;
291555163Sshin{
291655163Sshin	struct ifc *ifcp;
291755163Sshin	FILE *dump;
291855163Sshin	int i;
291955163Sshin
292055163Sshin	if (sig == 0)
292155163Sshin		dump = stderr;
292255163Sshin	else
292355163Sshin		if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL)
292455163Sshin			dump = stderr;
292555163Sshin
292655163Sshin	fprintf(dump, "%s: Interface Table Dump\n", hms());
292755163Sshin	fprintf(dump, "  Number of interfaces: %d\n", nifc);
292855163Sshin	for (i = 0; i < 2; i++) {
292955163Sshin		fprintf(dump, "  %sadvertising interfaces:\n", i ? "non-" : "");
293055163Sshin		for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
293155163Sshin			if (i == 0) {
293255163Sshin				if ((ifcp->ifc_flags & IFF_UP) == 0)
293355163Sshin					continue;
293455163Sshin				if (iff_find(ifcp, 'N') != NULL)
293555163Sshin					continue;
293655163Sshin			} else {
293755163Sshin				if (ifcp->ifc_flags & IFF_UP)
293855163Sshin					continue;
293955163Sshin			}
294055163Sshin			ifdump0(dump, ifcp);
294155163Sshin		}
294255163Sshin	}
294355163Sshin	fprintf(dump, "\n");
294455163Sshin	if (dump != stderr)
294555163Sshin		fclose(dump);
294655163Sshin}
294755163Sshin
294855163Sshinvoid
294955163Sshinifdump0(dump, ifcp)
295055163Sshin	FILE *dump;
295155163Sshin	const struct ifc *ifcp;
295255163Sshin{
295355163Sshin	struct ifac *ifa;
295455163Sshin	struct iff *iffp;
295555163Sshin	char buf[BUFSIZ];
295655163Sshin	const char *ft;
295755163Sshin	int addr;
295855163Sshin
295955163Sshin	fprintf(dump, "    %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)\n",
296055163Sshin		ifcp->ifc_name, ifcp->ifc_index, ifflags(ifcp->ifc_flags),
296155163Sshin		inet6_n2p(&ifcp->ifc_mylladdr),
296255163Sshin		ifcp->ifc_mtu, ifcp->ifc_metric);
296355163Sshin	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
296455163Sshin		if (ifcp->ifc_flags & IFF_POINTOPOINT) {
296555163Sshin			inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr,
296655163Sshin				buf, sizeof(buf));
296755163Sshin			fprintf(dump, "\t%s/%d -- %s\n",
296855163Sshin				inet6_n2p(&ifa->ifa_addr),
296955163Sshin				ifa->ifa_plen, buf);
297055163Sshin		} else {
297155163Sshin			fprintf(dump, "\t%s/%d\n",
297255163Sshin				inet6_n2p(&ifa->ifa_addr),
297355163Sshin				ifa->ifa_plen);
297455163Sshin		}
297555163Sshin	}
297655163Sshin	if (ifcp->ifc_filter) {
297755163Sshin		fprintf(dump, "\tFilter:");
297855163Sshin		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
297955163Sshin			addr = 0;
298055163Sshin			switch (iffp->iff_type) {
298155163Sshin			case 'A':
298255163Sshin				ft = "Aggregate"; addr++; break;
298355163Sshin			case 'N':
298478064Sume				ft = "No-use"; break;
298555163Sshin			case 'O':
298655163Sshin				ft = "Advertise-only"; addr++; break;
298755163Sshin			case 'T':
298855163Sshin				ft = "Default-only"; break;
298955163Sshin			case 'L':
299055163Sshin				ft = "Listen-only"; addr++; break;
299155163Sshin			default:
299255163Sshin				snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type);
299355163Sshin				ft = buf;
299455163Sshin				addr++;
299555163Sshin				break;
299655163Sshin			}
299755163Sshin			fprintf(dump, " %s", ft);
299855163Sshin			if (addr) {
299955163Sshin				fprintf(dump, "(%s/%d)", inet6_n2p(&iffp->iff_addr),
300055163Sshin					iffp->iff_plen);
300155163Sshin			}
300255163Sshin		}
300355163Sshin		fprintf(dump, "\n");
300455163Sshin	}
300555163Sshin}
300655163Sshin
300755163Sshinvoid
300855163Sshinrtdump(sig)
300955163Sshin	int sig;
301055163Sshin{
301155163Sshin	struct	riprt *rrt;
301255163Sshin	char	buf[BUFSIZ];
301355163Sshin	FILE	*dump;
301455163Sshin	time_t	t, age;
301555163Sshin
301655163Sshin	if (sig == 0)
301755163Sshin		dump = stderr;
301855163Sshin	else
301955163Sshin		if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL)
302055163Sshin			dump = stderr;
302155163Sshin
302255163Sshin	t = time(NULL);
302355163Sshin	fprintf(dump, "\n%s: Routing Table Dump\n", hms());
302455163Sshin	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
302555163Sshin		if (rrt->rrt_t == 0)
302655163Sshin			age = 0;
302755163Sshin		else
302855163Sshin			age = t - rrt->rrt_t;
302955163Sshin		inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest,
303055163Sshin			buf, sizeof(buf));
303155163Sshin		fprintf(dump, "    %s/%d if(%d:%s) gw(%s) [%d] age(%ld)",
303255163Sshin			buf, rrt->rrt_info.rip6_plen, rrt->rrt_index,
303355163Sshin			index2ifc[rrt->rrt_index]->ifc_name,
303455163Sshin			inet6_n2p(&rrt->rrt_gw),
303555163Sshin			rrt->rrt_info.rip6_metric, (long)age);
303655163Sshin		if (rrt->rrt_info.rip6_tag) {
303755163Sshin			fprintf(dump, " tag(0x%04x)",
303855163Sshin				ntohs(rrt->rrt_info.rip6_tag) & 0xffff);
303955163Sshin		}
304062607Sitojun		if (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)
304155163Sshin			fprintf(dump, " NOT-LL");
304262607Sitojun		if (rrt->rrt_rflags & RRTF_NOADVERTISE)
304355163Sshin			fprintf(dump, " NO-ADV");
304455163Sshin		fprintf(dump, "\n");
304555163Sshin	}
304655163Sshin	fprintf(dump, "\n");
304755163Sshin	if (dump != stderr)
304855163Sshin		fclose(dump);
304955163Sshin}
305055163Sshin
305155163Sshin/*
305255163Sshin * Parse the -A (and -O) options and put corresponding filter object to the
305378064Sume * specified interface structures.  Each of the -A/O option has the following
305455163Sshin * syntax:	-A 5f09:c400::/32,ef0,ef1  (aggregate)
305555163Sshin * 		-O 5f09:c400::/32,ef0,ef1  (only when match)
305655163Sshin */
305755163Sshinvoid
305855163Sshinfilterconfig()
305955163Sshin{
306055163Sshin	int i;
3061119083Sume	char *p, *ap, *iflp, *ifname, *ep;
306278064Sume	struct iff ftmp, *iff_obj;
306378064Sume	struct ifc *ifcp;
306478064Sume	struct riprt *rrt;
306564631Sitojun#if 0
306678064Sume	struct in6_addr gw;
306764631Sitojun#endif
3068119083Sume	u_long plen;
306955163Sshin
307055163Sshin	for (i = 0; i < nfilter; i++) {
307155163Sshin		ap = filter[i];
307255163Sshin		iflp = NULL;
307355163Sshin		ifcp = NULL;
307455163Sshin		if (filtertype[i] == 'N' || filtertype[i] == 'T') {
307555163Sshin			iflp = ap;
307655163Sshin			goto ifonly;
307755163Sshin		}
3078119038Sume		if ((p = strchr(ap, ',')) != NULL) {
307955163Sshin			*p++ = '\0';
308055163Sshin			iflp = p;
308155163Sshin		}
3082119038Sume		if ((p = strchr(ap, '/')) == NULL) {
308355163Sshin			fatal("no prefixlen specified for '%s'", ap);
308478064Sume			/*NOTREACHED*/
308578064Sume		}
308655163Sshin		*p++ = '\0';
308778064Sume		if (inet_pton(AF_INET6, ap, &ftmp.iff_addr) != 1) {
308855163Sshin			fatal("invalid prefix specified for '%s'", ap);
308978064Sume			/*NOTREACHED*/
309078064Sume		}
3091119083Sume		errno = 0;
3092119083Sume		ep = NULL;
3093119083Sume		plen = strtoul(p, &ep, 10);
3094119083Sume		if (errno || !*p || *ep || plen > sizeof(ftmp.iff_addr) * 8) {
3095119083Sume			fatal("invalid prefix length specified for '%s'", ap);
3096119083Sume			/*NOTREACHED*/
3097119083Sume		}
3098119083Sume		ftmp.iff_plen = plen;
309955163Sshin		ftmp.iff_next = NULL;
310055163Sshin		applyplen(&ftmp.iff_addr, ftmp.iff_plen);
310155163Sshinifonly:
310255163Sshin		ftmp.iff_type = filtertype[i];
310378064Sume		if (iflp == NULL || *iflp == '\0') {
310455163Sshin			fatal("no interface specified for '%s'", ap);
310578064Sume			/*NOTREACHED*/
310678064Sume		}
310755163Sshin		/* parse the interface listing portion */
310855163Sshin		while (iflp) {
310955163Sshin			ifname = iflp;
3110119038Sume			if ((iflp = strchr(iflp, ',')) != NULL)
311155163Sshin				*iflp++ = '\0';
311255163Sshin			ifcp = ifc_find(ifname);
311378064Sume			if (ifcp == NULL) {
311455163Sshin				fatal("no interface %s exists", ifname);
311578064Sume				/*NOTREACHED*/
311678064Sume			}
311755163Sshin			iff_obj = (struct iff *)malloc(sizeof(struct iff));
311878064Sume			if (iff_obj == NULL) {
311955163Sshin				fatal("malloc of iff_obj");
312078064Sume				/*NOTREACHED*/
312178064Sume			}
312255163Sshin			memcpy((void *)iff_obj, (void *)&ftmp,
312378064Sume			    sizeof(struct iff));
312455163Sshin			/* link it to the interface filter */
312555163Sshin			iff_obj->iff_next = ifcp->ifc_filter;
312655163Sshin			ifcp->ifc_filter = iff_obj;
312755163Sshin		}
312878064Sume
312978064Sume		/*
313078064Sume		 * -A: aggregate configuration.
313178064Sume		 */
313255163Sshin		if (filtertype[i] != 'A')
313355163Sshin			continue;
313455163Sshin		/* put the aggregate to the kernel routing table */
313555163Sshin		rrt = (struct riprt *)malloc(sizeof(struct riprt));
313678064Sume		if (rrt == NULL) {
313755163Sshin			fatal("malloc: rrt");
313878064Sume			/*NOTREACHED*/
313978064Sume		}
314055163Sshin		memset(rrt, 0, sizeof(struct riprt));
314155163Sshin		rrt->rrt_info.rip6_dest = ftmp.iff_addr;
314255163Sshin		rrt->rrt_info.rip6_plen = ftmp.iff_plen;
314355163Sshin		rrt->rrt_info.rip6_metric = 1;
314455163Sshin		rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
314555163Sshin		rrt->rrt_gw = in6addr_loopback;
314662607Sitojun		rrt->rrt_flags = RTF_UP | RTF_REJECT;
314762607Sitojun		rrt->rrt_rflags = RRTF_AGGREGATE;
314855163Sshin		rrt->rrt_t = 0;
3149119039Sume		rrt->rrt_index = loopifcp->ifc_index;
315064631Sitojun#if 0
315164631Sitojun		if (getroute(&rrt->rrt_info, &gw)) {
315264631Sitojun#if 0
315364631Sitojun			/*
315464631Sitojun			 * When the address has already been registered in the
315564631Sitojun			 * kernel routing table, it should be removed
315664631Sitojun			 */
315764631Sitojun			delroute(&rrt->rrt_info, &gw);
315864631Sitojun#else
315978064Sume			/* it is safer behavior */
316064631Sitojun			errno = EINVAL;
316164631Sitojun			fatal("%s/%u already in routing table, "
316264631Sitojun			    "cannot aggregate",
316364631Sitojun			    inet6_n2p(&rrt->rrt_info.rip6_dest),
316464631Sitojun			    rrt->rrt_info.rip6_plen);
316578064Sume			/*NOTREACHED*/
316664631Sitojun#endif
316764631Sitojun		}
316864631Sitojun#endif
316955163Sshin		/* Put the route to the list */
317055163Sshin		rrt->rrt_next = riprt;
317155163Sshin		riprt = rrt;
317255163Sshin		trace(1, "Aggregate: %s/%d for %s\n",
317355163Sshin			inet6_n2p(&ftmp.iff_addr), ftmp.iff_plen,
317455163Sshin			ifcp->ifc_name);
317555163Sshin		/* Add this route to the kernel */
317655163Sshin		if (nflag) 	/* do not modify kernel routing table */
317755163Sshin			continue;
317855163Sshin		addroute(rrt, &in6addr_loopback, loopifcp);
317955163Sshin	}
318055163Sshin}
318155163Sshin
318255163Sshin/***************** utility functions *****************/
318355163Sshin
318455163Sshin/*
318555163Sshin * Returns a pointer to ifac whose address and prefix length matches
318655163Sshin * with the address and prefix length specified in the arguments.
318755163Sshin */
318855163Sshinstruct ifac *
318955163Sshinifa_match(ifcp, ia, plen)
319055163Sshin	const struct ifc *ifcp;
319155163Sshin	const struct in6_addr *ia;
319255163Sshin	int plen;
319355163Sshin{
319455163Sshin	struct ifac *ifa;
319555163Sshin
319655163Sshin	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
319755163Sshin		if (IN6_ARE_ADDR_EQUAL(&ifa->ifa_addr, ia) &&
319855163Sshin		    ifa->ifa_plen == plen)
319955163Sshin			break;
320055163Sshin	}
320155163Sshin	return ifa;
320255163Sshin}
320355163Sshin
320455163Sshin/*
320555163Sshin * Return a pointer to riprt structure whose address and prefix length
320655163Sshin * matches with the address and prefix length found in the argument.
320778064Sume * Note: This is not a rtalloc().  Therefore exact match is necessary.
320855163Sshin */
320955163Sshinstruct riprt *
321078064Sumertsearch(np, prev_rrt)
321155163Sshin	struct	netinfo6 *np;
321278064Sume	struct	riprt **prev_rrt;
321355163Sshin{
321455163Sshin	struct	riprt	*rrt;
321555163Sshin
321678064Sume	if (prev_rrt)
321778064Sume		*prev_rrt = NULL;
321855163Sshin	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
321955163Sshin		if (rrt->rrt_info.rip6_plen == np->rip6_plen &&
322055163Sshin		    IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
322155163Sshin				       &np->rip6_dest))
322255163Sshin			return rrt;
322378064Sume		if (prev_rrt)
322478064Sume			*prev_rrt = rrt;
322555163Sshin	}
322678064Sume	if (prev_rrt)
322778064Sume		*prev_rrt = NULL;
322855163Sshin	return 0;
322955163Sshin}
323055163Sshin
323155163Sshinint
323278064Sumesin6mask2len(sin6)
323378064Sume	const struct sockaddr_in6 *sin6;
323478064Sume{
323578064Sume
323678064Sume	return mask2len(&sin6->sin6_addr,
323778064Sume	    sin6->sin6_len - offsetof(struct sockaddr_in6, sin6_addr));
323878064Sume}
323978064Sume
324078064Sumeint
324155163Sshinmask2len(addr, lenlim)
324255163Sshin	const struct in6_addr *addr;
324355163Sshin	int lenlim;
324455163Sshin{
324555163Sshin	int i = 0, j;
324678064Sume	const u_char *p = (const u_char *)addr;
324762607Sitojun
324855163Sshin	for (j = 0; j < lenlim; j++, p++) {
324955163Sshin		if (*p != 0xff)
325055163Sshin			break;
325155163Sshin		i += 8;
325255163Sshin	}
325355163Sshin	if (j < lenlim) {
325455163Sshin		switch (*p) {
325562607Sitojun#define	MASKLEN(m, l)	case m: do { i += l; break; } while (0)
325662607Sitojun		MASKLEN(0xfe, 7); break;
325762607Sitojun		MASKLEN(0xfc, 6); break;
325862607Sitojun		MASKLEN(0xf8, 5); break;
325962607Sitojun		MASKLEN(0xf0, 4); break;
326062607Sitojun		MASKLEN(0xe0, 3); break;
326162607Sitojun		MASKLEN(0xc0, 2); break;
326262607Sitojun		MASKLEN(0x80, 1); break;
326355163Sshin#undef	MASKLEN
326455163Sshin		}
326555163Sshin	}
326655163Sshin	return i;
326755163Sshin}
326855163Sshin
326955163Sshinvoid
327055163Sshinapplymask(addr, mask)
327155163Sshin	struct in6_addr *addr, *mask;
327255163Sshin{
327355163Sshin	int	i;
327455163Sshin	u_long	*p, *q;
327555163Sshin
327655163Sshin	p = (u_long *)addr; q = (u_long *)mask;
327755163Sshin	for (i = 0; i < 4; i++)
327855163Sshin		*p++ &= *q++;
327955163Sshin}
328055163Sshin
328155163Sshinstatic const u_char plent[8] = {
328255163Sshin	0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
328355163Sshin};
328455163Sshin
328555163Sshinvoid
328655163Sshinapplyplen(ia, plen)
328755163Sshin	struct	in6_addr *ia;
328855163Sshin	int	plen;
328955163Sshin{
329055163Sshin	u_char	*p;
329155163Sshin	int	i;
329255163Sshin
329355163Sshin	p = ia->s6_addr;
329455163Sshin	for (i = 0; i < 16; i++) {
329555163Sshin		if (plen <= 0)
329655163Sshin			*p = 0;
329755163Sshin		else if (plen < 8)
329855163Sshin			*p &= plent[plen];
329955163Sshin		p++, plen -= 8;
330055163Sshin	}
330155163Sshin}
330255163Sshin
330355163Sshinstatic const int pl2m[9] = {
330455163Sshin	0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
330555163Sshin};
330655163Sshin
330755163Sshinstruct in6_addr *
330855163Sshinplen2mask(n)
330955163Sshin	int	n;
331055163Sshin{
331155163Sshin	static struct in6_addr ia;
331255163Sshin	u_char	*p;
331355163Sshin	int	i;
331455163Sshin
331555163Sshin	memset(&ia, 0, sizeof(struct in6_addr));
331655163Sshin	p = (u_char *)&ia;
331755163Sshin	for (i = 0; i < 16; i++, p++, n -= 8) {
331855163Sshin		if (n >= 8) {
331955163Sshin			*p = 0xff;
332055163Sshin			continue;
332155163Sshin		}
332255163Sshin		*p = pl2m[n];
332355163Sshin		break;
332455163Sshin	}
332555163Sshin	return &ia;
332655163Sshin}
332755163Sshin
332855163Sshinchar *
332955163Sshinallocopy(p)
333055163Sshin	char *p;
333155163Sshin{
3332119033Sume	int len = strlen(p) + 1;
3333119033Sume	char *q = (char *)malloc(len);
333455163Sshin
3335119033Sume	if (!q) {
3336119033Sume		fatal("malloc");
3337119033Sume		/*NOTREACHED*/
3338119033Sume	}
3339119033Sume
3340119033Sume	strlcpy(q, p, len);
334155163Sshin	return q;
334255163Sshin}
334355163Sshin
334455163Sshinchar *
334555163Sshinhms()
334655163Sshin{
334755163Sshin	static char buf[BUFSIZ];
334855163Sshin	time_t t;
334955163Sshin	struct	tm *tm;
335055163Sshin
335155163Sshin	t = time(NULL);
335278064Sume	if ((tm = localtime(&t)) == 0) {
335355163Sshin		fatal("localtime");
335478064Sume		/*NOTREACHED*/
335578064Sume	}
335678064Sume	snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
335778064Sume	    tm->tm_sec);
335855163Sshin	return buf;
335955163Sshin}
336055163Sshin
336155163Sshin#define	RIPRANDDEV	1.0	/* 30 +- 15, max - min = 30 */
336255163Sshin
336355163Sshinint
336455163Sshinripinterval(timer)
336555163Sshin	int timer;
336655163Sshin{
336755163Sshin	double r = rand();
336855163Sshin
336955163Sshin	interval = (int)(timer + timer * RIPRANDDEV * (r / RAND_MAX - 0.5));
337055163Sshin	nextalarm = time(NULL) + interval;
337155163Sshin	return interval;
337255163Sshin}
337355163Sshin
337455163Sshintime_t
337555163Sshinripsuptrig()
337655163Sshin{
337755163Sshin	time_t t;
337855163Sshin
337955163Sshin	double r = rand();
338062607Sitojun	t  = (int)(RIP_TRIG_INT6_MIN +
338178064Sume		(RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / RAND_MAX));
338255163Sshin	sup_trig_update = time(NULL) + t;
338355163Sshin	return t;
338455163Sshin}
338555163Sshin
338655163Sshinvoid
338755163Sshin#ifdef __STDC__
338855163Sshinfatal(const char *fmt, ...)
338955163Sshin#else
339055163Sshinfatal(fmt, va_alist)
339155163Sshin	char	*fmt;
339255163Sshin	va_dcl
339355163Sshin#endif
339455163Sshin{
339555163Sshin	va_list ap;
339655163Sshin	char buf[1024];
339755163Sshin
339855163Sshin#ifdef __STDC__
339955163Sshin	va_start(ap, fmt);
340055163Sshin#else
340155163Sshin	va_start(ap);
340255163Sshin#endif
340355163Sshin	vsnprintf(buf, sizeof(buf), fmt, ap);
3404119043Sume	va_end(ap);
340555163Sshin	perror(buf);
3406119043Sume	if (errno)
3407119043Sume		syslog(LOG_ERR, "%s: %s", buf, strerror(errno));
3408119043Sume	else
3409119043Sume		syslog(LOG_ERR, "%s", buf);
341078064Sume	rtdexit();
341155163Sshin}
341255163Sshin
341355163Sshinvoid
341455163Sshin#ifdef __STDC__
341555163Sshintracet(int level, const char *fmt, ...)
341655163Sshin#else
341755163Sshintracet(level, fmt, va_alist)
341855163Sshin	int level;
341955163Sshin	char *fmt;
342055163Sshin	va_dcl
342155163Sshin#endif
342255163Sshin{
342355163Sshin	va_list ap;
342455163Sshin
3425119043Sume	if (level <= dflag) {
342655163Sshin#ifdef __STDC__
3427119043Sume		va_start(ap, fmt);
342855163Sshin#else
3429119043Sume		va_start(ap);
343055163Sshin#endif
343155163Sshin		fprintf(stderr, "%s: ", hms());
343255163Sshin		vfprintf(stderr, fmt, ap);
3433119043Sume		va_end(ap);
343455163Sshin	}
343555163Sshin	if (dflag) {
3436119043Sume#ifdef __STDC__
3437119043Sume		va_start(ap, fmt);
3438119043Sume#else
3439119043Sume		va_start(ap);
3440119043Sume#endif
344155163Sshin		if (level > 0)
344255163Sshin			vsyslog(LOG_DEBUG, fmt, ap);
344355163Sshin		else
344455163Sshin			vsyslog(LOG_WARNING, fmt, ap);
3445119043Sume		va_end(ap);
344655163Sshin	}
344755163Sshin}
344855163Sshin
344955163Sshinvoid
345055163Sshin#ifdef __STDC__
345155163Sshintrace(int level, const char *fmt, ...)
345255163Sshin#else
345355163Sshintrace(level, fmt, va_alist)
345455163Sshin	int level;
345555163Sshin	char *fmt;
345655163Sshin	va_dcl
345755163Sshin#endif
345855163Sshin{
345955163Sshin	va_list ap;
346055163Sshin
3461119043Sume	if (level <= dflag) {
346255163Sshin#ifdef __STDC__
3463119043Sume		va_start(ap, fmt);
346455163Sshin#else
3465119043Sume		va_start(ap);
346655163Sshin#endif
346755163Sshin		vfprintf(stderr, fmt, ap);
3468119043Sume		va_end(ap);
3469119043Sume	}
347055163Sshin	if (dflag) {
3471119043Sume#ifdef __STDC__
3472119043Sume		va_start(ap, fmt);
3473119043Sume#else
3474119043Sume		va_start(ap);
3475119043Sume#endif
347655163Sshin		if (level > 0)
347755163Sshin			vsyslog(LOG_DEBUG, fmt, ap);
347855163Sshin		else
347955163Sshin			vsyslog(LOG_WARNING, fmt, ap);
3480119043Sume		va_end(ap);
348155163Sshin	}
348255163Sshin}
348355163Sshin
348455163Sshinunsigned int
348555163Sshinif_maxindex()
348655163Sshin{
348755163Sshin	struct if_nameindex *p, *p0;
348855163Sshin	unsigned int max = 0;
348955163Sshin
349055163Sshin	p0 = if_nameindex();
349155163Sshin	for (p = p0; p && p->if_index && p->if_name; p++) {
349255163Sshin		if (max < p->if_index)
349355163Sshin			max = p->if_index;
349455163Sshin	}
349555163Sshin	if_freenameindex(p0);
349655163Sshin	return max;
349755163Sshin}
349855163Sshin
349955163Sshinstruct ifc *
350055163Sshinifc_find(name)
350155163Sshin	char *name;
350255163Sshin{
350355163Sshin	struct ifc *ifcp;
350455163Sshin
350555163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
350655163Sshin		if (strcmp(name, ifcp->ifc_name) == 0)
350755163Sshin			return ifcp;
350855163Sshin	}
350955163Sshin	return (struct ifc *)NULL;
351055163Sshin}
351155163Sshin
351255163Sshinstruct iff *
351355163Sshiniff_find(ifcp, type)
351455163Sshin	struct ifc *ifcp;
351555163Sshin	int type;
351655163Sshin{
351755163Sshin	struct iff *iffp;
351855163Sshin
351955163Sshin	for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
352055163Sshin		if (iffp->iff_type == type)
352155163Sshin			return iffp;
352255163Sshin	}
352355163Sshin	return NULL;
352455163Sshin}
352555163Sshin
352655163Sshinvoid
352778064Sumesetindex2ifc(idx, ifcp)
352878064Sume	int idx;
352955163Sshin	struct ifc *ifcp;
353055163Sshin{
3531122677Sume	int n, nsize;
353262607Sitojun	struct ifc **p;
353355163Sshin
353455163Sshin	if (!index2ifc) {
353555163Sshin		nindex2ifc = 5;	/*initial guess*/
353655163Sshin		index2ifc = (struct ifc **)
353755163Sshin			malloc(sizeof(*index2ifc) * nindex2ifc);
353878064Sume		if (index2ifc == NULL) {
353955163Sshin			fatal("malloc");
354078064Sume			/*NOTREACHED*/
354178064Sume		}
354255163Sshin		memset(index2ifc, 0, sizeof(*index2ifc) * nindex2ifc);
354355163Sshin	}
354455163Sshin	n = nindex2ifc;
3545122677Sume	for (nsize = nindex2ifc; nsize <= idx; nsize *= 2)
3546122677Sume		;
3547122677Sume	if (n != nsize) {
354862607Sitojun		p = (struct ifc **)realloc(index2ifc,
3549122677Sume		    sizeof(*index2ifc) * nsize);
355078064Sume		if (p == NULL) {
355155163Sshin			fatal("realloc");
355278064Sume			/*NOTREACHED*/
355378064Sume		}
355478064Sume		memset(p + n, 0, sizeof(*index2ifc) * (nindex2ifc - n));
355562607Sitojun		index2ifc = p;
3556122677Sume		nindex2ifc = nsize;
355755163Sshin	}
355878064Sume	index2ifc[idx] = ifcp;
355955163Sshin}
3560