route6d.c revision 173412
162607Sitojun/*	$FreeBSD: head/usr.sbin/route6d/route6d.c 173412 2007-11-07 10:53:41Z kevlo $	*/
2122677Sume/*	$KAME: route6d.c,v 1.104 2003/10/31 00:30:20 itojun Exp $	*/
355163Sshin
455163Sshin/*
555163Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
655163Sshin * All rights reserved.
762607Sitojun *
855163Sshin * Redistribution and use in source and binary forms, with or without
955163Sshin * modification, are permitted provided that the following conditions
1055163Sshin * are met:
1155163Sshin * 1. Redistributions of source code must retain the above copyright
1255163Sshin *    notice, this list of conditions and the following disclaimer.
1355163Sshin * 2. Redistributions in binary form must reproduce the above copyright
1455163Sshin *    notice, this list of conditions and the following disclaimer in the
1555163Sshin *    documentation and/or other materials provided with the distribution.
1655163Sshin * 3. Neither the name of the project nor the names of its contributors
1755163Sshin *    may be used to endorse or promote products derived from this software
1855163Sshin *    without specific prior written permission.
1962607Sitojun *
2055163Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2155163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2255163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2355163Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2455163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2555163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2655163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2755163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2855163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2955163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3055163Sshin * SUCH DAMAGE.
3155163Sshin */
3255163Sshin
3355163Sshin#ifndef	lint
34122677Sumestatic char _rcsid[] = "$KAME: route6d.c,v 1.104 2003/10/31 00:30:20 itojun Exp $";
3555163Sshin#endif
3655163Sshin
3755163Sshin#include <stdio.h>
3855163Sshin
3955163Sshin#include <time.h>
4055163Sshin#include <unistd.h>
4155163Sshin#include <stdlib.h>
4255163Sshin#include <string.h>
4355163Sshin#include <signal.h>
4455163Sshin#ifdef __STDC__
4555163Sshin#include <stdarg.h>
4655163Sshin#else
4755163Sshin#include <varargs.h>
4855163Sshin#endif
4955163Sshin#include <syslog.h>
5055163Sshin#include <stddef.h>
5162607Sitojun#include <errno.h>
5255163Sshin#include <err.h>
53119076Sume#ifdef HAVE_POLL_H
54119076Sume#include <poll.h>
55119076Sume#endif
5655163Sshin
5755163Sshin#include <sys/types.h>
5855163Sshin#include <sys/param.h>
5955163Sshin#include <sys/file.h>
6055163Sshin#include <sys/socket.h>
6155163Sshin#include <sys/ioctl.h>
6255163Sshin#include <sys/sysctl.h>
6355163Sshin#include <sys/uio.h>
6455163Sshin#include <net/if.h>
6555163Sshin#include <net/if_var.h>
6662607Sitojun#define	_KERNEL	1
6755163Sshin#include <net/route.h>
6862607Sitojun#undef _KERNEL
6955163Sshin#include <netinet/in.h>
7055163Sshin#include <netinet/in_var.h>
7155163Sshin#include <netinet/ip6.h>
7255163Sshin#include <netinet/udp.h>
7355163Sshin#include <netdb.h>
7462607Sitojun#include <ifaddrs.h>
7555163Sshin
7655163Sshin#include <arpa/inet.h>
7755163Sshin
7855163Sshin#include "route6d.h"
7955163Sshin
8055163Sshin#define	MAXFILTER	40
8155163Sshin
8255163Sshin#ifdef	DEBUG
8355163Sshin#define	INIT_INTERVAL6	6
8455163Sshin#else
85119039Sume#define	INIT_INTERVAL6	10	/* Wait to submit an initial riprequest */
8655163Sshin#endif
8755163Sshin
8855163Sshin/* alignment constraint for routing socket */
8962607Sitojun#define ROUNDUP(a) \
9055163Sshin	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
9162607Sitojun#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
9255163Sshin
9355163Sshin/*
9455163Sshin * Following two macros are highly depending on KAME Release
9555163Sshin */
9655163Sshin#define	IN6_LINKLOCAL_IFINDEX(addr) \
9755163Sshin	((addr).s6_addr[2] << 8 | (addr).s6_addr[3])
9855163Sshin
9955163Sshin#define	SET_IN6_LINKLOCAL_IFINDEX(addr, index) \
10055163Sshin	do { \
10155163Sshin		(addr).s6_addr[2] = ((index) >> 8) & 0xff; \
10255163Sshin		(addr).s6_addr[3] = (index) & 0xff; \
10355163Sshin	} while (0)
10455163Sshin
10555163Sshinstruct	ifc {			/* Configuration of an interface */
10655163Sshin	char	*ifc_name;			/* if name */
10755163Sshin	struct	ifc *ifc_next;
10855163Sshin	int	ifc_index;			/* if index */
10955163Sshin	int	ifc_mtu;			/* if mtu */
11055163Sshin	int	ifc_metric;			/* if metric */
11178064Sume	u_int	ifc_flags;			/* flags */
11278064Sume	short	ifc_cflags;			/* IFC_XXX */
11355163Sshin	struct	in6_addr ifc_mylladdr;		/* my link-local address */
11455163Sshin	struct	sockaddr_in6 ifc_ripsin;	/* rip multicast address */
11555163Sshin	struct	iff *ifc_filter;		/* filter structure */
11655163Sshin	struct	ifac *ifc_addr;			/* list of AF_INET6 addresses */
11755163Sshin	int	ifc_joined;			/* joined to ff02::9 */
11855163Sshin};
11955163Sshin
12062607Sitojunstruct	ifac {			/* Adddress associated to an interface */
12155163Sshin	struct	ifc *ifa_conf;		/* back pointer */
12255163Sshin	struct	ifac *ifa_next;
12355163Sshin	struct	in6_addr ifa_addr;	/* address */
12455163Sshin	struct	in6_addr ifa_raddr;	/* remote address, valid in p2p */
12555163Sshin	int	ifa_plen;		/* prefix length */
12655163Sshin};
12755163Sshin
12855163Sshinstruct	iff {
12955163Sshin	int	iff_type;
13055163Sshin	struct	in6_addr iff_addr;
13155163Sshin	int	iff_plen;
13255163Sshin	struct	iff *iff_next;
13355163Sshin};
13455163Sshin
13555163Sshinstruct	ifc *ifc;
13655163Sshinint	nifc;		/* number of valid ifc's */
13755163Sshinstruct	ifc **index2ifc;
13855163Sshinint	nindex2ifc;
13955163Sshinstruct	ifc *loopifcp = NULL;	/* pointing to loopback */
140119076Sume#ifdef HAVE_POLL_H
141119076Sumestruct	pollfd set[2];
142119076Sume#else
143119070Sumefd_set	*sockvecp;	/* vector to select() for receiving */
144119070Sumefd_set	*recvecp;
145119070Sumeint	fdmasks;
146119070Sumeint	maxfd;		/* maximum fd for select() */
147119076Sume#endif
14855163Sshinint	rtsock;		/* the routing socket */
14955163Sshinint	ripsock;	/* socket to send/receive RIP datagram */
15055163Sshin
15155163Sshinstruct	rip6 *ripbuf;	/* packet buffer for sending */
15255163Sshin
15355163Sshin/*
15478064Sume * Maintain the routes in a linked list.  When the number of the routes
15555163Sshin * grows, somebody would like to introduce a hash based or a radix tree
15678064Sume * based structure.  I believe the number of routes handled by RIP is
15755163Sshin * limited and I don't have to manage a complex data structure, however.
15855163Sshin *
15955163Sshin * One of the major drawbacks of the linear linked list is the difficulty
16078064Sume * of representing the relationship between a couple of routes.  This may
16155163Sshin * be a significant problem when we have to support route aggregation with
16255163Sshin * supressing the specifices covered by the aggregate.
16355163Sshin */
16455163Sshin
16555163Sshinstruct	riprt {
16655163Sshin	struct	riprt *rrt_next;	/* next destination */
16755163Sshin	struct	riprt *rrt_same;	/* same destination - future use */
16855163Sshin	struct	netinfo6 rrt_info;	/* network info */
16955163Sshin	struct	in6_addr rrt_gw;	/* gateway */
17062607Sitojun	u_long	rrt_flags;		/* kernel routing table flags */
17162607Sitojun	u_long	rrt_rflags;		/* route6d routing table flags */
17255163Sshin	time_t	rrt_t;			/* when the route validated */
17355163Sshin	int	rrt_index;		/* ifindex from which this route got */
17455163Sshin};
17555163Sshin
17655163Sshinstruct	riprt *riprt = 0;
17755163Sshin
17855163Sshinint	dflag = 0;	/* debug flag */
17955163Sshinint	qflag = 0;	/* quiet flag */
18055163Sshinint	nflag = 0;	/* don't update kernel routing table */
18155163Sshinint	aflag = 0;	/* age out even the statically defined routes */
18255163Sshinint	hflag = 0;	/* don't split horizon */
18355163Sshinint	lflag = 0;	/* exchange site local routes */
18455163Sshinint	sflag = 0;	/* announce static routes w/ split horizon */
18555163Sshinint	Sflag = 0;	/* announce static routes to every interface */
18662607Sitojununsigned long routetag = 0;	/* route tag attached on originating case */
18755163Sshin
18855163Sshinchar	*filter[MAXFILTER];
18955163Sshinint	filtertype[MAXFILTER];
19055163Sshinint	nfilter = 0;
19155163Sshin
19255163Sshinpid_t	pid;
19355163Sshin
19455163Sshinstruct	sockaddr_storage ripsin;
19555163Sshin
19655163Sshinint	interval = 1;
19755163Sshintime_t	nextalarm = 0;
19855163Sshintime_t	sup_trig_update = 0;
19955163Sshin
20055163SshinFILE	*rtlog = NULL;
20155163Sshin
20255163Sshinint logopened = 0;
20355163Sshin
204119085Sumestatic	int	seq = 0;
20555163Sshin
20678064Sumevolatile sig_atomic_t seenalrm;
20778064Sumevolatile sig_atomic_t seenquit;
20878064Sumevolatile sig_atomic_t seenusr1;
20978064Sume
21062607Sitojun#define	RRTF_AGGREGATE		0x08000000
21162607Sitojun#define	RRTF_NOADVERTISE	0x10000000
21262607Sitojun#define	RRTF_NH_NOT_LLADDR	0x20000000
21362607Sitojun#define RRTF_SENDANYWAY		0x40000000
21462607Sitojun#define	RRTF_CHANGED		0x80000000
21555163Sshin
216173412Skevloint main(int, char **);
217173412Skevlovoid sighandler(int);
218173412Skevlovoid ripalarm(void);
219173412Skevlovoid riprecv(void);
220173412Skevlovoid ripsend(struct ifc *, struct sockaddr_in6 *, int);
221173412Skevloint out_filter(struct riprt *, struct ifc *);
222173412Skevlovoid init(void);
223173412Skevlovoid sockopt(struct ifc *);
224173412Skevlovoid ifconfig(void);
225173412Skevlovoid ifconfig1(const char *, const struct sockaddr *, struct ifc *, int);
226173412Skevlovoid rtrecv(void);
227173412Skevloint rt_del(const struct sockaddr_in6 *, const struct sockaddr_in6 *,
228173412Skevlo	const struct sockaddr_in6 *);
229173412Skevloint rt_deladdr(struct ifc *, const struct sockaddr_in6 *,
230173412Skevlo	const struct sockaddr_in6 *);
231173412Skevlovoid filterconfig(void);
232173412Skevloint getifmtu(int);
233173412Skevloconst char *rttypes(struct rt_msghdr *);
234173412Skevloconst char *rtflags(struct rt_msghdr *);
235173412Skevloconst char *ifflags(int);
236173412Skevloint ifrt(struct ifc *, int);
237173412Skevlovoid ifrt_p2p(struct ifc *, int);
238173412Skevlovoid applymask(struct in6_addr *, struct in6_addr *);
239173412Skevlovoid applyplen(struct in6_addr *, int);
240173412Skevlovoid ifrtdump(int);
241173412Skevlovoid ifdump(int);
242173412Skevlovoid ifdump0(FILE *, const struct ifc *);
243173412Skevlovoid rtdump(int);
244173412Skevlovoid rt_entry(struct rt_msghdr *, int);
245173412Skevlovoid rtdexit(void);
246173412Skevlovoid riprequest(struct ifc *, struct netinfo6 *, int,
247173412Skevlo	struct sockaddr_in6 *);
248173412Skevlovoid ripflush(struct ifc *, struct sockaddr_in6 *);
249173412Skevlovoid sendrequest(struct ifc *);
250173412Skevloint sin6mask2len(const struct sockaddr_in6 *);
251173412Skevloint mask2len(const struct in6_addr *, int);
252173412Skevloint sendpacket(struct sockaddr_in6 *, int);
253173412Skevloint addroute(struct riprt *, const struct in6_addr *, struct ifc *);
254173412Skevloint delroute(struct netinfo6 *, struct in6_addr *);
255173412Skevlostruct in6_addr *getroute(struct netinfo6 *, struct in6_addr *);
256173412Skevlovoid krtread(int);
257173412Skevloint tobeadv(struct riprt *, struct ifc *);
258173412Skevlochar *allocopy(char *);
259173412Skevlochar *hms(void);
260173412Skevloconst char *inet6_n2p(const struct in6_addr *);
261173412Skevlostruct ifac *ifa_match(const struct ifc *, const struct in6_addr *, int);
262173412Skevlostruct in6_addr *plen2mask(int);
263173412Skevlostruct riprt *rtsearch(struct netinfo6 *, struct riprt **);
264173412Skevloint ripinterval(int);
265173412Skevlotime_t ripsuptrig(void);
266173412Skevlovoid fatal(const char *, ...)
26766807Skris	__attribute__((__format__(__printf__, 1, 2)));
268173412Skevlovoid trace(int, const char *, ...)
26966807Skris	__attribute__((__format__(__printf__, 2, 3)));
270173412Skevlovoid tracet(int, const char *, ...)
27166807Skris	__attribute__((__format__(__printf__, 2, 3)));
272173412Skevlounsigned int if_maxindex(void);
273173412Skevlostruct ifc *ifc_find(char *);
274173412Skevlostruct iff *iff_find(struct ifc *, int);
275173412Skevlovoid setindex2ifc(int, struct ifc *);
27655163Sshin
27755163Sshin#define	MALLOC(type)	((type *)malloc(sizeof(type)))
27855163Sshin
27955163Sshinint
28055163Sshinmain(argc, argv)
28155163Sshin	int	argc;
28255163Sshin	char	**argv;
28355163Sshin{
28455163Sshin	int	ch;
28555163Sshin	int	error = 0;
28655163Sshin	struct	ifc *ifcp;
28755163Sshin	sigset_t mask, omask;
28855163Sshin	FILE	*pidfile;
28955163Sshin	char *progname;
29062607Sitojun	char *ep;
29155163Sshin
29255163Sshin	progname = strrchr(*argv, '/');
29355163Sshin	if (progname)
29455163Sshin		progname++;
29555163Sshin	else
29655163Sshin		progname = *argv;
29755163Sshin
29855163Sshin	pid = getpid();
29978064Sume	while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnqsS")) != -1) {
30055163Sshin		switch (ch) {
30155163Sshin		case 'A':
30255163Sshin		case 'N':
30355163Sshin		case 'O':
30455163Sshin		case 'T':
30555163Sshin		case 'L':
30662607Sitojun			if (nfilter >= MAXFILTER) {
30755163Sshin				fatal("Exceeds MAXFILTER");
30862607Sitojun				/*NOTREACHED*/
30962607Sitojun			}
31055163Sshin			filtertype[nfilter] = ch;
31155163Sshin			filter[nfilter++] = allocopy(optarg);
31255163Sshin			break;
31355163Sshin		case 't':
31462607Sitojun			ep = NULL;
31562607Sitojun			routetag = strtoul(optarg, &ep, 0);
31662607Sitojun			if (!ep || *ep != '\0' || (routetag & ~0xffff) != 0) {
31755163Sshin				fatal("invalid route tag");
31855163Sshin				/*NOTREACHED*/
31955163Sshin			}
32055163Sshin			break;
32155163Sshin		case 'R':
32262607Sitojun			if ((rtlog = fopen(optarg, "w")) == NULL) {
32355163Sshin				fatal("Can not write to routelog");
32462607Sitojun				/*NOTREACHED*/
32562607Sitojun			}
32655163Sshin			break;
32762607Sitojun#define	FLAG(c, flag, n)	case c: do { flag = n; break; } while(0)
32862607Sitojun		FLAG('a', aflag, 1); break;
32962607Sitojun		FLAG('d', dflag, 1); break;
33062607Sitojun		FLAG('D', dflag, 2); break;
33162607Sitojun		FLAG('h', hflag, 1); break;
33262607Sitojun		FLAG('l', lflag, 1); break;
33362607Sitojun		FLAG('n', nflag, 1); break;
33462607Sitojun		FLAG('q', qflag, 1); break;
33562607Sitojun		FLAG('s', sflag, 1); break;
33662607Sitojun		FLAG('S', Sflag, 1); break;
33755163Sshin#undef	FLAG
33855163Sshin		default:
33955163Sshin			fatal("Invalid option specified, terminating");
34062607Sitojun			/*NOTREACHED*/
34155163Sshin		}
34255163Sshin	}
34355163Sshin	argc -= optind;
34455163Sshin	argv += optind;
34578064Sume	if (argc > 0) {
34655163Sshin		fatal("bogus extra arguments");
34778064Sume		/*NOTREACHED*/
34878064Sume	}
34955163Sshin
35055163Sshin	if (geteuid()) {
35155163Sshin		nflag = 1;
35255163Sshin		fprintf(stderr, "No kernel update is allowed\n");
35355163Sshin	}
354119037Sume
355119037Sume	if (dflag == 0) {
356119037Sume		if (daemon(0, 0) < 0) {
357119037Sume			fatal("daemon");
358119037Sume			/*NOTREACHED*/
359119037Sume		}
360119037Sume	}
361119037Sume
36255163Sshin	openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON);
36355163Sshin	logopened++;
36478064Sume
36578064Sume	if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL)
36678064Sume		fatal("malloc");
36778064Sume	memset(ripbuf, 0, RIP6_MAXMTU);
36878064Sume	ripbuf->rip6_cmd = RIP6_RESPONSE;
36978064Sume	ripbuf->rip6_vers = RIP6_VERSION;
37078064Sume	ripbuf->rip6_res1[0] = 0;
37178064Sume	ripbuf->rip6_res1[1] = 0;
37278064Sume
37355163Sshin	init();
37455163Sshin	ifconfig();
37555163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
37655163Sshin		if (ifcp->ifc_index < 0) {
37755163Sshin			fprintf(stderr,
37855163Sshin"No ifindex found at %s (no link-local address?)\n",
37955163Sshin				ifcp->ifc_name);
38055163Sshin			error++;
38155163Sshin		}
38255163Sshin	}
38355163Sshin	if (error)
38455163Sshin		exit(1);
38578064Sume	if (loopifcp == NULL) {
38655163Sshin		fatal("No loopback found");
38778064Sume		/*NOTREACHED*/
38878064Sume	}
38955163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next)
39055163Sshin		ifrt(ifcp, 0);
39155163Sshin	filterconfig();
39255163Sshin	krtread(0);
39355163Sshin	if (dflag)
39455163Sshin		ifrtdump(0);
39555163Sshin
396122677Sume#if 1
39755163Sshin	pid = getpid();
39855163Sshin	if ((pidfile = fopen(ROUTE6D_PID, "w")) != NULL) {
39955163Sshin		fprintf(pidfile, "%d\n", pid);
40055163Sshin		fclose(pidfile);
40155163Sshin	}
402122677Sume#endif
40355163Sshin
40478064Sume	if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) {
40555163Sshin		fatal("malloc");
40678064Sume		/*NOTREACHED*/
40778064Sume	}
40862607Sitojun	memset(ripbuf, 0, RIP6_MAXMTU);
40955163Sshin	ripbuf->rip6_cmd = RIP6_RESPONSE;
41055163Sshin	ripbuf->rip6_vers = RIP6_VERSION;
41155163Sshin	ripbuf->rip6_res1[0] = 0;
41255163Sshin	ripbuf->rip6_res1[1] = 0;
41355163Sshin
41478064Sume	if (signal(SIGALRM, sighandler) == SIG_ERR ||
41578064Sume	    signal(SIGQUIT, sighandler) == SIG_ERR ||
41678064Sume	    signal(SIGTERM, sighandler) == SIG_ERR ||
41778064Sume	    signal(SIGUSR1, sighandler) == SIG_ERR ||
41878064Sume	    signal(SIGHUP, sighandler) == SIG_ERR ||
41978064Sume	    signal(SIGINT, sighandler) == SIG_ERR) {
42078064Sume		fatal("signal");
42178064Sume		/*NOTREACHED*/
42278064Sume	}
42355163Sshin	/*
42455163Sshin	 * To avoid rip packet congestion (not on a cable but in this
42555163Sshin	 * process), wait for a moment to send the first RIP6_RESPONSE
42655163Sshin	 * packets.
42755163Sshin	 */
42855163Sshin	alarm(ripinterval(INIT_INTERVAL6));
42955163Sshin
43055163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
431119041Sume		if (iff_find(ifcp, 'N'))
432119041Sume			continue;
43355163Sshin		if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP))
43455163Sshin			sendrequest(ifcp);
43555163Sshin	}
43655163Sshin
43755163Sshin	syslog(LOG_INFO, "**** Started ****");
43855163Sshin	sigemptyset(&mask);
43955163Sshin	sigaddset(&mask, SIGALRM);
44055163Sshin	while (1) {
44178064Sume		if (seenalrm) {
44278064Sume			ripalarm();
44378064Sume			seenalrm = 0;
44478064Sume			continue;
44578064Sume		}
44678064Sume		if (seenquit) {
44778064Sume			rtdexit();
44878064Sume			seenquit = 0;
44978064Sume			continue;
45078064Sume		}
45178064Sume		if (seenusr1) {
45278064Sume			ifrtdump(SIGUSR1);
45378064Sume			seenusr1 = 0;
45478064Sume			continue;
45578064Sume		}
45678064Sume
457119076Sume#ifdef HAVE_POLL_H
458119076Sume		switch (poll(set, 2, INFTIM))
459119076Sume#else
460119070Sume		memcpy(recvecp, sockvecp, fdmasks);
461119076Sume		switch (select(maxfd + 1, recvecp, 0, 0, 0))
462119076Sume#endif
463119076Sume		{
46455163Sshin		case -1:
46578064Sume			if (errno != EINTR) {
46678064Sume				fatal("select");
46778064Sume				/*NOTREACHED*/
46878064Sume			}
46978064Sume			continue;
47055163Sshin		case 0:
47155163Sshin			continue;
47255163Sshin		default:
473119076Sume#ifdef HAVE_POLL_H
474119076Sume			if (set[0].revents & POLLIN)
475119076Sume#else
476119076Sume			if (FD_ISSET(ripsock, recvecp))
477119076Sume#endif
478119076Sume			{
47955163Sshin				sigprocmask(SIG_BLOCK, &mask, &omask);
48055163Sshin				riprecv();
48155163Sshin				sigprocmask(SIG_SETMASK, &omask, NULL);
48255163Sshin			}
483119076Sume#ifdef HAVE_POLL_H
484119076Sume			if (set[1].revents & POLLIN)
485119076Sume#else
486119076Sume			if (FD_ISSET(rtsock, recvecp))
487119076Sume#endif
488119076Sume			{
48955163Sshin				sigprocmask(SIG_BLOCK, &mask, &omask);
49055163Sshin				rtrecv();
49155163Sshin				sigprocmask(SIG_SETMASK, &omask, NULL);
49255163Sshin			}
49355163Sshin		}
49455163Sshin	}
49555163Sshin}
49655163Sshin
49778064Sumevoid
498119079Sumesighandler(signo)
499119079Sume	int signo;
50078064Sume{
50178064Sume
50278064Sume	switch (signo) {
50378064Sume	case SIGALRM:
50478064Sume		seenalrm++;
50578064Sume		break;
50678064Sume	case SIGQUIT:
50778064Sume	case SIGTERM:
50878064Sume		seenquit++;
50978064Sume		break;
51078064Sume	case SIGUSR1:
51178064Sume	case SIGHUP:
51278064Sume	case SIGINT:
51378064Sume		seenusr1++;
51478064Sume		break;
51578064Sume	}
51678064Sume}
51778064Sume
51855163Sshin/*
51955163Sshin * gracefully exits after resetting sockopts.
52055163Sshin */
52155163Sshin/* ARGSUSED */
52255163Sshinvoid
52378064Sumertdexit()
52455163Sshin{
52555163Sshin	struct	riprt *rrt;
52655163Sshin
52755163Sshin	alarm(0);
52855163Sshin	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
52962607Sitojun		if (rrt->rrt_rflags & RRTF_AGGREGATE) {
53055163Sshin			delroute(&rrt->rrt_info, &rrt->rrt_gw);
53155163Sshin		}
53255163Sshin	}
53355163Sshin	close(ripsock);
53455163Sshin	close(rtsock);
53555163Sshin	syslog(LOG_INFO, "**** Terminated ****");
53655163Sshin	closelog();
53755163Sshin	exit(1);
53855163Sshin}
53955163Sshin
54055163Sshin/*
54155163Sshin * Called periodically:
54255163Sshin *	1. age out the learned route. remove it if necessary.
54355163Sshin *	2. submit RIP6_RESPONSE packets.
54478064Sume * Invoked in every SUPPLY_INTERVAL6 (30) seconds.  I believe we don't have
54555163Sshin * to invoke this function in every 1 or 5 or 10 seconds only to age the
54655163Sshin * routes more precisely.
54755163Sshin */
54855163Sshin/* ARGSUSED */
54955163Sshinvoid
55078064Sumeripalarm()
55155163Sshin{
55255163Sshin	struct	ifc *ifcp;
55355163Sshin	struct	riprt *rrt, *rrt_prev, *rrt_next;
55455163Sshin	time_t	t_lifetime, t_holddown;
55555163Sshin
55655163Sshin	/* age the RIP routes */
55755163Sshin	rrt_prev = 0;
55855163Sshin	t_lifetime = time(NULL) - RIP_LIFETIME;
55955163Sshin	t_holddown = t_lifetime - RIP_HOLDDOWN;
56055163Sshin	for (rrt = riprt; rrt; rrt = rrt_next) {
56155163Sshin		rrt_next = rrt->rrt_next;
56255163Sshin
56355163Sshin		if (rrt->rrt_t == 0) {
56455163Sshin			rrt_prev = rrt;
56555163Sshin			continue;
56655163Sshin		}
56755163Sshin		if (rrt->rrt_t < t_holddown) {
56855163Sshin			if (rrt_prev) {
56955163Sshin				rrt_prev->rrt_next = rrt->rrt_next;
57055163Sshin			} else {
57155163Sshin				riprt = rrt->rrt_next;
57255163Sshin			}
57355163Sshin			delroute(&rrt->rrt_info, &rrt->rrt_gw);
57455163Sshin			free(rrt);
57555163Sshin			continue;
57655163Sshin		}
57755163Sshin		if (rrt->rrt_t < t_lifetime)
57855163Sshin			rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
57955163Sshin		rrt_prev = rrt;
58055163Sshin	}
58155163Sshin	/* Supply updates */
58255163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
58355163Sshin		if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP))
58455163Sshin			ripsend(ifcp, &ifcp->ifc_ripsin, 0);
58555163Sshin	}
58655163Sshin	alarm(ripinterval(SUPPLY_INTERVAL6));
58755163Sshin}
58855163Sshin
58955163Sshinvoid
59055163Sshininit()
59155163Sshin{
592119034Sume	int	error;
593119034Sume	const int int0 = 0, int1 = 1, int255 = 255;
59455163Sshin	struct	addrinfo hints, *res;
595119081Sume	char	port[NI_MAXSERV];
59655163Sshin
59755163Sshin	ifc = (struct ifc *)NULL;
59855163Sshin	nifc = 0;
59955163Sshin	nindex2ifc = 0;	/*initial guess*/
60055163Sshin	index2ifc = NULL;
601119081Sume	snprintf(port, sizeof(port), "%u", RIP6_PORT);
60255163Sshin
60355163Sshin	memset(&hints, 0, sizeof(hints));
60455163Sshin	hints.ai_family = PF_INET6;
60555163Sshin	hints.ai_socktype = SOCK_DGRAM;
606119080Sume	hints.ai_protocol = IPPROTO_UDP;
60755163Sshin	hints.ai_flags = AI_PASSIVE;
60855163Sshin	error = getaddrinfo(NULL, port, &hints, &res);
60978064Sume	if (error) {
61066807Skris		fatal("%s", gai_strerror(error));
61178064Sume		/*NOTREACHED*/
61278064Sume	}
61378064Sume	if (res->ai_next) {
61455163Sshin		fatal(":: resolved to multiple address");
61578064Sume		/*NOTREACHED*/
61678064Sume	}
61755163Sshin
61855163Sshin	ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
61978064Sume	if (ripsock < 0) {
62055163Sshin		fatal("rip socket");
62178064Sume		/*NOTREACHED*/
62278064Sume	}
623119034Sume#ifdef IPV6_V6ONLY
624119034Sume	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_V6ONLY,
625119034Sume	    &int1, sizeof(int1)) < 0) {
626119034Sume		fatal("rip IPV6_V6ONLY");
627119034Sume		/*NOTREACHED*/
628119034Sume	}
629119034Sume#endif
63078064Sume	if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0) {
63155163Sshin		fatal("rip bind");
63278064Sume		/*NOTREACHED*/
63378064Sume	}
63455163Sshin	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
63578064Sume	    &int255, sizeof(int255)) < 0) {
63655163Sshin		fatal("rip IPV6_MULTICAST_HOPS");
63778064Sume		/*NOTREACHED*/
63878064Sume	}
63955163Sshin	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
64078064Sume	    &int0, sizeof(int0)) < 0) {
64155163Sshin		fatal("rip IPV6_MULTICAST_LOOP");
64278064Sume		/*NOTREACHED*/
64378064Sume	}
64462921Sume
64562607Sitojun#ifdef IPV6_RECVPKTINFO
646119034Sume	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
647119034Sume	    &int1, sizeof(int1)) < 0) {
64862607Sitojun		fatal("rip IPV6_RECVPKTINFO");
64978064Sume		/*NOTREACHED*/
65078064Sume	}
65162607Sitojun#else  /* old adv. API */
652119034Sume	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_PKTINFO,
653119034Sume	    &int1, sizeof(int1)) < 0) {
65455163Sshin		fatal("rip IPV6_PKTINFO");
65578064Sume		/*NOTREACHED*/
65678064Sume	}
65762607Sitojun#endif
65855163Sshin
659164339Ssuz#ifdef IPV6_RECVPKTINFO
660164339Ssuz	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
661164339Ssuz	    &int1, sizeof(int1)) < 0) {
662164339Ssuz		fatal("rip IPV6_RECVHOPLIMIT");
663164339Ssuz		/*NOTREACHED*/
664164339Ssuz	}
665164339Ssuz#else  /* old adv. API */
666164339Ssuz	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_HOPLIMIT,
667164339Ssuz	    &int1, sizeof(int1)) < 0) {
668164339Ssuz		fatal("rip IPV6_HOPLIMIT");
669164339Ssuz		/*NOTREACHED*/
670164339Ssuz	}
671164339Ssuz#endif
672164339Ssuz
67355163Sshin	memset(&hints, 0, sizeof(hints));
67455163Sshin	hints.ai_family = PF_INET6;
67555163Sshin	hints.ai_socktype = SOCK_DGRAM;
676119080Sume	hints.ai_protocol = IPPROTO_UDP;
67755163Sshin	error = getaddrinfo(RIP6_DEST, port, &hints, &res);
67878064Sume	if (error) {
67966807Skris		fatal("%s", gai_strerror(error));
68078064Sume		/*NOTREACHED*/
68178064Sume	}
68278064Sume	if (res->ai_next) {
68355163Sshin		fatal("%s resolved to multiple address", RIP6_DEST);
68478064Sume		/*NOTREACHED*/
68578064Sume	}
68655163Sshin	memcpy(&ripsin, res->ai_addr, res->ai_addrlen);
68755163Sshin
688119076Sume#ifdef HAVE_POLL_H
689119076Sume	set[0].fd = ripsock;
690119076Sume	set[0].events = POLLIN;
691119076Sume#else
692119070Sume	maxfd = ripsock;
693119076Sume#endif
69455163Sshin
69555163Sshin	if (nflag == 0) {
69678064Sume		if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
69755163Sshin			fatal("route socket");
69878064Sume			/*NOTREACHED*/
69978064Sume		}
700119076Sume#ifdef HAVE_POLL_H
701119076Sume		set[1].fd = rtsock;
702119076Sume		set[1].events = POLLIN;
703119076Sume#else
704119070Sume		if (rtsock > maxfd)
705119070Sume			maxfd = rtsock;
706119076Sume#endif
707119076Sume	} else {
708119076Sume#ifdef HAVE_POLL_H
709119076Sume		set[1].fd = -1;
710119076Sume#else
71155163Sshin		rtsock = -1;	/*just for safety */
712119076Sume#endif
713119076Sume	}
714119070Sume
715119076Sume#ifndef HAVE_POLL_H
716119070Sume	fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask);
717119070Sume	if ((sockvecp = malloc(fdmasks)) == NULL) {
718119070Sume		fatal("malloc");
719119070Sume		/*NOTREACHED*/
720119070Sume	}
721119070Sume	if ((recvecp = malloc(fdmasks)) == NULL) {
722119070Sume		fatal("malloc");
723119070Sume		/*NOTREACHED*/
724119070Sume	}
725119070Sume	memset(sockvecp, 0, fdmasks);
726119070Sume	FD_SET(ripsock, sockvecp);
727119070Sume	if (rtsock >= 0)
728119070Sume		FD_SET(rtsock, sockvecp);
729119076Sume#endif
73055163Sshin}
73155163Sshin
73262607Sitojun#define	RIPSIZE(n) \
73362607Sitojun	(sizeof(struct rip6) + ((n)-1) * sizeof(struct netinfo6))
73455163Sshin
73555163Sshin/*
73655163Sshin * ripflush flushes the rip datagram stored in the rip buffer
73755163Sshin */
73855163Sshinstatic int nrt;
73955163Sshinstatic struct netinfo6 *np;
74055163Sshin
74155163Sshinvoid
742119031Sumeripflush(ifcp, sin6)
74355163Sshin	struct ifc *ifcp;
744119031Sume	struct sockaddr_in6 *sin6;
74555163Sshin{
74655163Sshin	int i;
74755163Sshin	int error;
74855163Sshin
74955163Sshin	if (ifcp)
75055163Sshin		tracet(1, "Send(%s): info(%d) to %s.%d\n",
75155163Sshin			ifcp->ifc_name, nrt,
752119031Sume			inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port));
75355163Sshin	else
75455163Sshin		tracet(1, "Send: info(%d) to %s.%d\n",
755119031Sume			nrt, inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port));
75655163Sshin	if (dflag >= 2) {
75755163Sshin		np = ripbuf->rip6_nets;
75855163Sshin		for (i = 0; i < nrt; i++, np++) {
75955163Sshin			if (np->rip6_metric == NEXTHOP_METRIC) {
76055163Sshin				if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest))
76162607Sitojun					trace(2, "    NextHop reset");
76255163Sshin				else {
76355163Sshin					trace(2, "    NextHop %s",
76455163Sshin						inet6_n2p(&np->rip6_dest));
76555163Sshin				}
76655163Sshin			} else {
76755163Sshin				trace(2, "    %s/%d[%d]",
76855163Sshin					inet6_n2p(&np->rip6_dest),
76955163Sshin					np->rip6_plen, np->rip6_metric);
77055163Sshin			}
77155163Sshin			if (np->rip6_tag) {
77255163Sshin				trace(2, "  tag=0x%04x",
77355163Sshin					ntohs(np->rip6_tag) & 0xffff);
77455163Sshin			}
77555163Sshin			trace(2, "\n");
77655163Sshin		}
77755163Sshin	}
778119031Sume	error = sendpacket(sin6, RIPSIZE(nrt));
77955163Sshin	if (error == EAFNOSUPPORT) {
78055163Sshin		/* Protocol not supported */
78155163Sshin		tracet(1, "Could not send info to %s (%s): "
78255163Sshin			"set IFF_UP to 0\n",
78355163Sshin			ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
78455163Sshin		ifcp->ifc_flags &= ~IFF_UP;	/* As if down for AF_INET6 */
78555163Sshin	}
78655163Sshin	nrt = 0; np = ripbuf->rip6_nets;
78755163Sshin}
78855163Sshin
78955163Sshin/*
79055163Sshin * Generate RIP6_RESPONSE packets and send them.
79155163Sshin */
79255163Sshinvoid
793119031Sumeripsend(ifcp, sin6, flag)
79455163Sshin	struct	ifc *ifcp;
795119031Sume	struct	sockaddr_in6 *sin6;
79655163Sshin	int flag;
79755163Sshin{
79855163Sshin	struct	riprt *rrt;
79955163Sshin	struct	in6_addr *nh;	/* next hop */
80078064Sume	int	maxrte;
80155163Sshin
802119084Sume	if (qflag)
803119084Sume		return;
804119084Sume
80555163Sshin	if (ifcp == NULL) {
80655163Sshin		/*
80755163Sshin		 * Request from non-link local address is not
80855163Sshin		 * a regular route6d update.
80955163Sshin		 */
81062607Sitojun		maxrte = (IFMINMTU - sizeof(struct ip6_hdr) -
81162607Sitojun				sizeof(struct udphdr) -
81255163Sshin				sizeof(struct rip6) + sizeof(struct netinfo6)) /
81355163Sshin				sizeof(struct netinfo6);
81455163Sshin		nrt = 0; np = ripbuf->rip6_nets; nh = NULL;
81555163Sshin		for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
81662607Sitojun			if (rrt->rrt_rflags & RRTF_NOADVERTISE)
81755163Sshin				continue;
81855163Sshin			/* Put the route to the buffer */
81955163Sshin			*np = rrt->rrt_info;
82055163Sshin			np++; nrt++;
82155163Sshin			if (nrt == maxrte) {
822119031Sume				ripflush(NULL, sin6);
82355163Sshin				nh = NULL;
82455163Sshin			}
82555163Sshin		}
82655163Sshin		if (nrt)	/* Send last packet */
827119031Sume			ripflush(NULL, sin6);
82855163Sshin		return;
82955163Sshin	}
83055163Sshin
83162607Sitojun	if ((flag & RRTF_SENDANYWAY) == 0 &&
83255163Sshin	    (qflag || (ifcp->ifc_flags & IFF_LOOPBACK)))
83355163Sshin		return;
83478064Sume
83578064Sume	/* -N: no use */
83655163Sshin	if (iff_find(ifcp, 'N') != NULL)
83755163Sshin		return;
83878064Sume
83978064Sume	/* -T: generate default route only */
84055163Sshin	if (iff_find(ifcp, 'T') != NULL) {
84155163Sshin		struct netinfo6 rrt_info;
84255163Sshin		memset(&rrt_info, 0, sizeof(struct netinfo6));
84355163Sshin		rrt_info.rip6_dest = in6addr_any;
84455163Sshin		rrt_info.rip6_plen = 0;
84555163Sshin		rrt_info.rip6_metric = 1;
84678064Sume		rrt_info.rip6_metric += ifcp->ifc_metric;
84755163Sshin		rrt_info.rip6_tag = htons(routetag & 0xffff);
84855163Sshin		np = ripbuf->rip6_nets;
84955163Sshin		*np = rrt_info;
85055163Sshin		nrt = 1;
851119031Sume		ripflush(ifcp, sin6);
85255163Sshin		return;
85355163Sshin	}
85478064Sume
85562607Sitojun	maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) -
85662607Sitojun			sizeof(struct udphdr) -
85755163Sshin			sizeof(struct rip6) + sizeof(struct netinfo6)) /
85855163Sshin			sizeof(struct netinfo6);
85978064Sume
86055163Sshin	nrt = 0; np = ripbuf->rip6_nets; nh = NULL;
86155163Sshin	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
86262607Sitojun		if (rrt->rrt_rflags & RRTF_NOADVERTISE)
86355163Sshin			continue;
86478064Sume
86578064Sume		/* Need to check filter here */
86678064Sume		if (out_filter(rrt, ifcp) == 0)
86755163Sshin			continue;
86878064Sume
86955163Sshin		/* Check split horizon and other conditions */
87055163Sshin		if (tobeadv(rrt, ifcp) == 0)
87155163Sshin			continue;
87278064Sume
87355163Sshin		/* Only considers the routes with flag if specified */
87462607Sitojun		if ((flag & RRTF_CHANGED) &&
87562607Sitojun		    (rrt->rrt_rflags & RRTF_CHANGED) == 0)
87655163Sshin			continue;
87778064Sume
87855163Sshin		/* Check nexthop */
87955163Sshin		if (rrt->rrt_index == ifcp->ifc_index &&
88055163Sshin		    !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) &&
88162607Sitojun		    (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) == 0) {
88255163Sshin			if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) {
88355163Sshin				if (nrt == maxrte - 2)
884119031Sume					ripflush(ifcp, sin6);
88555163Sshin				np->rip6_dest = rrt->rrt_gw;
88655163Sshin				if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest))
88755163Sshin					SET_IN6_LINKLOCAL_IFINDEX(np->rip6_dest, 0);
88855163Sshin				np->rip6_plen = 0;
88955163Sshin				np->rip6_tag = 0;
89055163Sshin				np->rip6_metric = NEXTHOP_METRIC;
89155163Sshin				nh = &rrt->rrt_gw;
89255163Sshin				np++; nrt++;
89355163Sshin			}
89455163Sshin		} else if (nh && (rrt->rrt_index != ifcp->ifc_index ||
89555163Sshin			          !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) ||
89662607Sitojun				  rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)) {
89755163Sshin			/* Reset nexthop */
89855163Sshin			if (nrt == maxrte - 2)
899119031Sume				ripflush(ifcp, sin6);
90055163Sshin			memset(np, 0, sizeof(struct netinfo6));
90155163Sshin			np->rip6_metric = NEXTHOP_METRIC;
90255163Sshin			nh = NULL;
90355163Sshin			np++; nrt++;
90455163Sshin		}
90578064Sume
90655163Sshin		/* Put the route to the buffer */
90755163Sshin		*np = rrt->rrt_info;
90855163Sshin		np++; nrt++;
90955163Sshin		if (nrt == maxrte) {
910119031Sume			ripflush(ifcp, sin6);
91155163Sshin			nh = NULL;
91255163Sshin		}
91355163Sshin	}
91455163Sshin	if (nrt)	/* Send last packet */
915119031Sume		ripflush(ifcp, sin6);
91655163Sshin}
91755163Sshin
91855163Sshin/*
91978064Sume * outbound filter logic, per-route/interface.
92078064Sume */
92178064Sumeint
92278064Sumeout_filter(rrt, ifcp)
92378064Sume	struct riprt *rrt;
92478064Sume	struct ifc *ifcp;
92578064Sume{
92678064Sume	struct iff *iffp;
92778064Sume	struct in6_addr ia;
92878064Sume	int ok;
92978064Sume
93078064Sume	/*
93178064Sume	 * -A: filter out less specific routes, if we have aggregated
93278064Sume	 * route configured.
93378064Sume	 */
93478064Sume	for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
93578064Sume		if (iffp->iff_type != 'A')
93678064Sume			continue;
93778064Sume		if (rrt->rrt_info.rip6_plen <= iffp->iff_plen)
93878064Sume			continue;
93978064Sume		ia = rrt->rrt_info.rip6_dest;
94078064Sume		applyplen(&ia, iffp->iff_plen);
94178064Sume		if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr))
94278064Sume			return 0;
94378064Sume	}
94478064Sume
94578064Sume	/*
94678064Sume	 * if it is an aggregated route, advertise it only to the
94778064Sume	 * interfaces specified on -A.
94878064Sume	 */
94978064Sume	if ((rrt->rrt_rflags & RRTF_AGGREGATE) != 0) {
95078064Sume		ok = 0;
95178064Sume		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
95278064Sume			if (iffp->iff_type != 'A')
95378064Sume				continue;
95478064Sume			if (rrt->rrt_info.rip6_plen == iffp->iff_plen &&
95578064Sume			    IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
95678064Sume			    &iffp->iff_addr)) {
95778064Sume				ok = 1;
95878064Sume				break;
95978064Sume			}
96078064Sume		}
96178064Sume		if (!ok)
96278064Sume			return 0;
96378064Sume	}
96478064Sume
96578064Sume	/*
96678064Sume	 * -O: advertise only if prefix matches the configured prefix.
96778064Sume	 */
96878064Sume	if (iff_find(ifcp, 'O')) {
96978064Sume		ok = 0;
97078064Sume		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
97178064Sume			if (iffp->iff_type != 'O')
97278064Sume				continue;
97378064Sume			if (rrt->rrt_info.rip6_plen < iffp->iff_plen)
97478064Sume				continue;
97578064Sume			ia = rrt->rrt_info.rip6_dest;
97678064Sume			applyplen(&ia, iffp->iff_plen);
97778064Sume			if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) {
97878064Sume				ok = 1;
97978064Sume				break;
98078064Sume			}
98178064Sume		}
98278064Sume		if (!ok)
98378064Sume			return 0;
98478064Sume	}
98578064Sume
98678064Sume	/* the prefix should be advertised */
98778064Sume	return 1;
98878064Sume}
98978064Sume
99078064Sume/*
99155163Sshin * Determine if the route is to be advertised on the specified interface.
99255163Sshin * It checks options specified in the arguments and the split horizon rule.
99355163Sshin */
99455163Sshinint
99555163Sshintobeadv(rrt, ifcp)
99655163Sshin	struct riprt *rrt;
99755163Sshin	struct ifc *ifcp;
99855163Sshin{
99955163Sshin
100055163Sshin	/* Special care for static routes */
100155163Sshin	if (rrt->rrt_flags & RTF_STATIC) {
100262607Sitojun		/* XXX don't advertise reject/blackhole routes */
100362607Sitojun		if (rrt->rrt_flags & (RTF_REJECT | RTF_BLACKHOLE))
100462607Sitojun			return 0;
100562607Sitojun
100655163Sshin		if (Sflag)	/* Yes, advertise it anyway */
100755163Sshin			return 1;
100855163Sshin		if (sflag && rrt->rrt_index != ifcp->ifc_index)
100955163Sshin			return 1;
101055163Sshin		return 0;
101155163Sshin	}
101255163Sshin	/* Regular split horizon */
101355163Sshin	if (hflag == 0 && rrt->rrt_index == ifcp->ifc_index)
101455163Sshin		return 0;
101555163Sshin	return 1;
101655163Sshin}
101755163Sshin
101855163Sshin/*
101955163Sshin * Send a rip packet actually.
102055163Sshin */
102155163Sshinint
1022119031Sumesendpacket(sin6, len)
1023119031Sume	struct	sockaddr_in6 *sin6;
102455163Sshin	int	len;
102555163Sshin{
102655163Sshin	struct msghdr m;
102755163Sshin	struct cmsghdr *cm;
102855163Sshin	struct iovec iov[2];
102955163Sshin	u_char cmsgbuf[256];
103055163Sshin	struct in6_pktinfo *pi;
103178064Sume	int idx;
103255163Sshin	struct sockaddr_in6 sincopy;
103355163Sshin
103455163Sshin	/* do not overwrite the given sin */
1035119031Sume	sincopy = *sin6;
1036119031Sume	sin6 = &sincopy;
103755163Sshin
1038119035Sume	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
1039119035Sume	    IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
1040122677Sume		/* XXX: do not mix the interface index and link index */
1041119031Sume		idx = IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr);
1042119031Sume		SET_IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr, 0);
1043122677Sume		sin6->sin6_scope_id = idx;
104455163Sshin	} else
104578064Sume		idx = 0;
104655163Sshin
1047119031Sume	m.msg_name = (caddr_t)sin6;
1048119031Sume	m.msg_namelen = sizeof(*sin6);
104955163Sshin	iov[0].iov_base = (caddr_t)ripbuf;
105055163Sshin	iov[0].iov_len = len;
105155163Sshin	m.msg_iov = iov;
105255163Sshin	m.msg_iovlen = 1;
105378064Sume	if (!idx) {
105455163Sshin		m.msg_control = NULL;
105555163Sshin		m.msg_controllen = 0;
105655163Sshin	} else {
105755163Sshin		memset(cmsgbuf, 0, sizeof(cmsgbuf));
105855163Sshin		cm = (struct cmsghdr *)cmsgbuf;
105955163Sshin		m.msg_control = (caddr_t)cm;
106055163Sshin		m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
106155163Sshin
106255163Sshin		cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
106355163Sshin		cm->cmsg_level = IPPROTO_IPV6;
106455163Sshin		cm->cmsg_type = IPV6_PKTINFO;
106555163Sshin		pi = (struct in6_pktinfo *)CMSG_DATA(cm);
106655163Sshin		memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/
106778064Sume		pi->ipi6_ifindex = idx;
106855163Sshin	}
106955163Sshin
107055163Sshin	if (sendmsg(ripsock, &m, 0 /*MSG_DONTROUTE*/) < 0) {
107155163Sshin		trace(1, "sendmsg: %s\n", strerror(errno));
107255163Sshin		return errno;
107355163Sshin	}
107462921Sume
107555163Sshin	return 0;
107655163Sshin}
107755163Sshin
107855163Sshin/*
107978064Sume * Receive and process RIP packets.  Update the routes/kernel forwarding
108055163Sshin * table if necessary.
108155163Sshin */
108255163Sshinvoid
108355163Sshinriprecv()
108455163Sshin{
108555163Sshin	struct	ifc *ifcp, *ic;
108655163Sshin	struct	sockaddr_in6 fsock;
108755163Sshin	struct	in6_addr nh;	/* next hop */
108855163Sshin	struct	rip6 *rp;
108955163Sshin	struct	netinfo6 *np, *nq;
109055163Sshin	struct	riprt *rrt;
1091122677Sume	ssize_t	len, nn;
1092122677Sume	unsigned int need_trigger, idx;
109355163Sshin	char	buf[4 * RIP6_MAXMTU];
109455163Sshin	time_t	t;
109555163Sshin	struct msghdr m;
109655163Sshin	struct cmsghdr *cm;
109755163Sshin	struct iovec iov[2];
109855163Sshin	u_char cmsgbuf[256];
1099164339Ssuz	struct in6_pktinfo *pi = NULL;
1100164339Ssuz	int *hlimp = NULL;
110155163Sshin	struct iff *iffp;
110255163Sshin	struct in6_addr ia;
110355163Sshin	int ok;
110478064Sume	time_t t_half_lifetime;
110555163Sshin
110655163Sshin	need_trigger = 0;
110762921Sume
110855163Sshin	m.msg_name = (caddr_t)&fsock;
110955163Sshin	m.msg_namelen = sizeof(fsock);
111055163Sshin	iov[0].iov_base = (caddr_t)buf;
111155163Sshin	iov[0].iov_len = sizeof(buf);
111255163Sshin	m.msg_iov = iov;
111355163Sshin	m.msg_iovlen = 1;
111455163Sshin	cm = (struct cmsghdr *)cmsgbuf;
111555163Sshin	m.msg_control = (caddr_t)cm;
111655163Sshin	m.msg_controllen = sizeof(cmsgbuf);
111778064Sume	if ((len = recvmsg(ripsock, &m, 0)) < 0) {
111855163Sshin		fatal("recvmsg");
111978064Sume		/*NOTREACHED*/
112078064Sume	}
112178064Sume	idx = 0;
112255163Sshin	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m);
112355163Sshin	     cm;
112455163Sshin	     cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) {
1125164339Ssuz		if (cm->cmsg_level != IPPROTO_IPV6)
1126164339Ssuz		    continue;
1127164339Ssuz		switch (cm->cmsg_type) {
1128164339Ssuz		case IPV6_PKTINFO:
1129164339Ssuz			if (cm->cmsg_len != CMSG_LEN(sizeof(*pi))) {
1130164339Ssuz				trace(1,
1131164339Ssuz				    "invalid cmsg length for IPV6_PKTINFO\n");
1132164339Ssuz				return;
1133164339Ssuz			}
113455163Sshin			pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
113578064Sume			idx = pi->ipi6_ifindex;
113655163Sshin			break;
1137164339Ssuz		case IPV6_HOPLIMIT:
1138164339Ssuz			if (cm->cmsg_len != CMSG_LEN(sizeof(int))) {
1139164339Ssuz				trace(1,
1140164339Ssuz				    "invalid cmsg length for IPV6_HOPLIMIT\n");
1141164339Ssuz				return;
1142164339Ssuz			}
1143164339Ssuz			hlimp = (int *)CMSG_DATA(cm);
1144164339Ssuz			break;
114555163Sshin		}
114655163Sshin	}
114778064Sume	if (idx && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr))
114878064Sume		SET_IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr, idx);
114955163Sshin
1150121779Ssuz	if (len < sizeof(struct rip6)) {
1151121779Ssuz		trace(1, "Packet too short\n");
1152121779Ssuz		return;
1153121779Ssuz	}
1154121779Ssuz
1155164339Ssuz	if (pi == NULL || hlimp == NULL) {
1156164339Ssuz		/*
1157164339Ssuz		 * This can happen when the kernel failed to allocate memory
1158164339Ssuz		 * for the ancillary data.  Although we might be able to handle
1159164339Ssuz		 * some cases without this info, those are minor and not so
1160164339Ssuz		 * important, so it's better to discard the packet for safer
1161164339Ssuz		 * operation.
1162164339Ssuz		 */
1163164339Ssuz		trace(1, "IPv6 packet information cannot be retrieved\n");
1164164339Ssuz		return;
1165164339Ssuz	}
1166164339Ssuz
116755163Sshin	nh = fsock.sin6_addr;
116855163Sshin	nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) /
116955163Sshin		sizeof(struct netinfo6);
117055163Sshin	rp = (struct rip6 *)buf;
117155163Sshin	np = rp->rip6_nets;
117255163Sshin
1173119035Sume	if (rp->rip6_vers != RIP6_VERSION) {
117455163Sshin		trace(1, "Incorrect RIP version %d\n", rp->rip6_vers);
117555163Sshin		return;
117655163Sshin	}
117755163Sshin	if (rp->rip6_cmd == RIP6_REQUEST) {
117878064Sume		if (idx && idx < nindex2ifc) {
117978064Sume			ifcp = index2ifc[idx];
118055163Sshin			riprequest(ifcp, np, nn, &fsock);
118155163Sshin		} else {
118255163Sshin			riprequest(NULL, np, nn, &fsock);
118355163Sshin		}
118462607Sitojun		return;
118562607Sitojun	}
118655163Sshin
118755163Sshin	if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) {
1188164339Ssuz		trace(1, "Response from non-ll addr: %s\n",
118978064Sume		    inet6_n2p(&fsock.sin6_addr));
119055163Sshin		return;		/* Ignore packets from non-link-local addr */
119155163Sshin	}
1192164339Ssuz	if (ntohs(fsock.sin6_port) != RIP6_PORT) {
1193164339Ssuz		trace(1, "Response from non-rip port from %s\n",
1194164339Ssuz		    inet6_n2p(&fsock.sin6_addr));
1195164339Ssuz		return;
1196164339Ssuz	}
1197164339Ssuz	if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) && *hlimp != 255) {
1198164339Ssuz		trace(1,
1199164339Ssuz		    "Response packet with a smaller hop limit (%d) from %s\n",
1200164339Ssuz		    *hlimp, inet6_n2p(&fsock.sin6_addr));
1201164339Ssuz		return;
1202164339Ssuz	}
1203164339Ssuz	/*
1204164339Ssuz	 * Further validation: since this program does not send off-link
1205164339Ssuz	 * requests, an incoming response must always come from an on-link
1206164339Ssuz	 * node.  Although this is normally ensured by the source address
1207164339Ssuz	 * check above, it may not 100% be safe because there are router
1208164339Ssuz	 * implementations that (invalidly) allow a packet with a link-local
1209164339Ssuz	 * source address to be forwarded to a different link.
1210164339Ssuz	 * So we also check whether the destination address is a link-local
1211164339Ssuz	 * address or the hop limit is 255.  Note that RFC2080 does not require
1212164339Ssuz	 * the specific hop limit for a unicast response, so we cannot assume
1213164339Ssuz	 * the limitation.
1214164339Ssuz	 */
1215164339Ssuz	if (!IN6_IS_ADDR_LINKLOCAL(&pi->ipi6_addr) && *hlimp != 255) {
1216164339Ssuz		trace(1,
1217164339Ssuz		    "Response packet possibly from an off-link node: "
1218164339Ssuz		    "from %s to %s hlim=%d\n",
1219164339Ssuz		    inet6_n2p(&fsock.sin6_addr),
1220164339Ssuz		    inet6_n2p(&pi->ipi6_addr), *hlimp);
1221164339Ssuz		return;
1222164339Ssuz	}
1223164339Ssuz
122478064Sume	idx = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr);
122578064Sume	ifcp = (idx < nindex2ifc) ? index2ifc[idx] : NULL;
122655163Sshin	if (!ifcp) {
122778064Sume		trace(1, "Packets to unknown interface index %d\n", idx);
122855163Sshin		return;		/* Ignore it */
122955163Sshin	}
123055163Sshin	if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr))
123155163Sshin		return;		/* The packet is from me; ignore */
123255163Sshin	if (rp->rip6_cmd != RIP6_RESPONSE) {
123355163Sshin		trace(1, "Invalid command %d\n", rp->rip6_cmd);
123462607Sitojun		return;
123555163Sshin	}
123678064Sume
123778064Sume	/* -N: no use */
123855163Sshin	if (iff_find(ifcp, 'N') != NULL)
123955163Sshin		return;
124078064Sume
124155163Sshin	tracet(1, "Recv(%s): from %s.%d info(%d)\n",
124278064Sume	    ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn);
124355163Sshin
124455163Sshin	t = time(NULL);
124578064Sume	t_half_lifetime = t - (RIP_LIFETIME/2);
124655163Sshin	for (; nn; nn--, np++) {
124755163Sshin		if (np->rip6_metric == NEXTHOP_METRIC) {
124855163Sshin			/* modify neighbor address */
124955163Sshin			if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) {
125055163Sshin				nh = np->rip6_dest;
125178064Sume				SET_IN6_LINKLOCAL_IFINDEX(nh, idx);
125255163Sshin				trace(1, "\tNexthop: %s\n", inet6_n2p(&nh));
125355163Sshin			} else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) {
125455163Sshin				nh = fsock.sin6_addr;
125555163Sshin				trace(1, "\tNexthop: %s\n", inet6_n2p(&nh));
125655163Sshin			} else {
125755163Sshin				nh = fsock.sin6_addr;
125855163Sshin				trace(1, "\tInvalid Nexthop: %s\n",
125978064Sume				    inet6_n2p(&np->rip6_dest));
126055163Sshin			}
126155163Sshin			continue;
126255163Sshin		}
126355163Sshin		if (IN6_IS_ADDR_MULTICAST(&np->rip6_dest)) {
126455163Sshin			trace(1, "\tMulticast netinfo6: %s/%d [%d]\n",
126555163Sshin				inet6_n2p(&np->rip6_dest),
126655163Sshin				np->rip6_plen, np->rip6_metric);
126755163Sshin			continue;
126855163Sshin		}
126955163Sshin		if (IN6_IS_ADDR_LOOPBACK(&np->rip6_dest)) {
127055163Sshin			trace(1, "\tLoopback netinfo6: %s/%d [%d]\n",
127155163Sshin				inet6_n2p(&np->rip6_dest),
127255163Sshin				np->rip6_plen, np->rip6_metric);
127355163Sshin			continue;
127455163Sshin		}
127555163Sshin		if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) {
127655163Sshin			trace(1, "\tLink Local netinfo6: %s/%d [%d]\n",
127755163Sshin				inet6_n2p(&np->rip6_dest),
127855163Sshin				np->rip6_plen, np->rip6_metric);
127955163Sshin			continue;
128055163Sshin		}
128155163Sshin		/* may need to pass sitelocal prefix in some case, however*/
128255163Sshin		if (IN6_IS_ADDR_SITELOCAL(&np->rip6_dest) && !lflag) {
128355163Sshin			trace(1, "\tSite Local netinfo6: %s/%d [%d]\n",
128455163Sshin				inet6_n2p(&np->rip6_dest),
128555163Sshin				np->rip6_plen, np->rip6_metric);
128655163Sshin			continue;
128755163Sshin		}
128855163Sshin		trace(2, "\tnetinfo6: %s/%d [%d]",
128955163Sshin			inet6_n2p(&np->rip6_dest),
129055163Sshin			np->rip6_plen, np->rip6_metric);
129155163Sshin		if (np->rip6_tag)
129255163Sshin			trace(2, "  tag=0x%04x", ntohs(np->rip6_tag) & 0xffff);
129362607Sitojun		if (dflag >= 2) {
129462607Sitojun			ia = np->rip6_dest;
129562607Sitojun			applyplen(&ia, np->rip6_plen);
129662607Sitojun			if (!IN6_ARE_ADDR_EQUAL(&ia, &np->rip6_dest))
129762607Sitojun				trace(2, " [junk outside prefix]");
129862607Sitojun		}
129955163Sshin
130078064Sume		/*
130178064Sume		 * -L: listen only if the prefix matches the configuration
130278064Sume		 */
130355163Sshin		ok = 1;		/* if there's no L filter, it is ok */
130455163Sshin		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
130555163Sshin			if (iffp->iff_type != 'L')
130655163Sshin				continue;
130755163Sshin			ok = 0;
130855163Sshin			if (np->rip6_plen < iffp->iff_plen)
130955163Sshin				continue;
131055163Sshin			/* special rule: ::/0 means default, not "in /0" */
131155163Sshin			if (iffp->iff_plen == 0 && np->rip6_plen > 0)
131255163Sshin				continue;
131362607Sitojun			ia = np->rip6_dest;
131455163Sshin			applyplen(&ia, iffp->iff_plen);
131555163Sshin			if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) {
131655163Sshin				ok = 1;
131755163Sshin				break;
131855163Sshin			}
131955163Sshin		}
132055163Sshin		if (!ok) {
132155163Sshin			trace(2, "  (filtered)\n");
132255163Sshin			continue;
132355163Sshin		}
132455163Sshin
132555163Sshin		trace(2, "\n");
132655163Sshin		np->rip6_metric++;
132755163Sshin		np->rip6_metric += ifcp->ifc_metric;
132855163Sshin		if (np->rip6_metric > HOPCNT_INFINITY6)
132955163Sshin			np->rip6_metric = HOPCNT_INFINITY6;
133055163Sshin
133155163Sshin		applyplen(&np->rip6_dest, np->rip6_plen);
133278064Sume		if ((rrt = rtsearch(np, NULL)) != NULL) {
133355163Sshin			if (rrt->rrt_t == 0)
133455163Sshin				continue;	/* Intf route has priority */
133555163Sshin			nq = &rrt->rrt_info;
133655163Sshin			if (nq->rip6_metric > np->rip6_metric) {
133755163Sshin				if (rrt->rrt_index == ifcp->ifc_index &&
133855163Sshin				    IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
133955163Sshin					/* Small metric from the same gateway */
134055163Sshin					nq->rip6_metric = np->rip6_metric;
134155163Sshin				} else {
134255163Sshin					/* Better route found */
134355163Sshin					rrt->rrt_index = ifcp->ifc_index;
134455163Sshin					/* Update routing table */
134555163Sshin					delroute(nq, &rrt->rrt_gw);
134655163Sshin					rrt->rrt_gw = nh;
134755163Sshin					*nq = *np;
134855163Sshin					addroute(rrt, &nh, ifcp);
134955163Sshin				}
135062607Sitojun				rrt->rrt_rflags |= RRTF_CHANGED;
135155163Sshin				rrt->rrt_t = t;
135255163Sshin				need_trigger = 1;
135355163Sshin			} else if (nq->rip6_metric < np->rip6_metric &&
135455163Sshin				   rrt->rrt_index == ifcp->ifc_index &&
135555163Sshin				   IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
135655163Sshin				/* Got worse route from same gw */
135755163Sshin				nq->rip6_metric = np->rip6_metric;
135855163Sshin				rrt->rrt_t = t;
135962607Sitojun				rrt->rrt_rflags |= RRTF_CHANGED;
136055163Sshin				need_trigger = 1;
136155163Sshin			} else if (nq->rip6_metric == np->rip6_metric &&
136255163Sshin				   np->rip6_metric < HOPCNT_INFINITY6) {
136378064Sume				if (rrt->rrt_index == ifcp->ifc_index &&
136478064Sume				   IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
136578064Sume					/* same metric, same route from same gw */
136678064Sume					rrt->rrt_t = t;
136778064Sume				} else if (rrt->rrt_t < t_half_lifetime) {
136878064Sume					/* Better route found */
136978064Sume					rrt->rrt_index = ifcp->ifc_index;
137078064Sume					/* Update routing table */
137178064Sume					delroute(nq, &rrt->rrt_gw);
137278064Sume					rrt->rrt_gw = nh;
137378064Sume					*nq = *np;
137478064Sume					addroute(rrt, &nh, ifcp);
137578064Sume					rrt->rrt_rflags |= RRTF_CHANGED;
137678064Sume					rrt->rrt_t = t;
137778064Sume				}
137855163Sshin			}
137962607Sitojun			/*
138055163Sshin			 * if nq->rip6_metric == HOPCNT_INFINITY6 then
138178064Sume			 * do not update age value.  Do nothing.
138255163Sshin			 */
138355163Sshin		} else if (np->rip6_metric < HOPCNT_INFINITY6) {
138455163Sshin			/* Got a new valid route */
138578064Sume			if ((rrt = MALLOC(struct riprt)) == NULL) {
138655163Sshin				fatal("malloc: struct riprt");
138778064Sume				/*NOTREACHED*/
138878064Sume			}
138962607Sitojun			memset(rrt, 0, sizeof(*rrt));
139055163Sshin			nq = &rrt->rrt_info;
139155163Sshin
139255163Sshin			rrt->rrt_same = NULL;
139355163Sshin			rrt->rrt_index = ifcp->ifc_index;
139455163Sshin			rrt->rrt_flags = RTF_UP|RTF_GATEWAY;
139555163Sshin			rrt->rrt_gw = nh;
139655163Sshin			*nq = *np;
139755163Sshin			applyplen(&nq->rip6_dest, nq->rip6_plen);
139855163Sshin			if (nq->rip6_plen == sizeof(struct in6_addr) * 8)
139955163Sshin				rrt->rrt_flags |= RTF_HOST;
140055163Sshin
140155163Sshin			/* Put the route to the list */
140255163Sshin			rrt->rrt_next = riprt;
140355163Sshin			riprt = rrt;
140455163Sshin			/* Update routing table */
140555163Sshin			addroute(rrt, &nh, ifcp);
140662607Sitojun			rrt->rrt_rflags |= RRTF_CHANGED;
140755163Sshin			need_trigger = 1;
140855163Sshin			rrt->rrt_t = t;
140955163Sshin		}
141055163Sshin	}
141155163Sshin	/* XXX need to care the interval between triggered updates */
141255163Sshin	if (need_trigger) {
141355163Sshin		if (nextalarm > time(NULL) + RIP_TRIG_INT6_MAX) {
141455163Sshin			for (ic = ifc; ic; ic = ic->ifc_next) {
141555163Sshin				if (ifcp->ifc_index == ic->ifc_index)
141655163Sshin					continue;
141755163Sshin				if (ic->ifc_flags & IFF_UP)
141855163Sshin					ripsend(ic, &ic->ifc_ripsin,
141962607Sitojun						RRTF_CHANGED);
142055163Sshin			}
142155163Sshin		}
142255163Sshin		/* Reset the flag */
142355163Sshin		for (rrt = riprt; rrt; rrt = rrt->rrt_next)
142462607Sitojun			rrt->rrt_rflags &= ~RRTF_CHANGED;
142555163Sshin	}
142655163Sshin}
142755163Sshin
142855163Sshin/*
142955163Sshin * Send all routes request packet to the specified interface.
143055163Sshin */
143155163Sshinvoid
143255163Sshinsendrequest(ifcp)
143355163Sshin	struct ifc *ifcp;
143455163Sshin{
143555163Sshin	struct netinfo6 *np;
143655163Sshin	int error;
143755163Sshin
143855163Sshin	if (ifcp->ifc_flags & IFF_LOOPBACK)
143955163Sshin		return;
144055163Sshin	ripbuf->rip6_cmd = RIP6_REQUEST;
144155163Sshin	np = ripbuf->rip6_nets;
144255163Sshin	memset(np, 0, sizeof(struct netinfo6));
144355163Sshin	np->rip6_metric = HOPCNT_INFINITY6;
144455163Sshin	tracet(1, "Send rtdump Request to %s (%s)\n",
144555163Sshin		ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
144655163Sshin	error = sendpacket(&ifcp->ifc_ripsin, RIPSIZE(1));
144755163Sshin	if (error == EAFNOSUPPORT) {
144855163Sshin		/* Protocol not supported */
144955163Sshin		tracet(1, "Could not send rtdump Request to %s (%s): "
145055163Sshin			"set IFF_UP to 0\n",
145155163Sshin			ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
145255163Sshin		ifcp->ifc_flags &= ~IFF_UP;	/* As if down for AF_INET6 */
145355163Sshin	}
145455163Sshin	ripbuf->rip6_cmd = RIP6_RESPONSE;
145555163Sshin}
145655163Sshin
145755163Sshin/*
145855163Sshin * Process a RIP6_REQUEST packet.
145955163Sshin */
146055163Sshinvoid
1461119031Sumeriprequest(ifcp, np, nn, sin6)
146255163Sshin	struct ifc *ifcp;
146355163Sshin	struct netinfo6 *np;
146455163Sshin	int nn;
1465119031Sume	struct sockaddr_in6 *sin6;
146655163Sshin{
146755163Sshin	int i;
146855163Sshin	struct riprt *rrt;
146955163Sshin
147055163Sshin	if (!(nn == 1 && IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest) &&
147155163Sshin	      np->rip6_plen == 0 && np->rip6_metric == HOPCNT_INFINITY6)) {
147255163Sshin		/* Specific response, don't split-horizon */
147355163Sshin		trace(1, "\tRIP Request\n");
147455163Sshin		for (i = 0; i < nn; i++, np++) {
147578064Sume			rrt = rtsearch(np, NULL);
147655163Sshin			if (rrt)
147755163Sshin				np->rip6_metric = rrt->rrt_info.rip6_metric;
147855163Sshin			else
147955163Sshin				np->rip6_metric = HOPCNT_INFINITY6;
148055163Sshin		}
1481119031Sume		(void)sendpacket(sin6, RIPSIZE(nn));
148255163Sshin		return;
148355163Sshin	}
148455163Sshin	/* Whole routing table dump */
148555163Sshin	trace(1, "\tRIP Request -- whole routing table\n");
1486119031Sume	ripsend(ifcp, sin6, RRTF_SENDANYWAY);
148755163Sshin}
148855163Sshin
148955163Sshin/*
149055163Sshin * Get information of each interface.
149155163Sshin */
149255163Sshinvoid
149355163Sshinifconfig()
149455163Sshin{
149562607Sitojun	struct ifaddrs *ifap, *ifa;
149662607Sitojun	struct ifc *ifcp;
149762607Sitojun	struct ipv6_mreq mreq;
149862607Sitojun	int s;
149962607Sitojun
150078064Sume	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
150162607Sitojun		fatal("socket");
150278064Sume		/*NOTREACHED*/
150378064Sume	}
150462607Sitojun
150578064Sume	if (getifaddrs(&ifap) != 0) {
150662607Sitojun		fatal("getifaddrs");
150778064Sume		/*NOTREACHED*/
150878064Sume	}
150962607Sitojun
151062607Sitojun	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
151162607Sitojun		if (ifa->ifa_addr->sa_family != AF_INET6)
151262607Sitojun			continue;
151362607Sitojun		ifcp = ifc_find(ifa->ifa_name);
151462607Sitojun		/* we are interested in multicast-capable interfaces */
151562607Sitojun		if ((ifa->ifa_flags & IFF_MULTICAST) == 0)
151662607Sitojun			continue;
151762607Sitojun		if (!ifcp) {
151862607Sitojun			/* new interface */
151978064Sume			if ((ifcp = MALLOC(struct ifc)) == NULL) {
152062607Sitojun				fatal("malloc: struct ifc");
152178064Sume				/*NOTREACHED*/
152278064Sume			}
152362607Sitojun			memset(ifcp, 0, sizeof(*ifcp));
152462607Sitojun			ifcp->ifc_index = -1;
152562607Sitojun			ifcp->ifc_next = ifc;
152662607Sitojun			ifc = ifcp;
152762607Sitojun			nifc++;
152862607Sitojun			ifcp->ifc_name = allocopy(ifa->ifa_name);
152962607Sitojun			ifcp->ifc_addr = 0;
153062607Sitojun			ifcp->ifc_filter = 0;
153162607Sitojun			ifcp->ifc_flags = ifa->ifa_flags;
153262607Sitojun			trace(1, "newif %s <%s>\n", ifcp->ifc_name,
153362607Sitojun				ifflags(ifcp->ifc_flags));
153462607Sitojun			if (!strcmp(ifcp->ifc_name, LOOPBACK_IF))
153562607Sitojun				loopifcp = ifcp;
153662607Sitojun		} else {
153762607Sitojun			/* update flag, this may be up again */
153862607Sitojun			if (ifcp->ifc_flags != ifa->ifa_flags) {
153962607Sitojun				trace(1, "%s: <%s> -> ", ifcp->ifc_name,
154062607Sitojun					ifflags(ifcp->ifc_flags));
154162607Sitojun				trace(1, "<%s>\n", ifflags(ifa->ifa_flags));
154278064Sume				ifcp->ifc_cflags |= IFC_CHANGED;
154362607Sitojun			}
154462607Sitojun			ifcp->ifc_flags = ifa->ifa_flags;
154562607Sitojun		}
154662607Sitojun		ifconfig1(ifa->ifa_name, ifa->ifa_addr, ifcp, s);
154762607Sitojun		if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP
154862607Sitojun		 && 0 < ifcp->ifc_index && !ifcp->ifc_joined) {
154962607Sitojun			mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr;
155062607Sitojun			mreq.ipv6mr_interface = ifcp->ifc_index;
155178064Sume			if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
155278064Sume			    &mreq, sizeof(mreq)) < 0) {
155362607Sitojun				fatal("IPV6_JOIN_GROUP");
155478064Sume				/*NOTREACHED*/
155578064Sume			}
155662607Sitojun			trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST);
155762607Sitojun			ifcp->ifc_joined++;
155862607Sitojun		}
155962607Sitojun	}
156062607Sitojun	close(s);
156162607Sitojun	freeifaddrs(ifap);
156255163Sshin}
156355163Sshin
156455163Sshinvoid
156562607Sitojunifconfig1(name, sa, ifcp, s)
156662607Sitojun	const char *name;
156762607Sitojun	const struct sockaddr *sa;
156855163Sshin	struct	ifc *ifcp;
156955163Sshin	int	s;
157055163Sshin{
157155163Sshin	struct	in6_ifreq ifr;
1572119031Sume	const struct sockaddr_in6 *sin6;
157355163Sshin	struct	ifac *ifa;
157455163Sshin	int	plen;
157555163Sshin	char	buf[BUFSIZ];
157655163Sshin
1577119031Sume	sin6 = (const struct sockaddr_in6 *)sa;
1578122677Sume	if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) && !lflag)
1579122677Sume		return;
1580119031Sume	ifr.ifr_addr = *sin6;
1581119032Sume	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
158278064Sume	if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0) {
158355163Sshin		fatal("ioctl: SIOCGIFNETMASK_IN6");
158478064Sume		/*NOTREACHED*/
158578064Sume	}
158678064Sume	plen = sin6mask2len(&ifr.ifr_addr);
1587119031Sume	if ((ifa = ifa_match(ifcp, &sin6->sin6_addr, plen)) != NULL) {
158855163Sshin		/* same interface found */
158955163Sshin		/* need check if something changed */
159055163Sshin		/* XXX not yet implemented */
159155163Sshin		return;
159255163Sshin	}
159355163Sshin	/*
159455163Sshin	 * New address is found
159555163Sshin	 */
159678064Sume	if ((ifa = MALLOC(struct ifac)) == NULL) {
159755163Sshin		fatal("malloc: struct ifac");
159878064Sume		/*NOTREACHED*/
159978064Sume	}
160062607Sitojun	memset(ifa, 0, sizeof(*ifa));
160155163Sshin	ifa->ifa_conf = ifcp;
160255163Sshin	ifa->ifa_next = ifcp->ifc_addr;
160355163Sshin	ifcp->ifc_addr = ifa;
1604119031Sume	ifa->ifa_addr = sin6->sin6_addr;
160555163Sshin	ifa->ifa_plen = plen;
160655163Sshin	if (ifcp->ifc_flags & IFF_POINTOPOINT) {
1607119031Sume		ifr.ifr_addr = *sin6;
160878064Sume		if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0) {
160955163Sshin			fatal("ioctl: SIOCGIFDSTADDR_IN6");
161078064Sume			/*NOTREACHED*/
161178064Sume		}
161255163Sshin		ifa->ifa_raddr = ifr.ifr_dstaddr.sin6_addr;
161355163Sshin		inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, buf, sizeof(buf));
161455163Sshin		trace(1, "found address %s/%d -- %s\n",
161555163Sshin			inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen, buf);
161655163Sshin	} else {
161755163Sshin		trace(1, "found address %s/%d\n",
161855163Sshin			inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen);
161955163Sshin	}
162055163Sshin	if (ifcp->ifc_index < 0 && IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) {
162155163Sshin		ifcp->ifc_mylladdr = ifa->ifa_addr;
162255163Sshin		ifcp->ifc_index = IN6_LINKLOCAL_IFINDEX(ifa->ifa_addr);
162355163Sshin		memcpy(&ifcp->ifc_ripsin, &ripsin, ripsin.ss_len);
162455163Sshin		SET_IN6_LINKLOCAL_IFINDEX(ifcp->ifc_ripsin.sin6_addr,
162555163Sshin			ifcp->ifc_index);
162655163Sshin		setindex2ifc(ifcp->ifc_index, ifcp);
162755163Sshin		ifcp->ifc_mtu = getifmtu(ifcp->ifc_index);
162855163Sshin		if (ifcp->ifc_mtu > RIP6_MAXMTU)
162955163Sshin			ifcp->ifc_mtu = RIP6_MAXMTU;
163078064Sume		if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0) {
163155163Sshin			fatal("ioctl: SIOCGIFMETRIC");
163278064Sume			/*NOTREACHED*/
163378064Sume		}
163455163Sshin		ifcp->ifc_metric = ifr.ifr_metric;
163555163Sshin		trace(1, "\tindex: %d, mtu: %d, metric: %d\n",
163655163Sshin			ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric);
163778064Sume	} else
163878064Sume		ifcp->ifc_cflags |= IFC_CHANGED;
163955163Sshin}
164055163Sshin
164155163Sshin/*
164255163Sshin * Receive and process routing messages.
164355163Sshin * Update interface information as necesssary.
164455163Sshin */
164555163Sshinvoid
164655163Sshinrtrecv()
164755163Sshin{
164855163Sshin	char buf[BUFSIZ];
164955163Sshin	char *p, *q;
165055163Sshin	struct rt_msghdr *rtm;
165155163Sshin	struct ifa_msghdr *ifam;
165255163Sshin	struct if_msghdr *ifm;
165355163Sshin	int len;
165478064Sume	struct ifc *ifcp, *ic;
165555163Sshin	int iface = 0, rtable = 0;
165655163Sshin	struct sockaddr_in6 *rta[RTAX_MAX];
165778064Sume	struct sockaddr_in6 mask;
165855163Sshin	int i, addrs;
165978064Sume	struct riprt *rrt;
166055163Sshin
166155163Sshin	if ((len = read(rtsock, buf, sizeof(buf))) < 0) {
166255163Sshin		perror("read from rtsock");
166378064Sume		exit(1);
166455163Sshin	}
166555163Sshin	if (len < sizeof(*rtm)) {
166669279Sume		trace(1, "short read from rtsock: %d (should be > %lu)\n",
166769279Sume			len, (u_long)sizeof(*rtm));
166855163Sshin		return;
166955163Sshin	}
1670119042Sume	if (dflag >= 2) {
1671119042Sume		fprintf(stderr, "rtmsg:\n");
1672119042Sume		for (i = 0; i < len; i++) {
1673119042Sume			fprintf(stderr, "%02x ", buf[i] & 0xff);
1674119042Sume			if (i % 16 == 15) fprintf(stderr, "\n");
1675119042Sume		}
1676119042Sume		fprintf(stderr, "\n");
1677119042Sume	}
167855163Sshin
167955163Sshin	for (p = buf; p - buf < len; p += ((struct rt_msghdr *)p)->rtm_msglen) {
168055163Sshin		/* safety against bogus message */
168155163Sshin		if (((struct rt_msghdr *)p)->rtm_msglen <= 0) {
168255163Sshin			trace(1, "bogus rtmsg: length=%d\n",
168355163Sshin				((struct rt_msghdr *)p)->rtm_msglen);
168455163Sshin			break;
168555163Sshin		}
168655163Sshin		rtm = NULL;
168755163Sshin		ifam = NULL;
168855163Sshin		ifm = NULL;
168955163Sshin		switch (((struct rt_msghdr *)p)->rtm_type) {
169055163Sshin		case RTM_NEWADDR:
169155163Sshin		case RTM_DELADDR:
169255163Sshin			ifam = (struct ifa_msghdr *)p;
169355163Sshin			addrs = ifam->ifam_addrs;
169455163Sshin			q = (char *)(ifam + 1);
169555163Sshin			break;
169655163Sshin		case RTM_IFINFO:
169755163Sshin			ifm = (struct if_msghdr *)p;
169855163Sshin			addrs = ifm->ifm_addrs;
169955163Sshin			q = (char *)(ifm + 1);
170055163Sshin			break;
170155163Sshin		default:
170255163Sshin			rtm = (struct rt_msghdr *)p;
170355163Sshin			addrs = rtm->rtm_addrs;
170455163Sshin			q = (char *)(rtm + 1);
170555163Sshin			if (rtm->rtm_version != RTM_VERSION) {
170655163Sshin				trace(1, "unexpected rtmsg version %d "
170755163Sshin					"(should be %d)\n",
170855163Sshin					rtm->rtm_version, RTM_VERSION);
170955163Sshin				continue;
171055163Sshin			}
171155163Sshin			if (rtm->rtm_pid == pid) {
171255163Sshin#if 0
171355163Sshin				trace(1, "rtmsg looped back to me, ignored\n");
171455163Sshin#endif
171555163Sshin				continue;
171655163Sshin			}
171755163Sshin			break;
171855163Sshin		}
171955163Sshin		memset(&rta, 0, sizeof(rta));
172055163Sshin		for (i = 0; i < RTAX_MAX; i++) {
172155163Sshin			if (addrs & (1 << i)) {
172255163Sshin				rta[i] = (struct sockaddr_in6 *)q;
172355163Sshin				q += ROUNDUP(rta[i]->sin6_len);
172455163Sshin			}
172555163Sshin		}
172655163Sshin
172755163Sshin		trace(1, "rtsock: %s (addrs=%x)\n",
172855163Sshin			rttypes((struct rt_msghdr *)p), addrs);
172955163Sshin		if (dflag >= 2) {
173055163Sshin			for (i = 0;
173155163Sshin			     i < ((struct rt_msghdr *)p)->rtm_msglen;
173255163Sshin			     i++) {
173355163Sshin				fprintf(stderr, "%02x ", p[i] & 0xff);
173455163Sshin				if (i % 16 == 15) fprintf(stderr, "\n");
173555163Sshin			}
173655163Sshin			fprintf(stderr, "\n");
173755163Sshin		}
173855163Sshin
173955163Sshin		/*
174055163Sshin		 * Easy ones first.
174155163Sshin		 *
174255163Sshin		 * We may be able to optimize by using ifm->ifm_index or
174355163Sshin		 * ifam->ifam_index.  For simplicity we don't do that here.
174455163Sshin		 */
174555163Sshin		switch (((struct rt_msghdr *)p)->rtm_type) {
174655163Sshin		case RTM_NEWADDR:
174755163Sshin		case RTM_IFINFO:
174855163Sshin			iface++;
174955163Sshin			continue;
175055163Sshin		case RTM_ADD:
175155163Sshin			rtable++;
175255163Sshin			continue;
175355163Sshin		case RTM_LOSING:
175455163Sshin		case RTM_MISS:
175555163Sshin		case RTM_RESOLVE:
175655163Sshin		case RTM_GET:
175755163Sshin		case RTM_LOCK:
175855163Sshin			/* nothing to be done here */
175955163Sshin			trace(1, "\tnothing to be done, ignored\n");
176055163Sshin			continue;
176155163Sshin		}
176255163Sshin
176355163Sshin#if 0
176455163Sshin		if (rta[RTAX_DST] == NULL) {
176555163Sshin			trace(1, "\tno destination, ignored\n");
176662607Sitojun			continue;
176755163Sshin		}
176855163Sshin		if (rta[RTAX_DST]->sin6_family != AF_INET6) {
176955163Sshin			trace(1, "\taf mismatch, ignored\n");
177055163Sshin			continue;
177155163Sshin		}
177255163Sshin		if (IN6_IS_ADDR_LINKLOCAL(&rta[RTAX_DST]->sin6_addr)) {
177355163Sshin			trace(1, "\tlinklocal destination, ignored\n");
177455163Sshin			continue;
177555163Sshin		}
177655163Sshin		if (IN6_ARE_ADDR_EQUAL(&rta[RTAX_DST]->sin6_addr, &in6addr_loopback)) {
177755163Sshin			trace(1, "\tloopback destination, ignored\n");
177855163Sshin			continue;		/* Loopback */
177955163Sshin		}
178055163Sshin		if (IN6_IS_ADDR_MULTICAST(&rta[RTAX_DST]->sin6_addr)) {
178155163Sshin			trace(1, "\tmulticast destination, ignored\n");
178255163Sshin			continue;
178355163Sshin		}
178455163Sshin#endif
178555163Sshin
178655163Sshin		/* hard ones */
178755163Sshin		switch (((struct rt_msghdr *)p)->rtm_type) {
178855163Sshin		case RTM_NEWADDR:
178955163Sshin		case RTM_IFINFO:
179055163Sshin		case RTM_ADD:
179155163Sshin		case RTM_LOSING:
179255163Sshin		case RTM_MISS:
179355163Sshin		case RTM_RESOLVE:
179455163Sshin		case RTM_GET:
179555163Sshin		case RTM_LOCK:
179655163Sshin			/* should already be handled */
179755163Sshin			fatal("rtrecv: never reach here");
179878064Sume			/*NOTREACHED*/
179955163Sshin		case RTM_DELETE:
180078064Sume			if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY]) {
180178064Sume				trace(1, "\tsome of dst/gw/netamsk are "
180278064Sume				    "unavailable, ignored\n");
180355163Sshin				break;
180455163Sshin			}
180578064Sume			if ((rtm->rtm_flags & RTF_HOST) != 0) {
180678064Sume				mask.sin6_len = sizeof(mask);
180778064Sume				memset(&mask.sin6_addr, 0xff,
180878064Sume				    sizeof(mask.sin6_addr));
180978064Sume				rta[RTAX_NETMASK] = &mask;
181078064Sume			} else if (!rta[RTAX_NETMASK]) {
181178064Sume				trace(1, "\tsome of dst/gw/netamsk are "
181278064Sume				    "unavailable, ignored\n");
181378064Sume				break;
181478064Sume			}
181578064Sume			if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY],
181678064Sume			    rta[RTAX_NETMASK]) == 0) {
181755163Sshin				rtable++;	/*just to be sure*/
181855163Sshin			}
181955163Sshin			break;
182055163Sshin		case RTM_CHANGE:
182155163Sshin		case RTM_REDIRECT:
182255163Sshin			trace(1, "\tnot supported yet, ignored\n");
182355163Sshin			break;
182455163Sshin		case RTM_DELADDR:
182555163Sshin			if (!rta[RTAX_NETMASK] || !rta[RTAX_IFA]) {
182655163Sshin				trace(1, "\tno netmask or ifa given, ignored\n");
182755163Sshin				break;
182855163Sshin			}
182955163Sshin			if (ifam->ifam_index < nindex2ifc)
183055163Sshin				ifcp = index2ifc[ifam->ifam_index];
183155163Sshin			else
183255163Sshin				ifcp = NULL;
183355163Sshin			if (!ifcp) {
183455163Sshin				trace(1, "\tinvalid ifam_index %d, ignored\n",
183555163Sshin					ifam->ifam_index);
183655163Sshin				break;
183755163Sshin			}
183878064Sume			if (!rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK]))
183978064Sume				iface++;
184055163Sshin			break;
184155163Sshin		case RTM_OLDADD:
184255163Sshin		case RTM_OLDDEL:
184355163Sshin			trace(1, "\tnot supported yet, ignored\n");
184455163Sshin			break;
184555163Sshin		}
184655163Sshin
184755163Sshin	}
184855163Sshin
184955163Sshin	if (iface) {
185055163Sshin		trace(1, "rtsock: reconfigure interfaces, refresh interface routes\n");
185155163Sshin		ifconfig();
185255163Sshin		for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next)
185378064Sume			if (ifcp->ifc_cflags & IFC_CHANGED) {
185478064Sume				if (ifrt(ifcp, 1)) {
185578064Sume					for (ic = ifc; ic; ic = ic->ifc_next) {
185678064Sume						if (ifcp->ifc_index == ic->ifc_index)
185778064Sume							continue;
185878064Sume						if (ic->ifc_flags & IFF_UP)
185978064Sume							ripsend(ic, &ic->ifc_ripsin,
186078064Sume							RRTF_CHANGED);
186178064Sume					}
186278064Sume					/* Reset the flag */
186378064Sume					for (rrt = riprt; rrt; rrt = rrt->rrt_next)
186478064Sume						rrt->rrt_rflags &= ~RRTF_CHANGED;
186578064Sume				}
186678064Sume				ifcp->ifc_cflags &= ~IFC_CHANGED;
186778064Sume			}
186855163Sshin	}
186955163Sshin	if (rtable) {
187055163Sshin		trace(1, "rtsock: read routing table again\n");
187155163Sshin		krtread(1);
187255163Sshin	}
187355163Sshin}
187455163Sshin
187555163Sshin/*
187655163Sshin * remove specified route from the internal routing table.
187755163Sshin */
187855163Sshinint
187955163Sshinrt_del(sdst, sgw, smask)
188055163Sshin	const struct sockaddr_in6 *sdst;
188155163Sshin	const struct sockaddr_in6 *sgw;
188255163Sshin	const struct sockaddr_in6 *smask;
188355163Sshin{
188455163Sshin	const struct in6_addr *dst = NULL;
188555163Sshin	const struct in6_addr *gw = NULL;
188655163Sshin	int prefix;
188755163Sshin	struct netinfo6 ni6;
188855163Sshin	struct riprt *rrt = NULL;
188955163Sshin	time_t t_lifetime;
189055163Sshin
189155163Sshin	if (sdst->sin6_family != AF_INET6) {
189255163Sshin		trace(1, "\tother AF, ignored\n");
189355163Sshin		return -1;
189455163Sshin	}
189555163Sshin	if (IN6_IS_ADDR_LINKLOCAL(&sdst->sin6_addr)
189655163Sshin	 || IN6_ARE_ADDR_EQUAL(&sdst->sin6_addr, &in6addr_loopback)
189755163Sshin	 || IN6_IS_ADDR_MULTICAST(&sdst->sin6_addr)) {
189855163Sshin		trace(1, "\taddress %s not interesting, ignored\n",
189955163Sshin			inet6_n2p(&sdst->sin6_addr));
190055163Sshin		return -1;
190155163Sshin	}
190255163Sshin	dst = &sdst->sin6_addr;
190378064Sume	if (sgw->sin6_family == AF_INET6) {
190455163Sshin		/* easy case */
190555163Sshin		gw = &sgw->sin6_addr;
190678064Sume		prefix = sin6mask2len(smask);
190755163Sshin	} else if (sgw->sin6_family == AF_LINK) {
190855163Sshin		/*
190955163Sshin		 * Interface route... a hard case.  We need to get the prefix
191055163Sshin		 * length from the kernel, but we now are parsing rtmsg.
191155163Sshin		 * We'll purge matching routes from my list, then get the
191255163Sshin		 * fresh list.
191355163Sshin		 */
191455163Sshin		struct riprt *longest;
1915108533Sschweikh		trace(1, "\t%s is an interface route, guessing prefixlen\n",
191655163Sshin			inet6_n2p(dst));
191755163Sshin		longest = NULL;
191855163Sshin		for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
191955163Sshin			if (IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
192055163Sshin					&sdst->sin6_addr)
192155163Sshin			 && IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) {
192255163Sshin				if (!longest
192355163Sshin				 || longest->rrt_info.rip6_plen <
192455163Sshin						 rrt->rrt_info.rip6_plen) {
192555163Sshin					longest = rrt;
192655163Sshin				}
192755163Sshin			}
192855163Sshin		}
192955163Sshin		rrt = longest;
193055163Sshin		if (!rrt) {
193155163Sshin			trace(1, "\tno matching interface route found\n");
193255163Sshin			return -1;
193355163Sshin		}
193455163Sshin		gw = &in6addr_loopback;
193555163Sshin		prefix = rrt->rrt_info.rip6_plen;
193655163Sshin	} else {
193778064Sume		trace(1, "\tunsupported af: (gw=%d)\n", sgw->sin6_family);
193855163Sshin		return -1;
193955163Sshin	}
194055163Sshin
194155163Sshin	trace(1, "\tdeleting %s/%d ", inet6_n2p(dst), prefix);
194255163Sshin	trace(1, "gw %s\n", inet6_n2p(gw));
194355163Sshin	t_lifetime = time(NULL) - RIP_LIFETIME;
194455163Sshin	/* age route for interface address */
194555163Sshin	memset(&ni6, 0, sizeof(ni6));
194655163Sshin	ni6.rip6_dest = *dst;
194755163Sshin	ni6.rip6_plen = prefix;
194855163Sshin	applyplen(&ni6.rip6_dest, ni6.rip6_plen);	/*to be sure*/
194955163Sshin	trace(1, "\tfind route %s/%d\n", inet6_n2p(&ni6.rip6_dest),
195055163Sshin		ni6.rip6_plen);
195178064Sume	if (!rrt && (rrt = rtsearch(&ni6, NULL)) == NULL) {
195255163Sshin		trace(1, "\tno route found\n");
195355163Sshin		return -1;
195455163Sshin	}
195578064Sume#if 0
195655163Sshin	if ((rrt->rrt_flags & RTF_STATIC) == 0) {
195755163Sshin		trace(1, "\tyou can delete static routes only\n");
195878064Sume	} else
195978064Sume#endif
196078064Sume	if (!IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, gw)) {
196155163Sshin		trace(1, "\tgw mismatch: %s <-> ",
196255163Sshin			inet6_n2p(&rrt->rrt_gw));
196355163Sshin		trace(1, "%s\n", inet6_n2p(gw));
196455163Sshin	} else {
196555163Sshin		trace(1, "\troute found, age it\n");
196655163Sshin		if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
196755163Sshin			rrt->rrt_t = t_lifetime;
196855163Sshin			rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
196955163Sshin		}
197055163Sshin	}
197155163Sshin	return 0;
197255163Sshin}
197355163Sshin
197455163Sshin/*
197555163Sshin * remove specified address from internal interface/routing table.
197655163Sshin */
197755163Sshinint
197855163Sshinrt_deladdr(ifcp, sifa, smask)
197955163Sshin	struct ifc *ifcp;
198055163Sshin	const struct sockaddr_in6 *sifa;
198155163Sshin	const struct sockaddr_in6 *smask;
198255163Sshin{
198355163Sshin	const struct in6_addr *addr = NULL;
198455163Sshin	int prefix;
198555163Sshin	struct ifac *ifa = NULL;
198655163Sshin	struct netinfo6 ni6;
198755163Sshin	struct riprt *rrt = NULL;
198855163Sshin	time_t t_lifetime;
198955163Sshin	int updated = 0;
199055163Sshin
199178064Sume	if (sifa->sin6_family != AF_INET6) {
199255163Sshin		trace(1, "\tother AF, ignored\n");
199355163Sshin		return -1;
199455163Sshin	}
199555163Sshin	addr = &sifa->sin6_addr;
199678064Sume	prefix = sin6mask2len(smask);
199755163Sshin
199855163Sshin	trace(1, "\tdeleting %s/%d from %s\n",
199955163Sshin		inet6_n2p(addr), prefix, ifcp->ifc_name);
200055163Sshin	ifa = ifa_match(ifcp, addr, prefix);
200155163Sshin	if (!ifa) {
200255163Sshin		trace(1, "\tno matching ifa found for %s/%d on %s\n",
200355163Sshin			inet6_n2p(addr), prefix, ifcp->ifc_name);
200455163Sshin		return -1;
200555163Sshin	}
200655163Sshin	if (ifa->ifa_conf != ifcp) {
200755163Sshin		trace(1, "\taddress table corrupt: back pointer does not match "
200855163Sshin			"(%s != %s)\n",
200955163Sshin			ifcp->ifc_name, ifa->ifa_conf->ifc_name);
201055163Sshin		return -1;
201155163Sshin	}
201255163Sshin	/* remove ifa from interface */
201355163Sshin	if (ifcp->ifc_addr == ifa)
201455163Sshin		ifcp->ifc_addr = ifa->ifa_next;
201555163Sshin	else {
201655163Sshin		struct ifac *p;
201755163Sshin		for (p = ifcp->ifc_addr; p; p = p->ifa_next) {
201855163Sshin			if (p->ifa_next == ifa) {
201955163Sshin				p->ifa_next = ifa->ifa_next;
202055163Sshin				break;
202155163Sshin			}
202255163Sshin		}
202355163Sshin	}
202455163Sshin	ifa->ifa_next = NULL;
202555163Sshin	ifa->ifa_conf = NULL;
202655163Sshin	t_lifetime = time(NULL) - RIP_LIFETIME;
202755163Sshin	/* age route for interface address */
202855163Sshin	memset(&ni6, 0, sizeof(ni6));
202955163Sshin	ni6.rip6_dest = ifa->ifa_addr;
203055163Sshin	ni6.rip6_plen = ifa->ifa_plen;
203155163Sshin	applyplen(&ni6.rip6_dest, ni6.rip6_plen);
203255163Sshin	trace(1, "\tfind interface route %s/%d on %d\n",
203355163Sshin		inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index);
203478064Sume	if ((rrt = rtsearch(&ni6, NULL)) != NULL) {
203555163Sshin		struct in6_addr none;
203655163Sshin		memset(&none, 0, sizeof(none));
203778064Sume		if (rrt->rrt_index == ifcp->ifc_index &&
203878064Sume		    (IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &none) ||
203978064Sume		     IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw))) {
204055163Sshin			trace(1, "\troute found, age it\n");
204155163Sshin			if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
204255163Sshin				rrt->rrt_t = t_lifetime;
204355163Sshin				rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
204455163Sshin			}
204555163Sshin			updated++;
204655163Sshin		} else {
204755163Sshin			trace(1, "\tnon-interface route found: %s/%d on %d\n",
204855163Sshin				inet6_n2p(&rrt->rrt_info.rip6_dest),
204955163Sshin				rrt->rrt_info.rip6_plen,
205055163Sshin				rrt->rrt_index);
205155163Sshin		}
205255163Sshin	} else
205355163Sshin		trace(1, "\tno interface route found\n");
205455163Sshin	/* age route for p2p destination */
205555163Sshin	if (ifcp->ifc_flags & IFF_POINTOPOINT) {
205655163Sshin		memset(&ni6, 0, sizeof(ni6));
205755163Sshin		ni6.rip6_dest = ifa->ifa_raddr;
205855163Sshin		ni6.rip6_plen = 128;
205955163Sshin		applyplen(&ni6.rip6_dest, ni6.rip6_plen);	/*to be sure*/
206055163Sshin		trace(1, "\tfind p2p route %s/%d on %d\n",
206155163Sshin			inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen,
206255163Sshin			ifcp->ifc_index);
206378064Sume		if ((rrt = rtsearch(&ni6, NULL)) != NULL) {
206478064Sume			if (rrt->rrt_index == ifcp->ifc_index &&
206578064Sume			    IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &ifa->ifa_addr)) {
206655163Sshin				trace(1, "\troute found, age it\n");
206755163Sshin				if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
206855163Sshin					rrt->rrt_t = t_lifetime;
206955163Sshin					rrt->rrt_info.rip6_metric =
207078064Sume					    HOPCNT_INFINITY6;
207155163Sshin					updated++;
207255163Sshin				}
207355163Sshin			} else {
207455163Sshin				trace(1, "\tnon-p2p route found: %s/%d on %d\n",
207555163Sshin					inet6_n2p(&rrt->rrt_info.rip6_dest),
207655163Sshin					rrt->rrt_info.rip6_plen,
207755163Sshin					rrt->rrt_index);
207855163Sshin			}
207955163Sshin		} else
208055163Sshin			trace(1, "\tno p2p route found\n");
208155163Sshin	}
208255163Sshin	return updated ? 0 : -1;
208355163Sshin}
208455163Sshin
208555163Sshin/*
208655163Sshin * Get each interface address and put those interface routes to the route
208755163Sshin * list.
208855163Sshin */
208978064Sumeint
209055163Sshinifrt(ifcp, again)
209162607Sitojun	struct ifc *ifcp;
209255163Sshin	int again;
209355163Sshin{
209462607Sitojun	struct ifac *ifa;
2095119042Sume	struct riprt *rrt = NULL, *search_rrt, *prev_rrt, *loop_rrt;
209662607Sitojun	struct netinfo6 *np;
209778064Sume	time_t t_lifetime;
209878064Sume	int need_trigger = 0;
209955163Sshin
2100122677Sume#if 0
210155163Sshin	if (ifcp->ifc_flags & IFF_LOOPBACK)
210278064Sume		return 0;			/* ignore loopback */
2103122677Sume#endif
2104122677Sume
210562607Sitojun	if (ifcp->ifc_flags & IFF_POINTOPOINT) {
210662607Sitojun		ifrt_p2p(ifcp, again);
210778064Sume		return 0;
210862607Sitojun	}
210962607Sitojun
211055163Sshin	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
211162607Sitojun		if (IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) {
211262607Sitojun#if 0
211362607Sitojun			trace(1, "route: %s on %s: "
211462607Sitojun			    "skip linklocal interface address\n",
211562607Sitojun			    inet6_n2p(&ifa->ifa_addr), ifcp->ifc_name);
211662607Sitojun#endif
211762607Sitojun			continue;
211862607Sitojun		}
211962607Sitojun		if (IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_addr)) {
212062607Sitojun#if 0
212162607Sitojun			trace(1, "route: %s: skip unspec interface address\n",
212262607Sitojun			    ifcp->ifc_name);
212362607Sitojun#endif
212462607Sitojun			continue;
212562607Sitojun		}
2126122677Sume		if (IN6_IS_ADDR_LOOPBACK(&ifa->ifa_addr)) {
2127122677Sume#if 0
2128122677Sume			trace(1, "route: %s: skip loopback address\n",
2129122677Sume			    ifcp->ifc_name);
2130122677Sume#endif
2131122677Sume			continue;
2132122677Sume		}
213378064Sume		if (ifcp->ifc_flags & IFF_UP) {
213478064Sume			if ((rrt = MALLOC(struct riprt)) == NULL)
213578064Sume				fatal("malloc: struct riprt");
213678064Sume			memset(rrt, 0, sizeof(*rrt));
213778064Sume			rrt->rrt_same = NULL;
213878064Sume			rrt->rrt_index = ifcp->ifc_index;
213978064Sume			rrt->rrt_t = 0;	/* don't age */
214078064Sume			rrt->rrt_info.rip6_dest = ifa->ifa_addr;
214178064Sume			rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
214278064Sume			rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric;
214378064Sume			rrt->rrt_info.rip6_plen = ifa->ifa_plen;
2144122677Sume			if (ifa->ifa_plen == 128)
2145122677Sume				rrt->rrt_flags = RTF_HOST;
2146122677Sume			else
2147122677Sume				rrt->rrt_flags = RTF_CLONING;
214878064Sume			rrt->rrt_rflags |= RRTF_CHANGED;
214978064Sume			applyplen(&rrt->rrt_info.rip6_dest, ifa->ifa_plen);
215078064Sume			memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
215178064Sume			rrt->rrt_gw = ifa->ifa_addr;
215278064Sume			np = &rrt->rrt_info;
215378064Sume			search_rrt = rtsearch(np, &prev_rrt);
215478064Sume			if (search_rrt != NULL) {
2155119042Sume				if (search_rrt->rrt_info.rip6_metric <=
215678064Sume				    rrt->rrt_info.rip6_metric) {
215778064Sume					/* Already have better route */
215878064Sume					if (!again) {
215978064Sume						trace(1, "route: %s/%d: "
216078064Sume						    "already registered (%s)\n",
216178064Sume						    inet6_n2p(&np->rip6_dest), np->rip6_plen,
216278064Sume						    ifcp->ifc_name);
216378064Sume					}
2164119042Sume					goto next;
216578064Sume				}
2166119042Sume
2167119042Sume				if (prev_rrt)
2168119042Sume					prev_rrt->rrt_next = rrt->rrt_next;
2169119042Sume				else
2170119042Sume					riprt = rrt->rrt_next;
2171119042Sume				delroute(&rrt->rrt_info, &rrt->rrt_gw);
217278064Sume			}
217355163Sshin			/* Attach the route to the list */
217462607Sitojun			trace(1, "route: %s/%d: register route (%s)\n",
217562607Sitojun			    inet6_n2p(&np->rip6_dest), np->rip6_plen,
217662607Sitojun			    ifcp->ifc_name);
217755163Sshin			rrt->rrt_next = riprt;
217855163Sshin			riprt = rrt;
217978064Sume			addroute(rrt, &rrt->rrt_gw, ifcp);
2180119042Sume			rrt = NULL;
218178064Sume			sendrequest(ifcp);
218278064Sume			ripsend(ifcp, &ifcp->ifc_ripsin, 0);
218378064Sume			need_trigger = 1;
218455163Sshin		} else {
218578064Sume			for (loop_rrt = riprt; loop_rrt; loop_rrt = loop_rrt->rrt_next) {
218678064Sume				if (loop_rrt->rrt_index == ifcp->ifc_index) {
218778064Sume					t_lifetime = time(NULL) - RIP_LIFETIME;
218878064Sume					if (loop_rrt->rrt_t == 0 || loop_rrt->rrt_t > t_lifetime) {
218978064Sume						loop_rrt->rrt_t = t_lifetime;
219078064Sume						loop_rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
219178064Sume						loop_rrt->rrt_rflags |= RRTF_CHANGED;
219278064Sume						need_trigger = 1;
219378064Sume					}
219478064Sume				}
219555163Sshin			}
219678064Sume                }
2197119042Sume	next:
2198119042Sume		if (rrt)
2199119042Sume			free(rrt);
220062607Sitojun	}
220178064Sume	return need_trigger;
220262607Sitojun}
220355163Sshin
220462607Sitojun/*
220562607Sitojun * there are couple of p2p interface routing models.  "behavior" lets
220662607Sitojun * you pick one.  it looks that gated behavior fits best with BSDs,
2207119035Sume * since BSD kernels do not look at prefix length on p2p interfaces.
220862607Sitojun */
220962607Sitojunvoid
221062607Sitojunifrt_p2p(ifcp, again)
221162607Sitojun	struct ifc *ifcp;
221262607Sitojun	int again;
221362607Sitojun{
221462607Sitojun	struct ifac *ifa;
221578064Sume	struct riprt *rrt, *orrt, *prevrrt;
221662607Sitojun	struct netinfo6 *np;
221762607Sitojun	struct in6_addr addr, dest;
221862607Sitojun	int advert, ignore, i;
221962607Sitojun#define P2PADVERT_NETWORK	1
222062607Sitojun#define P2PADVERT_ADDR		2
222162607Sitojun#define P2PADVERT_DEST		4
222262607Sitojun#define P2PADVERT_MAX		4
222362607Sitojun	const enum { CISCO, GATED, ROUTE6D } behavior = GATED;
222478064Sume	const char *category = "";
222562607Sitojun	const char *noadv;
222662607Sitojun
222762607Sitojun	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
222862607Sitojun		addr = ifa->ifa_addr;
222962607Sitojun		dest = ifa->ifa_raddr;
223062607Sitojun		applyplen(&addr, ifa->ifa_plen);
223162607Sitojun		applyplen(&dest, ifa->ifa_plen);
223262607Sitojun		advert = ignore = 0;
223362607Sitojun		switch (behavior) {
223462607Sitojun		case CISCO:
223562607Sitojun			/*
223662607Sitojun			 * honor addr/plen, just like normal shared medium
223762607Sitojun			 * interface.  this may cause trouble if you reuse
223862607Sitojun			 * addr/plen on other interfaces.
223962607Sitojun			 *
224062607Sitojun			 * advertise addr/plen.
224162607Sitojun			 */
224262607Sitojun			advert |= P2PADVERT_NETWORK;
224362607Sitojun			break;
224462607Sitojun		case GATED:
224562607Sitojun			/*
224662607Sitojun			 * prefixlen on p2p interface is meaningless.
224762607Sitojun			 * advertise addr/128 and dest/128.
224862607Sitojun			 *
224962607Sitojun			 * do not install network route to route6d routing
225062607Sitojun			 * table (if we do, it would prevent route installation
225162607Sitojun			 * for other p2p interface that shares addr/plen).
225278064Sume			 *
225378064Sume			 * XXX what should we do if dest is ::?  it will not
225478064Sume			 * get announced anyways (see following filter),
225578064Sume			 * but we need to think.
225662607Sitojun			 */
225762607Sitojun			advert |= P2PADVERT_ADDR;
225862607Sitojun			advert |= P2PADVERT_DEST;
225962607Sitojun			ignore |= P2PADVERT_NETWORK;
226062607Sitojun			break;
226162607Sitojun		case ROUTE6D:
226262607Sitojun			/*
226378064Sume			 * just for testing.  actually the code is redundant
226478064Sume			 * given the current p2p interface address assignment
226578064Sume			 * rule for kame kernel.
226678064Sume			 *
226778064Sume			 * intent:
226878064Sume			 *	A/n -> announce A/n
226978064Sume			 *	A B/n, A and B share prefix -> A/n (= B/n)
227078064Sume			 *	A B/n, do not share prefix -> A/128 and B/128
227178064Sume			 * actually, A/64 and A B/128 are the only cases
227278064Sume			 * permitted by the kernel:
227378064Sume			 *	A/64 -> A/64
227478064Sume			 *	A B/128 -> A/128 and B/128
227562607Sitojun			 */
227678064Sume			if (!IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_raddr)) {
227778064Sume				if (IN6_ARE_ADDR_EQUAL(&addr, &dest))
227878064Sume					advert |= P2PADVERT_NETWORK;
227978064Sume				else {
228078064Sume					advert |= P2PADVERT_ADDR;
228178064Sume					advert |= P2PADVERT_DEST;
228278064Sume					ignore |= P2PADVERT_NETWORK;
228378064Sume				}
228478064Sume			} else
228562607Sitojun				advert |= P2PADVERT_NETWORK;
228662607Sitojun			break;
228762607Sitojun		}
228862607Sitojun
228962607Sitojun		for (i = 1; i <= P2PADVERT_MAX; i *= 2) {
229062607Sitojun			if ((ignore & i) != 0)
229162607Sitojun				continue;
229278064Sume			if ((rrt = MALLOC(struct riprt)) == NULL) {
229355163Sshin				fatal("malloc: struct riprt");
229478064Sume				/*NOTREACHED*/
229578064Sume			}
229662607Sitojun			memset(rrt, 0, sizeof(*rrt));
229755163Sshin			rrt->rrt_same = NULL;
229855163Sshin			rrt->rrt_index = ifcp->ifc_index;
229962607Sitojun			rrt->rrt_t = 0;	/* don't age */
230062607Sitojun			switch (i) {
230162607Sitojun			case P2PADVERT_NETWORK:
230262607Sitojun				rrt->rrt_info.rip6_dest = ifa->ifa_addr;
230362607Sitojun				rrt->rrt_info.rip6_plen = ifa->ifa_plen;
230462607Sitojun				applyplen(&rrt->rrt_info.rip6_dest,
230562607Sitojun				    ifa->ifa_plen);
230662607Sitojun				category = "network";
230762607Sitojun				break;
230862607Sitojun			case P2PADVERT_ADDR:
230962607Sitojun				rrt->rrt_info.rip6_dest = ifa->ifa_addr;
231062607Sitojun				rrt->rrt_info.rip6_plen = 128;
231178064Sume				rrt->rrt_gw = in6addr_loopback;
231262607Sitojun				category = "addr";
231362607Sitojun				break;
231462607Sitojun			case P2PADVERT_DEST:
231562607Sitojun				rrt->rrt_info.rip6_dest = ifa->ifa_raddr;
231662607Sitojun				rrt->rrt_info.rip6_plen = 128;
231778064Sume				rrt->rrt_gw = ifa->ifa_addr;
231862607Sitojun				category = "dest";
231962607Sitojun				break;
232062607Sitojun			}
232162607Sitojun			if (IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_info.rip6_dest) ||
232262607Sitojun			    IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_info.rip6_dest)) {
232362607Sitojun#if 0
232462607Sitojun				trace(1, "route: %s: skip unspec/linklocal "
232562607Sitojun				    "(%s on %s)\n", category, ifcp->ifc_name);
232662607Sitojun#endif
232762607Sitojun				free(rrt);
232862607Sitojun				continue;
232962607Sitojun			}
233062607Sitojun			if ((advert & i) == 0) {
233162607Sitojun				rrt->rrt_rflags |= RRTF_NOADVERTISE;
233262607Sitojun				noadv = ", NO-ADV";
233362607Sitojun			} else
233462607Sitojun				noadv = "";
233555163Sshin			rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
233662607Sitojun			rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric;
233755163Sshin			np = &rrt->rrt_info;
233878064Sume			orrt = rtsearch(np, &prevrrt);
233978064Sume			if (!orrt) {
234055163Sshin				/* Attach the route to the list */
234162607Sitojun				trace(1, "route: %s/%d: register route "
234262607Sitojun				    "(%s on %s%s)\n",
234362607Sitojun				    inet6_n2p(&np->rip6_dest), np->rip6_plen,
234462607Sitojun				    category, ifcp->ifc_name, noadv);
234555163Sshin				rrt->rrt_next = riprt;
234655163Sshin				riprt = rrt;
234778064Sume			} else if (rrt->rrt_index != orrt->rrt_index ||
234878064Sume			    rrt->rrt_info.rip6_metric != orrt->rrt_info.rip6_metric) {
234978064Sume				/* swap route */
235078064Sume				rrt->rrt_next = orrt->rrt_next;
235178064Sume				if (prevrrt)
235278064Sume					prevrrt->rrt_next = rrt;
235378064Sume				else
235478064Sume					riprt = rrt;
235578064Sume				free(orrt);
235678064Sume
235778064Sume				trace(1, "route: %s/%d: update (%s on %s%s)\n",
235878064Sume				    inet6_n2p(&np->rip6_dest), np->rip6_plen,
235978064Sume				    category, ifcp->ifc_name, noadv);
236055163Sshin			} else {
236155163Sshin				/* Already found */
236255163Sshin				if (!again) {
236362607Sitojun					trace(1, "route: %s/%d: "
236462607Sitojun					    "already registered (%s on %s%s)\n",
236562607Sitojun					    inet6_n2p(&np->rip6_dest),
236662607Sitojun					    np->rip6_plen, category,
236762607Sitojun					    ifcp->ifc_name, noadv);
236855163Sshin				}
236955163Sshin				free(rrt);
237055163Sshin			}
237155163Sshin		}
237255163Sshin	}
237362607Sitojun#undef P2PADVERT_NETWORK
237462607Sitojun#undef P2PADVERT_ADDR
237562607Sitojun#undef P2PADVERT_DEST
237662607Sitojun#undef P2PADVERT_MAX
237755163Sshin}
237855163Sshin
237955163Sshinint
238055163Sshingetifmtu(ifindex)
238155163Sshin	int	ifindex;
238255163Sshin{
238355163Sshin	int	mib[6];
238455163Sshin	char	*buf;
238555163Sshin	size_t	msize;
238655163Sshin	struct	if_msghdr *ifm;
238755163Sshin	int	mtu;
238855163Sshin
238955163Sshin	mib[0] = CTL_NET;
239055163Sshin	mib[1] = PF_ROUTE;
239155163Sshin	mib[2] = 0;
239255163Sshin	mib[3] = AF_INET6;
239355163Sshin	mib[4] = NET_RT_IFLIST;
239455163Sshin	mib[5] = ifindex;
239578064Sume	if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) {
239655163Sshin		fatal("sysctl estimate NET_RT_IFLIST");
239778064Sume		/*NOTREACHED*/
239878064Sume	}
239978064Sume	if ((buf = malloc(msize)) == NULL) {
240055163Sshin		fatal("malloc");
240178064Sume		/*NOTREACHED*/
240278064Sume	}
240378064Sume	if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) {
240455163Sshin		fatal("sysctl NET_RT_IFLIST");
240578064Sume		/*NOTREACHED*/
240678064Sume	}
240755163Sshin	ifm = (struct if_msghdr *)buf;
240855163Sshin	mtu = ifm->ifm_data.ifi_mtu;
240978064Sume	if (ifindex != ifm->ifm_index) {
241055163Sshin		fatal("ifindex does not match with ifm_index");
241178064Sume		/*NOTREACHED*/
241278064Sume	}
241355163Sshin	free(buf);
241455163Sshin	return mtu;
241555163Sshin}
241655163Sshin
241755163Sshinconst char *
241855163Sshinrttypes(rtm)
241955163Sshin	struct rt_msghdr *rtm;
242055163Sshin{
242162607Sitojun#define	RTTYPE(s, f) \
242262607Sitojundo { \
242362607Sitojun	if (rtm->rtm_type == (f)) \
242462607Sitojun		return (s); \
242562607Sitojun} while (0)
242655163Sshin	RTTYPE("ADD", RTM_ADD);
242755163Sshin	RTTYPE("DELETE", RTM_DELETE);
242855163Sshin	RTTYPE("CHANGE", RTM_CHANGE);
242955163Sshin	RTTYPE("GET", RTM_GET);
243055163Sshin	RTTYPE("LOSING", RTM_LOSING);
243155163Sshin	RTTYPE("REDIRECT", RTM_REDIRECT);
243255163Sshin	RTTYPE("MISS", RTM_MISS);
243355163Sshin	RTTYPE("LOCK", RTM_LOCK);
243455163Sshin	RTTYPE("OLDADD", RTM_OLDADD);
243555163Sshin	RTTYPE("OLDDEL", RTM_OLDDEL);
243655163Sshin	RTTYPE("RESOLVE", RTM_RESOLVE);
243755163Sshin	RTTYPE("NEWADDR", RTM_NEWADDR);
243855163Sshin	RTTYPE("DELADDR", RTM_DELADDR);
243955163Sshin	RTTYPE("IFINFO", RTM_IFINFO);
244078064Sume#ifdef RTM_OLDADD
244178064Sume	RTTYPE("OLDADD", RTM_OLDADD);
244278064Sume#endif
244378064Sume#ifdef RTM_OLDDEL
244478064Sume	RTTYPE("OLDDEL", RTM_OLDDEL);
244578064Sume#endif
244678064Sume#ifdef RTM_OIFINFO
244778064Sume	RTTYPE("OIFINFO", RTM_OIFINFO);
244878064Sume#endif
244978064Sume#ifdef RTM_IFANNOUNCE
245078064Sume	RTTYPE("IFANNOUNCE", RTM_IFANNOUNCE);
245178064Sume#endif
245278064Sume#ifdef RTM_NEWMADDR
245378064Sume	RTTYPE("NEWMADDR", RTM_NEWMADDR);
245478064Sume#endif
245578064Sume#ifdef RTM_DELMADDR
245678064Sume	RTTYPE("DELMADDR", RTM_DELMADDR);
245778064Sume#endif
245855163Sshin#undef RTTYPE
245955163Sshin	return NULL;
246055163Sshin}
246155163Sshin
246255163Sshinconst char *
246355163Sshinrtflags(rtm)
246455163Sshin	struct rt_msghdr *rtm;
246555163Sshin{
246655163Sshin	static char buf[BUFSIZ];
246755163Sshin
246878064Sume	/*
246978064Sume	 * letter conflict should be okay.  painful when *BSD diverges...
247078064Sume	 */
247178064Sume	strlcpy(buf, "", sizeof(buf));
247262607Sitojun#define	RTFLAG(s, f) \
247362607Sitojundo { \
247462607Sitojun	if (rtm->rtm_flags & (f)) \
247578064Sume		strlcat(buf, (s), sizeof(buf)); \
247662607Sitojun} while (0)
247755163Sshin	RTFLAG("U", RTF_UP);
247855163Sshin	RTFLAG("G", RTF_GATEWAY);
247955163Sshin	RTFLAG("H", RTF_HOST);
248055163Sshin	RTFLAG("R", RTF_REJECT);
248155163Sshin	RTFLAG("D", RTF_DYNAMIC);
248255163Sshin	RTFLAG("M", RTF_MODIFIED);
248355163Sshin	RTFLAG("d", RTF_DONE);
248455163Sshin#ifdef	RTF_MASK
248555163Sshin	RTFLAG("m", RTF_MASK);
248655163Sshin#endif
248755163Sshin	RTFLAG("C", RTF_CLONING);
248878064Sume#ifdef RTF_CLONED
248978064Sume	RTFLAG("c", RTF_CLONED);
249078064Sume#endif
249178064Sume#ifdef RTF_PRCLONING
249278064Sume	RTFLAG("c", RTF_PRCLONING);
249378064Sume#endif
249478064Sume#ifdef RTF_WASCLONED
249578064Sume	RTFLAG("W", RTF_WASCLONED);
249678064Sume#endif
249755163Sshin	RTFLAG("X", RTF_XRESOLVE);
249855163Sshin	RTFLAG("L", RTF_LLINFO);
249955163Sshin	RTFLAG("S", RTF_STATIC);
250055163Sshin	RTFLAG("B", RTF_BLACKHOLE);
250178064Sume#ifdef RTF_PROTO3
250278064Sume	RTFLAG("3", RTF_PROTO3);
250378064Sume#endif
250455163Sshin	RTFLAG("2", RTF_PROTO2);
250555163Sshin	RTFLAG("1", RTF_PROTO1);
250678064Sume#ifdef RTF_BROADCAST
250778064Sume	RTFLAG("b", RTF_BROADCAST);
250878064Sume#endif
250978064Sume#ifdef RTF_DEFAULT
251078064Sume	RTFLAG("d", RTF_DEFAULT);
251178064Sume#endif
251278064Sume#ifdef RTF_ISAROUTER
251378064Sume	RTFLAG("r", RTF_ISAROUTER);
251478064Sume#endif
251578064Sume#ifdef RTF_TUNNEL
251678064Sume	RTFLAG("T", RTF_TUNNEL);
251778064Sume#endif
251878064Sume#ifdef RTF_AUTH
251978064Sume	RTFLAG("A", RTF_AUTH);
252078064Sume#endif
252178064Sume#ifdef RTF_CRYPT
252278064Sume	RTFLAG("E", RTF_CRYPT);
252378064Sume#endif
252455163Sshin#undef RTFLAG
252555163Sshin	return buf;
252655163Sshin}
252755163Sshin
252855163Sshinconst char *
252955163Sshinifflags(flags)
253055163Sshin	int flags;
253155163Sshin{
253255163Sshin	static char buf[BUFSIZ];
253355163Sshin
253478064Sume	strlcpy(buf, "", sizeof(buf));
253562607Sitojun#define	IFFLAG(s, f) \
253662607Sitojundo { \
2537119040Sume	if (flags & (f)) { \
253862607Sitojun		if (buf[0]) \
253978064Sume			strlcat(buf, ",", sizeof(buf)); \
2540119040Sume		strlcat(buf, (s), sizeof(buf)); \
254162607Sitojun	} \
254262607Sitojun} while (0)
254355163Sshin	IFFLAG("UP", IFF_UP);
254455163Sshin	IFFLAG("BROADCAST", IFF_BROADCAST);
254555163Sshin	IFFLAG("DEBUG", IFF_DEBUG);
254655163Sshin	IFFLAG("LOOPBACK", IFF_LOOPBACK);
254755163Sshin	IFFLAG("POINTOPOINT", IFF_POINTOPOINT);
254855163Sshin#ifdef IFF_NOTRAILERS
254955163Sshin	IFFLAG("NOTRAILERS", IFF_NOTRAILERS);
255055163Sshin#endif
255178064Sume#ifdef IFF_SMART
255278064Sume	IFFLAG("SMART", IFF_SMART);
255378064Sume#endif
255455163Sshin	IFFLAG("RUNNING", IFF_RUNNING);
255555163Sshin	IFFLAG("NOARP", IFF_NOARP);
255655163Sshin	IFFLAG("PROMISC", IFF_PROMISC);
255755163Sshin	IFFLAG("ALLMULTI", IFF_ALLMULTI);
255855163Sshin	IFFLAG("OACTIVE", IFF_OACTIVE);
255955163Sshin	IFFLAG("SIMPLEX", IFF_SIMPLEX);
256055163Sshin	IFFLAG("LINK0", IFF_LINK0);
256155163Sshin	IFFLAG("LINK1", IFF_LINK1);
256255163Sshin	IFFLAG("LINK2", IFF_LINK2);
256355163Sshin	IFFLAG("MULTICAST", IFF_MULTICAST);
256455163Sshin#undef IFFLAG
256555163Sshin	return buf;
256655163Sshin}
256755163Sshin
256855163Sshinvoid
256955163Sshinkrtread(again)
257055163Sshin	int again;
257155163Sshin{
257255163Sshin	int mib[6];
257355163Sshin	size_t msize;
257455163Sshin	char *buf, *p, *lim;
257555163Sshin	struct rt_msghdr *rtm;
257655163Sshin	int retry;
257755163Sshin	const char *errmsg;
257855163Sshin
257955163Sshin	retry = 0;
258055163Sshin	buf = NULL;
258155163Sshin	mib[0] = CTL_NET;
258255163Sshin	mib[1] = PF_ROUTE;
258355163Sshin	mib[2] = 0;
258455163Sshin	mib[3] = AF_INET6;	/* Address family */
258555163Sshin	mib[4] = NET_RT_DUMP;	/* Dump the kernel routing table */
258655163Sshin	mib[5] = 0;		/* No flags */
258755163Sshin	do {
258855163Sshin		retry++;
258955163Sshin		errmsg = NULL;
259055163Sshin		if (buf)
259155163Sshin			free(buf);
259255163Sshin		if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) {
259355163Sshin			errmsg = "sysctl estimate";
259455163Sshin			continue;
259555163Sshin		}
259655163Sshin		if ((buf = malloc(msize)) == NULL) {
259755163Sshin			errmsg = "malloc";
259855163Sshin			continue;
259955163Sshin		}
260055163Sshin		if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) {
260155163Sshin			errmsg = "sysctl NET_RT_DUMP";
260255163Sshin			continue;
260355163Sshin		}
260455163Sshin	} while (retry < 5 && errmsg != NULL);
260578064Sume	if (errmsg) {
260669279Sume		fatal("%s (with %d retries, msize=%lu)", errmsg, retry,
260769279Sume		    (u_long)msize);
260878064Sume		/*NOTREACHED*/
260978064Sume	} else if (1 < retry)
261055163Sshin		syslog(LOG_INFO, "NET_RT_DUMP %d retires", retry);
261155163Sshin
261255163Sshin	lim = buf + msize;
261355163Sshin	for (p = buf; p < lim; p += rtm->rtm_msglen) {
261455163Sshin		rtm = (struct rt_msghdr *)p;
261555163Sshin		rt_entry(rtm, again);
261655163Sshin	}
261755163Sshin	free(buf);
261855163Sshin}
261955163Sshin
262055163Sshinvoid
262155163Sshinrt_entry(rtm, again)
262255163Sshin	struct rt_msghdr *rtm;
262355163Sshin	int again;
262455163Sshin{
262555163Sshin	struct	sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask;
262655163Sshin	struct	sockaddr_in6 *sin6_genmask, *sin6_ifp;
262755163Sshin	char	*rtmp, *ifname = NULL;
262878064Sume	struct	riprt *rrt, *orrt;
262955163Sshin	struct	netinfo6 *np;
263055163Sshin	int	s;
263155163Sshin
263255163Sshin	sin6_dst = sin6_gw = sin6_mask = sin6_genmask = sin6_ifp = 0;
263355163Sshin	if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags &
263462607Sitojun		(RTF_CLONING|RTF_XRESOLVE|RTF_LLINFO|RTF_BLACKHOLE)) {
263555163Sshin		return;		/* not interested in the link route */
263662607Sitojun	}
263769279Sume	/* do not look at cloned routes */
263869279Sume#ifdef RTF_WASCLONED
263969279Sume	if (rtm->rtm_flags & RTF_WASCLONED)
264069279Sume		return;
264169279Sume#endif
264269279Sume#ifdef RTF_CLONED
264369279Sume	if (rtm->rtm_flags & RTF_CLONED)
264469279Sume		return;
264569279Sume#endif
264669279Sume	/*
264769279Sume	 * do not look at dynamic routes.
264869279Sume	 * netbsd/openbsd cloned routes have UGHD.
264969279Sume	 */
265069279Sume	if (rtm->rtm_flags & RTF_DYNAMIC)
265169279Sume		return;
265255163Sshin	rtmp = (char *)(rtm + 1);
265355163Sshin	/* Destination */
265455163Sshin	if ((rtm->rtm_addrs & RTA_DST) == 0)
265555163Sshin		return;		/* ignore routes without destination address */
265655163Sshin	sin6_dst = (struct sockaddr_in6 *)rtmp;
265764631Sitojun	rtmp += ROUNDUP(sin6_dst->sin6_len);
265855163Sshin	if (rtm->rtm_addrs & RTA_GATEWAY) {
265955163Sshin		sin6_gw = (struct sockaddr_in6 *)rtmp;
266055163Sshin		rtmp += ROUNDUP(sin6_gw->sin6_len);
266155163Sshin	}
266255163Sshin	if (rtm->rtm_addrs & RTA_NETMASK) {
266355163Sshin		sin6_mask = (struct sockaddr_in6 *)rtmp;
266455163Sshin		rtmp += ROUNDUP(sin6_mask->sin6_len);
266555163Sshin	}
266655163Sshin	if (rtm->rtm_addrs & RTA_GENMASK) {
266755163Sshin		sin6_genmask = (struct sockaddr_in6 *)rtmp;
266855163Sshin		rtmp += ROUNDUP(sin6_genmask->sin6_len);
266955163Sshin	}
267055163Sshin	if (rtm->rtm_addrs & RTA_IFP) {
267155163Sshin		sin6_ifp = (struct sockaddr_in6 *)rtmp;
267255163Sshin		rtmp += ROUNDUP(sin6_ifp->sin6_len);
267355163Sshin	}
267455163Sshin
267555163Sshin	/* Destination */
267655163Sshin	if (sin6_dst->sin6_family != AF_INET6)
267755163Sshin		return;
267855163Sshin	if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst->sin6_addr))
267955163Sshin		return;		/* Link-local */
268055163Sshin	if (IN6_ARE_ADDR_EQUAL(&sin6_dst->sin6_addr, &in6addr_loopback))
268155163Sshin		return;		/* Loopback */
268255163Sshin	if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr))
268355163Sshin		return;
268455163Sshin
268578064Sume	if ((rrt = MALLOC(struct riprt)) == NULL) {
268655163Sshin		fatal("malloc: struct riprt");
268778064Sume		/*NOTREACHED*/
268878064Sume	}
268962607Sitojun	memset(rrt, 0, sizeof(*rrt));
269055163Sshin	np = &rrt->rrt_info;
269155163Sshin	rrt->rrt_same = NULL;
269255163Sshin	rrt->rrt_t = time(NULL);
269355163Sshin	if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC))
269455163Sshin		rrt->rrt_t = 0;	/* Don't age static routes */
2695122677Sume	if ((rtm->rtm_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST)
2696122677Sume		rrt->rrt_t = 0;	/* Don't age non-gateway host routes */
269755163Sshin	np->rip6_tag = 0;
269855163Sshin	np->rip6_metric = rtm->rtm_rmx.rmx_hopcount;
269955163Sshin	if (np->rip6_metric < 1)
270055163Sshin		np->rip6_metric = 1;
270155163Sshin	rrt->rrt_flags = rtm->rtm_flags;
270255163Sshin	np->rip6_dest = sin6_dst->sin6_addr;
270355163Sshin
270455163Sshin	/* Mask or plen */
270555163Sshin	if (rtm->rtm_flags & RTF_HOST)
270655163Sshin		np->rip6_plen = 128;	/* Host route */
270778064Sume	else if (sin6_mask)
270878064Sume		np->rip6_plen = sin6mask2len(sin6_mask);
270978064Sume	else
271055163Sshin		np->rip6_plen = 0;
271155163Sshin
271278064Sume	orrt = rtsearch(np, NULL);
271378064Sume	if (orrt && orrt->rrt_info.rip6_metric != HOPCNT_INFINITY6) {
271455163Sshin		/* Already found */
271555163Sshin		if (!again) {
271655163Sshin			trace(1, "route: %s/%d flags %s: already registered\n",
271755163Sshin				inet6_n2p(&np->rip6_dest), np->rip6_plen,
271855163Sshin				rtflags(rtm));
271955163Sshin		}
272055163Sshin		free(rrt);
272155163Sshin		return;
272255163Sshin	}
272355163Sshin	/* Gateway */
272455163Sshin	if (!sin6_gw)
272555163Sshin		memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
272655163Sshin	else {
272755163Sshin		if (sin6_gw->sin6_family == AF_INET6)
272855163Sshin			rrt->rrt_gw = sin6_gw->sin6_addr;
272955163Sshin		else if (sin6_gw->sin6_family == AF_LINK) {
273055163Sshin			/* XXX in case ppp link? */
273155163Sshin			rrt->rrt_gw = in6addr_loopback;
273255163Sshin		} else
273355163Sshin			memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
273455163Sshin	}
273555163Sshin	trace(1, "route: %s/%d flags %s",
273655163Sshin		inet6_n2p(&np->rip6_dest), np->rip6_plen, rtflags(rtm));
273755163Sshin	trace(1, " gw %s", inet6_n2p(&rrt->rrt_gw));
273855163Sshin
273955163Sshin	/* Interface */
274055163Sshin	s = rtm->rtm_index;
274155163Sshin	if (s < nindex2ifc && index2ifc[s])
274255163Sshin		ifname = index2ifc[s]->ifc_name;
274358070Sshin	else {
274458070Sshin		trace(1, " not configured\n");
274562607Sitojun		free(rrt);
274658070Sshin		return;
274758070Sshin	}
274862607Sitojun	trace(1, " if %s sock %d", ifname, s);
274955163Sshin	rrt->rrt_index = s;
275055163Sshin
275162607Sitojun	trace(1, "\n");
275262607Sitojun
275355163Sshin	/* Check gateway */
275455163Sshin	if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_gw) &&
2755122677Sume	    !IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw) &&
2756122677Sume	    (rrt->rrt_flags & RTF_LOCAL) == 0) {
275755163Sshin		trace(0, "***** Gateway %s is not a link-local address.\n",
275855163Sshin			inet6_n2p(&rrt->rrt_gw));
275955163Sshin		trace(0, "*****     dest(%s) if(%s) -- Not optimized.\n",
276062607Sitojun			inet6_n2p(&rrt->rrt_info.rip6_dest), ifname);
276162607Sitojun		rrt->rrt_rflags |= RRTF_NH_NOT_LLADDR;
276255163Sshin	}
276355163Sshin
276455163Sshin	/* Put it to the route list */
276578064Sume	if (orrt && orrt->rrt_info.rip6_metric == HOPCNT_INFINITY6) {
276678064Sume		/* replace route list */
276778064Sume		rrt->rrt_next = orrt->rrt_next;
276878064Sume		*orrt = *rrt;
276978064Sume		trace(1, "route: %s/%d flags %s: replace new route\n",
277078064Sume		    inet6_n2p(&np->rip6_dest), np->rip6_plen,
277178064Sume		    rtflags(rtm));
277278064Sume		free(rrt);
277378064Sume	} else {
277478064Sume		rrt->rrt_next = riprt;
277578064Sume		riprt = rrt;
277678064Sume	}
277755163Sshin}
277855163Sshin
277955163Sshinint
278055163Sshinaddroute(rrt, gw, ifcp)
278155163Sshin	struct riprt *rrt;
278255163Sshin	const struct in6_addr *gw;
278355163Sshin	struct ifc *ifcp;
278455163Sshin{
278555163Sshin	struct	netinfo6 *np;
278655163Sshin	u_char	buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ];
278755163Sshin	struct	rt_msghdr	*rtm;
2788119031Sume	struct	sockaddr_in6	*sin6;
278955163Sshin	int	len;
279055163Sshin
279155163Sshin	np = &rrt->rrt_info;
279278064Sume	inet_ntop(AF_INET6, (const void *)gw, (char *)buf1, sizeof(buf1));
279355163Sshin	inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2));
279455163Sshin	tracet(1, "ADD: %s/%d gw %s [%d] ifa %s\n",
279555163Sshin		inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1,
279655163Sshin		np->rip6_metric - 1, buf2);
279755163Sshin	if (rtlog)
279855163Sshin		fprintf(rtlog, "%s: ADD: %s/%d gw %s [%d] ifa %s\n", hms(),
279955163Sshin			inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1,
280055163Sshin			np->rip6_metric - 1, buf2);
280155163Sshin	if (nflag)
280255163Sshin		return 0;
280355163Sshin
280455163Sshin	memset(buf, 0, sizeof(buf));
280555163Sshin	rtm = (struct rt_msghdr *)buf;
280655163Sshin	rtm->rtm_type = RTM_ADD;
280755163Sshin	rtm->rtm_version = RTM_VERSION;
280855163Sshin	rtm->rtm_seq = ++seq;
280955163Sshin	rtm->rtm_pid = pid;
281062607Sitojun	rtm->rtm_flags = rrt->rrt_flags;
281155163Sshin	rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
281255163Sshin	rtm->rtm_rmx.rmx_hopcount = np->rip6_metric - 1;
281355163Sshin	rtm->rtm_inits = RTV_HOPCOUNT;
2814119031Sume	sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
281555163Sshin	/* Destination */
2816119031Sume	sin6->sin6_len = sizeof(struct sockaddr_in6);
2817119031Sume	sin6->sin6_family = AF_INET6;
2818119031Sume	sin6->sin6_addr = np->rip6_dest;
2819119031Sume	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
282055163Sshin	/* Gateway */
2821119031Sume	sin6->sin6_len = sizeof(struct sockaddr_in6);
2822119031Sume	sin6->sin6_family = AF_INET6;
2823119031Sume	sin6->sin6_addr = *gw;
2824119031Sume	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
282555163Sshin	/* Netmask */
2826119031Sume	sin6->sin6_len = sizeof(struct sockaddr_in6);
2827119031Sume	sin6->sin6_family = AF_INET6;
2828119031Sume	sin6->sin6_addr = *(plen2mask(np->rip6_plen));
2829119031Sume	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
283055163Sshin
2831119031Sume	len = (char *)sin6 - (char *)buf;
283255163Sshin	rtm->rtm_msglen = len;
283355163Sshin	if (write(rtsock, buf, len) > 0)
283455163Sshin		return 0;
283555163Sshin
283655163Sshin	if (errno == EEXIST) {
283755163Sshin		trace(0, "ADD: Route already exists %s/%d gw %s\n",
2838119035Sume		    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1);
283955163Sshin		if (rtlog)
284055163Sshin			fprintf(rtlog, "ADD: Route already exists %s/%d gw %s\n",
2841119035Sume			    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1);
284255163Sshin	} else {
284355163Sshin		trace(0, "Can not write to rtsock (addroute): %s\n",
2844119035Sume		    strerror(errno));
284555163Sshin		if (rtlog)
284655163Sshin			fprintf(rtlog, "\tCan not write to rtsock: %s\n",
2847119035Sume			    strerror(errno));
284855163Sshin	}
284955163Sshin	return -1;
285055163Sshin}
285155163Sshin
285255163Sshinint
285355163Sshindelroute(np, gw)
285455163Sshin	struct netinfo6 *np;
285555163Sshin	struct in6_addr *gw;
285655163Sshin{
285755163Sshin	u_char	buf[BUFSIZ], buf2[BUFSIZ];
285855163Sshin	struct	rt_msghdr	*rtm;
2859119031Sume	struct	sockaddr_in6	*sin6;
286055163Sshin	int	len;
286155163Sshin
286255163Sshin	inet_ntop(AF_INET6, (void *)gw, (char *)buf2, sizeof(buf2));
286355163Sshin	tracet(1, "DEL: %s/%d gw %s\n", inet6_n2p(&np->rip6_dest),
286455163Sshin		np->rip6_plen, buf2);
286555163Sshin	if (rtlog)
286655163Sshin		fprintf(rtlog, "%s: DEL: %s/%d gw %s\n",
286755163Sshin			hms(), inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
286855163Sshin	if (nflag)
286955163Sshin		return 0;
287055163Sshin
287155163Sshin	memset(buf, 0, sizeof(buf));
287255163Sshin	rtm = (struct rt_msghdr *)buf;
287355163Sshin	rtm->rtm_type = RTM_DELETE;
287455163Sshin	rtm->rtm_version = RTM_VERSION;
287555163Sshin	rtm->rtm_seq = ++seq;
287655163Sshin	rtm->rtm_pid = pid;
287755163Sshin	rtm->rtm_flags = RTF_UP | RTF_GATEWAY;
287878064Sume	if (np->rip6_plen == sizeof(struct in6_addr) * 8)
287978064Sume		rtm->rtm_flags |= RTF_HOST;
288055163Sshin	rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
2881119031Sume	sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
288255163Sshin	/* Destination */
2883119031Sume	sin6->sin6_len = sizeof(struct sockaddr_in6);
2884119031Sume	sin6->sin6_family = AF_INET6;
2885119031Sume	sin6->sin6_addr = np->rip6_dest;
2886119031Sume	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
288755163Sshin	/* Gateway */
2888119031Sume	sin6->sin6_len = sizeof(struct sockaddr_in6);
2889119031Sume	sin6->sin6_family = AF_INET6;
2890119031Sume	sin6->sin6_addr = *gw;
2891119031Sume	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
289255163Sshin	/* Netmask */
2893119031Sume	sin6->sin6_len = sizeof(struct sockaddr_in6);
2894119031Sume	sin6->sin6_family = AF_INET6;
2895119031Sume	sin6->sin6_addr = *(plen2mask(np->rip6_plen));
2896119031Sume	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
289755163Sshin
2898119031Sume	len = (char *)sin6 - (char *)buf;
289955163Sshin	rtm->rtm_msglen = len;
290055163Sshin	if (write(rtsock, buf, len) >= 0)
290155163Sshin		return 0;
290255163Sshin
290355163Sshin	if (errno == ESRCH) {
290455163Sshin		trace(0, "RTDEL: Route does not exist: %s/%d gw %s\n",
2905119035Sume		    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
290655163Sshin		if (rtlog)
290755163Sshin			fprintf(rtlog, "RTDEL: Route does not exist: %s/%d gw %s\n",
2908119035Sume			    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
290955163Sshin	} else {
291055163Sshin		trace(0, "Can not write to rtsock (delroute): %s\n",
2911119035Sume		    strerror(errno));
291255163Sshin		if (rtlog)
291355163Sshin			fprintf(rtlog, "\tCan not write to rtsock: %s\n",
2914119035Sume			    strerror(errno));
291555163Sshin	}
291655163Sshin	return -1;
291755163Sshin}
291855163Sshin
291955163Sshinstruct in6_addr *
292055163Sshingetroute(np, gw)
292155163Sshin	struct netinfo6 *np;
292255163Sshin	struct in6_addr *gw;
292355163Sshin{
292455163Sshin	u_char buf[BUFSIZ];
2925119085Sume	int myseq;
292655163Sshin	int len;
292755163Sshin	struct rt_msghdr *rtm;
2928119031Sume	struct sockaddr_in6 *sin6;
292955163Sshin
293055163Sshin	rtm = (struct rt_msghdr *)buf;
293155163Sshin	len = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6);
293255163Sshin	memset(rtm, 0, len);
293355163Sshin	rtm->rtm_type = RTM_GET;
293455163Sshin	rtm->rtm_version = RTM_VERSION;
293555163Sshin	myseq = ++seq;
293655163Sshin	rtm->rtm_seq = myseq;
293755163Sshin	rtm->rtm_addrs = RTA_DST;
293855163Sshin	rtm->rtm_msglen = len;
2939119031Sume	sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
2940119031Sume	sin6->sin6_len = sizeof(struct sockaddr_in6);
2941119031Sume	sin6->sin6_family = AF_INET6;
2942119031Sume	sin6->sin6_addr = np->rip6_dest;
294355163Sshin	if (write(rtsock, buf, len) < 0) {
294455163Sshin		if (errno == ESRCH)	/* No such route found */
294555163Sshin			return NULL;
294655163Sshin		perror("write to rtsock");
294778064Sume		exit(1);
294855163Sshin	}
294955163Sshin	do {
295055163Sshin		if ((len = read(rtsock, buf, sizeof(buf))) < 0) {
295155163Sshin			perror("read from rtsock");
295278064Sume			exit(1);
295355163Sshin		}
295455163Sshin		rtm = (struct rt_msghdr *)buf;
295555163Sshin	} while (rtm->rtm_seq != myseq || rtm->rtm_pid != pid);
2956119031Sume	sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
295755163Sshin	if (rtm->rtm_addrs & RTA_DST) {
2958119031Sume		sin6 = (struct sockaddr_in6 *)
2959119031Sume			((char *)sin6 + ROUNDUP(sin6->sin6_len));
296055163Sshin	}
296155163Sshin	if (rtm->rtm_addrs & RTA_GATEWAY) {
2962119031Sume		*gw = sin6->sin6_addr;
296355163Sshin		return gw;
296455163Sshin	}
296555163Sshin	return NULL;
296655163Sshin}
296755163Sshin
296855163Sshinconst char *
296955163Sshininet6_n2p(p)
297055163Sshin	const struct in6_addr *p;
297155163Sshin{
297255163Sshin	static char buf[BUFSIZ];
297355163Sshin
297478064Sume	return inet_ntop(AF_INET6, (const void *)p, buf, sizeof(buf));
297555163Sshin}
297655163Sshin
297755163Sshinvoid
297855163Sshinifrtdump(sig)
297955163Sshin	int sig;
298055163Sshin{
298155163Sshin
298255163Sshin	ifdump(sig);
298355163Sshin	rtdump(sig);
298455163Sshin}
298555163Sshin
298655163Sshinvoid
298755163Sshinifdump(sig)
298855163Sshin	int sig;
298955163Sshin{
299055163Sshin	struct ifc *ifcp;
299155163Sshin	FILE *dump;
299255163Sshin	int i;
299355163Sshin
299455163Sshin	if (sig == 0)
299555163Sshin		dump = stderr;
299655163Sshin	else
299755163Sshin		if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL)
299855163Sshin			dump = stderr;
299955163Sshin
300055163Sshin	fprintf(dump, "%s: Interface Table Dump\n", hms());
300155163Sshin	fprintf(dump, "  Number of interfaces: %d\n", nifc);
300255163Sshin	for (i = 0; i < 2; i++) {
300355163Sshin		fprintf(dump, "  %sadvertising interfaces:\n", i ? "non-" : "");
300455163Sshin		for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
300555163Sshin			if (i == 0) {
300655163Sshin				if ((ifcp->ifc_flags & IFF_UP) == 0)
300755163Sshin					continue;
300855163Sshin				if (iff_find(ifcp, 'N') != NULL)
300955163Sshin					continue;
301055163Sshin			} else {
301155163Sshin				if (ifcp->ifc_flags & IFF_UP)
301255163Sshin					continue;
301355163Sshin			}
301455163Sshin			ifdump0(dump, ifcp);
301555163Sshin		}
301655163Sshin	}
301755163Sshin	fprintf(dump, "\n");
301855163Sshin	if (dump != stderr)
301955163Sshin		fclose(dump);
302055163Sshin}
302155163Sshin
302255163Sshinvoid
302355163Sshinifdump0(dump, ifcp)
302455163Sshin	FILE *dump;
302555163Sshin	const struct ifc *ifcp;
302655163Sshin{
302755163Sshin	struct ifac *ifa;
302855163Sshin	struct iff *iffp;
302955163Sshin	char buf[BUFSIZ];
303055163Sshin	const char *ft;
303155163Sshin	int addr;
303255163Sshin
303355163Sshin	fprintf(dump, "    %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)\n",
303455163Sshin		ifcp->ifc_name, ifcp->ifc_index, ifflags(ifcp->ifc_flags),
303555163Sshin		inet6_n2p(&ifcp->ifc_mylladdr),
303655163Sshin		ifcp->ifc_mtu, ifcp->ifc_metric);
303755163Sshin	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
303855163Sshin		if (ifcp->ifc_flags & IFF_POINTOPOINT) {
303955163Sshin			inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr,
304055163Sshin				buf, sizeof(buf));
304155163Sshin			fprintf(dump, "\t%s/%d -- %s\n",
304255163Sshin				inet6_n2p(&ifa->ifa_addr),
304355163Sshin				ifa->ifa_plen, buf);
304455163Sshin		} else {
304555163Sshin			fprintf(dump, "\t%s/%d\n",
304655163Sshin				inet6_n2p(&ifa->ifa_addr),
304755163Sshin				ifa->ifa_plen);
304855163Sshin		}
304955163Sshin	}
305055163Sshin	if (ifcp->ifc_filter) {
305155163Sshin		fprintf(dump, "\tFilter:");
305255163Sshin		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
305355163Sshin			addr = 0;
305455163Sshin			switch (iffp->iff_type) {
305555163Sshin			case 'A':
305655163Sshin				ft = "Aggregate"; addr++; break;
305755163Sshin			case 'N':
305878064Sume				ft = "No-use"; break;
305955163Sshin			case 'O':
306055163Sshin				ft = "Advertise-only"; addr++; break;
306155163Sshin			case 'T':
306255163Sshin				ft = "Default-only"; break;
306355163Sshin			case 'L':
306455163Sshin				ft = "Listen-only"; addr++; break;
306555163Sshin			default:
306655163Sshin				snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type);
306755163Sshin				ft = buf;
306855163Sshin				addr++;
306955163Sshin				break;
307055163Sshin			}
307155163Sshin			fprintf(dump, " %s", ft);
307255163Sshin			if (addr) {
307355163Sshin				fprintf(dump, "(%s/%d)", inet6_n2p(&iffp->iff_addr),
307455163Sshin					iffp->iff_plen);
307555163Sshin			}
307655163Sshin		}
307755163Sshin		fprintf(dump, "\n");
307855163Sshin	}
307955163Sshin}
308055163Sshin
308155163Sshinvoid
308255163Sshinrtdump(sig)
308355163Sshin	int sig;
308455163Sshin{
308555163Sshin	struct	riprt *rrt;
308655163Sshin	char	buf[BUFSIZ];
308755163Sshin	FILE	*dump;
308855163Sshin	time_t	t, age;
308955163Sshin
309055163Sshin	if (sig == 0)
309155163Sshin		dump = stderr;
309255163Sshin	else
309355163Sshin		if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL)
309455163Sshin			dump = stderr;
309555163Sshin
309655163Sshin	t = time(NULL);
309755163Sshin	fprintf(dump, "\n%s: Routing Table Dump\n", hms());
309855163Sshin	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
309955163Sshin		if (rrt->rrt_t == 0)
310055163Sshin			age = 0;
310155163Sshin		else
310255163Sshin			age = t - rrt->rrt_t;
310355163Sshin		inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest,
310455163Sshin			buf, sizeof(buf));
310555163Sshin		fprintf(dump, "    %s/%d if(%d:%s) gw(%s) [%d] age(%ld)",
310655163Sshin			buf, rrt->rrt_info.rip6_plen, rrt->rrt_index,
310755163Sshin			index2ifc[rrt->rrt_index]->ifc_name,
310855163Sshin			inet6_n2p(&rrt->rrt_gw),
310955163Sshin			rrt->rrt_info.rip6_metric, (long)age);
311055163Sshin		if (rrt->rrt_info.rip6_tag) {
311155163Sshin			fprintf(dump, " tag(0x%04x)",
311255163Sshin				ntohs(rrt->rrt_info.rip6_tag) & 0xffff);
311355163Sshin		}
311462607Sitojun		if (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)
311555163Sshin			fprintf(dump, " NOT-LL");
311662607Sitojun		if (rrt->rrt_rflags & RRTF_NOADVERTISE)
311755163Sshin			fprintf(dump, " NO-ADV");
311855163Sshin		fprintf(dump, "\n");
311955163Sshin	}
312055163Sshin	fprintf(dump, "\n");
312155163Sshin	if (dump != stderr)
312255163Sshin		fclose(dump);
312355163Sshin}
312455163Sshin
312555163Sshin/*
312655163Sshin * Parse the -A (and -O) options and put corresponding filter object to the
312778064Sume * specified interface structures.  Each of the -A/O option has the following
312855163Sshin * syntax:	-A 5f09:c400::/32,ef0,ef1  (aggregate)
312955163Sshin * 		-O 5f09:c400::/32,ef0,ef1  (only when match)
313055163Sshin */
313155163Sshinvoid
313255163Sshinfilterconfig()
313355163Sshin{
313455163Sshin	int i;
3135119083Sume	char *p, *ap, *iflp, *ifname, *ep;
313678064Sume	struct iff ftmp, *iff_obj;
313778064Sume	struct ifc *ifcp;
313878064Sume	struct riprt *rrt;
313964631Sitojun#if 0
314078064Sume	struct in6_addr gw;
314164631Sitojun#endif
3142119083Sume	u_long plen;
314355163Sshin
314455163Sshin	for (i = 0; i < nfilter; i++) {
314555163Sshin		ap = filter[i];
314655163Sshin		iflp = NULL;
314755163Sshin		ifcp = NULL;
314855163Sshin		if (filtertype[i] == 'N' || filtertype[i] == 'T') {
314955163Sshin			iflp = ap;
315055163Sshin			goto ifonly;
315155163Sshin		}
3152119038Sume		if ((p = strchr(ap, ',')) != NULL) {
315355163Sshin			*p++ = '\0';
315455163Sshin			iflp = p;
315555163Sshin		}
3156119038Sume		if ((p = strchr(ap, '/')) == NULL) {
315755163Sshin			fatal("no prefixlen specified for '%s'", ap);
315878064Sume			/*NOTREACHED*/
315978064Sume		}
316055163Sshin		*p++ = '\0';
316178064Sume		if (inet_pton(AF_INET6, ap, &ftmp.iff_addr) != 1) {
316255163Sshin			fatal("invalid prefix specified for '%s'", ap);
316378064Sume			/*NOTREACHED*/
316478064Sume		}
3165119083Sume		errno = 0;
3166119083Sume		ep = NULL;
3167119083Sume		plen = strtoul(p, &ep, 10);
3168119083Sume		if (errno || !*p || *ep || plen > sizeof(ftmp.iff_addr) * 8) {
3169119083Sume			fatal("invalid prefix length specified for '%s'", ap);
3170119083Sume			/*NOTREACHED*/
3171119083Sume		}
3172119083Sume		ftmp.iff_plen = plen;
317355163Sshin		ftmp.iff_next = NULL;
317455163Sshin		applyplen(&ftmp.iff_addr, ftmp.iff_plen);
317555163Sshinifonly:
317655163Sshin		ftmp.iff_type = filtertype[i];
317778064Sume		if (iflp == NULL || *iflp == '\0') {
317855163Sshin			fatal("no interface specified for '%s'", ap);
317978064Sume			/*NOTREACHED*/
318078064Sume		}
318155163Sshin		/* parse the interface listing portion */
318255163Sshin		while (iflp) {
318355163Sshin			ifname = iflp;
3184119038Sume			if ((iflp = strchr(iflp, ',')) != NULL)
318555163Sshin				*iflp++ = '\0';
318655163Sshin			ifcp = ifc_find(ifname);
318778064Sume			if (ifcp == NULL) {
318855163Sshin				fatal("no interface %s exists", ifname);
318978064Sume				/*NOTREACHED*/
319078064Sume			}
319155163Sshin			iff_obj = (struct iff *)malloc(sizeof(struct iff));
319278064Sume			if (iff_obj == NULL) {
319355163Sshin				fatal("malloc of iff_obj");
319478064Sume				/*NOTREACHED*/
319578064Sume			}
319655163Sshin			memcpy((void *)iff_obj, (void *)&ftmp,
319778064Sume			    sizeof(struct iff));
319855163Sshin			/* link it to the interface filter */
319955163Sshin			iff_obj->iff_next = ifcp->ifc_filter;
320055163Sshin			ifcp->ifc_filter = iff_obj;
320155163Sshin		}
320278064Sume
320378064Sume		/*
320478064Sume		 * -A: aggregate configuration.
320578064Sume		 */
320655163Sshin		if (filtertype[i] != 'A')
320755163Sshin			continue;
320855163Sshin		/* put the aggregate to the kernel routing table */
320955163Sshin		rrt = (struct riprt *)malloc(sizeof(struct riprt));
321078064Sume		if (rrt == NULL) {
321155163Sshin			fatal("malloc: rrt");
321278064Sume			/*NOTREACHED*/
321378064Sume		}
321455163Sshin		memset(rrt, 0, sizeof(struct riprt));
321555163Sshin		rrt->rrt_info.rip6_dest = ftmp.iff_addr;
321655163Sshin		rrt->rrt_info.rip6_plen = ftmp.iff_plen;
321755163Sshin		rrt->rrt_info.rip6_metric = 1;
321855163Sshin		rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
321955163Sshin		rrt->rrt_gw = in6addr_loopback;
322062607Sitojun		rrt->rrt_flags = RTF_UP | RTF_REJECT;
322162607Sitojun		rrt->rrt_rflags = RRTF_AGGREGATE;
322255163Sshin		rrt->rrt_t = 0;
3223119039Sume		rrt->rrt_index = loopifcp->ifc_index;
322464631Sitojun#if 0
322564631Sitojun		if (getroute(&rrt->rrt_info, &gw)) {
322664631Sitojun#if 0
322764631Sitojun			/*
322864631Sitojun			 * When the address has already been registered in the
322964631Sitojun			 * kernel routing table, it should be removed
323064631Sitojun			 */
323164631Sitojun			delroute(&rrt->rrt_info, &gw);
323264631Sitojun#else
323378064Sume			/* it is safer behavior */
323464631Sitojun			errno = EINVAL;
323564631Sitojun			fatal("%s/%u already in routing table, "
323664631Sitojun			    "cannot aggregate",
323764631Sitojun			    inet6_n2p(&rrt->rrt_info.rip6_dest),
323864631Sitojun			    rrt->rrt_info.rip6_plen);
323978064Sume			/*NOTREACHED*/
324064631Sitojun#endif
324164631Sitojun		}
324264631Sitojun#endif
324355163Sshin		/* Put the route to the list */
324455163Sshin		rrt->rrt_next = riprt;
324555163Sshin		riprt = rrt;
324655163Sshin		trace(1, "Aggregate: %s/%d for %s\n",
324755163Sshin			inet6_n2p(&ftmp.iff_addr), ftmp.iff_plen,
324855163Sshin			ifcp->ifc_name);
324955163Sshin		/* Add this route to the kernel */
325055163Sshin		if (nflag) 	/* do not modify kernel routing table */
325155163Sshin			continue;
325255163Sshin		addroute(rrt, &in6addr_loopback, loopifcp);
325355163Sshin	}
325455163Sshin}
325555163Sshin
325655163Sshin/***************** utility functions *****************/
325755163Sshin
325855163Sshin/*
325955163Sshin * Returns a pointer to ifac whose address and prefix length matches
326055163Sshin * with the address and prefix length specified in the arguments.
326155163Sshin */
326255163Sshinstruct ifac *
326355163Sshinifa_match(ifcp, ia, plen)
326455163Sshin	const struct ifc *ifcp;
326555163Sshin	const struct in6_addr *ia;
326655163Sshin	int plen;
326755163Sshin{
326855163Sshin	struct ifac *ifa;
326955163Sshin
327055163Sshin	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
327155163Sshin		if (IN6_ARE_ADDR_EQUAL(&ifa->ifa_addr, ia) &&
327255163Sshin		    ifa->ifa_plen == plen)
327355163Sshin			break;
327455163Sshin	}
327555163Sshin	return ifa;
327655163Sshin}
327755163Sshin
327855163Sshin/*
327955163Sshin * Return a pointer to riprt structure whose address and prefix length
328055163Sshin * matches with the address and prefix length found in the argument.
328178064Sume * Note: This is not a rtalloc().  Therefore exact match is necessary.
328255163Sshin */
328355163Sshinstruct riprt *
328478064Sumertsearch(np, prev_rrt)
328555163Sshin	struct	netinfo6 *np;
328678064Sume	struct	riprt **prev_rrt;
328755163Sshin{
328855163Sshin	struct	riprt	*rrt;
328955163Sshin
329078064Sume	if (prev_rrt)
329178064Sume		*prev_rrt = NULL;
329255163Sshin	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
329355163Sshin		if (rrt->rrt_info.rip6_plen == np->rip6_plen &&
329455163Sshin		    IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
329555163Sshin				       &np->rip6_dest))
329655163Sshin			return rrt;
329778064Sume		if (prev_rrt)
329878064Sume			*prev_rrt = rrt;
329955163Sshin	}
330078064Sume	if (prev_rrt)
330178064Sume		*prev_rrt = NULL;
330255163Sshin	return 0;
330355163Sshin}
330455163Sshin
330555163Sshinint
330678064Sumesin6mask2len(sin6)
330778064Sume	const struct sockaddr_in6 *sin6;
330878064Sume{
330978064Sume
331078064Sume	return mask2len(&sin6->sin6_addr,
331178064Sume	    sin6->sin6_len - offsetof(struct sockaddr_in6, sin6_addr));
331278064Sume}
331378064Sume
331478064Sumeint
331555163Sshinmask2len(addr, lenlim)
331655163Sshin	const struct in6_addr *addr;
331755163Sshin	int lenlim;
331855163Sshin{
331955163Sshin	int i = 0, j;
332078064Sume	const u_char *p = (const u_char *)addr;
332162607Sitojun
332255163Sshin	for (j = 0; j < lenlim; j++, p++) {
332355163Sshin		if (*p != 0xff)
332455163Sshin			break;
332555163Sshin		i += 8;
332655163Sshin	}
332755163Sshin	if (j < lenlim) {
332855163Sshin		switch (*p) {
332962607Sitojun#define	MASKLEN(m, l)	case m: do { i += l; break; } while (0)
333062607Sitojun		MASKLEN(0xfe, 7); break;
333162607Sitojun		MASKLEN(0xfc, 6); break;
333262607Sitojun		MASKLEN(0xf8, 5); break;
333362607Sitojun		MASKLEN(0xf0, 4); break;
333462607Sitojun		MASKLEN(0xe0, 3); break;
333562607Sitojun		MASKLEN(0xc0, 2); break;
333662607Sitojun		MASKLEN(0x80, 1); break;
333755163Sshin#undef	MASKLEN
333855163Sshin		}
333955163Sshin	}
334055163Sshin	return i;
334155163Sshin}
334255163Sshin
334355163Sshinvoid
334455163Sshinapplymask(addr, mask)
334555163Sshin	struct in6_addr *addr, *mask;
334655163Sshin{
334755163Sshin	int	i;
334855163Sshin	u_long	*p, *q;
334955163Sshin
335055163Sshin	p = (u_long *)addr; q = (u_long *)mask;
335155163Sshin	for (i = 0; i < 4; i++)
335255163Sshin		*p++ &= *q++;
335355163Sshin}
335455163Sshin
335555163Sshinstatic const u_char plent[8] = {
335655163Sshin	0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
335755163Sshin};
335855163Sshin
335955163Sshinvoid
336055163Sshinapplyplen(ia, plen)
336155163Sshin	struct	in6_addr *ia;
336255163Sshin	int	plen;
336355163Sshin{
336455163Sshin	u_char	*p;
336555163Sshin	int	i;
336655163Sshin
336755163Sshin	p = ia->s6_addr;
336855163Sshin	for (i = 0; i < 16; i++) {
336955163Sshin		if (plen <= 0)
337055163Sshin			*p = 0;
337155163Sshin		else if (plen < 8)
337255163Sshin			*p &= plent[plen];
337355163Sshin		p++, plen -= 8;
337455163Sshin	}
337555163Sshin}
337655163Sshin
337755163Sshinstatic const int pl2m[9] = {
337855163Sshin	0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
337955163Sshin};
338055163Sshin
338155163Sshinstruct in6_addr *
338255163Sshinplen2mask(n)
338355163Sshin	int	n;
338455163Sshin{
338555163Sshin	static struct in6_addr ia;
338655163Sshin	u_char	*p;
338755163Sshin	int	i;
338855163Sshin
338955163Sshin	memset(&ia, 0, sizeof(struct in6_addr));
339055163Sshin	p = (u_char *)&ia;
339155163Sshin	for (i = 0; i < 16; i++, p++, n -= 8) {
339255163Sshin		if (n >= 8) {
339355163Sshin			*p = 0xff;
339455163Sshin			continue;
339555163Sshin		}
339655163Sshin		*p = pl2m[n];
339755163Sshin		break;
339855163Sshin	}
339955163Sshin	return &ia;
340055163Sshin}
340155163Sshin
340255163Sshinchar *
340355163Sshinallocopy(p)
340455163Sshin	char *p;
340555163Sshin{
3406119033Sume	int len = strlen(p) + 1;
3407119033Sume	char *q = (char *)malloc(len);
340855163Sshin
3409119033Sume	if (!q) {
3410119033Sume		fatal("malloc");
3411119033Sume		/*NOTREACHED*/
3412119033Sume	}
3413119033Sume
3414119033Sume	strlcpy(q, p, len);
341555163Sshin	return q;
341655163Sshin}
341755163Sshin
341855163Sshinchar *
341955163Sshinhms()
342055163Sshin{
342155163Sshin	static char buf[BUFSIZ];
342255163Sshin	time_t t;
342355163Sshin	struct	tm *tm;
342455163Sshin
342555163Sshin	t = time(NULL);
342678064Sume	if ((tm = localtime(&t)) == 0) {
342755163Sshin		fatal("localtime");
342878064Sume		/*NOTREACHED*/
342978064Sume	}
343078064Sume	snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
343178064Sume	    tm->tm_sec);
343255163Sshin	return buf;
343355163Sshin}
343455163Sshin
343555163Sshin#define	RIPRANDDEV	1.0	/* 30 +- 15, max - min = 30 */
343655163Sshin
343755163Sshinint
343855163Sshinripinterval(timer)
343955163Sshin	int timer;
344055163Sshin{
344155163Sshin	double r = rand();
344255163Sshin
344355163Sshin	interval = (int)(timer + timer * RIPRANDDEV * (r / RAND_MAX - 0.5));
344455163Sshin	nextalarm = time(NULL) + interval;
344555163Sshin	return interval;
344655163Sshin}
344755163Sshin
344855163Sshintime_t
344955163Sshinripsuptrig()
345055163Sshin{
345155163Sshin	time_t t;
345255163Sshin
345355163Sshin	double r = rand();
345462607Sitojun	t  = (int)(RIP_TRIG_INT6_MIN +
345578064Sume		(RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / RAND_MAX));
345655163Sshin	sup_trig_update = time(NULL) + t;
345755163Sshin	return t;
345855163Sshin}
345955163Sshin
346055163Sshinvoid
346155163Sshin#ifdef __STDC__
346255163Sshinfatal(const char *fmt, ...)
346355163Sshin#else
346455163Sshinfatal(fmt, va_alist)
346555163Sshin	char	*fmt;
346655163Sshin	va_dcl
346755163Sshin#endif
346855163Sshin{
346955163Sshin	va_list ap;
347055163Sshin	char buf[1024];
347155163Sshin
347255163Sshin#ifdef __STDC__
347355163Sshin	va_start(ap, fmt);
347455163Sshin#else
347555163Sshin	va_start(ap);
347655163Sshin#endif
347755163Sshin	vsnprintf(buf, sizeof(buf), fmt, ap);
3478119043Sume	va_end(ap);
347955163Sshin	perror(buf);
3480119043Sume	if (errno)
3481119043Sume		syslog(LOG_ERR, "%s: %s", buf, strerror(errno));
3482119043Sume	else
3483119043Sume		syslog(LOG_ERR, "%s", buf);
348478064Sume	rtdexit();
348555163Sshin}
348655163Sshin
348755163Sshinvoid
348855163Sshin#ifdef __STDC__
348955163Sshintracet(int level, const char *fmt, ...)
349055163Sshin#else
349155163Sshintracet(level, fmt, va_alist)
349255163Sshin	int level;
349355163Sshin	char *fmt;
349455163Sshin	va_dcl
349555163Sshin#endif
349655163Sshin{
349755163Sshin	va_list ap;
349855163Sshin
3499119043Sume	if (level <= dflag) {
350055163Sshin#ifdef __STDC__
3501119043Sume		va_start(ap, fmt);
350255163Sshin#else
3503119043Sume		va_start(ap);
350455163Sshin#endif
350555163Sshin		fprintf(stderr, "%s: ", hms());
350655163Sshin		vfprintf(stderr, fmt, ap);
3507119043Sume		va_end(ap);
350855163Sshin	}
350955163Sshin	if (dflag) {
3510119043Sume#ifdef __STDC__
3511119043Sume		va_start(ap, fmt);
3512119043Sume#else
3513119043Sume		va_start(ap);
3514119043Sume#endif
351555163Sshin		if (level > 0)
351655163Sshin			vsyslog(LOG_DEBUG, fmt, ap);
351755163Sshin		else
351855163Sshin			vsyslog(LOG_WARNING, fmt, ap);
3519119043Sume		va_end(ap);
352055163Sshin	}
352155163Sshin}
352255163Sshin
352355163Sshinvoid
352455163Sshin#ifdef __STDC__
352555163Sshintrace(int level, const char *fmt, ...)
352655163Sshin#else
352755163Sshintrace(level, fmt, va_alist)
352855163Sshin	int level;
352955163Sshin	char *fmt;
353055163Sshin	va_dcl
353155163Sshin#endif
353255163Sshin{
353355163Sshin	va_list ap;
353455163Sshin
3535119043Sume	if (level <= dflag) {
353655163Sshin#ifdef __STDC__
3537119043Sume		va_start(ap, fmt);
353855163Sshin#else
3539119043Sume		va_start(ap);
354055163Sshin#endif
354155163Sshin		vfprintf(stderr, fmt, ap);
3542119043Sume		va_end(ap);
3543119043Sume	}
354455163Sshin	if (dflag) {
3545119043Sume#ifdef __STDC__
3546119043Sume		va_start(ap, fmt);
3547119043Sume#else
3548119043Sume		va_start(ap);
3549119043Sume#endif
355055163Sshin		if (level > 0)
355155163Sshin			vsyslog(LOG_DEBUG, fmt, ap);
355255163Sshin		else
355355163Sshin			vsyslog(LOG_WARNING, fmt, ap);
3554119043Sume		va_end(ap);
355555163Sshin	}
355655163Sshin}
355755163Sshin
355855163Sshinunsigned int
355955163Sshinif_maxindex()
356055163Sshin{
356155163Sshin	struct if_nameindex *p, *p0;
356255163Sshin	unsigned int max = 0;
356355163Sshin
356455163Sshin	p0 = if_nameindex();
356555163Sshin	for (p = p0; p && p->if_index && p->if_name; p++) {
356655163Sshin		if (max < p->if_index)
356755163Sshin			max = p->if_index;
356855163Sshin	}
356955163Sshin	if_freenameindex(p0);
357055163Sshin	return max;
357155163Sshin}
357255163Sshin
357355163Sshinstruct ifc *
357455163Sshinifc_find(name)
357555163Sshin	char *name;
357655163Sshin{
357755163Sshin	struct ifc *ifcp;
357855163Sshin
357955163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
358055163Sshin		if (strcmp(name, ifcp->ifc_name) == 0)
358155163Sshin			return ifcp;
358255163Sshin	}
358355163Sshin	return (struct ifc *)NULL;
358455163Sshin}
358555163Sshin
358655163Sshinstruct iff *
358755163Sshiniff_find(ifcp, type)
358855163Sshin	struct ifc *ifcp;
358955163Sshin	int type;
359055163Sshin{
359155163Sshin	struct iff *iffp;
359255163Sshin
359355163Sshin	for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
359455163Sshin		if (iffp->iff_type == type)
359555163Sshin			return iffp;
359655163Sshin	}
359755163Sshin	return NULL;
359855163Sshin}
359955163Sshin
360055163Sshinvoid
360178064Sumesetindex2ifc(idx, ifcp)
360278064Sume	int idx;
360355163Sshin	struct ifc *ifcp;
360455163Sshin{
3605122677Sume	int n, nsize;
360662607Sitojun	struct ifc **p;
360755163Sshin
360855163Sshin	if (!index2ifc) {
360955163Sshin		nindex2ifc = 5;	/*initial guess*/
361055163Sshin		index2ifc = (struct ifc **)
361155163Sshin			malloc(sizeof(*index2ifc) * nindex2ifc);
361278064Sume		if (index2ifc == NULL) {
361355163Sshin			fatal("malloc");
361478064Sume			/*NOTREACHED*/
361578064Sume		}
361655163Sshin		memset(index2ifc, 0, sizeof(*index2ifc) * nindex2ifc);
361755163Sshin	}
361855163Sshin	n = nindex2ifc;
3619122677Sume	for (nsize = nindex2ifc; nsize <= idx; nsize *= 2)
3620122677Sume		;
3621122677Sume	if (n != nsize) {
362262607Sitojun		p = (struct ifc **)realloc(index2ifc,
3623122677Sume		    sizeof(*index2ifc) * nsize);
362478064Sume		if (p == NULL) {
362555163Sshin			fatal("realloc");
362678064Sume			/*NOTREACHED*/
362778064Sume		}
362878064Sume		memset(p + n, 0, sizeof(*index2ifc) * (nindex2ifc - n));
362962607Sitojun		index2ifc = p;
3630122677Sume		nindex2ifc = nsize;
363155163Sshin	}
363278064Sume	index2ifc[idx] = ifcp;
363355163Sshin}
3634