route6d.c revision 62921
162607Sitojun/*	$FreeBSD: head/usr.sbin/route6d/route6d.c 62921 2000-07-10 18:27:55Z ume $	*/
262607Sitojun/*	$KAME: route6d.c,v 1.30 2000/06/04 06:48:03 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
3462607Sitojunstatic char _rcsid[] = "$KAME: route6d.c,v 1.30 2000/06/04 06:48:03 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>
5355163Sshin
5455163Sshin#include <sys/types.h>
5555163Sshin#include <sys/param.h>
5655163Sshin#include <sys/file.h>
5755163Sshin#include <sys/socket.h>
5855163Sshin#include <sys/ioctl.h>
5955163Sshin#include <sys/sysctl.h>
6055163Sshin#include <sys/uio.h>
6155163Sshin#include <net/if.h>
6262607Sitojun#if defined(__FreeBSD__) && __FreeBSD__ >= 3
6355163Sshin#include <net/if_var.h>
6462607Sitojun#endif /* __FreeBSD__ >= 3 */
6562607Sitojun#define	KERNEL	1
6662607Sitojun#define	_KERNEL	1
6755163Sshin#include <net/route.h>
6862607Sitojun#undef KERNEL
6962607Sitojun#undef _KERNEL
7055163Sshin#include <netinet/in.h>
7155163Sshin#include <netinet/in_var.h>
7255163Sshin#include <netinet/ip6.h>
7355163Sshin#include <netinet/udp.h>
7455163Sshin#include <netdb.h>
7562607Sitojun#ifdef HAVE_GETIFADDRS
7662607Sitojun#include <ifaddrs.h>
7762607Sitojun#endif
7855163Sshin
7955163Sshin#include <arpa/inet.h>
8055163Sshin
8155163Sshin#include "route6d.h"
8255163Sshin
8355163Sshin#define	MAXFILTER	40
8455163Sshin
8555163Sshin#ifdef	DEBUG
8655163Sshin#define	INIT_INTERVAL6	6
8755163Sshin#else
8855163Sshin#define	INIT_INTERVAL6	10	/* Wait to submit a initial riprequest */
8955163Sshin#endif
9055163Sshin
9155163Sshin/* alignment constraint for routing socket */
9262607Sitojun#define ROUNDUP(a) \
9355163Sshin	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
9462607Sitojun#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
9555163Sshin
9655163Sshin/*
9755163Sshin * Following two macros are highly depending on KAME Release
9855163Sshin */
9955163Sshin#define	IN6_LINKLOCAL_IFINDEX(addr) \
10055163Sshin	((addr).s6_addr[2] << 8 | (addr).s6_addr[3])
10155163Sshin
10255163Sshin#define	SET_IN6_LINKLOCAL_IFINDEX(addr, index) \
10355163Sshin	do { \
10455163Sshin		(addr).s6_addr[2] = ((index) >> 8) & 0xff; \
10555163Sshin		(addr).s6_addr[3] = (index) & 0xff; \
10655163Sshin	} while (0)
10755163Sshin
10855163Sshinstruct	ifc {			/* Configuration of an interface */
10955163Sshin	char	*ifc_name;			/* if name */
11055163Sshin	struct	ifc *ifc_next;
11155163Sshin	int	ifc_index;			/* if index */
11255163Sshin	int	ifc_mtu;			/* if mtu */
11355163Sshin	int	ifc_metric;			/* if metric */
11455163Sshin	short	ifc_flags;			/* flags */
11555163Sshin	struct	in6_addr ifc_mylladdr;		/* my link-local address */
11655163Sshin	struct	sockaddr_in6 ifc_ripsin;	/* rip multicast address */
11755163Sshin	struct	iff *ifc_filter;		/* filter structure */
11855163Sshin	struct	ifac *ifc_addr;			/* list of AF_INET6 addresses */
11955163Sshin	int	ifc_joined;			/* joined to ff02::9 */
12055163Sshin};
12155163Sshin
12262607Sitojunstruct	ifac {			/* Adddress associated to an interface */
12355163Sshin	struct	ifc *ifa_conf;		/* back pointer */
12455163Sshin	struct	ifac *ifa_next;
12555163Sshin	struct	in6_addr ifa_addr;	/* address */
12655163Sshin	struct	in6_addr ifa_raddr;	/* remote address, valid in p2p */
12755163Sshin	int	ifa_plen;		/* prefix length */
12855163Sshin};
12955163Sshin
13055163Sshinstruct	iff {
13155163Sshin	int	iff_type;
13255163Sshin	struct	in6_addr iff_addr;
13355163Sshin	int	iff_plen;
13455163Sshin	struct	iff *iff_next;
13555163Sshin};
13655163Sshin
13755163Sshinstruct	ifc *ifc;
13855163Sshinint	nifc;		/* number of valid ifc's */
13955163Sshinstruct	ifc **index2ifc;
14055163Sshinint	nindex2ifc;
14155163Sshinstruct	ifc *loopifcp = NULL;	/* pointing to loopback */
14255163Sshinint	loopifindex = 0;	/* ditto */
14355163Sshinfd_set	sockvec;	/* vector to select() for receiving */
14455163Sshinint	rtsock;		/* the routing socket */
14555163Sshinint	ripsock;	/* socket to send/receive RIP datagram */
14655163Sshin
14755163Sshinstruct	rip6 *ripbuf;	/* packet buffer for sending */
14855163Sshin
14955163Sshin/*
15055163Sshin * Maintain the routes in a linked list. When the number of the routes
15155163Sshin * grows, somebody would like to introduce a hash based or a radix tree
15255163Sshin * based strucutre. I believe the number of routes handled by RIP is
15355163Sshin * limited and I don't have to manage a complex data structure, however.
15455163Sshin *
15555163Sshin * One of the major drawbacks of the linear linked list is the difficulty
15655163Sshin * of representing the relationship between a couple of routes. This may
15755163Sshin * be a significant problem when we have to support route aggregation with
15855163Sshin * supressing the specifices covered by the aggregate.
15955163Sshin */
16055163Sshin
16155163Sshinstruct	riprt {
16255163Sshin	struct	riprt *rrt_next;	/* next destination */
16355163Sshin	struct	riprt *rrt_same;	/* same destination - future use */
16455163Sshin	struct	netinfo6 rrt_info;	/* network info */
16555163Sshin	struct	in6_addr rrt_gw;	/* gateway */
16662607Sitojun	u_long	rrt_flags;		/* kernel routing table flags */
16762607Sitojun	u_long	rrt_rflags;		/* route6d routing table flags */
16855163Sshin	time_t	rrt_t;			/* when the route validated */
16955163Sshin	int	rrt_index;		/* ifindex from which this route got */
17055163Sshin};
17155163Sshin
17255163Sshinstruct	riprt *riprt = 0;
17355163Sshin
17455163Sshinint	dflag = 0;	/* debug flag */
17555163Sshinint	qflag = 0;	/* quiet flag */
17655163Sshinint	nflag = 0;	/* don't update kernel routing table */
17755163Sshinint	aflag = 0;	/* age out even the statically defined routes */
17855163Sshinint	hflag = 0;	/* don't split horizon */
17955163Sshinint	lflag = 0;	/* exchange site local routes */
18055163Sshinint	sflag = 0;	/* announce static routes w/ split horizon */
18155163Sshinint	Sflag = 0;	/* announce static routes to every interface */
18262607Sitojununsigned long routetag = 0;	/* route tag attached on originating case */
18355163Sshin
18455163Sshinchar	*filter[MAXFILTER];
18555163Sshinint	filtertype[MAXFILTER];
18655163Sshinint	nfilter = 0;
18755163Sshin
18855163Sshinpid_t	pid;
18955163Sshin
19055163Sshinstruct	sockaddr_storage ripsin;
19155163Sshin
19255163Sshinstruct	rtentry rtentry;
19355163Sshin
19455163Sshinint	interval = 1;
19555163Sshintime_t	nextalarm = 0;
19655163Sshintime_t	sup_trig_update = 0;
19755163Sshin
19855163SshinFILE	*rtlog = NULL;
19955163Sshin
20055163Sshinint logopened = 0;
20155163Sshin
20255163Sshinstatic	u_long	seq = 0;
20355163Sshin
20462607Sitojun#define	RRTF_AGGREGATE		0x08000000
20562607Sitojun#define	RRTF_NOADVERTISE	0x10000000
20662607Sitojun#define	RRTF_NH_NOT_LLADDR	0x20000000
20762607Sitojun#define RRTF_SENDANYWAY		0x40000000
20862607Sitojun#define	RRTF_CHANGED		0x80000000
20955163Sshin
21055163Sshinint main __P((int, char **));
21155163Sshinvoid ripalarm __P((int));
21255163Sshinvoid riprecv __P((void));
21355163Sshinvoid ripsend __P((struct ifc *, struct sockaddr_in6 *, int));
21455163Sshinvoid init __P((void));
21555163Sshinvoid sockopt __P((struct ifc *));
21655163Sshinvoid ifconfig __P((void));
21762607Sitojunvoid ifconfig1 __P((const char *, const struct sockaddr *, struct ifc *, int));
21855163Sshinvoid rtrecv __P((void));
21955163Sshinint rt_del __P((const struct sockaddr_in6 *, const struct sockaddr_in6 *,
22055163Sshin	const struct sockaddr_in6 *));
22155163Sshinint rt_deladdr __P((struct ifc *, const struct sockaddr_in6 *,
22255163Sshin	const struct sockaddr_in6 *));
22355163Sshinvoid filterconfig __P((void));
22455163Sshinint getifmtu __P((int));
22555163Sshinconst char *rttypes __P((struct rt_msghdr *rtm));
22655163Sshinconst char *rtflags __P((struct rt_msghdr *rtm));
22755163Sshinconst char *ifflags __P((int flags));
22855163Sshinvoid ifrt __P((struct ifc *, int));
22962607Sitojunvoid ifrt_p2p __P((struct ifc *, int));
23055163Sshinvoid applymask __P((struct in6_addr *, struct in6_addr *));
23155163Sshinvoid applyplen __P((struct in6_addr *, int));
23255163Sshinvoid ifrtdump __P((int));
23355163Sshinvoid ifdump __P((int));
23455163Sshinvoid ifdump0 __P((FILE *, const struct ifc *));
23555163Sshinvoid rtdump __P((int));
23655163Sshinvoid rt_entry __P((struct rt_msghdr *, int));
23755163Sshinvoid rtdexit __P((int));
23855163Sshinvoid riprequest __P((struct ifc *, struct netinfo6 *, int, struct sockaddr_in6 *));
23955163Sshinvoid ripflush __P((struct ifc *, struct sockaddr_in6 *));
24055163Sshinvoid sendrequest __P((struct ifc *));
24155163Sshinint mask2len __P((const struct in6_addr *, int));
24255163Sshinint sendpacket __P((struct sockaddr_in6 *, int));
24355163Sshinint addroute __P((struct riprt *, const struct in6_addr *, struct ifc *));
24455163Sshinint delroute __P((struct netinfo6 *, struct in6_addr *));
24555163Sshinstruct in6_addr *getroute __P((struct netinfo6 *, struct in6_addr *));
24655163Sshinvoid krtread __P((int));
24755163Sshinint tobeadv __P((struct riprt *, struct ifc *));
24855163Sshinchar *allocopy __P((char *));
24955163Sshinchar *hms __P((void));
25055163Sshinconst char *inet6_n2p __P((const struct in6_addr *));
25155163Sshinstruct ifac *ifa_match __P((const struct ifc *, const struct in6_addr *, int));
25255163Sshinstruct in6_addr *plen2mask __P((int));
25355163Sshinstruct riprt *rtsearch __P((struct netinfo6 *));
25455163Sshinint ripinterval __P((int));
25555163Sshintime_t ripsuptrig __P((void));
25655163Sshinvoid fatal __P((const char *, ...));
25755163Sshinvoid trace __P((int, const char *, ...));
25855163Sshinvoid tracet __P((int, const char *, ...));
25955163Sshinunsigned int if_maxindex __P((void));
26055163Sshinstruct ifc *ifc_find __P((char *));
26155163Sshinstruct iff *iff_find __P((struct ifc *, int));
26255163Sshinvoid setindex2ifc __P((int, struct ifc *));
26355163Sshin
26455163Sshin#define	MALLOC(type)	((type *)malloc(sizeof(type)))
26555163Sshin
26655163Sshinint
26755163Sshinmain(argc, argv)
26855163Sshin	int	argc;
26955163Sshin	char	**argv;
27055163Sshin{
27155163Sshin	int	ch;
27255163Sshin	int	error = 0;
27355163Sshin	struct	ifc *ifcp;
27455163Sshin	sigset_t mask, omask;
27555163Sshin	FILE	*pidfile;
27655163Sshin	char *progname;
27762607Sitojun	char *ep;
27855163Sshin
27955163Sshin	progname = strrchr(*argv, '/');
28055163Sshin	if (progname)
28155163Sshin		progname++;
28255163Sshin	else
28355163Sshin		progname = *argv;
28455163Sshin
28555163Sshin	pid = getpid();
28655163Sshin	while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnqsS")) != EOF) {
28755163Sshin		switch (ch) {
28855163Sshin		case 'A':
28955163Sshin		case 'N':
29055163Sshin		case 'O':
29155163Sshin		case 'T':
29255163Sshin		case 'L':
29362607Sitojun			if (nfilter >= MAXFILTER) {
29455163Sshin				fatal("Exceeds MAXFILTER");
29562607Sitojun				/*NOTREACHED*/
29662607Sitojun			}
29755163Sshin			filtertype[nfilter] = ch;
29855163Sshin			filter[nfilter++] = allocopy(optarg);
29955163Sshin			break;
30055163Sshin		case 't':
30162607Sitojun			ep = NULL;
30262607Sitojun			routetag = strtoul(optarg, &ep, 0);
30362607Sitojun			if (!ep || *ep != '\0' || (routetag & ~0xffff) != 0) {
30455163Sshin				fatal("invalid route tag");
30555163Sshin				/*NOTREACHED*/
30655163Sshin			}
30755163Sshin			break;
30855163Sshin		case 'R':
30962607Sitojun			if ((rtlog = fopen(optarg, "w")) == NULL) {
31055163Sshin				fatal("Can not write to routelog");
31162607Sitojun				/*NOTREACHED*/
31262607Sitojun			}
31355163Sshin			break;
31462607Sitojun#define	FLAG(c, flag, n)	case c: do { flag = n; break; } while(0)
31562607Sitojun		FLAG('a', aflag, 1); break;
31662607Sitojun		FLAG('d', dflag, 1); break;
31762607Sitojun		FLAG('D', dflag, 2); break;
31862607Sitojun		FLAG('h', hflag, 1); break;
31962607Sitojun		FLAG('l', lflag, 1); break;
32062607Sitojun		FLAG('n', nflag, 1); break;
32162607Sitojun		FLAG('q', qflag, 1); break;
32262607Sitojun		FLAG('s', sflag, 1); break;
32362607Sitojun		FLAG('S', Sflag, 1); break;
32455163Sshin#undef	FLAG
32555163Sshin		default:
32655163Sshin			fatal("Invalid option specified, terminating");
32762607Sitojun			/*NOTREACHED*/
32855163Sshin		}
32955163Sshin	}
33055163Sshin	argc -= optind;
33155163Sshin	argv += optind;
33255163Sshin	if (argc > 0)
33355163Sshin		fatal("bogus extra arguments");
33455163Sshin
33555163Sshin	if (geteuid()) {
33655163Sshin		nflag = 1;
33755163Sshin		fprintf(stderr, "No kernel update is allowed\n");
33855163Sshin	}
33955163Sshin	openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON);
34055163Sshin	logopened++;
34155163Sshin	init();
34255163Sshin	ifconfig();
34355163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
34455163Sshin		if (ifcp->ifc_index < 0) {
34555163Sshin			fprintf(stderr,
34655163Sshin"No ifindex found at %s (no link-local address?)\n",
34755163Sshin				ifcp->ifc_name);
34855163Sshin			error++;
34955163Sshin		}
35055163Sshin	}
35155163Sshin	if (error)
35255163Sshin		exit(1);
35355163Sshin	if (loopifcp == NULL)
35455163Sshin		fatal("No loopback found");
35555163Sshin	loopifindex = loopifcp->ifc_index;
35655163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next)
35755163Sshin		ifrt(ifcp, 0);
35855163Sshin	filterconfig();
35955163Sshin	krtread(0);
36055163Sshin	if (dflag)
36155163Sshin		ifrtdump(0);
36255163Sshin
36355163Sshin	if (dflag == 0) {
36462607Sitojun#if 1
36555163Sshin		if (daemon(0, 0) < 0)
36655163Sshin			fatal("daemon");
36762607Sitojun#else
36862607Sitojun		if (fork())
36962607Sitojun			exit(0);
37062607Sitojun		if (setsid() < 0)
37162607Sitojun			fatal("setid");
37262607Sitojun#endif
37355163Sshin	}
37455163Sshin	pid = getpid();
37555163Sshin	if ((pidfile = fopen(ROUTE6D_PID, "w")) != NULL) {
37655163Sshin		fprintf(pidfile, "%d\n", pid);
37755163Sshin		fclose(pidfile);
37855163Sshin	}
37955163Sshin
38055163Sshin	if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL)
38155163Sshin		fatal("malloc");
38262607Sitojun	memset(ripbuf, 0, RIP6_MAXMTU);
38355163Sshin	ripbuf->rip6_cmd = RIP6_RESPONSE;
38455163Sshin	ripbuf->rip6_vers = RIP6_VERSION;
38555163Sshin	ripbuf->rip6_res1[0] = 0;
38655163Sshin	ripbuf->rip6_res1[1] = 0;
38755163Sshin
38855163Sshin	if (signal(SIGALRM, ripalarm) == SIG_ERR)
38955163Sshin		fatal("signal: SIGALRM");
39055163Sshin	if (signal(SIGQUIT, rtdexit) == SIG_ERR)
39155163Sshin		fatal("signal: SIGQUIT");
39255163Sshin	if (signal(SIGTERM, rtdexit) == SIG_ERR)
39355163Sshin		fatal("signal: SIGTERM");
39455163Sshin	if (signal(SIGUSR1, ifrtdump) == SIG_ERR)
39555163Sshin		fatal("signal: SIGUSR1");
39655163Sshin	if (signal(SIGHUP, ifrtdump) == SIG_ERR)
39755163Sshin		fatal("signal: SIGHUP");
39855163Sshin	if (signal(SIGINT, ifrtdump) == SIG_ERR)
39955163Sshin		fatal("signal: SIGINT");
40055163Sshin	/*
40155163Sshin	 * To avoid rip packet congestion (not on a cable but in this
40255163Sshin	 * process), wait for a moment to send the first RIP6_RESPONSE
40355163Sshin	 * packets.
40455163Sshin	 */
40555163Sshin	alarm(ripinterval(INIT_INTERVAL6));
40655163Sshin
40755163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
40855163Sshin		if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP))
40955163Sshin			sendrequest(ifcp);
41055163Sshin	}
41155163Sshin
41255163Sshin	syslog(LOG_INFO, "**** Started ****");
41355163Sshin	sigemptyset(&mask);
41455163Sshin	sigaddset(&mask, SIGALRM);
41555163Sshin	while (1) {
41655163Sshin		fd_set	recvec;
41755163Sshin
41855163Sshin		FD_COPY(&sockvec, &recvec);
41955163Sshin		switch (select(FD_SETSIZE, &recvec, 0, 0, 0)) {
42055163Sshin		case -1:
42155163Sshin			if (errno == EINTR)
42255163Sshin				continue;
42355163Sshin			fatal("select");
42455163Sshin		case 0:
42555163Sshin			continue;
42655163Sshin		default:
42755163Sshin			if (FD_ISSET(ripsock, &recvec)) {
42855163Sshin				sigprocmask(SIG_BLOCK, &mask, &omask);
42955163Sshin				riprecv();
43055163Sshin				sigprocmask(SIG_SETMASK, &omask, NULL);
43155163Sshin			}
43255163Sshin			if (FD_ISSET(rtsock, &recvec)) {
43355163Sshin				sigprocmask(SIG_BLOCK, &mask, &omask);
43455163Sshin				rtrecv();
43555163Sshin				sigprocmask(SIG_SETMASK, &omask, NULL);
43655163Sshin			}
43755163Sshin		}
43855163Sshin	}
43955163Sshin}
44055163Sshin
44155163Sshin/*
44255163Sshin * gracefully exits after resetting sockopts.
44355163Sshin */
44455163Sshin/* ARGSUSED */
44555163Sshinvoid
44655163Sshinrtdexit(sig)
44755163Sshin	int sig;
44855163Sshin{
44955163Sshin	struct	riprt *rrt;
45055163Sshin
45155163Sshin	alarm(0);
45255163Sshin	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
45362607Sitojun		if (rrt->rrt_rflags & RRTF_AGGREGATE) {
45455163Sshin			delroute(&rrt->rrt_info, &rrt->rrt_gw);
45555163Sshin		}
45655163Sshin	}
45755163Sshin	close(ripsock);
45855163Sshin	close(rtsock);
45955163Sshin	syslog(LOG_INFO, "**** Terminated ****");
46055163Sshin	closelog();
46155163Sshin	exit(1);
46255163Sshin}
46355163Sshin
46455163Sshin/*
46555163Sshin * Called periodically:
46655163Sshin *	1. age out the learned route. remove it if necessary.
46755163Sshin *	2. submit RIP6_RESPONSE packets.
46855163Sshin * Invoked in every SUPPLY_INTERVAL6 (30) seconds. I believe we don't have
46955163Sshin * to invoke this function in every 1 or 5 or 10 seconds only to age the
47055163Sshin * routes more precisely.
47155163Sshin */
47255163Sshin/* ARGSUSED */
47355163Sshinvoid
47455163Sshinripalarm(sig)
47555163Sshin	int sig;
47655163Sshin{
47755163Sshin	struct	ifc *ifcp;
47855163Sshin	struct	riprt *rrt, *rrt_prev, *rrt_next;
47955163Sshin	time_t	t_lifetime, t_holddown;
48055163Sshin
48155163Sshin	/* age the RIP routes */
48255163Sshin	rrt_prev = 0;
48355163Sshin	t_lifetime = time(NULL) - RIP_LIFETIME;
48455163Sshin	t_holddown = t_lifetime - RIP_HOLDDOWN;
48555163Sshin	for (rrt = riprt; rrt; rrt = rrt_next) {
48655163Sshin		rrt_next = rrt->rrt_next;
48755163Sshin
48855163Sshin		if (rrt->rrt_t == 0) {
48955163Sshin			rrt_prev = rrt;
49055163Sshin			continue;
49155163Sshin		}
49255163Sshin		if (rrt->rrt_t < t_holddown) {
49355163Sshin			if (rrt_prev) {
49455163Sshin				rrt_prev->rrt_next = rrt->rrt_next;
49555163Sshin			} else {
49655163Sshin				riprt = rrt->rrt_next;
49755163Sshin			}
49855163Sshin			delroute(&rrt->rrt_info, &rrt->rrt_gw);
49955163Sshin			free(rrt);
50055163Sshin			continue;
50155163Sshin		}
50255163Sshin		if (rrt->rrt_t < t_lifetime)
50355163Sshin			rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
50455163Sshin		rrt_prev = rrt;
50555163Sshin	}
50655163Sshin	/* Supply updates */
50755163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
50855163Sshin		if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP))
50955163Sshin			ripsend(ifcp, &ifcp->ifc_ripsin, 0);
51055163Sshin	}
51155163Sshin	alarm(ripinterval(SUPPLY_INTERVAL6));
51255163Sshin}
51355163Sshin
51455163Sshinvoid
51555163Sshininit()
51655163Sshin{
51762921Sume	int	i, int0, int255, error;
51855163Sshin	struct	addrinfo hints, *res;
51955163Sshin	char	port[10];
52055163Sshin
52155163Sshin	ifc = (struct ifc *)NULL;
52255163Sshin	nifc = 0;
52355163Sshin	nindex2ifc = 0;	/*initial guess*/
52455163Sshin	index2ifc = NULL;
52555163Sshin	snprintf(port, sizeof(port), "%d", RIP6_PORT);
52655163Sshin
52755163Sshin	memset(&hints, 0, sizeof(hints));
52855163Sshin	hints.ai_family = PF_INET6;
52955163Sshin	hints.ai_socktype = SOCK_DGRAM;
53055163Sshin	hints.ai_flags = AI_PASSIVE;
53155163Sshin	error = getaddrinfo(NULL, port, &hints, &res);
53255163Sshin	if (error)
53355163Sshin		fatal(gai_strerror(error));
53455163Sshin	if (res->ai_next)
53555163Sshin		fatal(":: resolved to multiple address");
53655163Sshin
53755163Sshin	int0 = 0; int255 = 255;
53855163Sshin	ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
53955163Sshin	if (ripsock < 0)
54055163Sshin		fatal("rip socket");
54155163Sshin	if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0)
54255163Sshin		fatal("rip bind");
54355163Sshin	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
54455163Sshin		&int255, sizeof(int255)) < 0)
54555163Sshin		fatal("rip IPV6_MULTICAST_HOPS");
54655163Sshin	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
54755163Sshin		&int0, sizeof(int0)) < 0)
54855163Sshin		fatal("rip IPV6_MULTICAST_LOOP");
54962921Sume
55055163Sshin	i = 1;
55162607Sitojun#ifdef IPV6_RECVPKTINFO
55262607Sitojun	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &i,
55362607Sitojun		       sizeof(i)) < 0)
55462607Sitojun		fatal("rip IPV6_RECVPKTINFO");
55562607Sitojun#else  /* old adv. API */
55662607Sitojun	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_PKTINFO, &i,
55762607Sitojun		       sizeof(i)) < 0)
55855163Sshin		fatal("rip IPV6_PKTINFO");
55962607Sitojun#endif
56055163Sshin
56155163Sshin	memset(&hints, 0, sizeof(hints));
56255163Sshin	hints.ai_family = PF_INET6;
56355163Sshin	hints.ai_socktype = SOCK_DGRAM;
56455163Sshin	error = getaddrinfo(RIP6_DEST, port, &hints, &res);
56555163Sshin	if (error)
56655163Sshin		fatal(gai_strerror(error));
56755163Sshin	if (res->ai_next)
56855163Sshin		fatal("%s resolved to multiple address", RIP6_DEST);
56955163Sshin	memcpy(&ripsin, res->ai_addr, res->ai_addrlen);
57055163Sshin
57155163Sshin#ifdef FD_ZERO
57255163Sshin	FD_ZERO(&sockvec);
57355163Sshin#else
57455163Sshin	memset(&sockvec, 0, sizeof(sockvec));
57555163Sshin#endif
57655163Sshin	FD_SET(ripsock, &sockvec);
57755163Sshin
57855163Sshin	if (nflag == 0) {
57955163Sshin		if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0)
58055163Sshin			fatal("route socket");
58155163Sshin		FD_SET(rtsock, &sockvec);
58255163Sshin	} else
58355163Sshin		rtsock = -1;	/*just for safety */
58455163Sshin}
58555163Sshin
58662607Sitojun#define	RIPSIZE(n) \
58762607Sitojun	(sizeof(struct rip6) + ((n)-1) * sizeof(struct netinfo6))
58855163Sshin
58955163Sshin/*
59055163Sshin * ripflush flushes the rip datagram stored in the rip buffer
59155163Sshin */
59255163Sshinstatic int nrt;
59355163Sshinstatic struct netinfo6 *np;
59455163Sshin
59555163Sshinvoid
59655163Sshinripflush(ifcp, sin)
59755163Sshin	struct ifc *ifcp;
59855163Sshin	struct sockaddr_in6 *sin;
59955163Sshin{
60055163Sshin	int i;
60155163Sshin	int error;
60255163Sshin
60355163Sshin	if (ifcp)
60455163Sshin		tracet(1, "Send(%s): info(%d) to %s.%d\n",
60555163Sshin			ifcp->ifc_name, nrt,
60655163Sshin			inet6_n2p(&sin->sin6_addr), ntohs(sin->sin6_port));
60755163Sshin	else
60855163Sshin		tracet(1, "Send: info(%d) to %s.%d\n",
60955163Sshin			nrt, inet6_n2p(&sin->sin6_addr), ntohs(sin->sin6_port));
61055163Sshin	if (dflag >= 2) {
61155163Sshin		np = ripbuf->rip6_nets;
61255163Sshin		for (i = 0; i < nrt; i++, np++) {
61355163Sshin			if (np->rip6_metric == NEXTHOP_METRIC) {
61455163Sshin				if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest))
61562607Sitojun					trace(2, "    NextHop reset");
61655163Sshin				else {
61755163Sshin					trace(2, "    NextHop %s",
61855163Sshin						inet6_n2p(&np->rip6_dest));
61955163Sshin				}
62055163Sshin			} else {
62155163Sshin				trace(2, "    %s/%d[%d]",
62255163Sshin					inet6_n2p(&np->rip6_dest),
62355163Sshin					np->rip6_plen, np->rip6_metric);
62455163Sshin			}
62555163Sshin			if (np->rip6_tag) {
62655163Sshin				trace(2, "  tag=0x%04x",
62755163Sshin					ntohs(np->rip6_tag) & 0xffff);
62855163Sshin			}
62955163Sshin			trace(2, "\n");
63055163Sshin		}
63155163Sshin	}
63255163Sshin	error = sendpacket(sin, RIPSIZE(nrt));
63355163Sshin	if (error == EAFNOSUPPORT) {
63455163Sshin		/* Protocol not supported */
63555163Sshin		tracet(1, "Could not send info to %s (%s): "
63655163Sshin			"set IFF_UP to 0\n",
63755163Sshin			ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
63855163Sshin		ifcp->ifc_flags &= ~IFF_UP;	/* As if down for AF_INET6 */
63955163Sshin	}
64055163Sshin	nrt = 0; np = ripbuf->rip6_nets;
64155163Sshin}
64255163Sshin
64355163Sshin/*
64455163Sshin * Generate RIP6_RESPONSE packets and send them.
64555163Sshin */
64655163Sshinvoid
64755163Sshinripsend(ifcp, sin, flag)
64855163Sshin	struct	ifc *ifcp;
64955163Sshin	struct	sockaddr_in6 *sin;
65055163Sshin	int flag;
65155163Sshin{
65255163Sshin	struct	riprt *rrt;
65355163Sshin	struct	in6_addr *nh;	/* next hop */
65455163Sshin	struct	in6_addr ia;
65555163Sshin	struct	iff *iffp;
65655163Sshin	int	maxrte, ok;
65755163Sshin
65855163Sshin	if (ifcp == NULL) {
65955163Sshin		/*
66055163Sshin		 * Request from non-link local address is not
66155163Sshin		 * a regular route6d update.
66255163Sshin		 */
66362607Sitojun		maxrte = (IFMINMTU - sizeof(struct ip6_hdr) -
66462607Sitojun				sizeof(struct udphdr) -
66555163Sshin				sizeof(struct rip6) + sizeof(struct netinfo6)) /
66655163Sshin				sizeof(struct netinfo6);
66755163Sshin		nrt = 0; np = ripbuf->rip6_nets; nh = NULL;
66855163Sshin		for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
66962607Sitojun			if (rrt->rrt_rflags & RRTF_NOADVERTISE)
67055163Sshin				continue;
67155163Sshin			/* Put the route to the buffer */
67255163Sshin			*np = rrt->rrt_info;
67355163Sshin			np++; nrt++;
67455163Sshin			if (nrt == maxrte) {
67555163Sshin				ripflush(NULL, sin);
67655163Sshin				nh = NULL;
67755163Sshin			}
67855163Sshin		}
67955163Sshin		if (nrt)	/* Send last packet */
68055163Sshin			ripflush(NULL, sin);
68155163Sshin		return;
68255163Sshin	}
68355163Sshin
68462607Sitojun	if ((flag & RRTF_SENDANYWAY) == 0 &&
68555163Sshin	    (qflag || (ifcp->ifc_flags & IFF_LOOPBACK)))
68655163Sshin		return;
68755163Sshin	if (iff_find(ifcp, 'N') != NULL)
68855163Sshin		return;
68955163Sshin	if (iff_find(ifcp, 'T') != NULL) {
69055163Sshin		struct netinfo6 rrt_info;
69155163Sshin		memset(&rrt_info, 0, sizeof(struct netinfo6));
69255163Sshin		rrt_info.rip6_dest = in6addr_any;
69355163Sshin		rrt_info.rip6_plen = 0;
69455163Sshin		rrt_info.rip6_metric = 1;
69555163Sshin		rrt_info.rip6_tag = htons(routetag & 0xffff);
69655163Sshin		np = ripbuf->rip6_nets;
69755163Sshin		*np = rrt_info;
69855163Sshin		nrt = 1;
69955163Sshin		ripflush(ifcp, sin);
70055163Sshin		return;
70155163Sshin	}
70262607Sitojun	maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) -
70362607Sitojun			sizeof(struct udphdr) -
70455163Sshin			sizeof(struct rip6) + sizeof(struct netinfo6)) /
70555163Sshin			sizeof(struct netinfo6);
70655163Sshin	nrt = 0; np = ripbuf->rip6_nets; nh = NULL;
70755163Sshin	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
70862607Sitojun		if (rrt->rrt_rflags & RRTF_NOADVERTISE)
70955163Sshin			continue;
71055163Sshin		/* Need to check filer here */
71155163Sshin		ok = 1;
71255163Sshin		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
71355163Sshin			if (iffp->iff_type != 'A')
71455163Sshin				continue;
71555163Sshin			if (rrt->rrt_info.rip6_plen <= iffp->iff_plen)
71655163Sshin				continue;
71762607Sitojun			ia = rrt->rrt_info.rip6_dest;
71855163Sshin			applyplen(&ia, iffp->iff_plen);
71955163Sshin			if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) {
72055163Sshin				ok = 0;
72155163Sshin				break;
72255163Sshin			}
72355163Sshin		}
72455163Sshin		if (!ok)
72555163Sshin			continue;
72655163Sshin		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
72755163Sshin			if (iffp->iff_type != 'O')
72855163Sshin				continue;
72955163Sshin			ok = 0;
73055163Sshin			if (rrt->rrt_info.rip6_plen < iffp->iff_plen)
73155163Sshin				continue;
73262607Sitojun			ia = rrt->rrt_info.rip6_dest;
73355163Sshin			applyplen(&ia, iffp->iff_plen);
73455163Sshin			if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) {
73555163Sshin				ok = 1;
73655163Sshin				break;
73755163Sshin			}
73855163Sshin		}
73955163Sshin		if (!ok)
74055163Sshin			continue;
74155163Sshin		/* Check split horizon and other conditions */
74255163Sshin		if (tobeadv(rrt, ifcp) == 0)
74355163Sshin			continue;
74455163Sshin		/* Only considers the routes with flag if specified */
74562607Sitojun		if ((flag & RRTF_CHANGED) &&
74662607Sitojun		    (rrt->rrt_rflags & RRTF_CHANGED) == 0)
74755163Sshin			continue;
74855163Sshin		/* Check nexthop */
74955163Sshin		if (rrt->rrt_index == ifcp->ifc_index &&
75055163Sshin		    !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) &&
75162607Sitojun		    (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) == 0) {
75255163Sshin			if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) {
75355163Sshin				if (nrt == maxrte - 2)
75455163Sshin					ripflush(ifcp, sin);
75555163Sshin				np->rip6_dest = rrt->rrt_gw;
75655163Sshin				if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest))
75755163Sshin					SET_IN6_LINKLOCAL_IFINDEX(np->rip6_dest, 0);
75855163Sshin				np->rip6_plen = 0;
75955163Sshin				np->rip6_tag = 0;
76055163Sshin				np->rip6_metric = NEXTHOP_METRIC;
76155163Sshin				nh = &rrt->rrt_gw;
76255163Sshin				np++; nrt++;
76355163Sshin			}
76455163Sshin		} else if (nh && (rrt->rrt_index != ifcp->ifc_index ||
76555163Sshin			          !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) ||
76662607Sitojun				  rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)) {
76755163Sshin			/* Reset nexthop */
76855163Sshin			if (nrt == maxrte - 2)
76955163Sshin				ripflush(ifcp, sin);
77055163Sshin			memset(np, 0, sizeof(struct netinfo6));
77155163Sshin			np->rip6_metric = NEXTHOP_METRIC;
77255163Sshin			nh = NULL;
77355163Sshin			np++; nrt++;
77455163Sshin		}
77555163Sshin		/* Put the route to the buffer */
77655163Sshin		*np = rrt->rrt_info;
77755163Sshin		np++; nrt++;
77855163Sshin		if (nrt == maxrte) {
77955163Sshin			ripflush(ifcp, sin);
78055163Sshin			nh = NULL;
78155163Sshin		}
78255163Sshin	}
78355163Sshin	if (nrt)	/* Send last packet */
78455163Sshin		ripflush(ifcp, sin);
78555163Sshin}
78655163Sshin
78755163Sshin/*
78855163Sshin * Determine if the route is to be advertised on the specified interface.
78955163Sshin * It checks options specified in the arguments and the split horizon rule.
79055163Sshin */
79155163Sshinint
79255163Sshintobeadv(rrt, ifcp)
79355163Sshin	struct riprt *rrt;
79455163Sshin	struct ifc *ifcp;
79555163Sshin{
79655163Sshin
79755163Sshin	/* Special care for static routes */
79855163Sshin	if (rrt->rrt_flags & RTF_STATIC) {
79962607Sitojun		/* XXX don't advertise reject/blackhole routes */
80062607Sitojun		if (rrt->rrt_flags & (RTF_REJECT | RTF_BLACKHOLE))
80162607Sitojun			return 0;
80262607Sitojun
80355163Sshin		if (Sflag)	/* Yes, advertise it anyway */
80455163Sshin			return 1;
80555163Sshin		if (sflag && rrt->rrt_index != ifcp->ifc_index)
80655163Sshin			return 1;
80755163Sshin		return 0;
80855163Sshin	}
80955163Sshin	/* Regular split horizon */
81055163Sshin	if (hflag == 0 && rrt->rrt_index == ifcp->ifc_index)
81155163Sshin		return 0;
81255163Sshin	return 1;
81355163Sshin}
81455163Sshin
81555163Sshin/*
81655163Sshin * Send a rip packet actually.
81755163Sshin */
81855163Sshinint
81955163Sshinsendpacket(sin, len)
82055163Sshin	struct	sockaddr_in6 *sin;
82155163Sshin	int	len;
82255163Sshin{
82355163Sshin	/*
82455163Sshin	 * MSG_DONTROUTE should not be specified when it responds with a
82555163Sshin	 * RIP6_REQUEST message. SO_DONTROUTE has been specified to
82655163Sshin	 * other sockets.
82755163Sshin	 */
82855163Sshin	struct msghdr m;
82955163Sshin	struct cmsghdr *cm;
83055163Sshin	struct iovec iov[2];
83155163Sshin	u_char cmsgbuf[256];
83255163Sshin	struct in6_pktinfo *pi;
83355163Sshin	int index;
83455163Sshin	struct sockaddr_in6 sincopy;
83555163Sshin
83655163Sshin	/* do not overwrite the given sin */
83755163Sshin	sincopy = *sin;
83855163Sshin	sin = &sincopy;
83955163Sshin
84055163Sshin	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)
84155163Sshin	 || IN6_IS_ADDR_MULTICAST(&sin->sin6_addr)) {
84255163Sshin		index = IN6_LINKLOCAL_IFINDEX(sin->sin6_addr);
84355163Sshin		SET_IN6_LINKLOCAL_IFINDEX(sin->sin6_addr, 0);
84455163Sshin	} else
84555163Sshin		index = 0;
84655163Sshin
84755163Sshin	m.msg_name = (caddr_t)sin;
84855163Sshin	m.msg_namelen = sizeof(*sin);
84955163Sshin	iov[0].iov_base = (caddr_t)ripbuf;
85055163Sshin	iov[0].iov_len = len;
85155163Sshin	m.msg_iov = iov;
85255163Sshin	m.msg_iovlen = 1;
85355163Sshin	if (!index) {
85455163Sshin		m.msg_control = NULL;
85555163Sshin		m.msg_controllen = 0;
85655163Sshin	} else {
85755163Sshin		memset(cmsgbuf, 0, sizeof(cmsgbuf));
85855163Sshin		cm = (struct cmsghdr *)cmsgbuf;
85955163Sshin		m.msg_control = (caddr_t)cm;
86055163Sshin		m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
86155163Sshin
86255163Sshin		cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
86355163Sshin		cm->cmsg_level = IPPROTO_IPV6;
86455163Sshin		cm->cmsg_type = IPV6_PKTINFO;
86555163Sshin		pi = (struct in6_pktinfo *)CMSG_DATA(cm);
86655163Sshin		memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/
86755163Sshin		pi->ipi6_ifindex = index;
86855163Sshin	}
86955163Sshin
87055163Sshin	if (sendmsg(ripsock, &m, 0 /*MSG_DONTROUTE*/) < 0) {
87155163Sshin		trace(1, "sendmsg: %s\n", strerror(errno));
87255163Sshin		return errno;
87355163Sshin	}
87462921Sume
87555163Sshin	return 0;
87655163Sshin}
87755163Sshin
87855163Sshin/*
87955163Sshin * Receive and process RIP packets. Update the routes/kernel forwarding
88055163Sshin * table if necessary.
88155163Sshin */
88255163Sshinvoid
88355163Sshinriprecv()
88455163Sshin{
88555163Sshin	struct	ifc *ifcp, *ic;
88655163Sshin	struct	sockaddr_in6 fsock;
88755163Sshin	struct	in6_addr nh;	/* next hop */
88855163Sshin	struct	rip6 *rp;
88955163Sshin	struct	netinfo6 *np, *nq;
89055163Sshin	struct	riprt *rrt;
89155163Sshin	int	len, nn, need_trigger, index;
89255163Sshin	char	buf[4 * RIP6_MAXMTU];
89355163Sshin	time_t	t;
89455163Sshin	struct msghdr m;
89555163Sshin	struct cmsghdr *cm;
89655163Sshin	struct iovec iov[2];
89755163Sshin	u_char cmsgbuf[256];
89855163Sshin	struct in6_pktinfo *pi;
89955163Sshin	struct iff *iffp;
90055163Sshin	struct in6_addr ia;
90155163Sshin	int ok;
90255163Sshin
90355163Sshin	need_trigger = 0;
90462921Sume
90555163Sshin	m.msg_name = (caddr_t)&fsock;
90655163Sshin	m.msg_namelen = sizeof(fsock);
90755163Sshin	iov[0].iov_base = (caddr_t)buf;
90855163Sshin	iov[0].iov_len = sizeof(buf);
90955163Sshin	m.msg_iov = iov;
91055163Sshin	m.msg_iovlen = 1;
91155163Sshin	cm = (struct cmsghdr *)cmsgbuf;
91255163Sshin	m.msg_control = (caddr_t)cm;
91355163Sshin	m.msg_controllen = sizeof(cmsgbuf);
91455163Sshin	if ((len = recvmsg(ripsock, &m, 0)) < 0)
91555163Sshin		fatal("recvmsg");
91655163Sshin	index = 0;
91755163Sshin	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m);
91855163Sshin	     cm;
91955163Sshin	     cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) {
92055163Sshin		if (cm->cmsg_level == IPPROTO_IPV6
92155163Sshin		 && cm->cmsg_type == IPV6_PKTINFO) {
92255163Sshin			pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
92355163Sshin			index = pi->ipi6_ifindex;
92455163Sshin			break;
92555163Sshin		}
92655163Sshin	}
92755163Sshin	if (index && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr))
92855163Sshin		SET_IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr, index);
92955163Sshin
93055163Sshin	nh = fsock.sin6_addr;
93155163Sshin	nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) /
93255163Sshin		sizeof(struct netinfo6);
93355163Sshin	rp = (struct rip6 *)buf;
93455163Sshin	np = rp->rip6_nets;
93555163Sshin
93655163Sshin	if (rp->rip6_vers !=  RIP6_VERSION) {
93755163Sshin		trace(1, "Incorrect RIP version %d\n", rp->rip6_vers);
93855163Sshin		return;
93955163Sshin	}
94055163Sshin	if (rp->rip6_cmd == RIP6_REQUEST) {
94155163Sshin		if (index && index < nindex2ifc) {
94255163Sshin			ifcp = index2ifc[index];
94355163Sshin			riprequest(ifcp, np, nn, &fsock);
94455163Sshin		} else {
94555163Sshin			riprequest(NULL, np, nn, &fsock);
94655163Sshin		}
94762607Sitojun		return;
94862607Sitojun	}
94955163Sshin
95055163Sshin	if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) {
95155163Sshin		trace(1, "Packets from non-ll addr: %s\n",
95255163Sshin			inet6_n2p(&fsock.sin6_addr));
95355163Sshin		return;		/* Ignore packets from non-link-local addr */
95455163Sshin	}
95555163Sshin	index = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr);
95655163Sshin	ifcp = (index < nindex2ifc) ? index2ifc[index] : NULL;
95755163Sshin	if (!ifcp) {
95855163Sshin		trace(1, "Packets to unknown interface index %d\n", index);
95955163Sshin		return;		/* Ignore it */
96055163Sshin	}
96155163Sshin	if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr))
96255163Sshin		return;		/* The packet is from me; ignore */
96355163Sshin	if (rp->rip6_cmd != RIP6_RESPONSE) {
96455163Sshin		trace(1, "Invalid command %d\n", rp->rip6_cmd);
96562607Sitojun		return;
96655163Sshin	}
96755163Sshin	if (iff_find(ifcp, 'N') != NULL)
96855163Sshin		return;
96955163Sshin	tracet(1, "Recv(%s): from %s.%d info(%d)\n",
97055163Sshin		ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn);
97155163Sshin
97255163Sshin	t = time(NULL);
97355163Sshin	for (; nn; nn--, np++) {
97455163Sshin		if (np->rip6_metric == NEXTHOP_METRIC) {
97555163Sshin			/* modify neighbor address */
97655163Sshin			if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) {
97755163Sshin				nh = np->rip6_dest;
97855163Sshin				SET_IN6_LINKLOCAL_IFINDEX(nh, index);
97955163Sshin				trace(1, "\tNexthop: %s\n", inet6_n2p(&nh));
98055163Sshin			} else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) {
98155163Sshin				nh = fsock.sin6_addr;
98255163Sshin				trace(1, "\tNexthop: %s\n", inet6_n2p(&nh));
98355163Sshin			} else {
98455163Sshin				nh = fsock.sin6_addr;
98555163Sshin				trace(1, "\tInvalid Nexthop: %s\n",
98655163Sshin					inet6_n2p(&np->rip6_dest));
98755163Sshin			}
98855163Sshin			continue;
98955163Sshin		}
99055163Sshin		if (IN6_IS_ADDR_MULTICAST(&np->rip6_dest)) {
99155163Sshin			trace(1, "\tMulticast netinfo6: %s/%d [%d]\n",
99255163Sshin				inet6_n2p(&np->rip6_dest),
99355163Sshin				np->rip6_plen, np->rip6_metric);
99455163Sshin			continue;
99555163Sshin		}
99655163Sshin		if (IN6_IS_ADDR_LOOPBACK(&np->rip6_dest)) {
99755163Sshin			trace(1, "\tLoopback netinfo6: %s/%d [%d]\n",
99855163Sshin				inet6_n2p(&np->rip6_dest),
99955163Sshin				np->rip6_plen, np->rip6_metric);
100055163Sshin			continue;
100155163Sshin		}
100255163Sshin		if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) {
100355163Sshin			trace(1, "\tLink Local netinfo6: %s/%d [%d]\n",
100455163Sshin				inet6_n2p(&np->rip6_dest),
100555163Sshin				np->rip6_plen, np->rip6_metric);
100655163Sshin			continue;
100755163Sshin		}
100855163Sshin		/* may need to pass sitelocal prefix in some case, however*/
100955163Sshin		if (IN6_IS_ADDR_SITELOCAL(&np->rip6_dest) && !lflag) {
101055163Sshin			trace(1, "\tSite Local netinfo6: %s/%d [%d]\n",
101155163Sshin				inet6_n2p(&np->rip6_dest),
101255163Sshin				np->rip6_plen, np->rip6_metric);
101355163Sshin			continue;
101455163Sshin		}
101555163Sshin		trace(2, "\tnetinfo6: %s/%d [%d]",
101655163Sshin			inet6_n2p(&np->rip6_dest),
101755163Sshin			np->rip6_plen, np->rip6_metric);
101855163Sshin		if (np->rip6_tag)
101955163Sshin			trace(2, "  tag=0x%04x", ntohs(np->rip6_tag) & 0xffff);
102062607Sitojun		if (dflag >= 2) {
102162607Sitojun			ia = np->rip6_dest;
102262607Sitojun			applyplen(&ia, np->rip6_plen);
102362607Sitojun			if (!IN6_ARE_ADDR_EQUAL(&ia, &np->rip6_dest))
102462607Sitojun				trace(2, " [junk outside prefix]");
102562607Sitojun		}
102655163Sshin
102755163Sshin		/* Listen-only filter */
102855163Sshin		ok = 1;		/* if there's no L filter, it is ok */
102955163Sshin		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
103055163Sshin			if (iffp->iff_type != 'L')
103155163Sshin				continue;
103255163Sshin			ok = 0;
103355163Sshin			if (np->rip6_plen < iffp->iff_plen)
103455163Sshin				continue;
103555163Sshin			/* special rule: ::/0 means default, not "in /0" */
103655163Sshin			if (iffp->iff_plen == 0 && np->rip6_plen > 0)
103755163Sshin				continue;
103862607Sitojun			ia = np->rip6_dest;
103955163Sshin			applyplen(&ia, iffp->iff_plen);
104055163Sshin			if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) {
104155163Sshin				ok = 1;
104255163Sshin				break;
104355163Sshin			}
104455163Sshin		}
104555163Sshin		if (!ok) {
104655163Sshin			trace(2, "  (filtered)\n");
104755163Sshin			continue;
104855163Sshin		}
104955163Sshin
105055163Sshin		trace(2, "\n");
105155163Sshin		np->rip6_metric++;
105255163Sshin		np->rip6_metric += ifcp->ifc_metric;
105355163Sshin		if (np->rip6_metric > HOPCNT_INFINITY6)
105455163Sshin			np->rip6_metric = HOPCNT_INFINITY6;
105555163Sshin
105655163Sshin		applyplen(&np->rip6_dest, np->rip6_plen);
105755163Sshin		if ((rrt = rtsearch(np)) != NULL) {
105855163Sshin			if (rrt->rrt_t == 0)
105955163Sshin				continue;	/* Intf route has priority */
106055163Sshin			nq = &rrt->rrt_info;
106155163Sshin			if (nq->rip6_metric > np->rip6_metric) {
106255163Sshin				if (rrt->rrt_index == ifcp->ifc_index &&
106355163Sshin				    IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
106455163Sshin					/* Small metric from the same gateway */
106555163Sshin					nq->rip6_metric = np->rip6_metric;
106655163Sshin				} else {
106755163Sshin					/* Better route found */
106855163Sshin					rrt->rrt_index = ifcp->ifc_index;
106955163Sshin					/* Update routing table */
107055163Sshin					delroute(nq, &rrt->rrt_gw);
107155163Sshin					rrt->rrt_gw = nh;
107255163Sshin					*nq = *np;
107355163Sshin					addroute(rrt, &nh, ifcp);
107455163Sshin				}
107562607Sitojun				rrt->rrt_rflags |= RRTF_CHANGED;
107655163Sshin				rrt->rrt_t = t;
107755163Sshin				need_trigger = 1;
107855163Sshin			} else if (nq->rip6_metric < np->rip6_metric &&
107955163Sshin				   rrt->rrt_index == ifcp->ifc_index &&
108055163Sshin				   IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
108155163Sshin				/* Got worse route from same gw */
108255163Sshin				nq->rip6_metric = np->rip6_metric;
108355163Sshin				rrt->rrt_t = t;
108462607Sitojun				rrt->rrt_rflags |= RRTF_CHANGED;
108555163Sshin				need_trigger = 1;
108655163Sshin			} else if (nq->rip6_metric == np->rip6_metric &&
108755163Sshin				   rrt->rrt_index == ifcp->ifc_index &&
108855163Sshin				   IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw) &&
108955163Sshin				   np->rip6_metric < HOPCNT_INFINITY6) {
109055163Sshin				/* same metric, same route from same gw */
109155163Sshin				rrt->rrt_t = t;
109255163Sshin			}
109362607Sitojun			/*
109455163Sshin			 * if nq->rip6_metric == HOPCNT_INFINITY6 then
109555163Sshin			 * do not update age value. Do nothing.
109655163Sshin			 */
109755163Sshin		} else if (np->rip6_metric < HOPCNT_INFINITY6) {
109855163Sshin			/* Got a new valid route */
109955163Sshin			if ((rrt = MALLOC(struct riprt)) == NULL)
110055163Sshin				fatal("malloc: struct riprt");
110162607Sitojun			memset(rrt, 0, sizeof(*rrt));
110255163Sshin			nq = &rrt->rrt_info;
110355163Sshin
110455163Sshin			rrt->rrt_same = NULL;
110555163Sshin			rrt->rrt_index = ifcp->ifc_index;
110655163Sshin			rrt->rrt_flags = RTF_UP|RTF_GATEWAY;
110755163Sshin			rrt->rrt_gw = nh;
110855163Sshin			*nq = *np;
110955163Sshin			applyplen(&nq->rip6_dest, nq->rip6_plen);
111055163Sshin			if (nq->rip6_plen == sizeof(struct in6_addr) * 8)
111155163Sshin				rrt->rrt_flags |= RTF_HOST;
111255163Sshin
111355163Sshin			/* Put the route to the list */
111455163Sshin			rrt->rrt_next = riprt;
111555163Sshin			riprt = rrt;
111655163Sshin			/* Update routing table */
111755163Sshin			addroute(rrt, &nh, ifcp);
111862607Sitojun			rrt->rrt_rflags |= RRTF_CHANGED;
111955163Sshin			need_trigger = 1;
112055163Sshin			rrt->rrt_t = t;
112155163Sshin		}
112255163Sshin	}
112355163Sshin	/* XXX need to care the interval between triggered updates */
112455163Sshin	if (need_trigger) {
112555163Sshin		if (nextalarm > time(NULL) + RIP_TRIG_INT6_MAX) {
112655163Sshin			for (ic = ifc; ic; ic = ic->ifc_next) {
112755163Sshin				if (ifcp->ifc_index == ic->ifc_index)
112855163Sshin					continue;
112955163Sshin				if (ic->ifc_flags & IFF_UP)
113055163Sshin					ripsend(ic, &ic->ifc_ripsin,
113162607Sitojun						RRTF_CHANGED);
113255163Sshin			}
113355163Sshin		}
113455163Sshin		/* Reset the flag */
113555163Sshin		for (rrt = riprt; rrt; rrt = rrt->rrt_next)
113662607Sitojun			rrt->rrt_rflags &= ~RRTF_CHANGED;
113755163Sshin	}
113855163Sshin}
113955163Sshin
114055163Sshin/*
114155163Sshin * Send all routes request packet to the specified interface.
114255163Sshin */
114355163Sshinvoid
114455163Sshinsendrequest(ifcp)
114555163Sshin	struct ifc *ifcp;
114655163Sshin{
114755163Sshin	struct netinfo6 *np;
114855163Sshin	int error;
114955163Sshin
115055163Sshin	if (ifcp->ifc_flags & IFF_LOOPBACK)
115155163Sshin		return;
115255163Sshin	ripbuf->rip6_cmd = RIP6_REQUEST;
115355163Sshin	np = ripbuf->rip6_nets;
115455163Sshin	memset(np, 0, sizeof(struct netinfo6));
115555163Sshin	np->rip6_metric = HOPCNT_INFINITY6;
115655163Sshin	tracet(1, "Send rtdump Request to %s (%s)\n",
115755163Sshin		ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
115855163Sshin	error = sendpacket(&ifcp->ifc_ripsin, RIPSIZE(1));
115955163Sshin	if (error == EAFNOSUPPORT) {
116055163Sshin		/* Protocol not supported */
116155163Sshin		tracet(1, "Could not send rtdump Request to %s (%s): "
116255163Sshin			"set IFF_UP to 0\n",
116355163Sshin			ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
116455163Sshin		ifcp->ifc_flags &= ~IFF_UP;	/* As if down for AF_INET6 */
116555163Sshin	}
116655163Sshin	ripbuf->rip6_cmd = RIP6_RESPONSE;
116755163Sshin}
116855163Sshin
116955163Sshin/*
117055163Sshin * Process a RIP6_REQUEST packet.
117155163Sshin */
117255163Sshinvoid
117355163Sshinriprequest(ifcp, np, nn, sin)
117455163Sshin	struct ifc *ifcp;
117555163Sshin	struct netinfo6 *np;
117655163Sshin	int nn;
117755163Sshin	struct sockaddr_in6 *sin;
117855163Sshin{
117955163Sshin	int i;
118055163Sshin	struct riprt *rrt;
118155163Sshin
118255163Sshin	if (!(nn == 1 && IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest) &&
118355163Sshin	      np->rip6_plen == 0 && np->rip6_metric == HOPCNT_INFINITY6)) {
118455163Sshin		/* Specific response, don't split-horizon */
118555163Sshin		trace(1, "\tRIP Request\n");
118655163Sshin		for (i = 0; i < nn; i++, np++) {
118755163Sshin			rrt = rtsearch(np);
118855163Sshin			if (rrt)
118955163Sshin				np->rip6_metric = rrt->rrt_info.rip6_metric;
119055163Sshin			else
119155163Sshin				np->rip6_metric = HOPCNT_INFINITY6;
119255163Sshin		}
119355163Sshin		(void)sendpacket(sin, RIPSIZE(nn));
119455163Sshin		return;
119555163Sshin	}
119655163Sshin	/* Whole routing table dump */
119755163Sshin	trace(1, "\tRIP Request -- whole routing table\n");
119862607Sitojun	ripsend(ifcp, sin, RRTF_SENDANYWAY);
119955163Sshin}
120055163Sshin
120155163Sshin/*
120255163Sshin * Get information of each interface.
120355163Sshin */
120455163Sshinvoid
120555163Sshinifconfig()
120655163Sshin{
120762607Sitojun#ifdef HAVE_GETIFADDRS
120862607Sitojun	struct ifaddrs *ifap, *ifa;
120962607Sitojun	struct ifc *ifcp;
121062607Sitojun	struct ipv6_mreq mreq;
121162607Sitojun	int s;
121262607Sitojun
121362607Sitojun	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
121462607Sitojun		fatal("socket");
121562607Sitojun
121662607Sitojun	if (getifaddrs(&ifap) != 0)
121762607Sitojun		fatal("getifaddrs");
121862607Sitojun
121962607Sitojun	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
122062607Sitojun		if (ifa->ifa_addr->sa_family != AF_INET6)
122162607Sitojun			continue;
122262607Sitojun		ifcp = ifc_find(ifa->ifa_name);
122362607Sitojun		/* we are interested in multicast-capable interfaces */
122462607Sitojun		if ((ifa->ifa_flags & IFF_MULTICAST) == 0)
122562607Sitojun			continue;
122662607Sitojun		if (!ifcp) {
122762607Sitojun			/* new interface */
122862607Sitojun			if ((ifcp = MALLOC(struct ifc)) == NULL)
122962607Sitojun				fatal("malloc: struct ifc");
123062607Sitojun			memset(ifcp, 0, sizeof(*ifcp));
123162607Sitojun			ifcp->ifc_index = -1;
123262607Sitojun			ifcp->ifc_next = ifc;
123362607Sitojun			ifc = ifcp;
123462607Sitojun			nifc++;
123562607Sitojun			ifcp->ifc_name = allocopy(ifa->ifa_name);
123662607Sitojun			ifcp->ifc_addr = 0;
123762607Sitojun			ifcp->ifc_filter = 0;
123862607Sitojun			ifcp->ifc_flags = ifa->ifa_flags;
123962607Sitojun			trace(1, "newif %s <%s>\n", ifcp->ifc_name,
124062607Sitojun				ifflags(ifcp->ifc_flags));
124162607Sitojun			if (!strcmp(ifcp->ifc_name, LOOPBACK_IF))
124262607Sitojun				loopifcp = ifcp;
124362607Sitojun		} else {
124462607Sitojun			/* update flag, this may be up again */
124562607Sitojun			if (ifcp->ifc_flags != ifa->ifa_flags) {
124662607Sitojun				trace(1, "%s: <%s> -> ", ifcp->ifc_name,
124762607Sitojun					ifflags(ifcp->ifc_flags));
124862607Sitojun				trace(1, "<%s>\n", ifflags(ifa->ifa_flags));
124962607Sitojun			}
125062607Sitojun			ifcp->ifc_flags = ifa->ifa_flags;
125162607Sitojun		}
125262607Sitojun		ifconfig1(ifa->ifa_name, ifa->ifa_addr, ifcp, s);
125362607Sitojun		if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP
125462607Sitojun		 && 0 < ifcp->ifc_index && !ifcp->ifc_joined) {
125562607Sitojun			mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr;
125662607Sitojun			mreq.ipv6mr_interface = ifcp->ifc_index;
125762607Sitojun			if (setsockopt(ripsock, IPPROTO_IPV6,
125862607Sitojun				IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0)
125962607Sitojun				fatal("IPV6_JOIN_GROUP");
126062607Sitojun			trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST);
126162607Sitojun			ifcp->ifc_joined++;
126262607Sitojun		}
126362607Sitojun	}
126462607Sitojun	close(s);
126562607Sitojun	freeifaddrs(ifap);
126662607Sitojun#else
126755163Sshin	int	s, i;
126855163Sshin	char	*buf;
126955163Sshin	struct	ifconf ifconf;
127055163Sshin	struct	ifreq *ifrp, ifr;
127155163Sshin	struct	ifc *ifcp;
127255163Sshin	struct	ipv6_mreq mreq;
127355163Sshin	int	bufsiz;
127455163Sshin
127555163Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
127655163Sshin		fatal("socket");
127755163Sshin
127855163Sshin	/* wild guess - v4, media, link, v6 * 3 */
127955163Sshin	bufsiz = if_maxindex() * sizeof(struct ifreq) * 6;
128055163Sshin	if ((buf = (char *)malloc(bufsiz)) == NULL)
128155163Sshin		fatal("malloc");
128255163Sshin
128355163Sshin	/*
128455163Sshin	 * ioctl(SIOCGIFCONF) does not return error on buffer size.
128555163Sshin	 * we'll try to guess the buffer size by trying it twice, with
128655163Sshin	 * different buffer size.
128755163Sshin	 */
128855163Sshin	ifconf.ifc_buf = buf;
128955163Sshin	ifconf.ifc_len = bufsiz / 2;
129055163Sshin	if (ioctl(s, SIOCGIFCONF, (char *)&ifconf) < 0)
129155163Sshin		fatal("ioctl: SIOCGIFCONF");
129255163Sshin	i = ifconf.ifc_len;
129355163Sshin	while (1) {
129462607Sitojun		char *newbuf;
129562607Sitojun
129655163Sshin		ifconf.ifc_buf = buf;
129755163Sshin		ifconf.ifc_len = bufsiz;
129855163Sshin		if (ioctl(s, SIOCGIFCONF, (char *)&ifconf) < 0)
129955163Sshin			fatal("ioctl: SIOCGIFCONF");
130055163Sshin		if (i == ifconf.ifc_len)
130155163Sshin			break;
130255163Sshin		i = ifconf.ifc_len;
130355163Sshin		bufsiz *= 2;
130462607Sitojun		if ((newbuf = (char *)realloc(buf, bufsiz)) == NULL) {
130562607Sitojun			free(buf);
130655163Sshin			fatal("realloc");
130762607Sitojun		}
130862607Sitojun		buf = newbuf;
130955163Sshin	}
131055163Sshin	for (i = 0; i < ifconf.ifc_len; ) {
131155163Sshin		ifrp = (struct ifreq *)(buf + i);
131255163Sshin		if (ifrp->ifr_addr.sa_family != AF_INET6)
131355163Sshin			goto skip;
131455163Sshin		ifcp = ifc_find(ifrp->ifr_name);
131555163Sshin		strcpy(ifr.ifr_name, ifrp->ifr_name);
131655163Sshin		if (ioctl(s, SIOCGIFFLAGS, (char *)&ifr) < 0)
131755163Sshin			fatal("ioctl: SIOCGIFFLAGS");
131855163Sshin		/* we are interested in multicast-capable interfaces */
131955163Sshin		if ((ifr.ifr_flags & IFF_MULTICAST) == 0)
132055163Sshin			goto skip;
132155163Sshin		if (!ifcp) {
132255163Sshin			/* new interface */
132362607Sitojun			if ((ifcp = MALLOC(struct ifc)) == NULL)
132462607Sitojun				fatal("malloc: struct ifc");
132555163Sshin			memset(ifcp, 0, sizeof(*ifcp));
132655163Sshin			ifcp->ifc_index = -1;
132755163Sshin			ifcp->ifc_next = ifc;
132855163Sshin			ifc = ifcp;
132955163Sshin			nifc++;
133055163Sshin			ifcp->ifc_name = allocopy(ifrp->ifr_name);
133155163Sshin			ifcp->ifc_addr = 0;
133255163Sshin			ifcp->ifc_filter = 0;
133355163Sshin			ifcp->ifc_flags = ifr.ifr_flags;
133455163Sshin			trace(1, "newif %s <%s>\n", ifcp->ifc_name,
133555163Sshin				ifflags(ifcp->ifc_flags));
133655163Sshin			if (!strcmp(ifcp->ifc_name, LOOPBACK_IF))
133755163Sshin				loopifcp = ifcp;
133855163Sshin		} else {
133955163Sshin			/* update flag, this may be up again */
134055163Sshin			if (ifcp->ifc_flags != ifr.ifr_flags) {
134155163Sshin				trace(1, "%s: <%s> -> ", ifcp->ifc_name,
134255163Sshin					ifflags(ifcp->ifc_flags));
134355163Sshin				trace(1, "<%s>\n", ifflags(ifr.ifr_flags));
134455163Sshin			}
134555163Sshin			ifcp->ifc_flags = ifr.ifr_flags;
134655163Sshin		}
134762607Sitojun		ifconfig1(ifrp->ifr_name, &ifrp->ifr_addr, ifcp, s);
134855163Sshin		if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP
134955163Sshin		 && 0 < ifcp->ifc_index && !ifcp->ifc_joined) {
135055163Sshin			mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr;
135155163Sshin			mreq.ipv6mr_interface = ifcp->ifc_index;
135255163Sshin			if (setsockopt(ripsock, IPPROTO_IPV6,
135355163Sshin				IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0)
135455163Sshin				fatal("IPV6_JOIN_GROUP");
135555163Sshin			trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST);
135655163Sshin			ifcp->ifc_joined++;
135755163Sshin		}
135855163Sshinskip:
135955163Sshin		i += IFNAMSIZ;
136055163Sshin		if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr))
136155163Sshin			i += ifrp->ifr_addr.sa_len;
136255163Sshin		else
136355163Sshin			i += sizeof(struct sockaddr);
136455163Sshin	}
136555163Sshin	close(s);
136655163Sshin	free(buf);
136762607Sitojun#endif
136855163Sshin}
136955163Sshin
137055163Sshinvoid
137162607Sitojunifconfig1(name, sa, ifcp, s)
137262607Sitojun	const char *name;
137362607Sitojun	const struct sockaddr *sa;
137455163Sshin	struct	ifc *ifcp;
137555163Sshin	int	s;
137655163Sshin{
137755163Sshin	struct	in6_ifreq ifr;
137855163Sshin	struct	sockaddr_in6 *sin;
137955163Sshin	struct	ifac *ifa;
138055163Sshin	int	plen;
138155163Sshin	char	buf[BUFSIZ];
138255163Sshin
138362607Sitojun	sin = (struct sockaddr_in6 *)sa;
138455163Sshin	ifr.ifr_addr = *sin;
138562607Sitojun	strcpy(ifr.ifr_name, name);
138655163Sshin	if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0)
138755163Sshin		fatal("ioctl: SIOCGIFNETMASK_IN6");
138855163Sshin	plen = mask2len(&ifr.ifr_addr.sin6_addr, 16);
138955163Sshin	if ((ifa = ifa_match(ifcp, &sin->sin6_addr, plen)) != NULL) {
139055163Sshin		/* same interface found */
139155163Sshin		/* need check if something changed */
139255163Sshin		/* XXX not yet implemented */
139355163Sshin		return;
139455163Sshin	}
139555163Sshin	/*
139655163Sshin	 * New address is found
139755163Sshin	 */
139855163Sshin	if ((ifa = MALLOC(struct ifac)) == NULL)
139955163Sshin		fatal("malloc: struct ifac");
140062607Sitojun	memset(ifa, 0, sizeof(*ifa));
140155163Sshin	ifa->ifa_conf = ifcp;
140255163Sshin	ifa->ifa_next = ifcp->ifc_addr;
140355163Sshin	ifcp->ifc_addr = ifa;
140455163Sshin	ifa->ifa_addr = sin->sin6_addr;
140555163Sshin	ifa->ifa_plen = plen;
140655163Sshin	if (ifcp->ifc_flags & IFF_POINTOPOINT) {
140755163Sshin		ifr.ifr_addr = *sin;
140855163Sshin		if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0)
140955163Sshin			fatal("ioctl: SIOCGIFDSTADDR_IN6");
141055163Sshin		ifa->ifa_raddr = ifr.ifr_dstaddr.sin6_addr;
141155163Sshin		inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, buf, sizeof(buf));
141255163Sshin		trace(1, "found address %s/%d -- %s\n",
141355163Sshin			inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen, buf);
141455163Sshin	} else {
141555163Sshin		trace(1, "found address %s/%d\n",
141655163Sshin			inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen);
141755163Sshin	}
141855163Sshin	if (ifcp->ifc_index < 0 && IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) {
141955163Sshin		ifcp->ifc_mylladdr = ifa->ifa_addr;
142055163Sshin		ifcp->ifc_index = IN6_LINKLOCAL_IFINDEX(ifa->ifa_addr);
142155163Sshin		memcpy(&ifcp->ifc_ripsin, &ripsin, ripsin.ss_len);
142255163Sshin		SET_IN6_LINKLOCAL_IFINDEX(ifcp->ifc_ripsin.sin6_addr,
142355163Sshin			ifcp->ifc_index);
142455163Sshin		setindex2ifc(ifcp->ifc_index, ifcp);
142555163Sshin		ifcp->ifc_mtu = getifmtu(ifcp->ifc_index);
142655163Sshin		if (ifcp->ifc_mtu > RIP6_MAXMTU)
142755163Sshin			ifcp->ifc_mtu = RIP6_MAXMTU;
142855163Sshin		if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0)
142955163Sshin			fatal("ioctl: SIOCGIFMETRIC");
143055163Sshin		ifcp->ifc_metric = ifr.ifr_metric;
143155163Sshin		trace(1, "\tindex: %d, mtu: %d, metric: %d\n",
143255163Sshin			ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric);
143355163Sshin	}
143455163Sshin}
143555163Sshin
143655163Sshin/*
143755163Sshin * Receive and process routing messages.
143855163Sshin * Update interface information as necesssary.
143955163Sshin */
144055163Sshinvoid
144155163Sshinrtrecv()
144255163Sshin{
144355163Sshin	char buf[BUFSIZ];
144455163Sshin	char *p, *q;
144555163Sshin	struct rt_msghdr *rtm;
144655163Sshin	struct ifa_msghdr *ifam;
144755163Sshin	struct if_msghdr *ifm;
144855163Sshin	int len;
144955163Sshin	struct ifc *ifcp;
145055163Sshin	int iface = 0, rtable = 0;
145155163Sshin	struct sockaddr_in6 *rta[RTAX_MAX];
145255163Sshin	int i, addrs;
145355163Sshin
145455163Sshin	if ((len = read(rtsock, buf, sizeof(buf))) < 0) {
145555163Sshin		perror("read from rtsock");
145655163Sshin		exit(-1);
145755163Sshin	}
145855163Sshin	if (len < sizeof(*rtm)) {
145955163Sshin		trace(1, "short read from rtsock: %d (should be > %d)\n",
146055163Sshin			len, sizeof(*rtm));
146155163Sshin		return;
146255163Sshin	}
146355163Sshin
146455163Sshin	for (p = buf; p - buf < len; p += ((struct rt_msghdr *)p)->rtm_msglen) {
146555163Sshin		/* safety against bogus message */
146655163Sshin		if (((struct rt_msghdr *)p)->rtm_msglen <= 0) {
146755163Sshin			trace(1, "bogus rtmsg: length=%d\n",
146855163Sshin				((struct rt_msghdr *)p)->rtm_msglen);
146955163Sshin			break;
147055163Sshin		}
147155163Sshin		rtm = NULL;
147255163Sshin		ifam = NULL;
147355163Sshin		ifm = NULL;
147455163Sshin		switch (((struct rt_msghdr *)p)->rtm_type) {
147555163Sshin		case RTM_NEWADDR:
147655163Sshin		case RTM_DELADDR:
147755163Sshin			ifam = (struct ifa_msghdr *)p;
147855163Sshin			addrs = ifam->ifam_addrs;
147955163Sshin			q = (char *)(ifam + 1);
148055163Sshin			break;
148155163Sshin		case RTM_IFINFO:
148255163Sshin			ifm = (struct if_msghdr *)p;
148355163Sshin			addrs = ifm->ifm_addrs;
148455163Sshin			q = (char *)(ifm + 1);
148555163Sshin			break;
148655163Sshin		default:
148755163Sshin			rtm = (struct rt_msghdr *)p;
148855163Sshin			addrs = rtm->rtm_addrs;
148955163Sshin			q = (char *)(rtm + 1);
149055163Sshin			if (rtm->rtm_version != RTM_VERSION) {
149155163Sshin				trace(1, "unexpected rtmsg version %d "
149255163Sshin					"(should be %d)\n",
149355163Sshin					rtm->rtm_version, RTM_VERSION);
149455163Sshin				continue;
149555163Sshin			}
149655163Sshin			if (rtm->rtm_pid == pid) {
149755163Sshin#if 0
149855163Sshin				trace(1, "rtmsg looped back to me, ignored\n");
149955163Sshin#endif
150055163Sshin				continue;
150155163Sshin			}
150255163Sshin			break;
150355163Sshin		}
150455163Sshin		memset(&rta, 0, sizeof(rta));
150555163Sshin		for (i = 0; i < RTAX_MAX; i++) {
150655163Sshin			if (addrs & (1 << i)) {
150755163Sshin				rta[i] = (struct sockaddr_in6 *)q;
150855163Sshin				q += ROUNDUP(rta[i]->sin6_len);
150955163Sshin			}
151055163Sshin		}
151155163Sshin
151255163Sshin		trace(1, "rtsock: %s (addrs=%x)\n",
151355163Sshin			rttypes((struct rt_msghdr *)p), addrs);
151455163Sshin		if (dflag >= 2) {
151555163Sshin			int i;
151655163Sshin			for (i = 0;
151755163Sshin			     i < ((struct rt_msghdr *)p)->rtm_msglen;
151855163Sshin			     i++) {
151955163Sshin				fprintf(stderr, "%02x ", p[i] & 0xff);
152055163Sshin				if (i % 16 == 15) fprintf(stderr, "\n");
152155163Sshin			}
152255163Sshin			fprintf(stderr, "\n");
152355163Sshin		}
152455163Sshin
152555163Sshin		/*
152655163Sshin		 * Easy ones first.
152755163Sshin		 *
152855163Sshin		 * We may be able to optimize by using ifm->ifm_index or
152955163Sshin		 * ifam->ifam_index.  For simplicity we don't do that here.
153055163Sshin		 */
153155163Sshin		switch (((struct rt_msghdr *)p)->rtm_type) {
153255163Sshin		case RTM_NEWADDR:
153355163Sshin		case RTM_IFINFO:
153455163Sshin			iface++;
153555163Sshin			continue;
153655163Sshin		case RTM_ADD:
153755163Sshin			rtable++;
153855163Sshin			continue;
153955163Sshin		case RTM_LOSING:
154055163Sshin		case RTM_MISS:
154155163Sshin		case RTM_RESOLVE:
154255163Sshin		case RTM_GET:
154355163Sshin		case RTM_LOCK:
154455163Sshin			/* nothing to be done here */
154555163Sshin			trace(1, "\tnothing to be done, ignored\n");
154655163Sshin			continue;
154755163Sshin		}
154855163Sshin
154955163Sshin#if 0
155055163Sshin		if (rta[RTAX_DST] == NULL) {
155155163Sshin			trace(1, "\tno destination, ignored\n");
155262607Sitojun			continue;
155355163Sshin		}
155455163Sshin		if (rta[RTAX_DST]->sin6_family != AF_INET6) {
155555163Sshin			trace(1, "\taf mismatch, ignored\n");
155655163Sshin			continue;
155755163Sshin		}
155855163Sshin		if (IN6_IS_ADDR_LINKLOCAL(&rta[RTAX_DST]->sin6_addr)) {
155955163Sshin			trace(1, "\tlinklocal destination, ignored\n");
156055163Sshin			continue;
156155163Sshin		}
156255163Sshin		if (IN6_ARE_ADDR_EQUAL(&rta[RTAX_DST]->sin6_addr, &in6addr_loopback)) {
156355163Sshin			trace(1, "\tloopback destination, ignored\n");
156455163Sshin			continue;		/* Loopback */
156555163Sshin		}
156655163Sshin		if (IN6_IS_ADDR_MULTICAST(&rta[RTAX_DST]->sin6_addr)) {
156755163Sshin			trace(1, "\tmulticast destination, ignored\n");
156855163Sshin			continue;
156955163Sshin		}
157055163Sshin#endif
157155163Sshin
157255163Sshin		/* hard ones */
157355163Sshin		switch (((struct rt_msghdr *)p)->rtm_type) {
157455163Sshin		case RTM_NEWADDR:
157555163Sshin		case RTM_IFINFO:
157655163Sshin		case RTM_ADD:
157755163Sshin		case RTM_LOSING:
157855163Sshin		case RTM_MISS:
157955163Sshin		case RTM_RESOLVE:
158055163Sshin		case RTM_GET:
158155163Sshin		case RTM_LOCK:
158255163Sshin			/* should already be handled */
158355163Sshin			fatal("rtrecv: never reach here");
158455163Sshin		case RTM_DELETE:
158555163Sshin			if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY]
158655163Sshin			 || !rta[RTAX_NETMASK]) {
158755163Sshin				trace(1, "\tsome of dst/gw/netamsk are unavailable, ignored\n");
158855163Sshin				break;
158955163Sshin			}
159055163Sshin			if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY], rta[RTAX_NETMASK]) == 0) {
159155163Sshin				rtable++;	/*just to be sure*/
159255163Sshin			}
159355163Sshin			break;
159455163Sshin		case RTM_CHANGE:
159555163Sshin		case RTM_REDIRECT:
159655163Sshin			trace(1, "\tnot supported yet, ignored\n");
159755163Sshin			break;
159855163Sshin		case RTM_DELADDR:
159955163Sshin			if (!rta[RTAX_NETMASK] || !rta[RTAX_IFA]) {
160055163Sshin				trace(1, "\tno netmask or ifa given, ignored\n");
160155163Sshin				break;
160255163Sshin			}
160355163Sshin			if (ifam->ifam_index < nindex2ifc)
160455163Sshin				ifcp = index2ifc[ifam->ifam_index];
160555163Sshin			else
160655163Sshin				ifcp = NULL;
160755163Sshin			if (!ifcp) {
160855163Sshin				trace(1, "\tinvalid ifam_index %d, ignored\n",
160955163Sshin					ifam->ifam_index);
161055163Sshin				break;
161155163Sshin			}
161255163Sshin			rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK]);
161355163Sshin			iface++;
161455163Sshin			break;
161555163Sshin		case RTM_OLDADD:
161655163Sshin		case RTM_OLDDEL:
161755163Sshin			trace(1, "\tnot supported yet, ignored\n");
161855163Sshin			break;
161955163Sshin		}
162055163Sshin
162155163Sshin	}
162255163Sshin
162355163Sshin	if (iface) {
162455163Sshin		trace(1, "rtsock: reconfigure interfaces, refresh interface routes\n");
162555163Sshin		ifconfig();
162655163Sshin		for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next)
162755163Sshin			ifrt(ifcp, 1);
162855163Sshin	}
162955163Sshin	if (rtable) {
163055163Sshin		trace(1, "rtsock: read routing table again\n");
163155163Sshin		krtread(1);
163255163Sshin	}
163355163Sshin}
163455163Sshin
163555163Sshin/*
163655163Sshin * remove specified route from the internal routing table.
163755163Sshin */
163855163Sshinint
163955163Sshinrt_del(sdst, sgw, smask)
164055163Sshin	const struct sockaddr_in6 *sdst;
164155163Sshin	const struct sockaddr_in6 *sgw;
164255163Sshin	const struct sockaddr_in6 *smask;
164355163Sshin{
164455163Sshin	const struct in6_addr *dst = NULL;
164555163Sshin	const struct in6_addr *gw = NULL;
164655163Sshin	int prefix;
164755163Sshin	struct netinfo6 ni6;
164855163Sshin	struct riprt *rrt = NULL;
164955163Sshin	time_t t_lifetime;
165055163Sshin
165155163Sshin	if (sdst->sin6_family != AF_INET6) {
165255163Sshin		trace(1, "\tother AF, ignored\n");
165355163Sshin		return -1;
165455163Sshin	}
165555163Sshin	if (IN6_IS_ADDR_LINKLOCAL(&sdst->sin6_addr)
165655163Sshin	 || IN6_ARE_ADDR_EQUAL(&sdst->sin6_addr, &in6addr_loopback)
165755163Sshin	 || IN6_IS_ADDR_MULTICAST(&sdst->sin6_addr)) {
165855163Sshin		trace(1, "\taddress %s not interesting, ignored\n",
165955163Sshin			inet6_n2p(&sdst->sin6_addr));
166055163Sshin		return -1;
166155163Sshin	}
166255163Sshin	dst = &sdst->sin6_addr;
166355163Sshin	if (sgw->sin6_family == AF_INET6
166455163Sshin	 && smask->sin6_family == AF_INET6) {
166555163Sshin		/* easy case */
166655163Sshin		gw = &sgw->sin6_addr;
166755163Sshin		prefix = mask2len(&smask->sin6_addr, 16);
166855163Sshin	} else if (sgw->sin6_family == AF_LINK) {
166955163Sshin		/*
167055163Sshin		 * Interface route... a hard case.  We need to get the prefix
167155163Sshin		 * length from the kernel, but we now are parsing rtmsg.
167255163Sshin		 * We'll purge matching routes from my list, then get the
167355163Sshin		 * fresh list.
167455163Sshin		 */
167555163Sshin		struct riprt *longest;
167655163Sshin		trace(1, "\t%s is a interface route, guessing prefixlen\n",
167755163Sshin			inet6_n2p(dst));
167855163Sshin		longest = NULL;
167955163Sshin		for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
168055163Sshin			if (IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
168155163Sshin					&sdst->sin6_addr)
168255163Sshin			 && IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) {
168355163Sshin				if (!longest
168455163Sshin				 || longest->rrt_info.rip6_plen <
168555163Sshin						 rrt->rrt_info.rip6_plen) {
168655163Sshin					longest = rrt;
168755163Sshin				}
168855163Sshin			}
168955163Sshin		}
169055163Sshin		rrt = longest;
169155163Sshin		if (!rrt) {
169255163Sshin			trace(1, "\tno matching interface route found\n");
169355163Sshin			return -1;
169455163Sshin		}
169555163Sshin		gw = &in6addr_loopback;
169655163Sshin		prefix = rrt->rrt_info.rip6_plen;
169755163Sshin	} else {
169862607Sitojun		trace(1, "\tunsupported af: (gw=%d, mask=%d)\n",
169955163Sshin			sgw->sin6_family, smask->sin6_family);
170055163Sshin		return -1;
170155163Sshin	}
170255163Sshin
170355163Sshin	trace(1, "\tdeleting %s/%d ", inet6_n2p(dst), prefix);
170455163Sshin	trace(1, "gw %s\n", inet6_n2p(gw));
170555163Sshin	t_lifetime = time(NULL) - RIP_LIFETIME;
170655163Sshin	/* age route for interface address */
170755163Sshin	memset(&ni6, 0, sizeof(ni6));
170855163Sshin	ni6.rip6_dest = *dst;
170955163Sshin	ni6.rip6_plen = prefix;
171055163Sshin	applyplen(&ni6.rip6_dest, ni6.rip6_plen);	/*to be sure*/
171155163Sshin	trace(1, "\tfind route %s/%d\n", inet6_n2p(&ni6.rip6_dest),
171255163Sshin		ni6.rip6_plen);
171355163Sshin	if (!rrt && (rrt = rtsearch(&ni6)) == NULL) {
171455163Sshin		trace(1, "\tno route found\n");
171555163Sshin		return -1;
171655163Sshin	}
171755163Sshin	if ((rrt->rrt_flags & RTF_STATIC) == 0) {
171855163Sshin		trace(1, "\tyou can delete static routes only\n");
171955163Sshin	} else if (memcmp(&rrt->rrt_gw, gw, sizeof(rrt->rrt_gw)) != 0) {
172055163Sshin		trace(1, "\tgw mismatch: %s <-> ",
172155163Sshin			inet6_n2p(&rrt->rrt_gw));
172255163Sshin		trace(1, "%s\n", inet6_n2p(gw));
172355163Sshin	} else {
172455163Sshin		trace(1, "\troute found, age it\n");
172555163Sshin		if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
172655163Sshin			rrt->rrt_t = t_lifetime;
172755163Sshin			rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
172855163Sshin		}
172955163Sshin	}
173055163Sshin	return 0;
173155163Sshin}
173255163Sshin
173355163Sshin/*
173455163Sshin * remove specified address from internal interface/routing table.
173555163Sshin */
173655163Sshinint
173755163Sshinrt_deladdr(ifcp, sifa, smask)
173855163Sshin	struct ifc *ifcp;
173955163Sshin	const struct sockaddr_in6 *sifa;
174055163Sshin	const struct sockaddr_in6 *smask;
174155163Sshin{
174255163Sshin	const struct in6_addr *addr = NULL;
174355163Sshin	int prefix;
174455163Sshin	struct ifac *ifa = NULL;
174555163Sshin	struct netinfo6 ni6;
174655163Sshin	struct riprt *rrt = NULL;
174755163Sshin	time_t t_lifetime;
174855163Sshin	int updated = 0;
174955163Sshin
175055163Sshin	if (sifa->sin6_family != AF_INET6 || smask->sin6_family != AF_INET6) {
175155163Sshin		trace(1, "\tother AF, ignored\n");
175255163Sshin		return -1;
175355163Sshin	}
175455163Sshin	addr = &sifa->sin6_addr;
175555163Sshin	prefix = mask2len(&smask->sin6_addr, 16);
175655163Sshin
175755163Sshin	trace(1, "\tdeleting %s/%d from %s\n",
175855163Sshin		inet6_n2p(addr), prefix, ifcp->ifc_name);
175955163Sshin	ifa = ifa_match(ifcp, addr, prefix);
176055163Sshin	if (!ifa) {
176155163Sshin		trace(1, "\tno matching ifa found for %s/%d on %s\n",
176255163Sshin			inet6_n2p(addr), prefix, ifcp->ifc_name);
176355163Sshin		return -1;
176455163Sshin	}
176555163Sshin	if (ifa->ifa_conf != ifcp) {
176655163Sshin		trace(1, "\taddress table corrupt: back pointer does not match "
176755163Sshin			"(%s != %s)\n",
176855163Sshin			ifcp->ifc_name, ifa->ifa_conf->ifc_name);
176955163Sshin		return -1;
177055163Sshin	}
177155163Sshin	/* remove ifa from interface */
177255163Sshin	if (ifcp->ifc_addr == ifa)
177355163Sshin		ifcp->ifc_addr = ifa->ifa_next;
177455163Sshin	else {
177555163Sshin		struct ifac *p;
177655163Sshin		for (p = ifcp->ifc_addr; p; p = p->ifa_next) {
177755163Sshin			if (p->ifa_next == ifa) {
177855163Sshin				p->ifa_next = ifa->ifa_next;
177955163Sshin				break;
178055163Sshin			}
178155163Sshin		}
178255163Sshin	}
178355163Sshin	ifa->ifa_next = NULL;
178455163Sshin	ifa->ifa_conf = NULL;
178555163Sshin	t_lifetime = time(NULL) - RIP_LIFETIME;
178655163Sshin	/* age route for interface address */
178755163Sshin	memset(&ni6, 0, sizeof(ni6));
178855163Sshin	ni6.rip6_dest = ifa->ifa_addr;
178955163Sshin	ni6.rip6_plen = ifa->ifa_plen;
179055163Sshin	applyplen(&ni6.rip6_dest, ni6.rip6_plen);
179155163Sshin	trace(1, "\tfind interface route %s/%d on %d\n",
179255163Sshin		inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index);
179355163Sshin	if ((rrt = rtsearch(&ni6)) != NULL) {
179455163Sshin		struct in6_addr none;
179555163Sshin		memset(&none, 0, sizeof(none));
179655163Sshin		if (rrt->rrt_index == ifcp->ifc_index
179755163Sshin		 && memcmp(&rrt->rrt_gw, &none, sizeof(rrt->rrt_gw)) == 0) {
179855163Sshin			trace(1, "\troute found, age it\n");
179955163Sshin			if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
180055163Sshin				rrt->rrt_t = t_lifetime;
180155163Sshin				rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
180255163Sshin			}
180355163Sshin			updated++;
180455163Sshin		} else {
180555163Sshin			trace(1, "\tnon-interface route found: %s/%d on %d\n",
180655163Sshin				inet6_n2p(&rrt->rrt_info.rip6_dest),
180755163Sshin				rrt->rrt_info.rip6_plen,
180855163Sshin				rrt->rrt_index);
180955163Sshin		}
181055163Sshin	} else
181155163Sshin		trace(1, "\tno interface route found\n");
181255163Sshin	/* age route for p2p destination */
181355163Sshin	if (ifcp->ifc_flags & IFF_POINTOPOINT) {
181455163Sshin		memset(&ni6, 0, sizeof(ni6));
181555163Sshin		ni6.rip6_dest = ifa->ifa_raddr;
181655163Sshin		ni6.rip6_plen = 128;
181755163Sshin		applyplen(&ni6.rip6_dest, ni6.rip6_plen);	/*to be sure*/
181855163Sshin		trace(1, "\tfind p2p route %s/%d on %d\n",
181955163Sshin			inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen,
182055163Sshin			ifcp->ifc_index);
182155163Sshin		if ((rrt = rtsearch(&ni6)) != NULL) {
182255163Sshin			if (rrt->rrt_index == ifcp->ifc_index
182355163Sshin			 && memcmp(&rrt->rrt_gw, &ifa->ifa_addr,
182455163Sshin					 sizeof(rrt->rrt_gw)) == 0) {
182555163Sshin				trace(1, "\troute found, age it\n");
182655163Sshin				if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
182755163Sshin					rrt->rrt_t = t_lifetime;
182855163Sshin					rrt->rrt_info.rip6_metric =
182955163Sshin						HOPCNT_INFINITY6;
183055163Sshin					updated++;
183155163Sshin				}
183255163Sshin			} else {
183355163Sshin				trace(1, "\tnon-p2p route found: %s/%d on %d\n",
183455163Sshin					inet6_n2p(&rrt->rrt_info.rip6_dest),
183555163Sshin					rrt->rrt_info.rip6_plen,
183655163Sshin					rrt->rrt_index);
183755163Sshin			}
183855163Sshin		} else
183955163Sshin			trace(1, "\tno p2p route found\n");
184055163Sshin	}
184155163Sshin	return updated ? 0 : -1;
184255163Sshin}
184355163Sshin
184455163Sshin/*
184555163Sshin * Get each interface address and put those interface routes to the route
184655163Sshin * list.
184755163Sshin */
184855163Sshinvoid
184955163Sshinifrt(ifcp, again)
185062607Sitojun	struct ifc *ifcp;
185155163Sshin	int again;
185255163Sshin{
185362607Sitojun	struct ifac *ifa;
185462607Sitojun	struct riprt *rrt;
185562607Sitojun	struct netinfo6 *np;
185655163Sshin
185755163Sshin	if (ifcp->ifc_flags & IFF_LOOPBACK)
185855163Sshin		return;			/* ignore loopback */
185962607Sitojun	if (ifcp->ifc_flags & IFF_POINTOPOINT) {
186062607Sitojun		ifrt_p2p(ifcp, again);
186162607Sitojun		return;
186262607Sitojun	}
186362607Sitojun
186455163Sshin	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
186562607Sitojun		if (IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) {
186662607Sitojun#if 0
186762607Sitojun			trace(1, "route: %s on %s: "
186862607Sitojun			    "skip linklocal interface address\n",
186962607Sitojun			    inet6_n2p(&ifa->ifa_addr), ifcp->ifc_name);
187062607Sitojun#endif
187162607Sitojun			continue;
187262607Sitojun		}
187362607Sitojun		if (IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_addr)) {
187462607Sitojun#if 0
187562607Sitojun			trace(1, "route: %s: skip unspec interface address\n",
187662607Sitojun			    ifcp->ifc_name);
187762607Sitojun#endif
187862607Sitojun			continue;
187962607Sitojun		}
188055163Sshin		if ((rrt = MALLOC(struct riprt)) == NULL)
188155163Sshin			fatal("malloc: struct riprt");
188262607Sitojun		memset(rrt, 0, sizeof(*rrt));
188355163Sshin		rrt->rrt_same = NULL;
188455163Sshin		rrt->rrt_index = ifcp->ifc_index;
188555163Sshin		rrt->rrt_t = 0;	/* don't age */
188655163Sshin		rrt->rrt_info.rip6_dest = ifa->ifa_addr;
188755163Sshin		rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
188855163Sshin		rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric;
188955163Sshin		rrt->rrt_info.rip6_plen = ifa->ifa_plen;
189055163Sshin		applyplen(&rrt->rrt_info.rip6_dest, ifa->ifa_plen);
189155163Sshin		memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
189255163Sshin		np = &rrt->rrt_info;
189355163Sshin		if (rtsearch(np) == NULL) {
189455163Sshin			/* Attach the route to the list */
189562607Sitojun			trace(1, "route: %s/%d: register route (%s)\n",
189662607Sitojun			    inet6_n2p(&np->rip6_dest), np->rip6_plen,
189762607Sitojun			    ifcp->ifc_name);
189855163Sshin			rrt->rrt_next = riprt;
189955163Sshin			riprt = rrt;
190055163Sshin		} else {
190155163Sshin			/* Already found */
190255163Sshin			if (!again) {
190362607Sitojun				trace(1, "route: %s/%d: "
190462607Sitojun				    "already registered (%s)\n",
190562607Sitojun				    inet6_n2p(&np->rip6_dest), np->rip6_plen,
190662607Sitojun				    ifcp->ifc_name);
190755163Sshin			}
190855163Sshin			free(rrt);
190955163Sshin		}
191062607Sitojun	}
191162607Sitojun}
191255163Sshin
191362607Sitojun/*
191462607Sitojun * there are couple of p2p interface routing models.  "behavior" lets
191562607Sitojun * you pick one.  it looks that gated behavior fits best with BSDs,
191662607Sitojun * since BSD kernels does not look at prefix length on p2p interfaces.
191762607Sitojun */
191862607Sitojunvoid
191962607Sitojunifrt_p2p(ifcp, again)
192062607Sitojun	struct ifc *ifcp;
192162607Sitojun	int again;
192262607Sitojun{
192362607Sitojun	struct ifac *ifa;
192462607Sitojun	struct riprt *rrt;
192562607Sitojun	struct netinfo6 *np;
192662607Sitojun	struct in6_addr addr, dest;
192762607Sitojun	int advert, ignore, i;
192862607Sitojun#define P2PADVERT_NETWORK	1
192962607Sitojun#define P2PADVERT_ADDR		2
193062607Sitojun#define P2PADVERT_DEST		4
193162607Sitojun#define P2PADVERT_MAX		4
193262607Sitojun	const enum { CISCO, GATED, ROUTE6D } behavior = GATED;
193362607Sitojun	const char *category;
193462607Sitojun	const char *noadv;
193562607Sitojun
193662607Sitojun	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
193762607Sitojun		addr = ifa->ifa_addr;
193862607Sitojun		dest = ifa->ifa_raddr;
193962607Sitojun		applyplen(&addr, ifa->ifa_plen);
194062607Sitojun		applyplen(&dest, ifa->ifa_plen);
194162607Sitojun		advert = ignore = 0;
194262607Sitojun		switch (behavior) {
194362607Sitojun		case CISCO:
194462607Sitojun			/*
194562607Sitojun			 * honor addr/plen, just like normal shared medium
194662607Sitojun			 * interface.  this may cause trouble if you reuse
194762607Sitojun			 * addr/plen on other interfaces.
194862607Sitojun			 *
194962607Sitojun			 * advertise addr/plen.
195062607Sitojun			 */
195162607Sitojun			advert |= P2PADVERT_NETWORK;
195262607Sitojun			break;
195362607Sitojun		case GATED:
195462607Sitojun			/*
195562607Sitojun			 * prefixlen on p2p interface is meaningless.
195662607Sitojun			 * advertise addr/128 and dest/128.
195762607Sitojun			 *
195862607Sitojun			 * do not install network route to route6d routing
195962607Sitojun			 * table (if we do, it would prevent route installation
196062607Sitojun			 * for other p2p interface that shares addr/plen).
196162607Sitojun			 */
196262607Sitojun			advert |= P2PADVERT_ADDR;
196362607Sitojun			advert |= P2PADVERT_DEST;
196462607Sitojun			ignore |= P2PADVERT_NETWORK;
196562607Sitojun			break;
196662607Sitojun		case ROUTE6D:
196762607Sitojun			/*
196862607Sitojun			 * just for testing...
196962607Sitojun			 */
197062607Sitojun			if (IN6_ARE_ADDR_EQUAL(&addr, &dest))
197162607Sitojun				advert |= P2PADVERT_NETWORK;
197262607Sitojun			else {
197362607Sitojun				advert |= P2PADVERT_ADDR;
197462607Sitojun				advert |= P2PADVERT_DEST;
197562607Sitojun				ignore |= P2PADVERT_NETWORK;
197662607Sitojun			}
197762607Sitojun			break;
197862607Sitojun		}
197962607Sitojun
198062607Sitojun		for (i = 1; i <= P2PADVERT_MAX; i *= 2) {
198162607Sitojun			if ((ignore & i) != 0)
198262607Sitojun				continue;
198355163Sshin			if ((rrt = MALLOC(struct riprt)) == NULL)
198455163Sshin				fatal("malloc: struct riprt");
198562607Sitojun			memset(rrt, 0, sizeof(*rrt));
198655163Sshin			rrt->rrt_same = NULL;
198755163Sshin			rrt->rrt_index = ifcp->ifc_index;
198862607Sitojun			rrt->rrt_t = 0;	/* don't age */
198962607Sitojun			switch (i) {
199062607Sitojun			case P2PADVERT_NETWORK:
199162607Sitojun				rrt->rrt_info.rip6_dest = ifa->ifa_addr;
199262607Sitojun				rrt->rrt_info.rip6_plen = ifa->ifa_plen;
199362607Sitojun				applyplen(&rrt->rrt_info.rip6_dest,
199462607Sitojun				    ifa->ifa_plen);
199562607Sitojun				category = "network";
199662607Sitojun				break;
199762607Sitojun			case P2PADVERT_ADDR:
199862607Sitojun				rrt->rrt_info.rip6_dest = ifa->ifa_addr;
199962607Sitojun				rrt->rrt_info.rip6_plen = 128;
200062607Sitojun				category = "addr";
200162607Sitojun				break;
200262607Sitojun			case P2PADVERT_DEST:
200362607Sitojun				rrt->rrt_info.rip6_dest = ifa->ifa_raddr;
200462607Sitojun				rrt->rrt_info.rip6_plen = 128;
200562607Sitojun				category = "dest";
200662607Sitojun				break;
200762607Sitojun			}
200862607Sitojun			if (IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_info.rip6_dest) ||
200962607Sitojun			    IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_info.rip6_dest)) {
201062607Sitojun#if 0
201162607Sitojun				trace(1, "route: %s: skip unspec/linklocal "
201262607Sitojun				    "(%s on %s)\n", category, ifcp->ifc_name);
201362607Sitojun#endif
201462607Sitojun				free(rrt);
201562607Sitojun				continue;
201662607Sitojun			}
201762607Sitojun			if ((advert & i) == 0) {
201862607Sitojun				rrt->rrt_rflags |= RRTF_NOADVERTISE;
201962607Sitojun				noadv = ", NO-ADV";
202062607Sitojun			} else
202162607Sitojun				noadv = "";
202255163Sshin			rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
202362607Sitojun			rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric;
202462607Sitojun			memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
202555163Sshin			np = &rrt->rrt_info;
202655163Sshin			if (rtsearch(np) == NULL) {
202755163Sshin				/* Attach the route to the list */
202862607Sitojun				trace(1, "route: %s/%d: register route "
202962607Sitojun				    "(%s on %s%s)\n",
203062607Sitojun				    inet6_n2p(&np->rip6_dest), np->rip6_plen,
203162607Sitojun				    category, ifcp->ifc_name, noadv);
203255163Sshin				rrt->rrt_next = riprt;
203355163Sshin				riprt = rrt;
203455163Sshin			} else {
203555163Sshin				/* Already found */
203655163Sshin				if (!again) {
203762607Sitojun					trace(1, "route: %s/%d: "
203862607Sitojun					    "already registered (%s on %s%s)\n",
203962607Sitojun					    inet6_n2p(&np->rip6_dest),
204062607Sitojun					    np->rip6_plen, category,
204162607Sitojun					    ifcp->ifc_name, noadv);
204255163Sshin				}
204355163Sshin				free(rrt);
204455163Sshin			}
204555163Sshin		}
204655163Sshin	}
204762607Sitojun#undef P2PADVERT_NETWORK
204862607Sitojun#undef P2PADVERT_ADDR
204962607Sitojun#undef P2PADVERT_DEST
205062607Sitojun#undef P2PADVERT_MAX
205155163Sshin}
205255163Sshin
205355163Sshinint
205455163Sshingetifmtu(ifindex)
205555163Sshin	int	ifindex;
205655163Sshin{
205755163Sshin	int	mib[6];
205855163Sshin	char	*buf;
205955163Sshin	size_t	msize;
206055163Sshin	struct	if_msghdr *ifm;
206155163Sshin	int	mtu;
206255163Sshin
206355163Sshin	mib[0] = CTL_NET;
206455163Sshin	mib[1] = PF_ROUTE;
206555163Sshin	mib[2] = 0;
206655163Sshin	mib[3] = AF_INET6;
206755163Sshin	mib[4] = NET_RT_IFLIST;
206855163Sshin	mib[5] = ifindex;
206955163Sshin	if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0)
207055163Sshin		fatal("sysctl estimate NET_RT_IFLIST");
207155163Sshin	if ((buf = malloc(msize)) == NULL)
207255163Sshin		fatal("malloc");
207355163Sshin	if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0)
207455163Sshin		fatal("sysctl NET_RT_IFLIST");
207555163Sshin	ifm = (struct if_msghdr *)buf;
207655163Sshin	mtu = ifm->ifm_data.ifi_mtu;
207755163Sshin#ifdef	__FREEBSD__
207855163Sshin	if (ifindex != ifm->ifm_index)
207955163Sshin		fatal("ifindex does not match with ifm_index");
208055163Sshin#endif	/* __FREEBSD__ */
208155163Sshin	free(buf);
208255163Sshin	return mtu;
208355163Sshin}
208455163Sshin
208555163Sshinconst char *
208655163Sshinrttypes(rtm)
208755163Sshin	struct rt_msghdr *rtm;
208855163Sshin{
208962607Sitojun#define	RTTYPE(s, f) \
209062607Sitojundo { \
209162607Sitojun	if (rtm->rtm_type == (f)) \
209262607Sitojun		return (s); \
209362607Sitojun} while (0)
209455163Sshin	RTTYPE("ADD", RTM_ADD);
209555163Sshin	RTTYPE("DELETE", RTM_DELETE);
209655163Sshin	RTTYPE("CHANGE", RTM_CHANGE);
209755163Sshin	RTTYPE("GET", RTM_GET);
209855163Sshin	RTTYPE("LOSING", RTM_LOSING);
209955163Sshin	RTTYPE("REDIRECT", RTM_REDIRECT);
210055163Sshin	RTTYPE("MISS", RTM_MISS);
210155163Sshin	RTTYPE("LOCK", RTM_LOCK);
210255163Sshin	RTTYPE("OLDADD", RTM_OLDADD);
210355163Sshin	RTTYPE("OLDDEL", RTM_OLDDEL);
210455163Sshin	RTTYPE("RESOLVE", RTM_RESOLVE);
210555163Sshin	RTTYPE("NEWADDR", RTM_NEWADDR);
210655163Sshin	RTTYPE("DELADDR", RTM_DELADDR);
210755163Sshin	RTTYPE("IFINFO", RTM_IFINFO);
210855163Sshin#undef RTTYPE
210955163Sshin	return NULL;
211055163Sshin}
211155163Sshin
211255163Sshinconst char *
211355163Sshinrtflags(rtm)
211455163Sshin	struct rt_msghdr *rtm;
211555163Sshin{
211655163Sshin	static char buf[BUFSIZ];
211755163Sshin
211855163Sshin	strcpy(buf, "");
211962607Sitojun#define	RTFLAG(s, f) \
212062607Sitojundo { \
212162607Sitojun	if (rtm->rtm_flags & (f)) \
212262607Sitojun		strcat(buf, (s)); \
212362607Sitojun} while (0)
212455163Sshin	RTFLAG("U", RTF_UP);
212555163Sshin	RTFLAG("G", RTF_GATEWAY);
212655163Sshin	RTFLAG("H", RTF_HOST);
212755163Sshin	RTFLAG("R", RTF_REJECT);
212855163Sshin	RTFLAG("D", RTF_DYNAMIC);
212955163Sshin	RTFLAG("M", RTF_MODIFIED);
213055163Sshin	RTFLAG("d", RTF_DONE);
213155163Sshin#ifdef	RTF_MASK
213255163Sshin	RTFLAG("m", RTF_MASK);
213355163Sshin#endif
213455163Sshin	RTFLAG("C", RTF_CLONING);
213555163Sshin	RTFLAG("X", RTF_XRESOLVE);
213655163Sshin	RTFLAG("L", RTF_LLINFO);
213755163Sshin	RTFLAG("S", RTF_STATIC);
213855163Sshin	RTFLAG("B", RTF_BLACKHOLE);
213955163Sshin	RTFLAG("2", RTF_PROTO2);
214055163Sshin	RTFLAG("1", RTF_PROTO1);
214155163Sshin#undef RTFLAG
214255163Sshin	return buf;
214355163Sshin}
214455163Sshin
214555163Sshinconst char *
214655163Sshinifflags(flags)
214755163Sshin	int flags;
214855163Sshin{
214955163Sshin	static char buf[BUFSIZ];
215055163Sshin
215155163Sshin	strcpy(buf, "");
215262607Sitojun#define	IFFLAG(s, f) \
215362607Sitojundo { \
215462607Sitojun	if (flags & f) { \
215562607Sitojun		if (buf[0]) \
215662607Sitojun			strcat(buf, ","); \
215762607Sitojun		strcat(buf, s); \
215862607Sitojun	} \
215962607Sitojun} while (0)
216055163Sshin	IFFLAG("UP", IFF_UP);
216155163Sshin	IFFLAG("BROADCAST", IFF_BROADCAST);
216255163Sshin	IFFLAG("DEBUG", IFF_DEBUG);
216355163Sshin	IFFLAG("LOOPBACK", IFF_LOOPBACK);
216455163Sshin	IFFLAG("POINTOPOINT", IFF_POINTOPOINT);
216555163Sshin#ifdef IFF_NOTRAILERS
216655163Sshin	IFFLAG("NOTRAILERS", IFF_NOTRAILERS);
216755163Sshin#endif
216855163Sshin	IFFLAG("RUNNING", IFF_RUNNING);
216955163Sshin	IFFLAG("NOARP", IFF_NOARP);
217055163Sshin	IFFLAG("PROMISC", IFF_PROMISC);
217155163Sshin	IFFLAG("ALLMULTI", IFF_ALLMULTI);
217255163Sshin	IFFLAG("OACTIVE", IFF_OACTIVE);
217355163Sshin	IFFLAG("SIMPLEX", IFF_SIMPLEX);
217455163Sshin	IFFLAG("LINK0", IFF_LINK0);
217555163Sshin	IFFLAG("LINK1", IFF_LINK1);
217655163Sshin	IFFLAG("LINK2", IFF_LINK2);
217755163Sshin	IFFLAG("MULTICAST", IFF_MULTICAST);
217855163Sshin#undef IFFLAG
217955163Sshin	return buf;
218055163Sshin}
218155163Sshin
218255163Sshinvoid
218355163Sshinkrtread(again)
218455163Sshin	int again;
218555163Sshin{
218655163Sshin	int mib[6];
218755163Sshin	size_t msize;
218855163Sshin	char *buf, *p, *lim;
218955163Sshin	struct rt_msghdr *rtm;
219055163Sshin	int retry;
219155163Sshin	const char *errmsg;
219255163Sshin
219355163Sshin	retry = 0;
219455163Sshin	buf = NULL;
219555163Sshin	mib[0] = CTL_NET;
219655163Sshin	mib[1] = PF_ROUTE;
219755163Sshin	mib[2] = 0;
219855163Sshin	mib[3] = AF_INET6;	/* Address family */
219955163Sshin	mib[4] = NET_RT_DUMP;	/* Dump the kernel routing table */
220055163Sshin	mib[5] = 0;		/* No flags */
220155163Sshin	do {
220255163Sshin		retry++;
220355163Sshin		errmsg = NULL;
220455163Sshin		if (buf)
220555163Sshin			free(buf);
220655163Sshin		if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) {
220755163Sshin			errmsg = "sysctl estimate";
220855163Sshin			continue;
220955163Sshin		}
221055163Sshin		if ((buf = malloc(msize)) == NULL) {
221155163Sshin			errmsg = "malloc";
221255163Sshin			continue;
221355163Sshin		}
221455163Sshin		if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) {
221555163Sshin			errmsg = "sysctl NET_RT_DUMP";
221655163Sshin			continue;
221755163Sshin		}
221855163Sshin	} while (retry < 5 && errmsg != NULL);
221955163Sshin	if (errmsg)
222055163Sshin		fatal("%s (with %d retries, msize=%d)", errmsg, retry, msize);
222155163Sshin	else if (1 < retry)
222255163Sshin		syslog(LOG_INFO, "NET_RT_DUMP %d retires", retry);
222355163Sshin
222455163Sshin	lim = buf + msize;
222555163Sshin	for (p = buf; p < lim; p += rtm->rtm_msglen) {
222655163Sshin		rtm = (struct rt_msghdr *)p;
222755163Sshin		rt_entry(rtm, again);
222855163Sshin	}
222955163Sshin	free(buf);
223055163Sshin}
223155163Sshin
223255163Sshinvoid
223355163Sshinrt_entry(rtm, again)
223455163Sshin	struct rt_msghdr *rtm;
223555163Sshin	int again;
223655163Sshin{
223755163Sshin	struct	sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask;
223855163Sshin	struct	sockaddr_in6 *sin6_genmask, *sin6_ifp;
223955163Sshin	char	*rtmp, *ifname = NULL;
224055163Sshin	struct	riprt *rrt;
224155163Sshin	struct	netinfo6 *np;
224255163Sshin	int	s;
224355163Sshin
224455163Sshin	sin6_dst = sin6_gw = sin6_mask = sin6_genmask = sin6_ifp = 0;
224555163Sshin	if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags &
224662607Sitojun		(RTF_CLONING|RTF_XRESOLVE|RTF_LLINFO|RTF_BLACKHOLE)) {
224755163Sshin		return;		/* not interested in the link route */
224862607Sitojun	}
224955163Sshin	rtmp = (char *)(rtm + 1);
225055163Sshin	/* Destination */
225155163Sshin	if ((rtm->rtm_addrs & RTA_DST) == 0)
225255163Sshin		return;		/* ignore routes without destination address */
225355163Sshin	sin6_dst = (struct sockaddr_in6 *)rtmp;
225455163Sshin	rtmp += sin6_dst->sin6_len;
225555163Sshin	if (rtm->rtm_addrs & RTA_GATEWAY) {
225655163Sshin		sin6_gw = (struct sockaddr_in6 *)rtmp;
225755163Sshin		rtmp += ROUNDUP(sin6_gw->sin6_len);
225855163Sshin	}
225955163Sshin	if (rtm->rtm_addrs & RTA_NETMASK) {
226055163Sshin		sin6_mask = (struct sockaddr_in6 *)rtmp;
226155163Sshin		rtmp += ROUNDUP(sin6_mask->sin6_len);
226255163Sshin	}
226355163Sshin	if (rtm->rtm_addrs & RTA_GENMASK) {
226455163Sshin		sin6_genmask = (struct sockaddr_in6 *)rtmp;
226555163Sshin		rtmp += ROUNDUP(sin6_genmask->sin6_len);
226655163Sshin	}
226755163Sshin	if (rtm->rtm_addrs & RTA_IFP) {
226855163Sshin		sin6_ifp = (struct sockaddr_in6 *)rtmp;
226955163Sshin		rtmp += ROUNDUP(sin6_ifp->sin6_len);
227055163Sshin	}
227155163Sshin
227255163Sshin	/* Destination */
227355163Sshin	if (sin6_dst->sin6_family != AF_INET6)
227455163Sshin		return;
227555163Sshin	if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst->sin6_addr))
227655163Sshin		return;		/* Link-local */
227755163Sshin	if (IN6_ARE_ADDR_EQUAL(&sin6_dst->sin6_addr, &in6addr_loopback))
227855163Sshin		return;		/* Loopback */
227955163Sshin	if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr))
228055163Sshin		return;
228155163Sshin
228255163Sshin	if ((rrt = MALLOC(struct riprt)) == NULL)
228355163Sshin		fatal("malloc: struct riprt");
228462607Sitojun	memset(rrt, 0, sizeof(*rrt));
228555163Sshin	np = &rrt->rrt_info;
228655163Sshin	rrt->rrt_same = NULL;
228755163Sshin	rrt->rrt_t = time(NULL);
228855163Sshin	if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC))
228955163Sshin		rrt->rrt_t = 0;	/* Don't age static routes */
229055163Sshin#if 0
229155163Sshin	np->rip6_tag = htons(routetag & 0xffff);
229255163Sshin#else
229355163Sshin	np->rip6_tag = 0;
229455163Sshin#endif
229555163Sshin	np->rip6_metric = rtm->rtm_rmx.rmx_hopcount;
229655163Sshin	if (np->rip6_metric < 1)
229755163Sshin		np->rip6_metric = 1;
229855163Sshin	rrt->rrt_flags = rtm->rtm_flags;
229955163Sshin	np->rip6_dest = sin6_dst->sin6_addr;
230055163Sshin
230155163Sshin	/* Mask or plen */
230255163Sshin	if (rtm->rtm_flags & RTF_HOST)
230355163Sshin		np->rip6_plen = 128;	/* Host route */
230455163Sshin	else if (sin6_mask) {
230555163Sshin		np->rip6_plen = mask2len(&sin6_mask->sin6_addr,
230655163Sshin			sin6_mask->sin6_len - offsetof(struct sockaddr_in6, sin6_addr));
230755163Sshin	} else
230855163Sshin		np->rip6_plen = 0;
230955163Sshin
231055163Sshin	if (rtsearch(np)) {
231155163Sshin		/* Already found */
231255163Sshin		if (!again) {
231355163Sshin			trace(1, "route: %s/%d flags %s: already registered\n",
231455163Sshin				inet6_n2p(&np->rip6_dest), np->rip6_plen,
231555163Sshin				rtflags(rtm));
231655163Sshin		}
231755163Sshin		free(rrt);
231855163Sshin		return;
231955163Sshin	}
232055163Sshin	/* Gateway */
232155163Sshin	if (!sin6_gw)
232255163Sshin		memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
232355163Sshin	else {
232455163Sshin		if (sin6_gw->sin6_family == AF_INET6)
232555163Sshin			rrt->rrt_gw = sin6_gw->sin6_addr;
232655163Sshin		else if (sin6_gw->sin6_family == AF_LINK) {
232755163Sshin			/* XXX in case ppp link? */
232855163Sshin			rrt->rrt_gw = in6addr_loopback;
232955163Sshin		} else
233055163Sshin			memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
233155163Sshin	}
233255163Sshin	trace(1, "route: %s/%d flags %s",
233355163Sshin		inet6_n2p(&np->rip6_dest), np->rip6_plen, rtflags(rtm));
233455163Sshin	trace(1, " gw %s", inet6_n2p(&rrt->rrt_gw));
233555163Sshin
233655163Sshin	/* Interface */
233755163Sshin	s = rtm->rtm_index;
233855163Sshin	if (s < nindex2ifc && index2ifc[s])
233955163Sshin		ifname = index2ifc[s]->ifc_name;
234058070Sshin	else {
234158070Sshin		trace(1, " not configured\n");
234262607Sitojun		free(rrt);
234358070Sshin		return;
234458070Sshin	}
234562607Sitojun	trace(1, " if %s sock %d", ifname, s);
234655163Sshin	rrt->rrt_index = s;
234755163Sshin
234862607Sitojun	trace(1, "\n");
234962607Sitojun
235055163Sshin	/* Check gateway */
235155163Sshin	if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_gw) &&
235255163Sshin	    !IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)
235355163Sshin#ifdef __FreeBSD__
235455163Sshin	 && (rrt->rrt_flags & RTF_LOCAL) == 0
235555163Sshin#endif
235655163Sshin	    ) {
235755163Sshin		trace(0, "***** Gateway %s is not a link-local address.\n",
235855163Sshin			inet6_n2p(&rrt->rrt_gw));
235955163Sshin		trace(0, "*****     dest(%s) if(%s) -- Not optimized.\n",
236062607Sitojun			inet6_n2p(&rrt->rrt_info.rip6_dest), ifname);
236162607Sitojun		rrt->rrt_rflags |= RRTF_NH_NOT_LLADDR;
236255163Sshin	}
236355163Sshin
236455163Sshin	/* Put it to the route list */
236555163Sshin	rrt->rrt_next = riprt;
236655163Sshin	riprt = rrt;
236755163Sshin}
236855163Sshin
236955163Sshinint
237055163Sshinaddroute(rrt, gw, ifcp)
237155163Sshin	struct riprt *rrt;
237255163Sshin	const struct in6_addr *gw;
237355163Sshin	struct ifc *ifcp;
237455163Sshin{
237555163Sshin	struct	netinfo6 *np;
237655163Sshin	u_char	buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ];
237755163Sshin	struct	rt_msghdr	*rtm;
237855163Sshin	struct	sockaddr_in6	*sin;
237955163Sshin	int	len;
238055163Sshin
238155163Sshin	np = &rrt->rrt_info;
238255163Sshin	inet_ntop(AF_INET6, (void *)gw, (char *)buf1, sizeof(buf1));
238355163Sshin	inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2));
238455163Sshin	tracet(1, "ADD: %s/%d gw %s [%d] ifa %s\n",
238555163Sshin		inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1,
238655163Sshin		np->rip6_metric - 1, buf2);
238755163Sshin	if (rtlog)
238855163Sshin		fprintf(rtlog, "%s: ADD: %s/%d gw %s [%d] ifa %s\n", hms(),
238955163Sshin			inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1,
239055163Sshin			np->rip6_metric - 1, buf2);
239155163Sshin	if (nflag)
239255163Sshin		return 0;
239355163Sshin
239455163Sshin	memset(buf, 0, sizeof(buf));
239555163Sshin	rtm = (struct rt_msghdr *)buf;
239655163Sshin	rtm->rtm_type = RTM_ADD;
239755163Sshin	rtm->rtm_version = RTM_VERSION;
239855163Sshin	rtm->rtm_seq = ++seq;
239955163Sshin	rtm->rtm_pid = pid;
240062607Sitojun	rtm->rtm_flags = rrt->rrt_flags;
240155163Sshin	rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
240255163Sshin	rtm->rtm_rmx.rmx_hopcount = np->rip6_metric - 1;
240355163Sshin	rtm->rtm_inits = RTV_HOPCOUNT;
240455163Sshin	sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
240555163Sshin	/* Destination */
240655163Sshin	sin->sin6_len = sizeof(struct sockaddr_in6);
240755163Sshin	sin->sin6_family = AF_INET6;
240855163Sshin	sin->sin6_addr = np->rip6_dest;
240955163Sshin	sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
241055163Sshin	/* Gateway */
241155163Sshin	sin->sin6_len = sizeof(struct sockaddr_in6);
241255163Sshin	sin->sin6_family = AF_INET6;
241355163Sshin	sin->sin6_addr = *gw;
241455163Sshin	sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
241555163Sshin	/* Netmask */
241655163Sshin	sin->sin6_len = sizeof(struct sockaddr_in6);
241755163Sshin	sin->sin6_family = AF_INET6;
241855163Sshin	sin->sin6_addr = *(plen2mask(np->rip6_plen));
241955163Sshin	sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
242055163Sshin
242155163Sshin	len = (char *)sin - (char *)buf;
242255163Sshin	rtm->rtm_msglen = len;
242355163Sshin	if (write(rtsock, buf, len) > 0)
242455163Sshin		return 0;
242555163Sshin
242655163Sshin	if (errno == EEXIST) {
242755163Sshin		trace(0, "ADD: Route already exists %s/%d gw %s\n",
242855163Sshin			inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1);
242955163Sshin		if (rtlog)
243055163Sshin			fprintf(rtlog, "ADD: Route already exists %s/%d gw %s\n",
243155163Sshin				inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1);
243255163Sshin	} else {
243355163Sshin		trace(0, "Can not write to rtsock (addroute): %s\n",
243455163Sshin			strerror(errno));
243555163Sshin		if (rtlog)
243655163Sshin			fprintf(rtlog, "\tCan not write to rtsock: %s\n",
243755163Sshin				strerror(errno));
243855163Sshin	}
243955163Sshin	return -1;
244055163Sshin}
244155163Sshin
244255163Sshinint
244355163Sshindelroute(np, gw)
244455163Sshin	struct netinfo6 *np;
244555163Sshin	struct in6_addr *gw;
244655163Sshin{
244755163Sshin	u_char	buf[BUFSIZ], buf2[BUFSIZ];
244855163Sshin	struct	rt_msghdr	*rtm;
244955163Sshin	struct	sockaddr_in6	*sin;
245055163Sshin	int	len;
245155163Sshin
245255163Sshin	inet_ntop(AF_INET6, (void *)gw, (char *)buf2, sizeof(buf2));
245355163Sshin	tracet(1, "DEL: %s/%d gw %s\n", inet6_n2p(&np->rip6_dest),
245455163Sshin		np->rip6_plen, buf2);
245555163Sshin	if (rtlog)
245655163Sshin		fprintf(rtlog, "%s: DEL: %s/%d gw %s\n",
245755163Sshin			hms(), inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
245855163Sshin	if (nflag)
245955163Sshin		return 0;
246055163Sshin
246155163Sshin	memset(buf, 0, sizeof(buf));
246255163Sshin	rtm = (struct rt_msghdr *)buf;
246355163Sshin	rtm->rtm_type = RTM_DELETE;
246455163Sshin	rtm->rtm_version = RTM_VERSION;
246555163Sshin	rtm->rtm_seq = ++seq;
246655163Sshin	rtm->rtm_pid = pid;
246755163Sshin	rtm->rtm_flags = RTF_UP | RTF_GATEWAY;
246855163Sshin	rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
246955163Sshin	sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
247055163Sshin	/* Destination */
247155163Sshin	sin->sin6_len = sizeof(struct sockaddr_in6);
247255163Sshin	sin->sin6_family = AF_INET6;
247355163Sshin	sin->sin6_addr = np->rip6_dest;
247455163Sshin	sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
247555163Sshin	/* Gateway */
247655163Sshin	sin->sin6_len = sizeof(struct sockaddr_in6);
247755163Sshin	sin->sin6_family = AF_INET6;
247855163Sshin	sin->sin6_addr = *gw;
247955163Sshin	sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
248055163Sshin	/* Netmask */
248155163Sshin	sin->sin6_len = sizeof(struct sockaddr_in6);
248255163Sshin	sin->sin6_family = AF_INET6;
248355163Sshin	sin->sin6_addr = *(plen2mask(np->rip6_plen));
248455163Sshin	sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
248555163Sshin
248655163Sshin	len = (char *)sin - (char *)buf;
248755163Sshin	rtm->rtm_msglen = len;
248855163Sshin	if (write(rtsock, buf, len) >= 0)
248955163Sshin		return 0;
249055163Sshin
249155163Sshin	if (errno == ESRCH) {
249255163Sshin		trace(0, "RTDEL: Route does not exist: %s/%d gw %s\n",
249355163Sshin			inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
249455163Sshin		if (rtlog)
249555163Sshin			fprintf(rtlog, "RTDEL: Route does not exist: %s/%d gw %s\n",
249655163Sshin				inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
249755163Sshin	} else {
249855163Sshin		trace(0, "Can not write to rtsock (delroute): %s\n",
249955163Sshin			strerror(errno));
250055163Sshin		if (rtlog)
250155163Sshin			fprintf(rtlog, "\tCan not write to rtsock: %s\n",
250255163Sshin				strerror(errno));
250355163Sshin	}
250455163Sshin	return -1;
250555163Sshin}
250655163Sshin
250755163Sshinstruct in6_addr *
250855163Sshingetroute(np, gw)
250955163Sshin	struct netinfo6 *np;
251055163Sshin	struct in6_addr *gw;
251155163Sshin{
251255163Sshin	u_char buf[BUFSIZ];
251355163Sshin	u_long myseq;
251455163Sshin	int len;
251555163Sshin	struct rt_msghdr *rtm;
251655163Sshin	struct sockaddr_in6 *sin;
251755163Sshin
251855163Sshin	rtm = (struct rt_msghdr *)buf;
251955163Sshin	len = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6);
252055163Sshin	memset(rtm, 0, len);
252155163Sshin	rtm->rtm_type = RTM_GET;
252255163Sshin	rtm->rtm_version = RTM_VERSION;
252355163Sshin	myseq = ++seq;
252455163Sshin	rtm->rtm_seq = myseq;
252555163Sshin	rtm->rtm_addrs = RTA_DST;
252655163Sshin	rtm->rtm_msglen = len;
252755163Sshin	sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
252855163Sshin	sin->sin6_len = sizeof(struct sockaddr_in6);
252955163Sshin	sin->sin6_family = AF_INET6;
253055163Sshin	sin->sin6_addr = np->rip6_dest;
253155163Sshin	if (write(rtsock, buf, len) < 0) {
253255163Sshin		if (errno == ESRCH)	/* No such route found */
253355163Sshin			return NULL;
253455163Sshin		perror("write to rtsock");
253555163Sshin		exit(-1);
253655163Sshin	}
253755163Sshin	do {
253855163Sshin		if ((len = read(rtsock, buf, sizeof(buf))) < 0) {
253955163Sshin			perror("read from rtsock");
254055163Sshin			exit(-1);
254155163Sshin		}
254255163Sshin		rtm = (struct rt_msghdr *)buf;
254355163Sshin	} while (rtm->rtm_seq != myseq || rtm->rtm_pid != pid);
254455163Sshin	sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
254555163Sshin	if (rtm->rtm_addrs & RTA_DST) {
254655163Sshin		sin = (struct sockaddr_in6 *)
254755163Sshin			((char *)sin + ROUNDUP(sin->sin6_len));
254855163Sshin	}
254955163Sshin	if (rtm->rtm_addrs & RTA_GATEWAY) {
255055163Sshin		*gw = sin->sin6_addr;
255155163Sshin		return gw;
255255163Sshin	}
255355163Sshin	return NULL;
255455163Sshin}
255555163Sshin
255655163Sshinconst char *
255755163Sshininet6_n2p(p)
255855163Sshin	const struct in6_addr *p;
255955163Sshin{
256055163Sshin	static char buf[BUFSIZ];
256155163Sshin
256255163Sshin	return inet_ntop(AF_INET6, (void *)p, buf, sizeof(buf));
256355163Sshin}
256455163Sshin
256555163Sshinvoid
256655163Sshinifrtdump(sig)
256755163Sshin	int sig;
256855163Sshin{
256955163Sshin
257055163Sshin	ifdump(sig);
257155163Sshin	rtdump(sig);
257255163Sshin}
257355163Sshin
257455163Sshinvoid
257555163Sshinifdump(sig)
257655163Sshin	int sig;
257755163Sshin{
257855163Sshin	struct ifc *ifcp;
257955163Sshin	FILE *dump;
258055163Sshin	int i;
258155163Sshin
258255163Sshin	if (sig == 0)
258355163Sshin		dump = stderr;
258455163Sshin	else
258555163Sshin		if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL)
258655163Sshin			dump = stderr;
258755163Sshin
258855163Sshin	fprintf(dump, "%s: Interface Table Dump\n", hms());
258955163Sshin	fprintf(dump, "  Number of interfaces: %d\n", nifc);
259055163Sshin	for (i = 0; i < 2; i++) {
259155163Sshin		fprintf(dump, "  %sadvertising interfaces:\n", i ? "non-" : "");
259255163Sshin		for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
259355163Sshin			if (i == 0) {
259455163Sshin				if ((ifcp->ifc_flags & IFF_UP) == 0)
259555163Sshin					continue;
259655163Sshin				if (iff_find(ifcp, 'N') != NULL)
259755163Sshin					continue;
259855163Sshin			} else {
259955163Sshin				if (ifcp->ifc_flags & IFF_UP)
260055163Sshin					continue;
260155163Sshin			}
260255163Sshin			ifdump0(dump, ifcp);
260355163Sshin		}
260455163Sshin	}
260555163Sshin	fprintf(dump, "\n");
260655163Sshin	if (dump != stderr)
260755163Sshin		fclose(dump);
260855163Sshin}
260955163Sshin
261055163Sshinvoid
261155163Sshinifdump0(dump, ifcp)
261255163Sshin	FILE *dump;
261355163Sshin	const struct ifc *ifcp;
261455163Sshin{
261555163Sshin	struct ifac *ifa;
261655163Sshin	struct iff *iffp;
261755163Sshin	char buf[BUFSIZ];
261855163Sshin	const char *ft;
261955163Sshin	int addr;
262055163Sshin
262155163Sshin	fprintf(dump, "    %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)\n",
262255163Sshin		ifcp->ifc_name, ifcp->ifc_index, ifflags(ifcp->ifc_flags),
262355163Sshin		inet6_n2p(&ifcp->ifc_mylladdr),
262455163Sshin		ifcp->ifc_mtu, ifcp->ifc_metric);
262555163Sshin	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
262655163Sshin		if (ifcp->ifc_flags & IFF_POINTOPOINT) {
262755163Sshin			inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr,
262855163Sshin				buf, sizeof(buf));
262955163Sshin			fprintf(dump, "\t%s/%d -- %s\n",
263055163Sshin				inet6_n2p(&ifa->ifa_addr),
263155163Sshin				ifa->ifa_plen, buf);
263255163Sshin		} else {
263355163Sshin			fprintf(dump, "\t%s/%d\n",
263455163Sshin				inet6_n2p(&ifa->ifa_addr),
263555163Sshin				ifa->ifa_plen);
263655163Sshin		}
263755163Sshin	}
263855163Sshin	if (ifcp->ifc_filter) {
263955163Sshin		fprintf(dump, "\tFilter:");
264055163Sshin		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
264155163Sshin			addr = 0;
264255163Sshin			switch (iffp->iff_type) {
264355163Sshin			case 'A':
264455163Sshin				ft = "Aggregate"; addr++; break;
264555163Sshin			case 'N':
264655163Sshin				ft = "No-advertise"; break;
264755163Sshin			case 'O':
264855163Sshin				ft = "Advertise-only"; addr++; break;
264955163Sshin			case 'T':
265055163Sshin				ft = "Default-only"; break;
265155163Sshin			case 'L':
265255163Sshin				ft = "Listen-only"; addr++; break;
265355163Sshin			default:
265455163Sshin				snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type);
265555163Sshin				ft = buf;
265655163Sshin				addr++;
265755163Sshin				break;
265855163Sshin			}
265955163Sshin			fprintf(dump, " %s", ft);
266055163Sshin			if (addr) {
266155163Sshin				fprintf(dump, "(%s/%d)", inet6_n2p(&iffp->iff_addr),
266255163Sshin					iffp->iff_plen);
266355163Sshin			}
266455163Sshin		}
266555163Sshin		fprintf(dump, "\n");
266655163Sshin	}
266755163Sshin}
266855163Sshin
266955163Sshinvoid
267055163Sshinrtdump(sig)
267155163Sshin	int sig;
267255163Sshin{
267355163Sshin	struct	riprt *rrt;
267455163Sshin	char	buf[BUFSIZ];
267555163Sshin	FILE	*dump;
267655163Sshin	time_t	t, age;
267755163Sshin
267855163Sshin	if (sig == 0)
267955163Sshin		dump = stderr;
268055163Sshin	else
268155163Sshin		if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL)
268255163Sshin			dump = stderr;
268355163Sshin
268455163Sshin	t = time(NULL);
268555163Sshin	fprintf(dump, "\n%s: Routing Table Dump\n", hms());
268655163Sshin	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
268755163Sshin		if (rrt->rrt_t == 0)
268855163Sshin			age = 0;
268955163Sshin		else
269055163Sshin			age = t - rrt->rrt_t;
269155163Sshin		inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest,
269255163Sshin			buf, sizeof(buf));
269355163Sshin		fprintf(dump, "    %s/%d if(%d:%s) gw(%s) [%d] age(%ld)",
269455163Sshin			buf, rrt->rrt_info.rip6_plen, rrt->rrt_index,
269555163Sshin			index2ifc[rrt->rrt_index]->ifc_name,
269655163Sshin			inet6_n2p(&rrt->rrt_gw),
269755163Sshin			rrt->rrt_info.rip6_metric, (long)age);
269855163Sshin		if (rrt->rrt_info.rip6_tag) {
269955163Sshin			fprintf(dump, " tag(0x%04x)",
270055163Sshin				ntohs(rrt->rrt_info.rip6_tag) & 0xffff);
270155163Sshin		}
270262607Sitojun		if (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)
270355163Sshin			fprintf(dump, " NOT-LL");
270462607Sitojun		if (rrt->rrt_rflags & RRTF_NOADVERTISE)
270555163Sshin			fprintf(dump, " NO-ADV");
270655163Sshin		fprintf(dump, "\n");
270755163Sshin	}
270855163Sshin	fprintf(dump, "\n");
270955163Sshin	if (dump != stderr)
271055163Sshin		fclose(dump);
271155163Sshin}
271255163Sshin
271355163Sshin/*
271455163Sshin * Parse the -A (and -O) options and put corresponding filter object to the
271555163Sshin * specified interface structures. Each of the -A/O option has the following
271655163Sshin * syntax:	-A 5f09:c400::/32,ef0,ef1  (aggregate)
271755163Sshin * 		-O 5f09:c400::/32,ef0,ef1  (only when match)
271855163Sshin */
271955163Sshinvoid
272055163Sshinfilterconfig()
272155163Sshin{
272255163Sshin	int i;
272355163Sshin	char *p, *ap, *iflp, *ifname;
272455163Sshin	struct	iff ftmp, *iff_obj;
272555163Sshin	struct	ifc *ifcp;
272655163Sshin	struct	riprt *rrt;
272755163Sshin	struct	in6_addr gw;
272855163Sshin
272955163Sshin	for (i = 0; i < nfilter; i++) {
273055163Sshin		ap = filter[i];
273155163Sshin		iflp = NULL;
273255163Sshin		ifcp = NULL;
273355163Sshin		if (filtertype[i] == 'N' || filtertype[i] == 'T') {
273455163Sshin			iflp = ap;
273555163Sshin			goto ifonly;
273655163Sshin		}
273755163Sshin		if ((p = index(ap, ',')) != NULL) {
273855163Sshin			*p++ = '\0';
273955163Sshin			iflp = p;
274055163Sshin		}
274155163Sshin		if ((p = index(ap, '/')) == NULL)
274255163Sshin			fatal("no prefixlen specified for '%s'", ap);
274355163Sshin		*p++ = '\0';
274455163Sshin		if (inet_pton(AF_INET6, ap, &ftmp.iff_addr) != 1)
274555163Sshin			fatal("invalid prefix specified for '%s'", ap);
274655163Sshin		ftmp.iff_plen = atoi(p);
274755163Sshin		ftmp.iff_next = NULL;
274855163Sshin		applyplen(&ftmp.iff_addr, ftmp.iff_plen);
274955163Sshinifonly:
275055163Sshin		ftmp.iff_type = filtertype[i];
275155163Sshin		if (iflp == NULL || *iflp == '\0')
275255163Sshin			fatal("no interface specified for '%s'", ap);
275355163Sshin		/* parse the interface listing portion */
275455163Sshin		while (iflp) {
275555163Sshin			ifname = iflp;
275655163Sshin			if ((iflp = index(iflp, ',')) != NULL)
275755163Sshin				*iflp++ = '\0';
275855163Sshin			ifcp = ifc_find(ifname);
275955163Sshin			if (ifcp == NULL)
276055163Sshin				fatal("no interface %s exists", ifname);
276155163Sshin			iff_obj = (struct iff *)malloc(sizeof(struct iff));
276255163Sshin			if (iff_obj == NULL)
276355163Sshin				fatal("malloc of iff_obj");
276455163Sshin			memcpy((void *)iff_obj, (void *)&ftmp,
276555163Sshin				sizeof(struct iff));
276655163Sshin			/* link it to the interface filter */
276755163Sshin			iff_obj->iff_next = ifcp->ifc_filter;
276855163Sshin			ifcp->ifc_filter = iff_obj;
276955163Sshin		}
277055163Sshin		if (filtertype[i] != 'A')
277155163Sshin			continue;
277255163Sshin		/* put the aggregate to the kernel routing table */
277355163Sshin		rrt = (struct riprt *)malloc(sizeof(struct riprt));
277455163Sshin		if (rrt == NULL)
277555163Sshin			fatal("malloc: rrt");
277655163Sshin		memset(rrt, 0, sizeof(struct riprt));
277755163Sshin		rrt->rrt_info.rip6_dest = ftmp.iff_addr;
277855163Sshin		rrt->rrt_info.rip6_plen = ftmp.iff_plen;
277955163Sshin		rrt->rrt_info.rip6_metric = 1;
278055163Sshin		rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
278155163Sshin		rrt->rrt_gw = in6addr_loopback;
278262607Sitojun		rrt->rrt_flags = RTF_UP | RTF_REJECT;
278362607Sitojun		rrt->rrt_rflags = RRTF_AGGREGATE;
278455163Sshin		rrt->rrt_t = 0;
278555163Sshin		rrt->rrt_index = loopifindex;
278655163Sshin		/* Put the route to the list */
278755163Sshin		rrt->rrt_next = riprt;
278855163Sshin		riprt = rrt;
278955163Sshin		trace(1, "Aggregate: %s/%d for %s\n",
279055163Sshin			inet6_n2p(&ftmp.iff_addr), ftmp.iff_plen,
279155163Sshin			ifcp->ifc_name);
279255163Sshin		/* Add this route to the kernel */
279355163Sshin		if (nflag) 	/* do not modify kernel routing table */
279455163Sshin			continue;
279555163Sshin		if (getroute(&rrt->rrt_info, &gw)) {
279655163Sshin			/*
279755163Sshin			 * When the address has already been registered in the
279862607Sitojun			 * kernel routing table, it should be removed
279955163Sshin			 */
280055163Sshin			delroute(&rrt->rrt_info, &gw);
280155163Sshin		}
280255163Sshin		addroute(rrt, &in6addr_loopback, loopifcp);
280355163Sshin	}
280455163Sshin}
280555163Sshin
280655163Sshin/***************** utility functions *****************/
280755163Sshin
280855163Sshin/*
280955163Sshin * Returns a pointer to ifac whose address and prefix length matches
281055163Sshin * with the address and prefix length specified in the arguments.
281155163Sshin */
281255163Sshinstruct ifac *
281355163Sshinifa_match(ifcp, ia, plen)
281455163Sshin	const struct ifc *ifcp;
281555163Sshin	const struct in6_addr *ia;
281655163Sshin	int plen;
281755163Sshin{
281855163Sshin	struct ifac *ifa;
281955163Sshin
282055163Sshin	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
282155163Sshin		if (IN6_ARE_ADDR_EQUAL(&ifa->ifa_addr, ia) &&
282255163Sshin		    ifa->ifa_plen == plen)
282355163Sshin			break;
282455163Sshin	}
282555163Sshin	return ifa;
282655163Sshin}
282755163Sshin
282855163Sshin/*
282955163Sshin * Return a pointer to riprt structure whose address and prefix length
283055163Sshin * matches with the address and prefix length found in the argument.
283155163Sshin * Note: This is not a rtalloc(). Therefore exact match is necessary.
283255163Sshin */
283355163Sshin
283455163Sshinstruct riprt *
283555163Sshinrtsearch(np)
283655163Sshin	struct	netinfo6 *np;
283755163Sshin{
283855163Sshin	struct	riprt	*rrt;
283955163Sshin
284055163Sshin	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
284155163Sshin		if (rrt->rrt_info.rip6_plen == np->rip6_plen &&
284255163Sshin		    IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
284355163Sshin				       &np->rip6_dest))
284455163Sshin			return rrt;
284555163Sshin	}
284655163Sshin	return 0;
284755163Sshin}
284855163Sshin
284955163Sshinint
285055163Sshinmask2len(addr, lenlim)
285155163Sshin	const struct in6_addr *addr;
285255163Sshin	int lenlim;
285355163Sshin{
285455163Sshin	int i = 0, j;
285555163Sshin	u_char *p = (u_char *)addr;
285662607Sitojun
285755163Sshin	for (j = 0; j < lenlim; j++, p++) {
285855163Sshin		if (*p != 0xff)
285955163Sshin			break;
286055163Sshin		i += 8;
286155163Sshin	}
286255163Sshin	if (j < lenlim) {
286355163Sshin		switch (*p) {
286462607Sitojun#define	MASKLEN(m, l)	case m: do { i += l; break; } while (0)
286562607Sitojun		MASKLEN(0xfe, 7); break;
286662607Sitojun		MASKLEN(0xfc, 6); break;
286762607Sitojun		MASKLEN(0xf8, 5); break;
286862607Sitojun		MASKLEN(0xf0, 4); break;
286962607Sitojun		MASKLEN(0xe0, 3); break;
287062607Sitojun		MASKLEN(0xc0, 2); break;
287162607Sitojun		MASKLEN(0x80, 1); break;
287255163Sshin#undef	MASKLEN
287355163Sshin		}
287455163Sshin	}
287555163Sshin	return i;
287655163Sshin}
287755163Sshin
287855163Sshinvoid
287955163Sshinapplymask(addr, mask)
288055163Sshin	struct in6_addr *addr, *mask;
288155163Sshin{
288255163Sshin	int	i;
288355163Sshin	u_long	*p, *q;
288455163Sshin
288555163Sshin	p = (u_long *)addr; q = (u_long *)mask;
288655163Sshin	for (i = 0; i < 4; i++)
288755163Sshin		*p++ &= *q++;
288855163Sshin}
288955163Sshin
289055163Sshinstatic const u_char plent[8] = {
289155163Sshin	0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
289255163Sshin};
289355163Sshin
289455163Sshinvoid
289555163Sshinapplyplen(ia, plen)
289655163Sshin	struct	in6_addr *ia;
289755163Sshin	int	plen;
289855163Sshin{
289955163Sshin	u_char	*p;
290055163Sshin	int	i;
290155163Sshin
290255163Sshin	p = ia->s6_addr;
290355163Sshin	for (i = 0; i < 16; i++) {
290455163Sshin		if (plen <= 0)
290555163Sshin			*p = 0;
290655163Sshin		else if (plen < 8)
290755163Sshin			*p &= plent[plen];
290855163Sshin		p++, plen -= 8;
290955163Sshin	}
291055163Sshin}
291155163Sshin
291255163Sshinstatic const int pl2m[9] = {
291355163Sshin	0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
291455163Sshin};
291555163Sshin
291655163Sshinstruct in6_addr *
291755163Sshinplen2mask(n)
291855163Sshin	int	n;
291955163Sshin{
292055163Sshin	static struct in6_addr ia;
292155163Sshin	u_char	*p;
292255163Sshin	int	i;
292355163Sshin
292455163Sshin	memset(&ia, 0, sizeof(struct in6_addr));
292555163Sshin	p = (u_char *)&ia;
292655163Sshin	for (i = 0; i < 16; i++, p++, n -= 8) {
292755163Sshin		if (n >= 8) {
292855163Sshin			*p = 0xff;
292955163Sshin			continue;
293055163Sshin		}
293155163Sshin		*p = pl2m[n];
293255163Sshin		break;
293355163Sshin	}
293455163Sshin	return &ia;
293555163Sshin}
293655163Sshin
293755163Sshinchar *
293855163Sshinallocopy(p)
293955163Sshin	char *p;
294055163Sshin{
294155163Sshin	char *q = (char *)malloc(strlen(p) + 1);
294255163Sshin
294355163Sshin	strcpy(q, p);
294455163Sshin	return q;
294555163Sshin}
294655163Sshin
294755163Sshinchar *
294855163Sshinhms()
294955163Sshin{
295055163Sshin	static char buf[BUFSIZ];
295155163Sshin	time_t t;
295255163Sshin	struct	tm *tm;
295355163Sshin
295455163Sshin	t = time(NULL);
295555163Sshin	if ((tm = localtime(&t)) == 0)
295655163Sshin		fatal("localtime");
295755163Sshin	snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec);
295855163Sshin	return buf;
295955163Sshin}
296055163Sshin
296155163Sshin#define	RIPRANDDEV	1.0	/* 30 +- 15, max - min = 30 */
296255163Sshin
296355163Sshinint
296455163Sshinripinterval(timer)
296555163Sshin	int timer;
296655163Sshin{
296755163Sshin	double r = rand();
296855163Sshin
296955163Sshin	interval = (int)(timer + timer * RIPRANDDEV * (r / RAND_MAX - 0.5));
297055163Sshin	nextalarm = time(NULL) + interval;
297155163Sshin	return interval;
297255163Sshin}
297355163Sshin
297455163Sshintime_t
297555163Sshinripsuptrig()
297655163Sshin{
297755163Sshin	time_t t;
297855163Sshin
297955163Sshin	double r = rand();
298062607Sitojun	t  = (int)(RIP_TRIG_INT6_MIN +
298155163Sshin		(RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / RAND_MAX ));
298255163Sshin	sup_trig_update = time(NULL) + t;
298355163Sshin	return t;
298455163Sshin}
298555163Sshin
298655163Sshinvoid
298755163Sshin#ifdef __STDC__
298855163Sshinfatal(const char *fmt, ...)
298955163Sshin#else
299055163Sshinfatal(fmt, va_alist)
299155163Sshin	char	*fmt;
299255163Sshin	va_dcl
299355163Sshin#endif
299455163Sshin{
299555163Sshin	va_list ap;
299655163Sshin	char buf[1024];
299755163Sshin
299855163Sshin#ifdef __STDC__
299955163Sshin	va_start(ap, fmt);
300055163Sshin#else
300155163Sshin	va_start(ap);
300255163Sshin#endif
300355163Sshin	vsnprintf(buf, sizeof(buf), fmt, ap);
300455163Sshin	perror(buf);
300555163Sshin	syslog(LOG_ERR, "%s: %s", buf, strerror(errno));
300655163Sshin	rtdexit(0);
300755163Sshin	va_end(ap);
300855163Sshin}
300955163Sshin
301055163Sshinvoid
301155163Sshin#ifdef __STDC__
301255163Sshintracet(int level, const char *fmt, ...)
301355163Sshin#else
301455163Sshintracet(level, fmt, va_alist)
301555163Sshin	int level;
301655163Sshin	char *fmt;
301755163Sshin	va_dcl
301855163Sshin#endif
301955163Sshin{
302055163Sshin	va_list ap;
302155163Sshin
302255163Sshin#ifdef __STDC__
302355163Sshin	va_start(ap, fmt);
302455163Sshin#else
302555163Sshin	va_start(ap);
302655163Sshin#endif
302755163Sshin	if (level <= dflag) {
302855163Sshin		fprintf(stderr, "%s: ", hms());
302955163Sshin		vfprintf(stderr, fmt, ap);
303055163Sshin	}
303155163Sshin	if (dflag) {
303255163Sshin		if (level > 0)
303355163Sshin			vsyslog(LOG_DEBUG, fmt, ap);
303455163Sshin		else
303555163Sshin			vsyslog(LOG_WARNING, fmt, ap);
303655163Sshin	}
303755163Sshin	va_end(ap);
303855163Sshin}
303955163Sshin
304055163Sshinvoid
304155163Sshin#ifdef __STDC__
304255163Sshintrace(int level, const char *fmt, ...)
304355163Sshin#else
304455163Sshintrace(level, fmt, va_alist)
304555163Sshin	int level;
304655163Sshin	char *fmt;
304755163Sshin	va_dcl
304855163Sshin#endif
304955163Sshin{
305055163Sshin	va_list ap;
305155163Sshin
305255163Sshin#ifdef __STDC__
305355163Sshin	va_start(ap, fmt);
305455163Sshin#else
305555163Sshin	va_start(ap);
305655163Sshin#endif
305755163Sshin	if (level <= dflag)
305855163Sshin		vfprintf(stderr, fmt, ap);
305955163Sshin	if (dflag) {
306055163Sshin		if (level > 0)
306155163Sshin			vsyslog(LOG_DEBUG, fmt, ap);
306255163Sshin		else
306355163Sshin			vsyslog(LOG_WARNING, fmt, ap);
306455163Sshin	}
306555163Sshin	va_end(ap);
306655163Sshin}
306755163Sshin
306855163Sshinunsigned int
306955163Sshinif_maxindex()
307055163Sshin{
307155163Sshin	struct if_nameindex *p, *p0;
307255163Sshin	unsigned int max = 0;
307355163Sshin
307455163Sshin	p0 = if_nameindex();
307555163Sshin	for (p = p0; p && p->if_index && p->if_name; p++) {
307655163Sshin		if (max < p->if_index)
307755163Sshin			max = p->if_index;
307855163Sshin	}
307955163Sshin	if_freenameindex(p0);
308055163Sshin	return max;
308155163Sshin}
308255163Sshin
308355163Sshinstruct ifc *
308455163Sshinifc_find(name)
308555163Sshin	char *name;
308655163Sshin{
308755163Sshin	struct ifc *ifcp;
308855163Sshin
308955163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
309055163Sshin		if (strcmp(name, ifcp->ifc_name) == 0)
309155163Sshin			return ifcp;
309255163Sshin	}
309355163Sshin	return (struct ifc *)NULL;
309455163Sshin}
309555163Sshin
309655163Sshinstruct iff *
309755163Sshiniff_find(ifcp, type)
309855163Sshin	struct ifc *ifcp;
309955163Sshin	int type;
310055163Sshin{
310155163Sshin	struct iff *iffp;
310255163Sshin
310355163Sshin	for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
310455163Sshin		if (iffp->iff_type == type)
310555163Sshin			return iffp;
310655163Sshin	}
310755163Sshin	return NULL;
310855163Sshin}
310955163Sshin
311055163Sshinvoid
311155163Sshinsetindex2ifc(index, ifcp)
311255163Sshin	int index;
311355163Sshin	struct ifc *ifcp;
311455163Sshin{
311555163Sshin	int n;
311662607Sitojun	struct ifc **p;
311755163Sshin
311855163Sshin	if (!index2ifc) {
311955163Sshin		nindex2ifc = 5;	/*initial guess*/
312055163Sshin		index2ifc = (struct ifc **)
312155163Sshin			malloc(sizeof(*index2ifc) * nindex2ifc);
312255163Sshin		if (index2ifc == NULL)
312355163Sshin			fatal("malloc");
312455163Sshin		memset(index2ifc, 0, sizeof(*index2ifc) * nindex2ifc);
312555163Sshin	}
312655163Sshin	n = nindex2ifc;
312755163Sshin	while (nindex2ifc <= index)
312855163Sshin		nindex2ifc *= 2;
312955163Sshin	if (n != nindex2ifc) {
313062607Sitojun		p = (struct ifc **)realloc(index2ifc,
313162607Sitojun		    sizeof(*index2ifc) * nindex2ifc);
313262607Sitojun		if (p == NULL)
313355163Sshin			fatal("realloc");
313462607Sitojun		index2ifc = p;
313555163Sshin	}
313655163Sshin	index2ifc[index] = ifcp;
313755163Sshin}
3138