route6d.c revision 119042
162607Sitojun/*	$FreeBSD: head/usr.sbin/route6d/route6d.c 119042 2003-08-17 18:12:11Z ume $	*/
278064Sume/*	$KAME: route6d.c,v 1.64 2001/05/08 04:36:37 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
3478064Sumestatic char _rcsid[] = "$KAME: route6d.c,v 1.64 2001/05/08 04:36:37 itojun Exp $";
3555163Sshin#endif
3655163Sshin
3755163Sshin#include <stdio.h>
3855163Sshin
3955163Sshin#include <time.h>
4055163Sshin#include <unistd.h>
4155163Sshin#include <stdlib.h>
4255163Sshin#include <string.h>
4355163Sshin#include <signal.h>
4455163Sshin#ifdef __STDC__
4555163Sshin#include <stdarg.h>
4655163Sshin#else
4755163Sshin#include <varargs.h>
4855163Sshin#endif
4955163Sshin#include <syslog.h>
5055163Sshin#include <stddef.h>
5162607Sitojun#include <errno.h>
5255163Sshin#include <err.h>
5355163Sshin
5455163Sshin#include <sys/types.h>
5555163Sshin#include <sys/param.h>
5655163Sshin#include <sys/file.h>
5755163Sshin#include <sys/socket.h>
5855163Sshin#include <sys/ioctl.h>
5955163Sshin#include <sys/sysctl.h>
6055163Sshin#include <sys/uio.h>
6155163Sshin#include <net/if.h>
6262607Sitojun#if defined(__FreeBSD__) && __FreeBSD__ >= 3
6355163Sshin#include <net/if_var.h>
6462607Sitojun#endif /* __FreeBSD__ >= 3 */
6562607Sitojun#define	KERNEL	1
6662607Sitojun#define	_KERNEL	1
6755163Sshin#include <net/route.h>
6862607Sitojun#undef KERNEL
6962607Sitojun#undef _KERNEL
7055163Sshin#include <netinet/in.h>
7155163Sshin#include <netinet/in_var.h>
7255163Sshin#include <netinet/ip6.h>
7355163Sshin#include <netinet/udp.h>
7455163Sshin#include <netdb.h>
7562607Sitojun#include <ifaddrs.h>
7655163Sshin
7755163Sshin#include <arpa/inet.h>
7855163Sshin
7955163Sshin#include "route6d.h"
8055163Sshin
8155163Sshin#define	MAXFILTER	40
8255163Sshin
8355163Sshin#ifdef	DEBUG
8455163Sshin#define	INIT_INTERVAL6	6
8555163Sshin#else
86119039Sume#define	INIT_INTERVAL6	10	/* Wait to submit an initial riprequest */
8755163Sshin#endif
8855163Sshin
8955163Sshin/* alignment constraint for routing socket */
9062607Sitojun#define ROUNDUP(a) \
9155163Sshin	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
9262607Sitojun#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
9355163Sshin
9455163Sshin/*
9555163Sshin * Following two macros are highly depending on KAME Release
9655163Sshin */
9755163Sshin#define	IN6_LINKLOCAL_IFINDEX(addr) \
9855163Sshin	((addr).s6_addr[2] << 8 | (addr).s6_addr[3])
9955163Sshin
10055163Sshin#define	SET_IN6_LINKLOCAL_IFINDEX(addr, index) \
10155163Sshin	do { \
10255163Sshin		(addr).s6_addr[2] = ((index) >> 8) & 0xff; \
10355163Sshin		(addr).s6_addr[3] = (index) & 0xff; \
10455163Sshin	} while (0)
10555163Sshin
10655163Sshinstruct	ifc {			/* Configuration of an interface */
10755163Sshin	char	*ifc_name;			/* if name */
10855163Sshin	struct	ifc *ifc_next;
10955163Sshin	int	ifc_index;			/* if index */
11055163Sshin	int	ifc_mtu;			/* if mtu */
11155163Sshin	int	ifc_metric;			/* if metric */
11278064Sume	u_int	ifc_flags;			/* flags */
11378064Sume	short	ifc_cflags;			/* IFC_XXX */
11455163Sshin	struct	in6_addr ifc_mylladdr;		/* my link-local address */
11555163Sshin	struct	sockaddr_in6 ifc_ripsin;	/* rip multicast address */
11655163Sshin	struct	iff *ifc_filter;		/* filter structure */
11755163Sshin	struct	ifac *ifc_addr;			/* list of AF_INET6 addresses */
11855163Sshin	int	ifc_joined;			/* joined to ff02::9 */
11955163Sshin};
12055163Sshin
12162607Sitojunstruct	ifac {			/* Adddress associated to an interface */
12255163Sshin	struct	ifc *ifa_conf;		/* back pointer */
12355163Sshin	struct	ifac *ifa_next;
12455163Sshin	struct	in6_addr ifa_addr;	/* address */
12555163Sshin	struct	in6_addr ifa_raddr;	/* remote address, valid in p2p */
12655163Sshin	int	ifa_plen;		/* prefix length */
12755163Sshin};
12855163Sshin
12955163Sshinstruct	iff {
13055163Sshin	int	iff_type;
13155163Sshin	struct	in6_addr iff_addr;
13255163Sshin	int	iff_plen;
13355163Sshin	struct	iff *iff_next;
13455163Sshin};
13555163Sshin
13655163Sshinstruct	ifc *ifc;
13755163Sshinint	nifc;		/* number of valid ifc's */
13855163Sshinstruct	ifc **index2ifc;
13955163Sshinint	nindex2ifc;
14055163Sshinstruct	ifc *loopifcp = NULL;	/* pointing to loopback */
14155163Sshinfd_set	sockvec;	/* vector to select() for receiving */
14255163Sshinint	rtsock;		/* the routing socket */
14355163Sshinint	ripsock;	/* socket to send/receive RIP datagram */
14455163Sshin
14555163Sshinstruct	rip6 *ripbuf;	/* packet buffer for sending */
14655163Sshin
14755163Sshin/*
14878064Sume * Maintain the routes in a linked list.  When the number of the routes
14955163Sshin * grows, somebody would like to introduce a hash based or a radix tree
15078064Sume * based structure.  I believe the number of routes handled by RIP is
15155163Sshin * limited and I don't have to manage a complex data structure, however.
15255163Sshin *
15355163Sshin * One of the major drawbacks of the linear linked list is the difficulty
15478064Sume * of representing the relationship between a couple of routes.  This may
15555163Sshin * be a significant problem when we have to support route aggregation with
15655163Sshin * supressing the specifices covered by the aggregate.
15755163Sshin */
15855163Sshin
15955163Sshinstruct	riprt {
16055163Sshin	struct	riprt *rrt_next;	/* next destination */
16155163Sshin	struct	riprt *rrt_same;	/* same destination - future use */
16255163Sshin	struct	netinfo6 rrt_info;	/* network info */
16355163Sshin	struct	in6_addr rrt_gw;	/* gateway */
16462607Sitojun	u_long	rrt_flags;		/* kernel routing table flags */
16562607Sitojun	u_long	rrt_rflags;		/* route6d routing table flags */
16655163Sshin	time_t	rrt_t;			/* when the route validated */
16755163Sshin	int	rrt_index;		/* ifindex from which this route got */
16855163Sshin};
16955163Sshin
17055163Sshinstruct	riprt *riprt = 0;
17155163Sshin
17255163Sshinint	dflag = 0;	/* debug flag */
17355163Sshinint	qflag = 0;	/* quiet flag */
17455163Sshinint	nflag = 0;	/* don't update kernel routing table */
17555163Sshinint	aflag = 0;	/* age out even the statically defined routes */
17655163Sshinint	hflag = 0;	/* don't split horizon */
17755163Sshinint	lflag = 0;	/* exchange site local routes */
17855163Sshinint	sflag = 0;	/* announce static routes w/ split horizon */
17955163Sshinint	Sflag = 0;	/* announce static routes to every interface */
18062607Sitojununsigned long routetag = 0;	/* route tag attached on originating case */
18155163Sshin
18255163Sshinchar	*filter[MAXFILTER];
18355163Sshinint	filtertype[MAXFILTER];
18455163Sshinint	nfilter = 0;
18555163Sshin
18655163Sshinpid_t	pid;
18755163Sshin
18855163Sshinstruct	sockaddr_storage ripsin;
18955163Sshin
19055163Sshinstruct	rtentry rtentry;
19155163Sshin
19255163Sshinint	interval = 1;
19355163Sshintime_t	nextalarm = 0;
19455163Sshintime_t	sup_trig_update = 0;
19555163Sshin
19655163SshinFILE	*rtlog = NULL;
19755163Sshin
19855163Sshinint logopened = 0;
19955163Sshin
20055163Sshinstatic	u_long	seq = 0;
20155163Sshin
20278064Sumevolatile int signo;
20378064Sumevolatile sig_atomic_t seenalrm;
20478064Sumevolatile sig_atomic_t seenquit;
20578064Sumevolatile sig_atomic_t seenusr1;
20678064Sume
20762607Sitojun#define	RRTF_AGGREGATE		0x08000000
20862607Sitojun#define	RRTF_NOADVERTISE	0x10000000
20962607Sitojun#define	RRTF_NH_NOT_LLADDR	0x20000000
21062607Sitojun#define RRTF_SENDANYWAY		0x40000000
21162607Sitojun#define	RRTF_CHANGED		0x80000000
21255163Sshin
21355163Sshinint main __P((int, char **));
21478064Sumevoid sighandler __P((int));
21578064Sumevoid ripalarm __P((void));
21655163Sshinvoid riprecv __P((void));
21755163Sshinvoid ripsend __P((struct ifc *, struct sockaddr_in6 *, int));
21878064Sumeint out_filter __P((struct riprt *, struct ifc *));
21955163Sshinvoid init __P((void));
22055163Sshinvoid sockopt __P((struct ifc *));
22155163Sshinvoid ifconfig __P((void));
22262607Sitojunvoid ifconfig1 __P((const char *, const struct sockaddr *, struct ifc *, int));
22355163Sshinvoid rtrecv __P((void));
22455163Sshinint rt_del __P((const struct sockaddr_in6 *, const struct sockaddr_in6 *,
22555163Sshin	const struct sockaddr_in6 *));
22655163Sshinint rt_deladdr __P((struct ifc *, const struct sockaddr_in6 *,
22755163Sshin	const struct sockaddr_in6 *));
22855163Sshinvoid filterconfig __P((void));
22955163Sshinint getifmtu __P((int));
23078064Sumeconst char *rttypes __P((struct rt_msghdr *));
23178064Sumeconst char *rtflags __P((struct rt_msghdr *));
23278064Sumeconst char *ifflags __P((int));
23378064Sumeint ifrt __P((struct ifc *, int));
23462607Sitojunvoid ifrt_p2p __P((struct ifc *, int));
23555163Sshinvoid applymask __P((struct in6_addr *, struct in6_addr *));
23655163Sshinvoid applyplen __P((struct in6_addr *, int));
23755163Sshinvoid ifrtdump __P((int));
23855163Sshinvoid ifdump __P((int));
23955163Sshinvoid ifdump0 __P((FILE *, const struct ifc *));
24055163Sshinvoid rtdump __P((int));
24155163Sshinvoid rt_entry __P((struct rt_msghdr *, int));
24278064Sumevoid rtdexit __P((void));
24378064Sumevoid riprequest __P((struct ifc *, struct netinfo6 *, int,
24478064Sume	struct sockaddr_in6 *));
24555163Sshinvoid ripflush __P((struct ifc *, struct sockaddr_in6 *));
24655163Sshinvoid sendrequest __P((struct ifc *));
24778064Sumeint sin6mask2len __P((const struct sockaddr_in6 *));
24855163Sshinint mask2len __P((const struct in6_addr *, int));
24955163Sshinint sendpacket __P((struct sockaddr_in6 *, int));
25055163Sshinint addroute __P((struct riprt *, const struct in6_addr *, struct ifc *));
25155163Sshinint delroute __P((struct netinfo6 *, struct in6_addr *));
25255163Sshinstruct in6_addr *getroute __P((struct netinfo6 *, struct in6_addr *));
25355163Sshinvoid krtread __P((int));
25455163Sshinint tobeadv __P((struct riprt *, struct ifc *));
25555163Sshinchar *allocopy __P((char *));
25655163Sshinchar *hms __P((void));
25755163Sshinconst char *inet6_n2p __P((const struct in6_addr *));
25855163Sshinstruct ifac *ifa_match __P((const struct ifc *, const struct in6_addr *, int));
25955163Sshinstruct in6_addr *plen2mask __P((int));
26078064Sumestruct riprt *rtsearch __P((struct netinfo6 *, struct riprt **));
26155163Sshinint ripinterval __P((int));
26255163Sshintime_t ripsuptrig __P((void));
26366807Skrisvoid fatal __P((const char *, ...))
26466807Skris	__attribute__((__format__(__printf__, 1, 2)));
26566807Skrisvoid trace __P((int, const char *, ...))
26666807Skris	__attribute__((__format__(__printf__, 2, 3)));
26766807Skrisvoid tracet __P((int, const char *, ...))
26866807Skris	__attribute__((__format__(__printf__, 2, 3)));
26955163Sshinunsigned int if_maxindex __P((void));
27055163Sshinstruct ifc *ifc_find __P((char *));
27155163Sshinstruct iff *iff_find __P((struct ifc *, int));
27255163Sshinvoid setindex2ifc __P((int, struct ifc *));
27355163Sshin
27455163Sshin#define	MALLOC(type)	((type *)malloc(sizeof(type)))
27555163Sshin
27655163Sshinint
27755163Sshinmain(argc, argv)
27855163Sshin	int	argc;
27955163Sshin	char	**argv;
28055163Sshin{
28155163Sshin	int	ch;
28255163Sshin	int	error = 0;
28355163Sshin	struct	ifc *ifcp;
28455163Sshin	sigset_t mask, omask;
28555163Sshin	FILE	*pidfile;
28655163Sshin	char *progname;
28762607Sitojun	char *ep;
28855163Sshin
28955163Sshin	progname = strrchr(*argv, '/');
29055163Sshin	if (progname)
29155163Sshin		progname++;
29255163Sshin	else
29355163Sshin		progname = *argv;
29455163Sshin
29555163Sshin	pid = getpid();
29678064Sume	while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnqsS")) != -1) {
29755163Sshin		switch (ch) {
29855163Sshin		case 'A':
29955163Sshin		case 'N':
30055163Sshin		case 'O':
30155163Sshin		case 'T':
30255163Sshin		case 'L':
30362607Sitojun			if (nfilter >= MAXFILTER) {
30455163Sshin				fatal("Exceeds MAXFILTER");
30562607Sitojun				/*NOTREACHED*/
30662607Sitojun			}
30755163Sshin			filtertype[nfilter] = ch;
30855163Sshin			filter[nfilter++] = allocopy(optarg);
30955163Sshin			break;
31055163Sshin		case 't':
31162607Sitojun			ep = NULL;
31262607Sitojun			routetag = strtoul(optarg, &ep, 0);
31362607Sitojun			if (!ep || *ep != '\0' || (routetag & ~0xffff) != 0) {
31455163Sshin				fatal("invalid route tag");
31555163Sshin				/*NOTREACHED*/
31655163Sshin			}
31755163Sshin			break;
31855163Sshin		case 'R':
31962607Sitojun			if ((rtlog = fopen(optarg, "w")) == NULL) {
32055163Sshin				fatal("Can not write to routelog");
32162607Sitojun				/*NOTREACHED*/
32262607Sitojun			}
32355163Sshin			break;
32462607Sitojun#define	FLAG(c, flag, n)	case c: do { flag = n; break; } while(0)
32562607Sitojun		FLAG('a', aflag, 1); break;
32662607Sitojun		FLAG('d', dflag, 1); break;
32762607Sitojun		FLAG('D', dflag, 2); break;
32862607Sitojun		FLAG('h', hflag, 1); break;
32962607Sitojun		FLAG('l', lflag, 1); break;
33062607Sitojun		FLAG('n', nflag, 1); break;
33162607Sitojun		FLAG('q', qflag, 1); break;
33262607Sitojun		FLAG('s', sflag, 1); break;
33362607Sitojun		FLAG('S', Sflag, 1); break;
33455163Sshin#undef	FLAG
33555163Sshin		default:
33655163Sshin			fatal("Invalid option specified, terminating");
33762607Sitojun			/*NOTREACHED*/
33855163Sshin		}
33955163Sshin	}
34055163Sshin	argc -= optind;
34155163Sshin	argv += optind;
34278064Sume	if (argc > 0) {
34355163Sshin		fatal("bogus extra arguments");
34478064Sume		/*NOTREACHED*/
34578064Sume	}
34655163Sshin
34755163Sshin	if (geteuid()) {
34855163Sshin		nflag = 1;
34955163Sshin		fprintf(stderr, "No kernel update is allowed\n");
35055163Sshin	}
351119037Sume
352119037Sume	if (dflag == 0) {
353119037Sume		if (daemon(0, 0) < 0) {
354119037Sume			fatal("daemon");
355119037Sume			/*NOTREACHED*/
356119037Sume		}
357119037Sume	}
358119037Sume
35955163Sshin	openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON);
36055163Sshin	logopened++;
36178064Sume
36278064Sume	if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL)
36378064Sume		fatal("malloc");
36478064Sume	memset(ripbuf, 0, RIP6_MAXMTU);
36578064Sume	ripbuf->rip6_cmd = RIP6_RESPONSE;
36678064Sume	ripbuf->rip6_vers = RIP6_VERSION;
36778064Sume	ripbuf->rip6_res1[0] = 0;
36878064Sume	ripbuf->rip6_res1[1] = 0;
36978064Sume
37055163Sshin	init();
37155163Sshin	ifconfig();
37255163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
37355163Sshin		if (ifcp->ifc_index < 0) {
37455163Sshin			fprintf(stderr,
37555163Sshin"No ifindex found at %s (no link-local address?)\n",
37655163Sshin				ifcp->ifc_name);
37755163Sshin			error++;
37855163Sshin		}
37955163Sshin	}
38055163Sshin	if (error)
38155163Sshin		exit(1);
38278064Sume	if (loopifcp == NULL) {
38355163Sshin		fatal("No loopback found");
38478064Sume		/*NOTREACHED*/
38578064Sume	}
386110666Sache#ifdef __FreeBSD__
387110666Sache	sranddev();
388110666Sache#else
389110666Sache	srand((unsigned)(time(NULL)^(pid<<16)));
390110666Sache#endif
39155163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next)
39255163Sshin		ifrt(ifcp, 0);
39355163Sshin	filterconfig();
39455163Sshin	krtread(0);
39555163Sshin	if (dflag)
39655163Sshin		ifrtdump(0);
39755163Sshin
39855163Sshin	pid = getpid();
39955163Sshin	if ((pidfile = fopen(ROUTE6D_PID, "w")) != NULL) {
40055163Sshin		fprintf(pidfile, "%d\n", pid);
40155163Sshin		fclose(pidfile);
40255163Sshin	}
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) {
44155163Sshin		fd_set	recvec;
44255163Sshin
44378064Sume		if (seenalrm) {
44478064Sume			ripalarm();
44578064Sume			seenalrm = 0;
44678064Sume			continue;
44778064Sume		}
44878064Sume		if (seenquit) {
44978064Sume			rtdexit();
45078064Sume			seenquit = 0;
45178064Sume			continue;
45278064Sume		}
45378064Sume		if (seenusr1) {
45478064Sume			ifrtdump(SIGUSR1);
45578064Sume			seenusr1 = 0;
45678064Sume			continue;
45778064Sume		}
45878064Sume
45955163Sshin		FD_COPY(&sockvec, &recvec);
46078064Sume		signo = 0;
46155163Sshin		switch (select(FD_SETSIZE, &recvec, 0, 0, 0)) {
46255163Sshin		case -1:
46378064Sume			if (errno != EINTR) {
46478064Sume				fatal("select");
46578064Sume				/*NOTREACHED*/
46678064Sume			}
46778064Sume			continue;
46855163Sshin		case 0:
46955163Sshin			continue;
47055163Sshin		default:
47155163Sshin			if (FD_ISSET(ripsock, &recvec)) {
47255163Sshin				sigprocmask(SIG_BLOCK, &mask, &omask);
47355163Sshin				riprecv();
47455163Sshin				sigprocmask(SIG_SETMASK, &omask, NULL);
47555163Sshin			}
47655163Sshin			if (FD_ISSET(rtsock, &recvec)) {
47755163Sshin				sigprocmask(SIG_BLOCK, &mask, &omask);
47855163Sshin				rtrecv();
47955163Sshin				sigprocmask(SIG_SETMASK, &omask, NULL);
48055163Sshin			}
48155163Sshin		}
48255163Sshin	}
48355163Sshin}
48455163Sshin
48578064Sumevoid
48678064Sumesighandler(sig)
48778064Sume	int sig;
48878064Sume{
48978064Sume
49078064Sume	signo = sig;
49178064Sume	switch (signo) {
49278064Sume	case SIGALRM:
49378064Sume		seenalrm++;
49478064Sume		break;
49578064Sume	case SIGQUIT:
49678064Sume	case SIGTERM:
49778064Sume		seenquit++;
49878064Sume		break;
49978064Sume	case SIGUSR1:
50078064Sume	case SIGHUP:
50178064Sume	case SIGINT:
50278064Sume		seenusr1++;
50378064Sume		break;
50478064Sume	}
50578064Sume}
50678064Sume
50755163Sshin/*
50855163Sshin * gracefully exits after resetting sockopts.
50955163Sshin */
51055163Sshin/* ARGSUSED */
51155163Sshinvoid
51278064Sumertdexit()
51355163Sshin{
51455163Sshin	struct	riprt *rrt;
51555163Sshin
51655163Sshin	alarm(0);
51755163Sshin	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
51862607Sitojun		if (rrt->rrt_rflags & RRTF_AGGREGATE) {
51955163Sshin			delroute(&rrt->rrt_info, &rrt->rrt_gw);
52055163Sshin		}
52155163Sshin	}
52255163Sshin	close(ripsock);
52355163Sshin	close(rtsock);
52455163Sshin	syslog(LOG_INFO, "**** Terminated ****");
52555163Sshin	closelog();
52655163Sshin	exit(1);
52755163Sshin}
52855163Sshin
52955163Sshin/*
53055163Sshin * Called periodically:
53155163Sshin *	1. age out the learned route. remove it if necessary.
53255163Sshin *	2. submit RIP6_RESPONSE packets.
53378064Sume * Invoked in every SUPPLY_INTERVAL6 (30) seconds.  I believe we don't have
53455163Sshin * to invoke this function in every 1 or 5 or 10 seconds only to age the
53555163Sshin * routes more precisely.
53655163Sshin */
53755163Sshin/* ARGSUSED */
53855163Sshinvoid
53978064Sumeripalarm()
54055163Sshin{
54155163Sshin	struct	ifc *ifcp;
54255163Sshin	struct	riprt *rrt, *rrt_prev, *rrt_next;
54355163Sshin	time_t	t_lifetime, t_holddown;
54455163Sshin
54555163Sshin	/* age the RIP routes */
54655163Sshin	rrt_prev = 0;
54755163Sshin	t_lifetime = time(NULL) - RIP_LIFETIME;
54855163Sshin	t_holddown = t_lifetime - RIP_HOLDDOWN;
54955163Sshin	for (rrt = riprt; rrt; rrt = rrt_next) {
55055163Sshin		rrt_next = rrt->rrt_next;
55155163Sshin
55255163Sshin		if (rrt->rrt_t == 0) {
55355163Sshin			rrt_prev = rrt;
55455163Sshin			continue;
55555163Sshin		}
55655163Sshin		if (rrt->rrt_t < t_holddown) {
55755163Sshin			if (rrt_prev) {
55855163Sshin				rrt_prev->rrt_next = rrt->rrt_next;
55955163Sshin			} else {
56055163Sshin				riprt = rrt->rrt_next;
56155163Sshin			}
56255163Sshin			delroute(&rrt->rrt_info, &rrt->rrt_gw);
56355163Sshin			free(rrt);
56455163Sshin			continue;
56555163Sshin		}
56655163Sshin		if (rrt->rrt_t < t_lifetime)
56755163Sshin			rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
56855163Sshin		rrt_prev = rrt;
56955163Sshin	}
57055163Sshin	/* Supply updates */
57155163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
57255163Sshin		if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP))
57355163Sshin			ripsend(ifcp, &ifcp->ifc_ripsin, 0);
57455163Sshin	}
57555163Sshin	alarm(ripinterval(SUPPLY_INTERVAL6));
57655163Sshin}
57755163Sshin
57855163Sshinvoid
57955163Sshininit()
58055163Sshin{
581119034Sume	int	error;
582119034Sume	const int int0 = 0, int1 = 1, int255 = 255;
58355163Sshin	struct	addrinfo hints, *res;
58455163Sshin	char	port[10];
58555163Sshin
58655163Sshin	ifc = (struct ifc *)NULL;
58755163Sshin	nifc = 0;
58855163Sshin	nindex2ifc = 0;	/*initial guess*/
58955163Sshin	index2ifc = NULL;
59055163Sshin	snprintf(port, sizeof(port), "%d", RIP6_PORT);
59155163Sshin
59255163Sshin	memset(&hints, 0, sizeof(hints));
59355163Sshin	hints.ai_family = PF_INET6;
59455163Sshin	hints.ai_socktype = SOCK_DGRAM;
59555163Sshin	hints.ai_flags = AI_PASSIVE;
59655163Sshin	error = getaddrinfo(NULL, port, &hints, &res);
59778064Sume	if (error) {
59866807Skris		fatal("%s", gai_strerror(error));
59978064Sume		/*NOTREACHED*/
60078064Sume	}
60178064Sume	if (res->ai_next) {
60255163Sshin		fatal(":: resolved to multiple address");
60378064Sume		/*NOTREACHED*/
60478064Sume	}
60555163Sshin
60655163Sshin	ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
60778064Sume	if (ripsock < 0) {
60855163Sshin		fatal("rip socket");
60978064Sume		/*NOTREACHED*/
61078064Sume	}
611119034Sume#ifdef IPV6_V6ONLY
612119034Sume	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_V6ONLY,
613119034Sume	    &int1, sizeof(int1)) < 0) {
614119034Sume		fatal("rip IPV6_V6ONLY");
615119034Sume		/*NOTREACHED*/
616119034Sume	}
617119034Sume#endif
61878064Sume	if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0) {
61955163Sshin		fatal("rip bind");
62078064Sume		/*NOTREACHED*/
62178064Sume	}
62255163Sshin	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
62378064Sume	    &int255, sizeof(int255)) < 0) {
62455163Sshin		fatal("rip IPV6_MULTICAST_HOPS");
62578064Sume		/*NOTREACHED*/
62678064Sume	}
62755163Sshin	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
62878064Sume	    &int0, sizeof(int0)) < 0) {
62955163Sshin		fatal("rip IPV6_MULTICAST_LOOP");
63078064Sume		/*NOTREACHED*/
63178064Sume	}
63262921Sume
63362607Sitojun#ifdef IPV6_RECVPKTINFO
634119034Sume	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
635119034Sume	    &int1, sizeof(int1)) < 0) {
63662607Sitojun		fatal("rip IPV6_RECVPKTINFO");
63778064Sume		/*NOTREACHED*/
63878064Sume	}
63962607Sitojun#else  /* old adv. API */
640119034Sume	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_PKTINFO,
641119034Sume	    &int1, sizeof(int1)) < 0) {
64255163Sshin		fatal("rip IPV6_PKTINFO");
64378064Sume		/*NOTREACHED*/
64478064Sume	}
64562607Sitojun#endif
64655163Sshin
64755163Sshin	memset(&hints, 0, sizeof(hints));
64855163Sshin	hints.ai_family = PF_INET6;
64955163Sshin	hints.ai_socktype = SOCK_DGRAM;
65055163Sshin	error = getaddrinfo(RIP6_DEST, port, &hints, &res);
65178064Sume	if (error) {
65266807Skris		fatal("%s", gai_strerror(error));
65378064Sume		/*NOTREACHED*/
65478064Sume	}
65578064Sume	if (res->ai_next) {
65655163Sshin		fatal("%s resolved to multiple address", RIP6_DEST);
65778064Sume		/*NOTREACHED*/
65878064Sume	}
65955163Sshin	memcpy(&ripsin, res->ai_addr, res->ai_addrlen);
66055163Sshin
66155163Sshin#ifdef FD_ZERO
66255163Sshin	FD_ZERO(&sockvec);
66355163Sshin#else
66455163Sshin	memset(&sockvec, 0, sizeof(sockvec));
66555163Sshin#endif
66655163Sshin	FD_SET(ripsock, &sockvec);
66755163Sshin
66855163Sshin	if (nflag == 0) {
66978064Sume		if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
67055163Sshin			fatal("route socket");
67178064Sume			/*NOTREACHED*/
67278064Sume		}
67355163Sshin		FD_SET(rtsock, &sockvec);
67455163Sshin	} else
67555163Sshin		rtsock = -1;	/*just for safety */
67655163Sshin}
67755163Sshin
67862607Sitojun#define	RIPSIZE(n) \
67962607Sitojun	(sizeof(struct rip6) + ((n)-1) * sizeof(struct netinfo6))
68055163Sshin
68155163Sshin/*
68255163Sshin * ripflush flushes the rip datagram stored in the rip buffer
68355163Sshin */
68455163Sshinstatic int nrt;
68555163Sshinstatic struct netinfo6 *np;
68655163Sshin
68755163Sshinvoid
688119031Sumeripflush(ifcp, sin6)
68955163Sshin	struct ifc *ifcp;
690119031Sume	struct sockaddr_in6 *sin6;
69155163Sshin{
69255163Sshin	int i;
69355163Sshin	int error;
69455163Sshin
69555163Sshin	if (ifcp)
69655163Sshin		tracet(1, "Send(%s): info(%d) to %s.%d\n",
69755163Sshin			ifcp->ifc_name, nrt,
698119031Sume			inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port));
69955163Sshin	else
70055163Sshin		tracet(1, "Send: info(%d) to %s.%d\n",
701119031Sume			nrt, inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port));
70255163Sshin	if (dflag >= 2) {
70355163Sshin		np = ripbuf->rip6_nets;
70455163Sshin		for (i = 0; i < nrt; i++, np++) {
70555163Sshin			if (np->rip6_metric == NEXTHOP_METRIC) {
70655163Sshin				if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest))
70762607Sitojun					trace(2, "    NextHop reset");
70855163Sshin				else {
70955163Sshin					trace(2, "    NextHop %s",
71055163Sshin						inet6_n2p(&np->rip6_dest));
71155163Sshin				}
71255163Sshin			} else {
71355163Sshin				trace(2, "    %s/%d[%d]",
71455163Sshin					inet6_n2p(&np->rip6_dest),
71555163Sshin					np->rip6_plen, np->rip6_metric);
71655163Sshin			}
71755163Sshin			if (np->rip6_tag) {
71855163Sshin				trace(2, "  tag=0x%04x",
71955163Sshin					ntohs(np->rip6_tag) & 0xffff);
72055163Sshin			}
72155163Sshin			trace(2, "\n");
72255163Sshin		}
72355163Sshin	}
724119031Sume	error = sendpacket(sin6, RIPSIZE(nrt));
72555163Sshin	if (error == EAFNOSUPPORT) {
72655163Sshin		/* Protocol not supported */
72755163Sshin		tracet(1, "Could not send info to %s (%s): "
72855163Sshin			"set IFF_UP to 0\n",
72955163Sshin			ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
73055163Sshin		ifcp->ifc_flags &= ~IFF_UP;	/* As if down for AF_INET6 */
73155163Sshin	}
73255163Sshin	nrt = 0; np = ripbuf->rip6_nets;
73355163Sshin}
73455163Sshin
73555163Sshin/*
73655163Sshin * Generate RIP6_RESPONSE packets and send them.
73755163Sshin */
73855163Sshinvoid
739119031Sumeripsend(ifcp, sin6, flag)
74055163Sshin	struct	ifc *ifcp;
741119031Sume	struct	sockaddr_in6 *sin6;
74255163Sshin	int flag;
74355163Sshin{
74455163Sshin	struct	riprt *rrt;
74555163Sshin	struct	in6_addr *nh;	/* next hop */
74678064Sume	int	maxrte;
74755163Sshin
74855163Sshin	if (ifcp == NULL) {
74955163Sshin		/*
75055163Sshin		 * Request from non-link local address is not
75155163Sshin		 * a regular route6d update.
75255163Sshin		 */
75362607Sitojun		maxrte = (IFMINMTU - sizeof(struct ip6_hdr) -
75462607Sitojun				sizeof(struct udphdr) -
75555163Sshin				sizeof(struct rip6) + sizeof(struct netinfo6)) /
75655163Sshin				sizeof(struct netinfo6);
75755163Sshin		nrt = 0; np = ripbuf->rip6_nets; nh = NULL;
75855163Sshin		for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
75962607Sitojun			if (rrt->rrt_rflags & RRTF_NOADVERTISE)
76055163Sshin				continue;
76155163Sshin			/* Put the route to the buffer */
76255163Sshin			*np = rrt->rrt_info;
76355163Sshin			np++; nrt++;
76455163Sshin			if (nrt == maxrte) {
765119031Sume				ripflush(NULL, sin6);
76655163Sshin				nh = NULL;
76755163Sshin			}
76855163Sshin		}
76955163Sshin		if (nrt)	/* Send last packet */
770119031Sume			ripflush(NULL, sin6);
77155163Sshin		return;
77255163Sshin	}
77355163Sshin
77462607Sitojun	if ((flag & RRTF_SENDANYWAY) == 0 &&
77555163Sshin	    (qflag || (ifcp->ifc_flags & IFF_LOOPBACK)))
77655163Sshin		return;
77778064Sume
77878064Sume	/* -N: no use */
77955163Sshin	if (iff_find(ifcp, 'N') != NULL)
78055163Sshin		return;
78178064Sume
78278064Sume	/* -T: generate default route only */
78355163Sshin	if (iff_find(ifcp, 'T') != NULL) {
78455163Sshin		struct netinfo6 rrt_info;
78555163Sshin		memset(&rrt_info, 0, sizeof(struct netinfo6));
78655163Sshin		rrt_info.rip6_dest = in6addr_any;
78755163Sshin		rrt_info.rip6_plen = 0;
78855163Sshin		rrt_info.rip6_metric = 1;
78978064Sume		rrt_info.rip6_metric += ifcp->ifc_metric;
79055163Sshin		rrt_info.rip6_tag = htons(routetag & 0xffff);
79155163Sshin		np = ripbuf->rip6_nets;
79255163Sshin		*np = rrt_info;
79355163Sshin		nrt = 1;
794119031Sume		ripflush(ifcp, sin6);
79555163Sshin		return;
79655163Sshin	}
79778064Sume
79862607Sitojun	maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) -
79962607Sitojun			sizeof(struct udphdr) -
80055163Sshin			sizeof(struct rip6) + sizeof(struct netinfo6)) /
80155163Sshin			sizeof(struct netinfo6);
80278064Sume
80355163Sshin	nrt = 0; np = ripbuf->rip6_nets; nh = NULL;
80455163Sshin	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
80562607Sitojun		if (rrt->rrt_rflags & RRTF_NOADVERTISE)
80655163Sshin			continue;
80778064Sume
80878064Sume		/* Need to check filter here */
80978064Sume		if (out_filter(rrt, ifcp) == 0)
81055163Sshin			continue;
81178064Sume
81255163Sshin		/* Check split horizon and other conditions */
81355163Sshin		if (tobeadv(rrt, ifcp) == 0)
81455163Sshin			continue;
81578064Sume
81655163Sshin		/* Only considers the routes with flag if specified */
81762607Sitojun		if ((flag & RRTF_CHANGED) &&
81862607Sitojun		    (rrt->rrt_rflags & RRTF_CHANGED) == 0)
81955163Sshin			continue;
82078064Sume
82155163Sshin		/* Check nexthop */
82255163Sshin		if (rrt->rrt_index == ifcp->ifc_index &&
82355163Sshin		    !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) &&
82462607Sitojun		    (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) == 0) {
82555163Sshin			if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) {
82655163Sshin				if (nrt == maxrte - 2)
827119031Sume					ripflush(ifcp, sin6);
82855163Sshin				np->rip6_dest = rrt->rrt_gw;
82955163Sshin				if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest))
83055163Sshin					SET_IN6_LINKLOCAL_IFINDEX(np->rip6_dest, 0);
83155163Sshin				np->rip6_plen = 0;
83255163Sshin				np->rip6_tag = 0;
83355163Sshin				np->rip6_metric = NEXTHOP_METRIC;
83455163Sshin				nh = &rrt->rrt_gw;
83555163Sshin				np++; nrt++;
83655163Sshin			}
83755163Sshin		} else if (nh && (rrt->rrt_index != ifcp->ifc_index ||
83855163Sshin			          !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) ||
83962607Sitojun				  rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)) {
84055163Sshin			/* Reset nexthop */
84155163Sshin			if (nrt == maxrte - 2)
842119031Sume				ripflush(ifcp, sin6);
84355163Sshin			memset(np, 0, sizeof(struct netinfo6));
84455163Sshin			np->rip6_metric = NEXTHOP_METRIC;
84555163Sshin			nh = NULL;
84655163Sshin			np++; nrt++;
84755163Sshin		}
84878064Sume
84955163Sshin		/* Put the route to the buffer */
85055163Sshin		*np = rrt->rrt_info;
85155163Sshin		np++; nrt++;
85255163Sshin		if (nrt == maxrte) {
853119031Sume			ripflush(ifcp, sin6);
85455163Sshin			nh = NULL;
85555163Sshin		}
85655163Sshin	}
85755163Sshin	if (nrt)	/* Send last packet */
858119031Sume		ripflush(ifcp, sin6);
85955163Sshin}
86055163Sshin
86155163Sshin/*
86278064Sume * outbound filter logic, per-route/interface.
86378064Sume */
86478064Sumeint
86578064Sumeout_filter(rrt, ifcp)
86678064Sume	struct riprt *rrt;
86778064Sume	struct ifc *ifcp;
86878064Sume{
86978064Sume	struct iff *iffp;
87078064Sume	struct in6_addr ia;
87178064Sume	int ok;
87278064Sume
87378064Sume	/*
87478064Sume	 * -A: filter out less specific routes, if we have aggregated
87578064Sume	 * route configured.
87678064Sume	 */
87778064Sume	for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
87878064Sume		if (iffp->iff_type != 'A')
87978064Sume			continue;
88078064Sume		if (rrt->rrt_info.rip6_plen <= iffp->iff_plen)
88178064Sume			continue;
88278064Sume		ia = rrt->rrt_info.rip6_dest;
88378064Sume		applyplen(&ia, iffp->iff_plen);
88478064Sume		if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr))
88578064Sume			return 0;
88678064Sume	}
88778064Sume
88878064Sume	/*
88978064Sume	 * if it is an aggregated route, advertise it only to the
89078064Sume	 * interfaces specified on -A.
89178064Sume	 */
89278064Sume	if ((rrt->rrt_rflags & RRTF_AGGREGATE) != 0) {
89378064Sume		ok = 0;
89478064Sume		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
89578064Sume			if (iffp->iff_type != 'A')
89678064Sume				continue;
89778064Sume			if (rrt->rrt_info.rip6_plen == iffp->iff_plen &&
89878064Sume			    IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
89978064Sume			    &iffp->iff_addr)) {
90078064Sume				ok = 1;
90178064Sume				break;
90278064Sume			}
90378064Sume		}
90478064Sume		if (!ok)
90578064Sume			return 0;
90678064Sume	}
90778064Sume
90878064Sume	/*
90978064Sume	 * -O: advertise only if prefix matches the configured prefix.
91078064Sume	 */
91178064Sume	if (iff_find(ifcp, 'O')) {
91278064Sume		ok = 0;
91378064Sume		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
91478064Sume			if (iffp->iff_type != 'O')
91578064Sume				continue;
91678064Sume			if (rrt->rrt_info.rip6_plen < iffp->iff_plen)
91778064Sume				continue;
91878064Sume			ia = rrt->rrt_info.rip6_dest;
91978064Sume			applyplen(&ia, iffp->iff_plen);
92078064Sume			if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) {
92178064Sume				ok = 1;
92278064Sume				break;
92378064Sume			}
92478064Sume		}
92578064Sume		if (!ok)
92678064Sume			return 0;
92778064Sume	}
92878064Sume
92978064Sume	/* the prefix should be advertised */
93078064Sume	return 1;
93178064Sume}
93278064Sume
93378064Sume/*
93455163Sshin * Determine if the route is to be advertised on the specified interface.
93555163Sshin * It checks options specified in the arguments and the split horizon rule.
93655163Sshin */
93755163Sshinint
93855163Sshintobeadv(rrt, ifcp)
93955163Sshin	struct riprt *rrt;
94055163Sshin	struct ifc *ifcp;
94155163Sshin{
94255163Sshin
94355163Sshin	/* Special care for static routes */
94455163Sshin	if (rrt->rrt_flags & RTF_STATIC) {
94562607Sitojun		/* XXX don't advertise reject/blackhole routes */
94662607Sitojun		if (rrt->rrt_flags & (RTF_REJECT | RTF_BLACKHOLE))
94762607Sitojun			return 0;
94862607Sitojun
94955163Sshin		if (Sflag)	/* Yes, advertise it anyway */
95055163Sshin			return 1;
95155163Sshin		if (sflag && rrt->rrt_index != ifcp->ifc_index)
95255163Sshin			return 1;
95355163Sshin		return 0;
95455163Sshin	}
95555163Sshin	/* Regular split horizon */
95655163Sshin	if (hflag == 0 && rrt->rrt_index == ifcp->ifc_index)
95755163Sshin		return 0;
95855163Sshin	return 1;
95955163Sshin}
96055163Sshin
96155163Sshin/*
96255163Sshin * Send a rip packet actually.
96355163Sshin */
96455163Sshinint
965119031Sumesendpacket(sin6, len)
966119031Sume	struct	sockaddr_in6 *sin6;
96755163Sshin	int	len;
96855163Sshin{
96955163Sshin	/*
97055163Sshin	 * MSG_DONTROUTE should not be specified when it responds with a
97178064Sume	 * RIP6_REQUEST message.  SO_DONTROUTE has been specified to
97255163Sshin	 * other sockets.
97355163Sshin	 */
97455163Sshin	struct msghdr m;
97555163Sshin	struct cmsghdr *cm;
97655163Sshin	struct iovec iov[2];
97755163Sshin	u_char cmsgbuf[256];
97855163Sshin	struct in6_pktinfo *pi;
97978064Sume	int idx;
98055163Sshin	struct sockaddr_in6 sincopy;
98155163Sshin
98255163Sshin	/* do not overwrite the given sin */
983119031Sume	sincopy = *sin6;
984119031Sume	sin6 = &sincopy;
98555163Sshin
986119035Sume	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
987119035Sume	    IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
988119031Sume		idx = IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr);
989119031Sume		SET_IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr, 0);
99055163Sshin	} else
99178064Sume		idx = 0;
99255163Sshin
993119031Sume	m.msg_name = (caddr_t)sin6;
994119031Sume	m.msg_namelen = sizeof(*sin6);
99555163Sshin	iov[0].iov_base = (caddr_t)ripbuf;
99655163Sshin	iov[0].iov_len = len;
99755163Sshin	m.msg_iov = iov;
99855163Sshin	m.msg_iovlen = 1;
99978064Sume	if (!idx) {
100055163Sshin		m.msg_control = NULL;
100155163Sshin		m.msg_controllen = 0;
100255163Sshin	} else {
100355163Sshin		memset(cmsgbuf, 0, sizeof(cmsgbuf));
100455163Sshin		cm = (struct cmsghdr *)cmsgbuf;
100555163Sshin		m.msg_control = (caddr_t)cm;
100655163Sshin		m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
100755163Sshin
100855163Sshin		cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
100955163Sshin		cm->cmsg_level = IPPROTO_IPV6;
101055163Sshin		cm->cmsg_type = IPV6_PKTINFO;
101155163Sshin		pi = (struct in6_pktinfo *)CMSG_DATA(cm);
101255163Sshin		memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/
101378064Sume		pi->ipi6_ifindex = idx;
101455163Sshin	}
101555163Sshin
101655163Sshin	if (sendmsg(ripsock, &m, 0 /*MSG_DONTROUTE*/) < 0) {
101755163Sshin		trace(1, "sendmsg: %s\n", strerror(errno));
101855163Sshin		return errno;
101955163Sshin	}
102062921Sume
102155163Sshin	return 0;
102255163Sshin}
102355163Sshin
102455163Sshin/*
102578064Sume * Receive and process RIP packets.  Update the routes/kernel forwarding
102655163Sshin * table if necessary.
102755163Sshin */
102855163Sshinvoid
102955163Sshinriprecv()
103055163Sshin{
103155163Sshin	struct	ifc *ifcp, *ic;
103255163Sshin	struct	sockaddr_in6 fsock;
103355163Sshin	struct	in6_addr nh;	/* next hop */
103455163Sshin	struct	rip6 *rp;
103555163Sshin	struct	netinfo6 *np, *nq;
103655163Sshin	struct	riprt *rrt;
103778064Sume	int	len, nn, need_trigger, idx;
103855163Sshin	char	buf[4 * RIP6_MAXMTU];
103955163Sshin	time_t	t;
104055163Sshin	struct msghdr m;
104155163Sshin	struct cmsghdr *cm;
104255163Sshin	struct iovec iov[2];
104355163Sshin	u_char cmsgbuf[256];
104455163Sshin	struct in6_pktinfo *pi;
104555163Sshin	struct iff *iffp;
104655163Sshin	struct in6_addr ia;
104755163Sshin	int ok;
104878064Sume	time_t t_half_lifetime;
104955163Sshin
105055163Sshin	need_trigger = 0;
105162921Sume
105255163Sshin	m.msg_name = (caddr_t)&fsock;
105355163Sshin	m.msg_namelen = sizeof(fsock);
105455163Sshin	iov[0].iov_base = (caddr_t)buf;
105555163Sshin	iov[0].iov_len = sizeof(buf);
105655163Sshin	m.msg_iov = iov;
105755163Sshin	m.msg_iovlen = 1;
105855163Sshin	cm = (struct cmsghdr *)cmsgbuf;
105955163Sshin	m.msg_control = (caddr_t)cm;
106055163Sshin	m.msg_controllen = sizeof(cmsgbuf);
106178064Sume	if ((len = recvmsg(ripsock, &m, 0)) < 0) {
106255163Sshin		fatal("recvmsg");
106378064Sume		/*NOTREACHED*/
106478064Sume	}
106578064Sume	idx = 0;
106655163Sshin	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m);
106755163Sshin	     cm;
106855163Sshin	     cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) {
106978064Sume		if (cm->cmsg_level == IPPROTO_IPV6 &&
107078064Sume		    cm->cmsg_type == IPV6_PKTINFO) {
107155163Sshin			pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
107278064Sume			idx = pi->ipi6_ifindex;
107355163Sshin			break;
107455163Sshin		}
107555163Sshin	}
107678064Sume	if (idx && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr))
107778064Sume		SET_IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr, idx);
107855163Sshin
107955163Sshin	nh = fsock.sin6_addr;
108055163Sshin	nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) /
108155163Sshin		sizeof(struct netinfo6);
108255163Sshin	rp = (struct rip6 *)buf;
108355163Sshin	np = rp->rip6_nets;
108455163Sshin
1085119035Sume	if (rp->rip6_vers != RIP6_VERSION) {
108655163Sshin		trace(1, "Incorrect RIP version %d\n", rp->rip6_vers);
108755163Sshin		return;
108855163Sshin	}
108955163Sshin	if (rp->rip6_cmd == RIP6_REQUEST) {
109078064Sume		if (idx && idx < nindex2ifc) {
109178064Sume			ifcp = index2ifc[idx];
109255163Sshin			riprequest(ifcp, np, nn, &fsock);
109355163Sshin		} else {
109455163Sshin			riprequest(NULL, np, nn, &fsock);
109555163Sshin		}
109662607Sitojun		return;
109762607Sitojun	}
109855163Sshin
109955163Sshin	if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) {
110055163Sshin		trace(1, "Packets from non-ll addr: %s\n",
110178064Sume		    inet6_n2p(&fsock.sin6_addr));
110255163Sshin		return;		/* Ignore packets from non-link-local addr */
110355163Sshin	}
110478064Sume	idx = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr);
110578064Sume	ifcp = (idx < nindex2ifc) ? index2ifc[idx] : NULL;
110655163Sshin	if (!ifcp) {
110778064Sume		trace(1, "Packets to unknown interface index %d\n", idx);
110855163Sshin		return;		/* Ignore it */
110955163Sshin	}
111055163Sshin	if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr))
111155163Sshin		return;		/* The packet is from me; ignore */
111255163Sshin	if (rp->rip6_cmd != RIP6_RESPONSE) {
111355163Sshin		trace(1, "Invalid command %d\n", rp->rip6_cmd);
111462607Sitojun		return;
111555163Sshin	}
111678064Sume
111778064Sume	/* -N: no use */
111855163Sshin	if (iff_find(ifcp, 'N') != NULL)
111955163Sshin		return;
112078064Sume
112155163Sshin	tracet(1, "Recv(%s): from %s.%d info(%d)\n",
112278064Sume	    ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn);
112355163Sshin
112455163Sshin	t = time(NULL);
112578064Sume	t_half_lifetime = t - (RIP_LIFETIME/2);
112655163Sshin	for (; nn; nn--, np++) {
112755163Sshin		if (np->rip6_metric == NEXTHOP_METRIC) {
112855163Sshin			/* modify neighbor address */
112955163Sshin			if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) {
113055163Sshin				nh = np->rip6_dest;
113178064Sume				SET_IN6_LINKLOCAL_IFINDEX(nh, idx);
113255163Sshin				trace(1, "\tNexthop: %s\n", inet6_n2p(&nh));
113355163Sshin			} else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) {
113455163Sshin				nh = fsock.sin6_addr;
113555163Sshin				trace(1, "\tNexthop: %s\n", inet6_n2p(&nh));
113655163Sshin			} else {
113755163Sshin				nh = fsock.sin6_addr;
113855163Sshin				trace(1, "\tInvalid Nexthop: %s\n",
113978064Sume				    inet6_n2p(&np->rip6_dest));
114055163Sshin			}
114155163Sshin			continue;
114255163Sshin		}
114355163Sshin		if (IN6_IS_ADDR_MULTICAST(&np->rip6_dest)) {
114455163Sshin			trace(1, "\tMulticast netinfo6: %s/%d [%d]\n",
114555163Sshin				inet6_n2p(&np->rip6_dest),
114655163Sshin				np->rip6_plen, np->rip6_metric);
114755163Sshin			continue;
114855163Sshin		}
114955163Sshin		if (IN6_IS_ADDR_LOOPBACK(&np->rip6_dest)) {
115055163Sshin			trace(1, "\tLoopback netinfo6: %s/%d [%d]\n",
115155163Sshin				inet6_n2p(&np->rip6_dest),
115255163Sshin				np->rip6_plen, np->rip6_metric);
115355163Sshin			continue;
115455163Sshin		}
115555163Sshin		if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) {
115655163Sshin			trace(1, "\tLink Local netinfo6: %s/%d [%d]\n",
115755163Sshin				inet6_n2p(&np->rip6_dest),
115855163Sshin				np->rip6_plen, np->rip6_metric);
115955163Sshin			continue;
116055163Sshin		}
116155163Sshin		/* may need to pass sitelocal prefix in some case, however*/
116255163Sshin		if (IN6_IS_ADDR_SITELOCAL(&np->rip6_dest) && !lflag) {
116355163Sshin			trace(1, "\tSite Local netinfo6: %s/%d [%d]\n",
116455163Sshin				inet6_n2p(&np->rip6_dest),
116555163Sshin				np->rip6_plen, np->rip6_metric);
116655163Sshin			continue;
116755163Sshin		}
116855163Sshin		trace(2, "\tnetinfo6: %s/%d [%d]",
116955163Sshin			inet6_n2p(&np->rip6_dest),
117055163Sshin			np->rip6_plen, np->rip6_metric);
117155163Sshin		if (np->rip6_tag)
117255163Sshin			trace(2, "  tag=0x%04x", ntohs(np->rip6_tag) & 0xffff);
117362607Sitojun		if (dflag >= 2) {
117462607Sitojun			ia = np->rip6_dest;
117562607Sitojun			applyplen(&ia, np->rip6_plen);
117662607Sitojun			if (!IN6_ARE_ADDR_EQUAL(&ia, &np->rip6_dest))
117762607Sitojun				trace(2, " [junk outside prefix]");
117862607Sitojun		}
117955163Sshin
118078064Sume		/*
118178064Sume		 * -L: listen only if the prefix matches the configuration
118278064Sume		 */
118355163Sshin		ok = 1;		/* if there's no L filter, it is ok */
118455163Sshin		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
118555163Sshin			if (iffp->iff_type != 'L')
118655163Sshin				continue;
118755163Sshin			ok = 0;
118855163Sshin			if (np->rip6_plen < iffp->iff_plen)
118955163Sshin				continue;
119055163Sshin			/* special rule: ::/0 means default, not "in /0" */
119155163Sshin			if (iffp->iff_plen == 0 && np->rip6_plen > 0)
119255163Sshin				continue;
119362607Sitojun			ia = np->rip6_dest;
119455163Sshin			applyplen(&ia, iffp->iff_plen);
119555163Sshin			if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) {
119655163Sshin				ok = 1;
119755163Sshin				break;
119855163Sshin			}
119955163Sshin		}
120055163Sshin		if (!ok) {
120155163Sshin			trace(2, "  (filtered)\n");
120255163Sshin			continue;
120355163Sshin		}
120455163Sshin
120555163Sshin		trace(2, "\n");
120655163Sshin		np->rip6_metric++;
120755163Sshin		np->rip6_metric += ifcp->ifc_metric;
120855163Sshin		if (np->rip6_metric > HOPCNT_INFINITY6)
120955163Sshin			np->rip6_metric = HOPCNT_INFINITY6;
121055163Sshin
121155163Sshin		applyplen(&np->rip6_dest, np->rip6_plen);
121278064Sume		if ((rrt = rtsearch(np, NULL)) != NULL) {
121355163Sshin			if (rrt->rrt_t == 0)
121455163Sshin				continue;	/* Intf route has priority */
121555163Sshin			nq = &rrt->rrt_info;
121655163Sshin			if (nq->rip6_metric > np->rip6_metric) {
121755163Sshin				if (rrt->rrt_index == ifcp->ifc_index &&
121855163Sshin				    IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
121955163Sshin					/* Small metric from the same gateway */
122055163Sshin					nq->rip6_metric = np->rip6_metric;
122155163Sshin				} else {
122255163Sshin					/* Better route found */
122355163Sshin					rrt->rrt_index = ifcp->ifc_index;
122455163Sshin					/* Update routing table */
122555163Sshin					delroute(nq, &rrt->rrt_gw);
122655163Sshin					rrt->rrt_gw = nh;
122755163Sshin					*nq = *np;
122855163Sshin					addroute(rrt, &nh, ifcp);
122955163Sshin				}
123062607Sitojun				rrt->rrt_rflags |= RRTF_CHANGED;
123155163Sshin				rrt->rrt_t = t;
123255163Sshin				need_trigger = 1;
123355163Sshin			} else if (nq->rip6_metric < np->rip6_metric &&
123455163Sshin				   rrt->rrt_index == ifcp->ifc_index &&
123555163Sshin				   IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
123655163Sshin				/* Got worse route from same gw */
123755163Sshin				nq->rip6_metric = np->rip6_metric;
123855163Sshin				rrt->rrt_t = t;
123962607Sitojun				rrt->rrt_rflags |= RRTF_CHANGED;
124055163Sshin				need_trigger = 1;
124155163Sshin			} else if (nq->rip6_metric == np->rip6_metric &&
124255163Sshin				   np->rip6_metric < HOPCNT_INFINITY6) {
124378064Sume				if (rrt->rrt_index == ifcp->ifc_index &&
124478064Sume				   IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
124578064Sume					/* same metric, same route from same gw */
124678064Sume					rrt->rrt_t = t;
124778064Sume				} else if (rrt->rrt_t < t_half_lifetime) {
124878064Sume					/* Better route found */
124978064Sume					rrt->rrt_index = ifcp->ifc_index;
125078064Sume					/* Update routing table */
125178064Sume					delroute(nq, &rrt->rrt_gw);
125278064Sume					rrt->rrt_gw = nh;
125378064Sume					*nq = *np;
125478064Sume					addroute(rrt, &nh, ifcp);
125578064Sume					rrt->rrt_rflags |= RRTF_CHANGED;
125678064Sume					rrt->rrt_t = t;
125778064Sume				}
125855163Sshin			}
125962607Sitojun			/*
126055163Sshin			 * if nq->rip6_metric == HOPCNT_INFINITY6 then
126178064Sume			 * do not update age value.  Do nothing.
126255163Sshin			 */
126355163Sshin		} else if (np->rip6_metric < HOPCNT_INFINITY6) {
126455163Sshin			/* Got a new valid route */
126578064Sume			if ((rrt = MALLOC(struct riprt)) == NULL) {
126655163Sshin				fatal("malloc: struct riprt");
126778064Sume				/*NOTREACHED*/
126878064Sume			}
126962607Sitojun			memset(rrt, 0, sizeof(*rrt));
127055163Sshin			nq = &rrt->rrt_info;
127155163Sshin
127255163Sshin			rrt->rrt_same = NULL;
127355163Sshin			rrt->rrt_index = ifcp->ifc_index;
127455163Sshin			rrt->rrt_flags = RTF_UP|RTF_GATEWAY;
127555163Sshin			rrt->rrt_gw = nh;
127655163Sshin			*nq = *np;
127755163Sshin			applyplen(&nq->rip6_dest, nq->rip6_plen);
127855163Sshin			if (nq->rip6_plen == sizeof(struct in6_addr) * 8)
127955163Sshin				rrt->rrt_flags |= RTF_HOST;
128055163Sshin
128155163Sshin			/* Put the route to the list */
128255163Sshin			rrt->rrt_next = riprt;
128355163Sshin			riprt = rrt;
128455163Sshin			/* Update routing table */
128555163Sshin			addroute(rrt, &nh, ifcp);
128662607Sitojun			rrt->rrt_rflags |= RRTF_CHANGED;
128755163Sshin			need_trigger = 1;
128855163Sshin			rrt->rrt_t = t;
128955163Sshin		}
129055163Sshin	}
129155163Sshin	/* XXX need to care the interval between triggered updates */
129255163Sshin	if (need_trigger) {
129355163Sshin		if (nextalarm > time(NULL) + RIP_TRIG_INT6_MAX) {
129455163Sshin			for (ic = ifc; ic; ic = ic->ifc_next) {
129555163Sshin				if (ifcp->ifc_index == ic->ifc_index)
129655163Sshin					continue;
129755163Sshin				if (ic->ifc_flags & IFF_UP)
129855163Sshin					ripsend(ic, &ic->ifc_ripsin,
129962607Sitojun						RRTF_CHANGED);
130055163Sshin			}
130155163Sshin		}
130255163Sshin		/* Reset the flag */
130355163Sshin		for (rrt = riprt; rrt; rrt = rrt->rrt_next)
130462607Sitojun			rrt->rrt_rflags &= ~RRTF_CHANGED;
130555163Sshin	}
130655163Sshin}
130755163Sshin
130855163Sshin/*
130955163Sshin * Send all routes request packet to the specified interface.
131055163Sshin */
131155163Sshinvoid
131255163Sshinsendrequest(ifcp)
131355163Sshin	struct ifc *ifcp;
131455163Sshin{
131555163Sshin	struct netinfo6 *np;
131655163Sshin	int error;
131755163Sshin
131855163Sshin	if (ifcp->ifc_flags & IFF_LOOPBACK)
131955163Sshin		return;
132055163Sshin	ripbuf->rip6_cmd = RIP6_REQUEST;
132155163Sshin	np = ripbuf->rip6_nets;
132255163Sshin	memset(np, 0, sizeof(struct netinfo6));
132355163Sshin	np->rip6_metric = HOPCNT_INFINITY6;
132455163Sshin	tracet(1, "Send rtdump Request to %s (%s)\n",
132555163Sshin		ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
132655163Sshin	error = sendpacket(&ifcp->ifc_ripsin, RIPSIZE(1));
132755163Sshin	if (error == EAFNOSUPPORT) {
132855163Sshin		/* Protocol not supported */
132955163Sshin		tracet(1, "Could not send rtdump Request to %s (%s): "
133055163Sshin			"set IFF_UP to 0\n",
133155163Sshin			ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
133255163Sshin		ifcp->ifc_flags &= ~IFF_UP;	/* As if down for AF_INET6 */
133355163Sshin	}
133455163Sshin	ripbuf->rip6_cmd = RIP6_RESPONSE;
133555163Sshin}
133655163Sshin
133755163Sshin/*
133855163Sshin * Process a RIP6_REQUEST packet.
133955163Sshin */
134055163Sshinvoid
1341119031Sumeriprequest(ifcp, np, nn, sin6)
134255163Sshin	struct ifc *ifcp;
134355163Sshin	struct netinfo6 *np;
134455163Sshin	int nn;
1345119031Sume	struct sockaddr_in6 *sin6;
134655163Sshin{
134755163Sshin	int i;
134855163Sshin	struct riprt *rrt;
134955163Sshin
135055163Sshin	if (!(nn == 1 && IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest) &&
135155163Sshin	      np->rip6_plen == 0 && np->rip6_metric == HOPCNT_INFINITY6)) {
135255163Sshin		/* Specific response, don't split-horizon */
135355163Sshin		trace(1, "\tRIP Request\n");
135455163Sshin		for (i = 0; i < nn; i++, np++) {
135578064Sume			rrt = rtsearch(np, NULL);
135655163Sshin			if (rrt)
135755163Sshin				np->rip6_metric = rrt->rrt_info.rip6_metric;
135855163Sshin			else
135955163Sshin				np->rip6_metric = HOPCNT_INFINITY6;
136055163Sshin		}
1361119031Sume		(void)sendpacket(sin6, RIPSIZE(nn));
136255163Sshin		return;
136355163Sshin	}
136455163Sshin	/* Whole routing table dump */
136555163Sshin	trace(1, "\tRIP Request -- whole routing table\n");
1366119031Sume	ripsend(ifcp, sin6, RRTF_SENDANYWAY);
136755163Sshin}
136855163Sshin
136955163Sshin/*
137055163Sshin * Get information of each interface.
137155163Sshin */
137255163Sshinvoid
137355163Sshinifconfig()
137455163Sshin{
137562607Sitojun	struct ifaddrs *ifap, *ifa;
137662607Sitojun	struct ifc *ifcp;
137762607Sitojun	struct ipv6_mreq mreq;
137862607Sitojun	int s;
137962607Sitojun
138078064Sume	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
138162607Sitojun		fatal("socket");
138278064Sume		/*NOTREACHED*/
138378064Sume	}
138462607Sitojun
138578064Sume	if (getifaddrs(&ifap) != 0) {
138662607Sitojun		fatal("getifaddrs");
138778064Sume		/*NOTREACHED*/
138878064Sume	}
138962607Sitojun
139062607Sitojun	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
139162607Sitojun		if (ifa->ifa_addr->sa_family != AF_INET6)
139262607Sitojun			continue;
139362607Sitojun		ifcp = ifc_find(ifa->ifa_name);
139462607Sitojun		/* we are interested in multicast-capable interfaces */
139562607Sitojun		if ((ifa->ifa_flags & IFF_MULTICAST) == 0)
139662607Sitojun			continue;
139762607Sitojun		if (!ifcp) {
139862607Sitojun			/* new interface */
139978064Sume			if ((ifcp = MALLOC(struct ifc)) == NULL) {
140062607Sitojun				fatal("malloc: struct ifc");
140178064Sume				/*NOTREACHED*/
140278064Sume			}
140362607Sitojun			memset(ifcp, 0, sizeof(*ifcp));
140462607Sitojun			ifcp->ifc_index = -1;
140562607Sitojun			ifcp->ifc_next = ifc;
140662607Sitojun			ifc = ifcp;
140762607Sitojun			nifc++;
140862607Sitojun			ifcp->ifc_name = allocopy(ifa->ifa_name);
140962607Sitojun			ifcp->ifc_addr = 0;
141062607Sitojun			ifcp->ifc_filter = 0;
141162607Sitojun			ifcp->ifc_flags = ifa->ifa_flags;
141262607Sitojun			trace(1, "newif %s <%s>\n", ifcp->ifc_name,
141362607Sitojun				ifflags(ifcp->ifc_flags));
141462607Sitojun			if (!strcmp(ifcp->ifc_name, LOOPBACK_IF))
141562607Sitojun				loopifcp = ifcp;
141662607Sitojun		} else {
141762607Sitojun			/* update flag, this may be up again */
141862607Sitojun			if (ifcp->ifc_flags != ifa->ifa_flags) {
141962607Sitojun				trace(1, "%s: <%s> -> ", ifcp->ifc_name,
142062607Sitojun					ifflags(ifcp->ifc_flags));
142162607Sitojun				trace(1, "<%s>\n", ifflags(ifa->ifa_flags));
142278064Sume				ifcp->ifc_cflags |= IFC_CHANGED;
142362607Sitojun			}
142462607Sitojun			ifcp->ifc_flags = ifa->ifa_flags;
142562607Sitojun		}
142662607Sitojun		ifconfig1(ifa->ifa_name, ifa->ifa_addr, ifcp, s);
142762607Sitojun		if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP
142862607Sitojun		 && 0 < ifcp->ifc_index && !ifcp->ifc_joined) {
142962607Sitojun			mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr;
143062607Sitojun			mreq.ipv6mr_interface = ifcp->ifc_index;
143178064Sume			if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
143278064Sume			    &mreq, sizeof(mreq)) < 0) {
143362607Sitojun				fatal("IPV6_JOIN_GROUP");
143478064Sume				/*NOTREACHED*/
143578064Sume			}
143662607Sitojun			trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST);
143762607Sitojun			ifcp->ifc_joined++;
143862607Sitojun		}
143962607Sitojun	}
144062607Sitojun	close(s);
144162607Sitojun	freeifaddrs(ifap);
144255163Sshin}
144355163Sshin
144455163Sshinvoid
144562607Sitojunifconfig1(name, sa, ifcp, s)
144662607Sitojun	const char *name;
144762607Sitojun	const struct sockaddr *sa;
144855163Sshin	struct	ifc *ifcp;
144955163Sshin	int	s;
145055163Sshin{
145155163Sshin	struct	in6_ifreq ifr;
1452119031Sume	const struct sockaddr_in6 *sin6;
145355163Sshin	struct	ifac *ifa;
145455163Sshin	int	plen;
145555163Sshin	char	buf[BUFSIZ];
145655163Sshin
1457119031Sume	sin6 = (const struct sockaddr_in6 *)sa;
1458119031Sume	ifr.ifr_addr = *sin6;
1459119032Sume	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
146078064Sume	if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0) {
146155163Sshin		fatal("ioctl: SIOCGIFNETMASK_IN6");
146278064Sume		/*NOTREACHED*/
146378064Sume	}
146478064Sume	plen = sin6mask2len(&ifr.ifr_addr);
1465119031Sume	if ((ifa = ifa_match(ifcp, &sin6->sin6_addr, plen)) != NULL) {
146655163Sshin		/* same interface found */
146755163Sshin		/* need check if something changed */
146855163Sshin		/* XXX not yet implemented */
146955163Sshin		return;
147055163Sshin	}
147155163Sshin	/*
147255163Sshin	 * New address is found
147355163Sshin	 */
147478064Sume	if ((ifa = MALLOC(struct ifac)) == NULL) {
147555163Sshin		fatal("malloc: struct ifac");
147678064Sume		/*NOTREACHED*/
147778064Sume	}
147862607Sitojun	memset(ifa, 0, sizeof(*ifa));
147955163Sshin	ifa->ifa_conf = ifcp;
148055163Sshin	ifa->ifa_next = ifcp->ifc_addr;
148155163Sshin	ifcp->ifc_addr = ifa;
1482119031Sume	ifa->ifa_addr = sin6->sin6_addr;
148355163Sshin	ifa->ifa_plen = plen;
148455163Sshin	if (ifcp->ifc_flags & IFF_POINTOPOINT) {
1485119031Sume		ifr.ifr_addr = *sin6;
148678064Sume		if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0) {
148755163Sshin			fatal("ioctl: SIOCGIFDSTADDR_IN6");
148878064Sume			/*NOTREACHED*/
148978064Sume		}
149055163Sshin		ifa->ifa_raddr = ifr.ifr_dstaddr.sin6_addr;
149155163Sshin		inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, buf, sizeof(buf));
149255163Sshin		trace(1, "found address %s/%d -- %s\n",
149355163Sshin			inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen, buf);
149455163Sshin	} else {
149555163Sshin		trace(1, "found address %s/%d\n",
149655163Sshin			inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen);
149755163Sshin	}
149855163Sshin	if (ifcp->ifc_index < 0 && IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) {
149955163Sshin		ifcp->ifc_mylladdr = ifa->ifa_addr;
150055163Sshin		ifcp->ifc_index = IN6_LINKLOCAL_IFINDEX(ifa->ifa_addr);
150155163Sshin		memcpy(&ifcp->ifc_ripsin, &ripsin, ripsin.ss_len);
150255163Sshin		SET_IN6_LINKLOCAL_IFINDEX(ifcp->ifc_ripsin.sin6_addr,
150355163Sshin			ifcp->ifc_index);
150455163Sshin		setindex2ifc(ifcp->ifc_index, ifcp);
150555163Sshin		ifcp->ifc_mtu = getifmtu(ifcp->ifc_index);
150655163Sshin		if (ifcp->ifc_mtu > RIP6_MAXMTU)
150755163Sshin			ifcp->ifc_mtu = RIP6_MAXMTU;
150878064Sume		if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0) {
150955163Sshin			fatal("ioctl: SIOCGIFMETRIC");
151078064Sume			/*NOTREACHED*/
151178064Sume		}
151255163Sshin		ifcp->ifc_metric = ifr.ifr_metric;
151355163Sshin		trace(1, "\tindex: %d, mtu: %d, metric: %d\n",
151455163Sshin			ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric);
151578064Sume	} else
151678064Sume		ifcp->ifc_cflags |= IFC_CHANGED;
151755163Sshin}
151855163Sshin
151955163Sshin/*
152055163Sshin * Receive and process routing messages.
152155163Sshin * Update interface information as necesssary.
152255163Sshin */
152355163Sshinvoid
152455163Sshinrtrecv()
152555163Sshin{
152655163Sshin	char buf[BUFSIZ];
152755163Sshin	char *p, *q;
152855163Sshin	struct rt_msghdr *rtm;
152955163Sshin	struct ifa_msghdr *ifam;
153055163Sshin	struct if_msghdr *ifm;
153155163Sshin	int len;
153278064Sume	struct ifc *ifcp, *ic;
153355163Sshin	int iface = 0, rtable = 0;
153455163Sshin	struct sockaddr_in6 *rta[RTAX_MAX];
153578064Sume	struct sockaddr_in6 mask;
153655163Sshin	int i, addrs;
153778064Sume	struct riprt *rrt;
153855163Sshin
153955163Sshin	if ((len = read(rtsock, buf, sizeof(buf))) < 0) {
154055163Sshin		perror("read from rtsock");
154178064Sume		exit(1);
154255163Sshin	}
154355163Sshin	if (len < sizeof(*rtm)) {
154469279Sume		trace(1, "short read from rtsock: %d (should be > %lu)\n",
154569279Sume			len, (u_long)sizeof(*rtm));
154655163Sshin		return;
154755163Sshin	}
1548119042Sume	if (dflag >= 2) {
1549119042Sume		fprintf(stderr, "rtmsg:\n");
1550119042Sume		for (i = 0; i < len; i++) {
1551119042Sume			fprintf(stderr, "%02x ", buf[i] & 0xff);
1552119042Sume			if (i % 16 == 15) fprintf(stderr, "\n");
1553119042Sume		}
1554119042Sume		fprintf(stderr, "\n");
1555119042Sume	}
155655163Sshin
155755163Sshin	for (p = buf; p - buf < len; p += ((struct rt_msghdr *)p)->rtm_msglen) {
155855163Sshin		/* safety against bogus message */
155955163Sshin		if (((struct rt_msghdr *)p)->rtm_msglen <= 0) {
156055163Sshin			trace(1, "bogus rtmsg: length=%d\n",
156155163Sshin				((struct rt_msghdr *)p)->rtm_msglen);
156255163Sshin			break;
156355163Sshin		}
156455163Sshin		rtm = NULL;
156555163Sshin		ifam = NULL;
156655163Sshin		ifm = NULL;
156755163Sshin		switch (((struct rt_msghdr *)p)->rtm_type) {
156855163Sshin		case RTM_NEWADDR:
156955163Sshin		case RTM_DELADDR:
157055163Sshin			ifam = (struct ifa_msghdr *)p;
157155163Sshin			addrs = ifam->ifam_addrs;
157255163Sshin			q = (char *)(ifam + 1);
157355163Sshin			break;
157455163Sshin		case RTM_IFINFO:
157555163Sshin			ifm = (struct if_msghdr *)p;
157655163Sshin			addrs = ifm->ifm_addrs;
157755163Sshin			q = (char *)(ifm + 1);
157855163Sshin			break;
157955163Sshin		default:
158055163Sshin			rtm = (struct rt_msghdr *)p;
158155163Sshin			addrs = rtm->rtm_addrs;
158255163Sshin			q = (char *)(rtm + 1);
158355163Sshin			if (rtm->rtm_version != RTM_VERSION) {
158455163Sshin				trace(1, "unexpected rtmsg version %d "
158555163Sshin					"(should be %d)\n",
158655163Sshin					rtm->rtm_version, RTM_VERSION);
158755163Sshin				continue;
158855163Sshin			}
158955163Sshin			if (rtm->rtm_pid == pid) {
159055163Sshin#if 0
159155163Sshin				trace(1, "rtmsg looped back to me, ignored\n");
159255163Sshin#endif
159355163Sshin				continue;
159455163Sshin			}
159555163Sshin			break;
159655163Sshin		}
159755163Sshin		memset(&rta, 0, sizeof(rta));
159855163Sshin		for (i = 0; i < RTAX_MAX; i++) {
159955163Sshin			if (addrs & (1 << i)) {
160055163Sshin				rta[i] = (struct sockaddr_in6 *)q;
160155163Sshin				q += ROUNDUP(rta[i]->sin6_len);
160255163Sshin			}
160355163Sshin		}
160455163Sshin
160555163Sshin		trace(1, "rtsock: %s (addrs=%x)\n",
160655163Sshin			rttypes((struct rt_msghdr *)p), addrs);
160755163Sshin		if (dflag >= 2) {
160855163Sshin			for (i = 0;
160955163Sshin			     i < ((struct rt_msghdr *)p)->rtm_msglen;
161055163Sshin			     i++) {
161155163Sshin				fprintf(stderr, "%02x ", p[i] & 0xff);
161255163Sshin				if (i % 16 == 15) fprintf(stderr, "\n");
161355163Sshin			}
161455163Sshin			fprintf(stderr, "\n");
161555163Sshin		}
161655163Sshin
161755163Sshin		/*
161855163Sshin		 * Easy ones first.
161955163Sshin		 *
162055163Sshin		 * We may be able to optimize by using ifm->ifm_index or
162155163Sshin		 * ifam->ifam_index.  For simplicity we don't do that here.
162255163Sshin		 */
162355163Sshin		switch (((struct rt_msghdr *)p)->rtm_type) {
162455163Sshin		case RTM_NEWADDR:
162555163Sshin		case RTM_IFINFO:
162655163Sshin			iface++;
162755163Sshin			continue;
162855163Sshin		case RTM_ADD:
162955163Sshin			rtable++;
163055163Sshin			continue;
163155163Sshin		case RTM_LOSING:
163255163Sshin		case RTM_MISS:
163355163Sshin		case RTM_RESOLVE:
163455163Sshin		case RTM_GET:
163555163Sshin		case RTM_LOCK:
163655163Sshin			/* nothing to be done here */
163755163Sshin			trace(1, "\tnothing to be done, ignored\n");
163855163Sshin			continue;
163955163Sshin		}
164055163Sshin
164155163Sshin#if 0
164255163Sshin		if (rta[RTAX_DST] == NULL) {
164355163Sshin			trace(1, "\tno destination, ignored\n");
164462607Sitojun			continue;
164555163Sshin		}
164655163Sshin		if (rta[RTAX_DST]->sin6_family != AF_INET6) {
164755163Sshin			trace(1, "\taf mismatch, ignored\n");
164855163Sshin			continue;
164955163Sshin		}
165055163Sshin		if (IN6_IS_ADDR_LINKLOCAL(&rta[RTAX_DST]->sin6_addr)) {
165155163Sshin			trace(1, "\tlinklocal destination, ignored\n");
165255163Sshin			continue;
165355163Sshin		}
165455163Sshin		if (IN6_ARE_ADDR_EQUAL(&rta[RTAX_DST]->sin6_addr, &in6addr_loopback)) {
165555163Sshin			trace(1, "\tloopback destination, ignored\n");
165655163Sshin			continue;		/* Loopback */
165755163Sshin		}
165855163Sshin		if (IN6_IS_ADDR_MULTICAST(&rta[RTAX_DST]->sin6_addr)) {
165955163Sshin			trace(1, "\tmulticast destination, ignored\n");
166055163Sshin			continue;
166155163Sshin		}
166255163Sshin#endif
166355163Sshin
166455163Sshin		/* hard ones */
166555163Sshin		switch (((struct rt_msghdr *)p)->rtm_type) {
166655163Sshin		case RTM_NEWADDR:
166755163Sshin		case RTM_IFINFO:
166855163Sshin		case RTM_ADD:
166955163Sshin		case RTM_LOSING:
167055163Sshin		case RTM_MISS:
167155163Sshin		case RTM_RESOLVE:
167255163Sshin		case RTM_GET:
167355163Sshin		case RTM_LOCK:
167455163Sshin			/* should already be handled */
167555163Sshin			fatal("rtrecv: never reach here");
167678064Sume			/*NOTREACHED*/
167755163Sshin		case RTM_DELETE:
167878064Sume			if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY]) {
167978064Sume				trace(1, "\tsome of dst/gw/netamsk are "
168078064Sume				    "unavailable, ignored\n");
168155163Sshin				break;
168255163Sshin			}
168378064Sume			if ((rtm->rtm_flags & RTF_HOST) != 0) {
168478064Sume				mask.sin6_len = sizeof(mask);
168578064Sume				memset(&mask.sin6_addr, 0xff,
168678064Sume				    sizeof(mask.sin6_addr));
168778064Sume				rta[RTAX_NETMASK] = &mask;
168878064Sume			} else if (!rta[RTAX_NETMASK]) {
168978064Sume				trace(1, "\tsome of dst/gw/netamsk are "
169078064Sume				    "unavailable, ignored\n");
169178064Sume				break;
169278064Sume			}
169378064Sume			if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY],
169478064Sume			    rta[RTAX_NETMASK]) == 0) {
169555163Sshin				rtable++;	/*just to be sure*/
169655163Sshin			}
169755163Sshin			break;
169855163Sshin		case RTM_CHANGE:
169955163Sshin		case RTM_REDIRECT:
170055163Sshin			trace(1, "\tnot supported yet, ignored\n");
170155163Sshin			break;
170255163Sshin		case RTM_DELADDR:
170355163Sshin			if (!rta[RTAX_NETMASK] || !rta[RTAX_IFA]) {
170455163Sshin				trace(1, "\tno netmask or ifa given, ignored\n");
170555163Sshin				break;
170655163Sshin			}
170755163Sshin			if (ifam->ifam_index < nindex2ifc)
170855163Sshin				ifcp = index2ifc[ifam->ifam_index];
170955163Sshin			else
171055163Sshin				ifcp = NULL;
171155163Sshin			if (!ifcp) {
171255163Sshin				trace(1, "\tinvalid ifam_index %d, ignored\n",
171355163Sshin					ifam->ifam_index);
171455163Sshin				break;
171555163Sshin			}
171678064Sume			if (!rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK]))
171778064Sume				iface++;
171855163Sshin			break;
171955163Sshin		case RTM_OLDADD:
172055163Sshin		case RTM_OLDDEL:
172155163Sshin			trace(1, "\tnot supported yet, ignored\n");
172255163Sshin			break;
172355163Sshin		}
172455163Sshin
172555163Sshin	}
172655163Sshin
172755163Sshin	if (iface) {
172855163Sshin		trace(1, "rtsock: reconfigure interfaces, refresh interface routes\n");
172955163Sshin		ifconfig();
173055163Sshin		for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next)
173178064Sume			if (ifcp->ifc_cflags & IFC_CHANGED) {
173278064Sume				if (ifrt(ifcp, 1)) {
173378064Sume					for (ic = ifc; ic; ic = ic->ifc_next) {
173478064Sume						if (ifcp->ifc_index == ic->ifc_index)
173578064Sume							continue;
173678064Sume						if (ic->ifc_flags & IFF_UP)
173778064Sume							ripsend(ic, &ic->ifc_ripsin,
173878064Sume							RRTF_CHANGED);
173978064Sume					}
174078064Sume					/* Reset the flag */
174178064Sume					for (rrt = riprt; rrt; rrt = rrt->rrt_next)
174278064Sume						rrt->rrt_rflags &= ~RRTF_CHANGED;
174378064Sume				}
174478064Sume				ifcp->ifc_cflags &= ~IFC_CHANGED;
174578064Sume			}
174655163Sshin	}
174755163Sshin	if (rtable) {
174855163Sshin		trace(1, "rtsock: read routing table again\n");
174955163Sshin		krtread(1);
175055163Sshin	}
175155163Sshin}
175255163Sshin
175355163Sshin/*
175455163Sshin * remove specified route from the internal routing table.
175555163Sshin */
175655163Sshinint
175755163Sshinrt_del(sdst, sgw, smask)
175855163Sshin	const struct sockaddr_in6 *sdst;
175955163Sshin	const struct sockaddr_in6 *sgw;
176055163Sshin	const struct sockaddr_in6 *smask;
176155163Sshin{
176255163Sshin	const struct in6_addr *dst = NULL;
176355163Sshin	const struct in6_addr *gw = NULL;
176455163Sshin	int prefix;
176555163Sshin	struct netinfo6 ni6;
176655163Sshin	struct riprt *rrt = NULL;
176755163Sshin	time_t t_lifetime;
176855163Sshin
176955163Sshin	if (sdst->sin6_family != AF_INET6) {
177055163Sshin		trace(1, "\tother AF, ignored\n");
177155163Sshin		return -1;
177255163Sshin	}
177355163Sshin	if (IN6_IS_ADDR_LINKLOCAL(&sdst->sin6_addr)
177455163Sshin	 || IN6_ARE_ADDR_EQUAL(&sdst->sin6_addr, &in6addr_loopback)
177555163Sshin	 || IN6_IS_ADDR_MULTICAST(&sdst->sin6_addr)) {
177655163Sshin		trace(1, "\taddress %s not interesting, ignored\n",
177755163Sshin			inet6_n2p(&sdst->sin6_addr));
177855163Sshin		return -1;
177955163Sshin	}
178055163Sshin	dst = &sdst->sin6_addr;
178178064Sume	if (sgw->sin6_family == AF_INET6) {
178255163Sshin		/* easy case */
178355163Sshin		gw = &sgw->sin6_addr;
178478064Sume		prefix = sin6mask2len(smask);
178555163Sshin	} else if (sgw->sin6_family == AF_LINK) {
178655163Sshin		/*
178755163Sshin		 * Interface route... a hard case.  We need to get the prefix
178855163Sshin		 * length from the kernel, but we now are parsing rtmsg.
178955163Sshin		 * We'll purge matching routes from my list, then get the
179055163Sshin		 * fresh list.
179155163Sshin		 */
179255163Sshin		struct riprt *longest;
1793108533Sschweikh		trace(1, "\t%s is an interface route, guessing prefixlen\n",
179455163Sshin			inet6_n2p(dst));
179555163Sshin		longest = NULL;
179655163Sshin		for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
179755163Sshin			if (IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
179855163Sshin					&sdst->sin6_addr)
179955163Sshin			 && IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) {
180055163Sshin				if (!longest
180155163Sshin				 || longest->rrt_info.rip6_plen <
180255163Sshin						 rrt->rrt_info.rip6_plen) {
180355163Sshin					longest = rrt;
180455163Sshin				}
180555163Sshin			}
180655163Sshin		}
180755163Sshin		rrt = longest;
180855163Sshin		if (!rrt) {
180955163Sshin			trace(1, "\tno matching interface route found\n");
181055163Sshin			return -1;
181155163Sshin		}
181255163Sshin		gw = &in6addr_loopback;
181355163Sshin		prefix = rrt->rrt_info.rip6_plen;
181455163Sshin	} else {
181578064Sume		trace(1, "\tunsupported af: (gw=%d)\n", sgw->sin6_family);
181655163Sshin		return -1;
181755163Sshin	}
181855163Sshin
181955163Sshin	trace(1, "\tdeleting %s/%d ", inet6_n2p(dst), prefix);
182055163Sshin	trace(1, "gw %s\n", inet6_n2p(gw));
182155163Sshin	t_lifetime = time(NULL) - RIP_LIFETIME;
182255163Sshin	/* age route for interface address */
182355163Sshin	memset(&ni6, 0, sizeof(ni6));
182455163Sshin	ni6.rip6_dest = *dst;
182555163Sshin	ni6.rip6_plen = prefix;
182655163Sshin	applyplen(&ni6.rip6_dest, ni6.rip6_plen);	/*to be sure*/
182755163Sshin	trace(1, "\tfind route %s/%d\n", inet6_n2p(&ni6.rip6_dest),
182855163Sshin		ni6.rip6_plen);
182978064Sume	if (!rrt && (rrt = rtsearch(&ni6, NULL)) == NULL) {
183055163Sshin		trace(1, "\tno route found\n");
183155163Sshin		return -1;
183255163Sshin	}
183378064Sume#if 0
183455163Sshin	if ((rrt->rrt_flags & RTF_STATIC) == 0) {
183555163Sshin		trace(1, "\tyou can delete static routes only\n");
183678064Sume	} else
183778064Sume#endif
183878064Sume	if (!IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, gw)) {
183955163Sshin		trace(1, "\tgw mismatch: %s <-> ",
184055163Sshin			inet6_n2p(&rrt->rrt_gw));
184155163Sshin		trace(1, "%s\n", inet6_n2p(gw));
184255163Sshin	} else {
184355163Sshin		trace(1, "\troute found, age it\n");
184455163Sshin		if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
184555163Sshin			rrt->rrt_t = t_lifetime;
184655163Sshin			rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
184755163Sshin		}
184855163Sshin	}
184955163Sshin	return 0;
185055163Sshin}
185155163Sshin
185255163Sshin/*
185355163Sshin * remove specified address from internal interface/routing table.
185455163Sshin */
185555163Sshinint
185655163Sshinrt_deladdr(ifcp, sifa, smask)
185755163Sshin	struct ifc *ifcp;
185855163Sshin	const struct sockaddr_in6 *sifa;
185955163Sshin	const struct sockaddr_in6 *smask;
186055163Sshin{
186155163Sshin	const struct in6_addr *addr = NULL;
186255163Sshin	int prefix;
186355163Sshin	struct ifac *ifa = NULL;
186455163Sshin	struct netinfo6 ni6;
186555163Sshin	struct riprt *rrt = NULL;
186655163Sshin	time_t t_lifetime;
186755163Sshin	int updated = 0;
186855163Sshin
186978064Sume	if (sifa->sin6_family != AF_INET6) {
187055163Sshin		trace(1, "\tother AF, ignored\n");
187155163Sshin		return -1;
187255163Sshin	}
187355163Sshin	addr = &sifa->sin6_addr;
187478064Sume	prefix = sin6mask2len(smask);
187555163Sshin
187655163Sshin	trace(1, "\tdeleting %s/%d from %s\n",
187755163Sshin		inet6_n2p(addr), prefix, ifcp->ifc_name);
187855163Sshin	ifa = ifa_match(ifcp, addr, prefix);
187955163Sshin	if (!ifa) {
188055163Sshin		trace(1, "\tno matching ifa found for %s/%d on %s\n",
188155163Sshin			inet6_n2p(addr), prefix, ifcp->ifc_name);
188255163Sshin		return -1;
188355163Sshin	}
188455163Sshin	if (ifa->ifa_conf != ifcp) {
188555163Sshin		trace(1, "\taddress table corrupt: back pointer does not match "
188655163Sshin			"(%s != %s)\n",
188755163Sshin			ifcp->ifc_name, ifa->ifa_conf->ifc_name);
188855163Sshin		return -1;
188955163Sshin	}
189055163Sshin	/* remove ifa from interface */
189155163Sshin	if (ifcp->ifc_addr == ifa)
189255163Sshin		ifcp->ifc_addr = ifa->ifa_next;
189355163Sshin	else {
189455163Sshin		struct ifac *p;
189555163Sshin		for (p = ifcp->ifc_addr; p; p = p->ifa_next) {
189655163Sshin			if (p->ifa_next == ifa) {
189755163Sshin				p->ifa_next = ifa->ifa_next;
189855163Sshin				break;
189955163Sshin			}
190055163Sshin		}
190155163Sshin	}
190255163Sshin	ifa->ifa_next = NULL;
190355163Sshin	ifa->ifa_conf = NULL;
190455163Sshin	t_lifetime = time(NULL) - RIP_LIFETIME;
190555163Sshin	/* age route for interface address */
190655163Sshin	memset(&ni6, 0, sizeof(ni6));
190755163Sshin	ni6.rip6_dest = ifa->ifa_addr;
190855163Sshin	ni6.rip6_plen = ifa->ifa_plen;
190955163Sshin	applyplen(&ni6.rip6_dest, ni6.rip6_plen);
191055163Sshin	trace(1, "\tfind interface route %s/%d on %d\n",
191155163Sshin		inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index);
191278064Sume	if ((rrt = rtsearch(&ni6, NULL)) != NULL) {
191355163Sshin		struct in6_addr none;
191455163Sshin		memset(&none, 0, sizeof(none));
191578064Sume		if (rrt->rrt_index == ifcp->ifc_index &&
191678064Sume		    (IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &none) ||
191778064Sume		     IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw))) {
191855163Sshin			trace(1, "\troute found, age it\n");
191955163Sshin			if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
192055163Sshin				rrt->rrt_t = t_lifetime;
192155163Sshin				rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
192255163Sshin			}
192355163Sshin			updated++;
192455163Sshin		} else {
192555163Sshin			trace(1, "\tnon-interface route found: %s/%d on %d\n",
192655163Sshin				inet6_n2p(&rrt->rrt_info.rip6_dest),
192755163Sshin				rrt->rrt_info.rip6_plen,
192855163Sshin				rrt->rrt_index);
192955163Sshin		}
193055163Sshin	} else
193155163Sshin		trace(1, "\tno interface route found\n");
193255163Sshin	/* age route for p2p destination */
193355163Sshin	if (ifcp->ifc_flags & IFF_POINTOPOINT) {
193455163Sshin		memset(&ni6, 0, sizeof(ni6));
193555163Sshin		ni6.rip6_dest = ifa->ifa_raddr;
193655163Sshin		ni6.rip6_plen = 128;
193755163Sshin		applyplen(&ni6.rip6_dest, ni6.rip6_plen);	/*to be sure*/
193855163Sshin		trace(1, "\tfind p2p route %s/%d on %d\n",
193955163Sshin			inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen,
194055163Sshin			ifcp->ifc_index);
194178064Sume		if ((rrt = rtsearch(&ni6, NULL)) != NULL) {
194278064Sume			if (rrt->rrt_index == ifcp->ifc_index &&
194378064Sume			    IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &ifa->ifa_addr)) {
194455163Sshin				trace(1, "\troute found, age it\n");
194555163Sshin				if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
194655163Sshin					rrt->rrt_t = t_lifetime;
194755163Sshin					rrt->rrt_info.rip6_metric =
194878064Sume					    HOPCNT_INFINITY6;
194955163Sshin					updated++;
195055163Sshin				}
195155163Sshin			} else {
195255163Sshin				trace(1, "\tnon-p2p route found: %s/%d on %d\n",
195355163Sshin					inet6_n2p(&rrt->rrt_info.rip6_dest),
195455163Sshin					rrt->rrt_info.rip6_plen,
195555163Sshin					rrt->rrt_index);
195655163Sshin			}
195755163Sshin		} else
195855163Sshin			trace(1, "\tno p2p route found\n");
195955163Sshin	}
196055163Sshin	return updated ? 0 : -1;
196155163Sshin}
196255163Sshin
196355163Sshin/*
196455163Sshin * Get each interface address and put those interface routes to the route
196555163Sshin * list.
196655163Sshin */
196778064Sumeint
196855163Sshinifrt(ifcp, again)
196962607Sitojun	struct ifc *ifcp;
197055163Sshin	int again;
197155163Sshin{
197262607Sitojun	struct ifac *ifa;
1973119042Sume	struct riprt *rrt = NULL, *search_rrt, *prev_rrt, *loop_rrt;
197462607Sitojun	struct netinfo6 *np;
197578064Sume	time_t t_lifetime;
197678064Sume	int need_trigger = 0;
197755163Sshin
197855163Sshin	if (ifcp->ifc_flags & IFF_LOOPBACK)
197978064Sume		return 0;			/* ignore loopback */
198062607Sitojun	if (ifcp->ifc_flags & IFF_POINTOPOINT) {
198162607Sitojun		ifrt_p2p(ifcp, again);
198278064Sume		return 0;
198362607Sitojun	}
198462607Sitojun
198555163Sshin	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
198662607Sitojun		if (IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) {
198762607Sitojun#if 0
198862607Sitojun			trace(1, "route: %s on %s: "
198962607Sitojun			    "skip linklocal interface address\n",
199062607Sitojun			    inet6_n2p(&ifa->ifa_addr), ifcp->ifc_name);
199162607Sitojun#endif
199262607Sitojun			continue;
199362607Sitojun		}
199462607Sitojun		if (IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_addr)) {
199562607Sitojun#if 0
199662607Sitojun			trace(1, "route: %s: skip unspec interface address\n",
199762607Sitojun			    ifcp->ifc_name);
199862607Sitojun#endif
199962607Sitojun			continue;
200062607Sitojun		}
200178064Sume		if (ifcp->ifc_flags & IFF_UP) {
200278064Sume			if ((rrt = MALLOC(struct riprt)) == NULL)
200378064Sume				fatal("malloc: struct riprt");
200478064Sume			memset(rrt, 0, sizeof(*rrt));
200578064Sume			rrt->rrt_same = NULL;
200678064Sume			rrt->rrt_index = ifcp->ifc_index;
200778064Sume			rrt->rrt_t = 0;	/* don't age */
200878064Sume			rrt->rrt_info.rip6_dest = ifa->ifa_addr;
200978064Sume			rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
201078064Sume			rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric;
201178064Sume			rrt->rrt_info.rip6_plen = ifa->ifa_plen;
201278064Sume			rrt->rrt_flags = RTF_CLONING;
201378064Sume			rrt->rrt_rflags |= RRTF_CHANGED;
201478064Sume			applyplen(&rrt->rrt_info.rip6_dest, ifa->ifa_plen);
201578064Sume			memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
201678064Sume			rrt->rrt_gw = ifa->ifa_addr;
201778064Sume			np = &rrt->rrt_info;
201878064Sume			search_rrt = rtsearch(np, &prev_rrt);
201978064Sume			if (search_rrt != NULL) {
2020119042Sume				if (search_rrt->rrt_info.rip6_metric <=
202178064Sume				    rrt->rrt_info.rip6_metric) {
202278064Sume					/* Already have better route */
202378064Sume					if (!again) {
202478064Sume						trace(1, "route: %s/%d: "
202578064Sume						    "already registered (%s)\n",
202678064Sume						    inet6_n2p(&np->rip6_dest), np->rip6_plen,
202778064Sume						    ifcp->ifc_name);
202878064Sume					}
2029119042Sume					goto next;
203078064Sume				}
2031119042Sume
2032119042Sume				if (prev_rrt)
2033119042Sume					prev_rrt->rrt_next = rrt->rrt_next;
2034119042Sume				else
2035119042Sume					riprt = rrt->rrt_next;
2036119042Sume				delroute(&rrt->rrt_info, &rrt->rrt_gw);
203778064Sume			}
203855163Sshin			/* Attach the route to the list */
203962607Sitojun			trace(1, "route: %s/%d: register route (%s)\n",
204062607Sitojun			    inet6_n2p(&np->rip6_dest), np->rip6_plen,
204162607Sitojun			    ifcp->ifc_name);
204255163Sshin			rrt->rrt_next = riprt;
204355163Sshin			riprt = rrt;
204478064Sume			addroute(rrt, &rrt->rrt_gw, ifcp);
2045119042Sume			rrt = NULL;
204678064Sume			sendrequest(ifcp);
204778064Sume			ripsend(ifcp, &ifcp->ifc_ripsin, 0);
204878064Sume			need_trigger = 1;
204955163Sshin		} else {
205078064Sume			for (loop_rrt = riprt; loop_rrt; loop_rrt = loop_rrt->rrt_next) {
205178064Sume				if (loop_rrt->rrt_index == ifcp->ifc_index) {
205278064Sume					t_lifetime = time(NULL) - RIP_LIFETIME;
205378064Sume					if (loop_rrt->rrt_t == 0 || loop_rrt->rrt_t > t_lifetime) {
205478064Sume						loop_rrt->rrt_t = t_lifetime;
205578064Sume						loop_rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
205678064Sume						loop_rrt->rrt_rflags |= RRTF_CHANGED;
205778064Sume						need_trigger = 1;
205878064Sume					}
205978064Sume				}
206055163Sshin			}
206178064Sume                }
2062119042Sume	next:
2063119042Sume		if (rrt)
2064119042Sume			free(rrt);
206562607Sitojun	}
206678064Sume	return need_trigger;
206762607Sitojun}
206855163Sshin
206962607Sitojun/*
207062607Sitojun * there are couple of p2p interface routing models.  "behavior" lets
207162607Sitojun * you pick one.  it looks that gated behavior fits best with BSDs,
2072119035Sume * since BSD kernels do not look at prefix length on p2p interfaces.
207362607Sitojun */
207462607Sitojunvoid
207562607Sitojunifrt_p2p(ifcp, again)
207662607Sitojun	struct ifc *ifcp;
207762607Sitojun	int again;
207862607Sitojun{
207962607Sitojun	struct ifac *ifa;
208078064Sume	struct riprt *rrt, *orrt, *prevrrt;
208162607Sitojun	struct netinfo6 *np;
208262607Sitojun	struct in6_addr addr, dest;
208362607Sitojun	int advert, ignore, i;
208462607Sitojun#define P2PADVERT_NETWORK	1
208562607Sitojun#define P2PADVERT_ADDR		2
208662607Sitojun#define P2PADVERT_DEST		4
208762607Sitojun#define P2PADVERT_MAX		4
208862607Sitojun	const enum { CISCO, GATED, ROUTE6D } behavior = GATED;
208978064Sume	const char *category = "";
209062607Sitojun	const char *noadv;
209162607Sitojun
209262607Sitojun	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
209362607Sitojun		addr = ifa->ifa_addr;
209462607Sitojun		dest = ifa->ifa_raddr;
209562607Sitojun		applyplen(&addr, ifa->ifa_plen);
209662607Sitojun		applyplen(&dest, ifa->ifa_plen);
209762607Sitojun		advert = ignore = 0;
209862607Sitojun		switch (behavior) {
209962607Sitojun		case CISCO:
210062607Sitojun			/*
210162607Sitojun			 * honor addr/plen, just like normal shared medium
210262607Sitojun			 * interface.  this may cause trouble if you reuse
210362607Sitojun			 * addr/plen on other interfaces.
210462607Sitojun			 *
210562607Sitojun			 * advertise addr/plen.
210662607Sitojun			 */
210762607Sitojun			advert |= P2PADVERT_NETWORK;
210862607Sitojun			break;
210962607Sitojun		case GATED:
211062607Sitojun			/*
211162607Sitojun			 * prefixlen on p2p interface is meaningless.
211262607Sitojun			 * advertise addr/128 and dest/128.
211362607Sitojun			 *
211462607Sitojun			 * do not install network route to route6d routing
211562607Sitojun			 * table (if we do, it would prevent route installation
211662607Sitojun			 * for other p2p interface that shares addr/plen).
211778064Sume			 *
211878064Sume			 * XXX what should we do if dest is ::?  it will not
211978064Sume			 * get announced anyways (see following filter),
212078064Sume			 * but we need to think.
212162607Sitojun			 */
212262607Sitojun			advert |= P2PADVERT_ADDR;
212362607Sitojun			advert |= P2PADVERT_DEST;
212462607Sitojun			ignore |= P2PADVERT_NETWORK;
212562607Sitojun			break;
212662607Sitojun		case ROUTE6D:
212762607Sitojun			/*
212878064Sume			 * just for testing.  actually the code is redundant
212978064Sume			 * given the current p2p interface address assignment
213078064Sume			 * rule for kame kernel.
213178064Sume			 *
213278064Sume			 * intent:
213378064Sume			 *	A/n -> announce A/n
213478064Sume			 *	A B/n, A and B share prefix -> A/n (= B/n)
213578064Sume			 *	A B/n, do not share prefix -> A/128 and B/128
213678064Sume			 * actually, A/64 and A B/128 are the only cases
213778064Sume			 * permitted by the kernel:
213878064Sume			 *	A/64 -> A/64
213978064Sume			 *	A B/128 -> A/128 and B/128
214062607Sitojun			 */
214178064Sume			if (!IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_raddr)) {
214278064Sume				if (IN6_ARE_ADDR_EQUAL(&addr, &dest))
214378064Sume					advert |= P2PADVERT_NETWORK;
214478064Sume				else {
214578064Sume					advert |= P2PADVERT_ADDR;
214678064Sume					advert |= P2PADVERT_DEST;
214778064Sume					ignore |= P2PADVERT_NETWORK;
214878064Sume				}
214978064Sume			} else
215062607Sitojun				advert |= P2PADVERT_NETWORK;
215162607Sitojun			break;
215262607Sitojun		}
215362607Sitojun
215462607Sitojun		for (i = 1; i <= P2PADVERT_MAX; i *= 2) {
215562607Sitojun			if ((ignore & i) != 0)
215662607Sitojun				continue;
215778064Sume			if ((rrt = MALLOC(struct riprt)) == NULL) {
215855163Sshin				fatal("malloc: struct riprt");
215978064Sume				/*NOTREACHED*/
216078064Sume			}
216162607Sitojun			memset(rrt, 0, sizeof(*rrt));
216255163Sshin			rrt->rrt_same = NULL;
216355163Sshin			rrt->rrt_index = ifcp->ifc_index;
216462607Sitojun			rrt->rrt_t = 0;	/* don't age */
216562607Sitojun			switch (i) {
216662607Sitojun			case P2PADVERT_NETWORK:
216762607Sitojun				rrt->rrt_info.rip6_dest = ifa->ifa_addr;
216862607Sitojun				rrt->rrt_info.rip6_plen = ifa->ifa_plen;
216962607Sitojun				applyplen(&rrt->rrt_info.rip6_dest,
217062607Sitojun				    ifa->ifa_plen);
217162607Sitojun				category = "network";
217262607Sitojun				break;
217362607Sitojun			case P2PADVERT_ADDR:
217462607Sitojun				rrt->rrt_info.rip6_dest = ifa->ifa_addr;
217562607Sitojun				rrt->rrt_info.rip6_plen = 128;
217678064Sume				rrt->rrt_gw = in6addr_loopback;
217762607Sitojun				category = "addr";
217862607Sitojun				break;
217962607Sitojun			case P2PADVERT_DEST:
218062607Sitojun				rrt->rrt_info.rip6_dest = ifa->ifa_raddr;
218162607Sitojun				rrt->rrt_info.rip6_plen = 128;
218278064Sume				rrt->rrt_gw = ifa->ifa_addr;
218362607Sitojun				category = "dest";
218462607Sitojun				break;
218562607Sitojun			}
218662607Sitojun			if (IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_info.rip6_dest) ||
218762607Sitojun			    IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_info.rip6_dest)) {
218862607Sitojun#if 0
218962607Sitojun				trace(1, "route: %s: skip unspec/linklocal "
219062607Sitojun				    "(%s on %s)\n", category, ifcp->ifc_name);
219162607Sitojun#endif
219262607Sitojun				free(rrt);
219362607Sitojun				continue;
219462607Sitojun			}
219562607Sitojun			if ((advert & i) == 0) {
219662607Sitojun				rrt->rrt_rflags |= RRTF_NOADVERTISE;
219762607Sitojun				noadv = ", NO-ADV";
219862607Sitojun			} else
219962607Sitojun				noadv = "";
220055163Sshin			rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
220162607Sitojun			rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric;
220255163Sshin			np = &rrt->rrt_info;
220378064Sume			orrt = rtsearch(np, &prevrrt);
220478064Sume			if (!orrt) {
220555163Sshin				/* Attach the route to the list */
220662607Sitojun				trace(1, "route: %s/%d: register route "
220762607Sitojun				    "(%s on %s%s)\n",
220862607Sitojun				    inet6_n2p(&np->rip6_dest), np->rip6_plen,
220962607Sitojun				    category, ifcp->ifc_name, noadv);
221055163Sshin				rrt->rrt_next = riprt;
221155163Sshin				riprt = rrt;
221278064Sume			} else if (rrt->rrt_index != orrt->rrt_index ||
221378064Sume			    rrt->rrt_info.rip6_metric != orrt->rrt_info.rip6_metric) {
221478064Sume				/* swap route */
221578064Sume				rrt->rrt_next = orrt->rrt_next;
221678064Sume				if (prevrrt)
221778064Sume					prevrrt->rrt_next = rrt;
221878064Sume				else
221978064Sume					riprt = rrt;
222078064Sume				free(orrt);
222178064Sume
222278064Sume				trace(1, "route: %s/%d: update (%s on %s%s)\n",
222378064Sume				    inet6_n2p(&np->rip6_dest), np->rip6_plen,
222478064Sume				    category, ifcp->ifc_name, noadv);
222555163Sshin			} else {
222655163Sshin				/* Already found */
222755163Sshin				if (!again) {
222862607Sitojun					trace(1, "route: %s/%d: "
222962607Sitojun					    "already registered (%s on %s%s)\n",
223062607Sitojun					    inet6_n2p(&np->rip6_dest),
223162607Sitojun					    np->rip6_plen, category,
223262607Sitojun					    ifcp->ifc_name, noadv);
223355163Sshin				}
223455163Sshin				free(rrt);
223555163Sshin			}
223655163Sshin		}
223755163Sshin	}
223862607Sitojun#undef P2PADVERT_NETWORK
223962607Sitojun#undef P2PADVERT_ADDR
224062607Sitojun#undef P2PADVERT_DEST
224162607Sitojun#undef P2PADVERT_MAX
224255163Sshin}
224355163Sshin
224455163Sshinint
224555163Sshingetifmtu(ifindex)
224655163Sshin	int	ifindex;
224755163Sshin{
224855163Sshin	int	mib[6];
224955163Sshin	char	*buf;
225055163Sshin	size_t	msize;
225155163Sshin	struct	if_msghdr *ifm;
225255163Sshin	int	mtu;
225355163Sshin
225455163Sshin	mib[0] = CTL_NET;
225555163Sshin	mib[1] = PF_ROUTE;
225655163Sshin	mib[2] = 0;
225755163Sshin	mib[3] = AF_INET6;
225855163Sshin	mib[4] = NET_RT_IFLIST;
225955163Sshin	mib[5] = ifindex;
226078064Sume	if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) {
226155163Sshin		fatal("sysctl estimate NET_RT_IFLIST");
226278064Sume		/*NOTREACHED*/
226378064Sume	}
226478064Sume	if ((buf = malloc(msize)) == NULL) {
226555163Sshin		fatal("malloc");
226678064Sume		/*NOTREACHED*/
226778064Sume	}
226878064Sume	if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) {
226955163Sshin		fatal("sysctl NET_RT_IFLIST");
227078064Sume		/*NOTREACHED*/
227178064Sume	}
227255163Sshin	ifm = (struct if_msghdr *)buf;
227355163Sshin	mtu = ifm->ifm_data.ifi_mtu;
227478064Sume#ifdef __FreeBSD__
227578064Sume	if (ifindex != ifm->ifm_index) {
227655163Sshin		fatal("ifindex does not match with ifm_index");
227778064Sume		/*NOTREACHED*/
227878064Sume	}
227978064Sume#endif
228055163Sshin	free(buf);
228155163Sshin	return mtu;
228255163Sshin}
228355163Sshin
228455163Sshinconst char *
228555163Sshinrttypes(rtm)
228655163Sshin	struct rt_msghdr *rtm;
228755163Sshin{
228862607Sitojun#define	RTTYPE(s, f) \
228962607Sitojundo { \
229062607Sitojun	if (rtm->rtm_type == (f)) \
229162607Sitojun		return (s); \
229262607Sitojun} while (0)
229355163Sshin	RTTYPE("ADD", RTM_ADD);
229455163Sshin	RTTYPE("DELETE", RTM_DELETE);
229555163Sshin	RTTYPE("CHANGE", RTM_CHANGE);
229655163Sshin	RTTYPE("GET", RTM_GET);
229755163Sshin	RTTYPE("LOSING", RTM_LOSING);
229855163Sshin	RTTYPE("REDIRECT", RTM_REDIRECT);
229955163Sshin	RTTYPE("MISS", RTM_MISS);
230055163Sshin	RTTYPE("LOCK", RTM_LOCK);
230155163Sshin	RTTYPE("OLDADD", RTM_OLDADD);
230255163Sshin	RTTYPE("OLDDEL", RTM_OLDDEL);
230355163Sshin	RTTYPE("RESOLVE", RTM_RESOLVE);
230455163Sshin	RTTYPE("NEWADDR", RTM_NEWADDR);
230555163Sshin	RTTYPE("DELADDR", RTM_DELADDR);
230655163Sshin	RTTYPE("IFINFO", RTM_IFINFO);
230778064Sume#ifdef RTM_OLDADD
230878064Sume	RTTYPE("OLDADD", RTM_OLDADD);
230978064Sume#endif
231078064Sume#ifdef RTM_OLDDEL
231178064Sume	RTTYPE("OLDDEL", RTM_OLDDEL);
231278064Sume#endif
231378064Sume#ifdef RTM_OIFINFO
231478064Sume	RTTYPE("OIFINFO", RTM_OIFINFO);
231578064Sume#endif
231678064Sume#ifdef RTM_IFANNOUNCE
231778064Sume	RTTYPE("IFANNOUNCE", RTM_IFANNOUNCE);
231878064Sume#endif
231978064Sume#ifdef RTM_NEWMADDR
232078064Sume	RTTYPE("NEWMADDR", RTM_NEWMADDR);
232178064Sume#endif
232278064Sume#ifdef RTM_DELMADDR
232378064Sume	RTTYPE("DELMADDR", RTM_DELMADDR);
232478064Sume#endif
232555163Sshin#undef RTTYPE
232655163Sshin	return NULL;
232755163Sshin}
232855163Sshin
232955163Sshinconst char *
233055163Sshinrtflags(rtm)
233155163Sshin	struct rt_msghdr *rtm;
233255163Sshin{
233355163Sshin	static char buf[BUFSIZ];
233455163Sshin
233578064Sume	/*
233678064Sume	 * letter conflict should be okay.  painful when *BSD diverges...
233778064Sume	 */
233878064Sume	strlcpy(buf, "", sizeof(buf));
233962607Sitojun#define	RTFLAG(s, f) \
234062607Sitojundo { \
234162607Sitojun	if (rtm->rtm_flags & (f)) \
234278064Sume		strlcat(buf, (s), sizeof(buf)); \
234362607Sitojun} while (0)
234455163Sshin	RTFLAG("U", RTF_UP);
234555163Sshin	RTFLAG("G", RTF_GATEWAY);
234655163Sshin	RTFLAG("H", RTF_HOST);
234755163Sshin	RTFLAG("R", RTF_REJECT);
234855163Sshin	RTFLAG("D", RTF_DYNAMIC);
234955163Sshin	RTFLAG("M", RTF_MODIFIED);
235055163Sshin	RTFLAG("d", RTF_DONE);
235155163Sshin#ifdef	RTF_MASK
235255163Sshin	RTFLAG("m", RTF_MASK);
235355163Sshin#endif
235455163Sshin	RTFLAG("C", RTF_CLONING);
235578064Sume#ifdef RTF_CLONED
235678064Sume	RTFLAG("c", RTF_CLONED);
235778064Sume#endif
235878064Sume#ifdef RTF_PRCLONING
235978064Sume	RTFLAG("c", RTF_PRCLONING);
236078064Sume#endif
236178064Sume#ifdef RTF_WASCLONED
236278064Sume	RTFLAG("W", RTF_WASCLONED);
236378064Sume#endif
236455163Sshin	RTFLAG("X", RTF_XRESOLVE);
236555163Sshin	RTFLAG("L", RTF_LLINFO);
236655163Sshin	RTFLAG("S", RTF_STATIC);
236755163Sshin	RTFLAG("B", RTF_BLACKHOLE);
236878064Sume#ifdef RTF_PROTO3
236978064Sume	RTFLAG("3", RTF_PROTO3);
237078064Sume#endif
237155163Sshin	RTFLAG("2", RTF_PROTO2);
237255163Sshin	RTFLAG("1", RTF_PROTO1);
237378064Sume#ifdef RTF_BROADCAST
237478064Sume	RTFLAG("b", RTF_BROADCAST);
237578064Sume#endif
237678064Sume#ifdef RTF_DEFAULT
237778064Sume	RTFLAG("d", RTF_DEFAULT);
237878064Sume#endif
237978064Sume#ifdef RTF_ISAROUTER
238078064Sume	RTFLAG("r", RTF_ISAROUTER);
238178064Sume#endif
238278064Sume#ifdef RTF_TUNNEL
238378064Sume	RTFLAG("T", RTF_TUNNEL);
238478064Sume#endif
238578064Sume#ifdef RTF_AUTH
238678064Sume	RTFLAG("A", RTF_AUTH);
238778064Sume#endif
238878064Sume#ifdef RTF_CRYPT
238978064Sume	RTFLAG("E", RTF_CRYPT);
239078064Sume#endif
239155163Sshin#undef RTFLAG
239255163Sshin	return buf;
239355163Sshin}
239455163Sshin
239555163Sshinconst char *
239655163Sshinifflags(flags)
239755163Sshin	int flags;
239855163Sshin{
239955163Sshin	static char buf[BUFSIZ];
240055163Sshin
240178064Sume	strlcpy(buf, "", sizeof(buf));
240262607Sitojun#define	IFFLAG(s, f) \
240362607Sitojundo { \
2404119040Sume	if (flags & (f)) { \
240562607Sitojun		if (buf[0]) \
240678064Sume			strlcat(buf, ",", sizeof(buf)); \
2407119040Sume		strlcat(buf, (s), sizeof(buf)); \
240862607Sitojun	} \
240962607Sitojun} while (0)
241055163Sshin	IFFLAG("UP", IFF_UP);
241155163Sshin	IFFLAG("BROADCAST", IFF_BROADCAST);
241255163Sshin	IFFLAG("DEBUG", IFF_DEBUG);
241355163Sshin	IFFLAG("LOOPBACK", IFF_LOOPBACK);
241455163Sshin	IFFLAG("POINTOPOINT", IFF_POINTOPOINT);
241555163Sshin#ifdef IFF_NOTRAILERS
241655163Sshin	IFFLAG("NOTRAILERS", IFF_NOTRAILERS);
241755163Sshin#endif
241878064Sume#ifdef IFF_SMART
241978064Sume	IFFLAG("SMART", IFF_SMART);
242078064Sume#endif
242155163Sshin	IFFLAG("RUNNING", IFF_RUNNING);
242255163Sshin	IFFLAG("NOARP", IFF_NOARP);
242355163Sshin	IFFLAG("PROMISC", IFF_PROMISC);
242455163Sshin	IFFLAG("ALLMULTI", IFF_ALLMULTI);
242555163Sshin	IFFLAG("OACTIVE", IFF_OACTIVE);
242655163Sshin	IFFLAG("SIMPLEX", IFF_SIMPLEX);
242755163Sshin	IFFLAG("LINK0", IFF_LINK0);
242855163Sshin	IFFLAG("LINK1", IFF_LINK1);
242955163Sshin	IFFLAG("LINK2", IFF_LINK2);
243055163Sshin	IFFLAG("MULTICAST", IFF_MULTICAST);
243155163Sshin#undef IFFLAG
243255163Sshin	return buf;
243355163Sshin}
243455163Sshin
243555163Sshinvoid
243655163Sshinkrtread(again)
243755163Sshin	int again;
243855163Sshin{
243955163Sshin	int mib[6];
244055163Sshin	size_t msize;
244155163Sshin	char *buf, *p, *lim;
244255163Sshin	struct rt_msghdr *rtm;
244355163Sshin	int retry;
244455163Sshin	const char *errmsg;
244555163Sshin
244655163Sshin	retry = 0;
244755163Sshin	buf = NULL;
244855163Sshin	mib[0] = CTL_NET;
244955163Sshin	mib[1] = PF_ROUTE;
245055163Sshin	mib[2] = 0;
245155163Sshin	mib[3] = AF_INET6;	/* Address family */
245255163Sshin	mib[4] = NET_RT_DUMP;	/* Dump the kernel routing table */
245355163Sshin	mib[5] = 0;		/* No flags */
245455163Sshin	do {
245555163Sshin		retry++;
245655163Sshin		errmsg = NULL;
245755163Sshin		if (buf)
245855163Sshin			free(buf);
245955163Sshin		if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) {
246055163Sshin			errmsg = "sysctl estimate";
246155163Sshin			continue;
246255163Sshin		}
246355163Sshin		if ((buf = malloc(msize)) == NULL) {
246455163Sshin			errmsg = "malloc";
246555163Sshin			continue;
246655163Sshin		}
246755163Sshin		if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) {
246855163Sshin			errmsg = "sysctl NET_RT_DUMP";
246955163Sshin			continue;
247055163Sshin		}
247155163Sshin	} while (retry < 5 && errmsg != NULL);
247278064Sume	if (errmsg) {
247369279Sume		fatal("%s (with %d retries, msize=%lu)", errmsg, retry,
247469279Sume		    (u_long)msize);
247578064Sume		/*NOTREACHED*/
247678064Sume	} else if (1 < retry)
247755163Sshin		syslog(LOG_INFO, "NET_RT_DUMP %d retires", retry);
247855163Sshin
247955163Sshin	lim = buf + msize;
248055163Sshin	for (p = buf; p < lim; p += rtm->rtm_msglen) {
248155163Sshin		rtm = (struct rt_msghdr *)p;
248255163Sshin		rt_entry(rtm, again);
248355163Sshin	}
248455163Sshin	free(buf);
248555163Sshin}
248655163Sshin
248755163Sshinvoid
248855163Sshinrt_entry(rtm, again)
248955163Sshin	struct rt_msghdr *rtm;
249055163Sshin	int again;
249155163Sshin{
249255163Sshin	struct	sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask;
249355163Sshin	struct	sockaddr_in6 *sin6_genmask, *sin6_ifp;
249455163Sshin	char	*rtmp, *ifname = NULL;
249578064Sume	struct	riprt *rrt, *orrt;
249655163Sshin	struct	netinfo6 *np;
249755163Sshin	int	s;
249855163Sshin
249955163Sshin	sin6_dst = sin6_gw = sin6_mask = sin6_genmask = sin6_ifp = 0;
250055163Sshin	if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags &
250162607Sitojun		(RTF_CLONING|RTF_XRESOLVE|RTF_LLINFO|RTF_BLACKHOLE)) {
250255163Sshin		return;		/* not interested in the link route */
250362607Sitojun	}
250469279Sume	/* do not look at cloned routes */
250569279Sume#ifdef RTF_WASCLONED
250669279Sume	if (rtm->rtm_flags & RTF_WASCLONED)
250769279Sume		return;
250869279Sume#endif
250969279Sume#ifdef RTF_CLONED
251069279Sume	if (rtm->rtm_flags & RTF_CLONED)
251169279Sume		return;
251269279Sume#endif
251369279Sume	/*
251469279Sume	 * do not look at dynamic routes.
251569279Sume	 * netbsd/openbsd cloned routes have UGHD.
251669279Sume	 */
251769279Sume	if (rtm->rtm_flags & RTF_DYNAMIC)
251869279Sume		return;
251955163Sshin	rtmp = (char *)(rtm + 1);
252055163Sshin	/* Destination */
252155163Sshin	if ((rtm->rtm_addrs & RTA_DST) == 0)
252255163Sshin		return;		/* ignore routes without destination address */
252355163Sshin	sin6_dst = (struct sockaddr_in6 *)rtmp;
252464631Sitojun	rtmp += ROUNDUP(sin6_dst->sin6_len);
252555163Sshin	if (rtm->rtm_addrs & RTA_GATEWAY) {
252655163Sshin		sin6_gw = (struct sockaddr_in6 *)rtmp;
252755163Sshin		rtmp += ROUNDUP(sin6_gw->sin6_len);
252855163Sshin	}
252955163Sshin	if (rtm->rtm_addrs & RTA_NETMASK) {
253055163Sshin		sin6_mask = (struct sockaddr_in6 *)rtmp;
253155163Sshin		rtmp += ROUNDUP(sin6_mask->sin6_len);
253255163Sshin	}
253355163Sshin	if (rtm->rtm_addrs & RTA_GENMASK) {
253455163Sshin		sin6_genmask = (struct sockaddr_in6 *)rtmp;
253555163Sshin		rtmp += ROUNDUP(sin6_genmask->sin6_len);
253655163Sshin	}
253755163Sshin	if (rtm->rtm_addrs & RTA_IFP) {
253855163Sshin		sin6_ifp = (struct sockaddr_in6 *)rtmp;
253955163Sshin		rtmp += ROUNDUP(sin6_ifp->sin6_len);
254055163Sshin	}
254155163Sshin
254255163Sshin	/* Destination */
254355163Sshin	if (sin6_dst->sin6_family != AF_INET6)
254455163Sshin		return;
254555163Sshin	if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst->sin6_addr))
254655163Sshin		return;		/* Link-local */
254755163Sshin	if (IN6_ARE_ADDR_EQUAL(&sin6_dst->sin6_addr, &in6addr_loopback))
254855163Sshin		return;		/* Loopback */
254955163Sshin	if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr))
255055163Sshin		return;
255155163Sshin
255278064Sume	if ((rrt = MALLOC(struct riprt)) == NULL) {
255355163Sshin		fatal("malloc: struct riprt");
255478064Sume		/*NOTREACHED*/
255578064Sume	}
255662607Sitojun	memset(rrt, 0, sizeof(*rrt));
255755163Sshin	np = &rrt->rrt_info;
255855163Sshin	rrt->rrt_same = NULL;
255955163Sshin	rrt->rrt_t = time(NULL);
256055163Sshin	if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC))
256155163Sshin		rrt->rrt_t = 0;	/* Don't age static routes */
256255163Sshin	np->rip6_tag = 0;
256355163Sshin	np->rip6_metric = rtm->rtm_rmx.rmx_hopcount;
256455163Sshin	if (np->rip6_metric < 1)
256555163Sshin		np->rip6_metric = 1;
256655163Sshin	rrt->rrt_flags = rtm->rtm_flags;
256755163Sshin	np->rip6_dest = sin6_dst->sin6_addr;
256855163Sshin
256955163Sshin	/* Mask or plen */
257055163Sshin	if (rtm->rtm_flags & RTF_HOST)
257155163Sshin		np->rip6_plen = 128;	/* Host route */
257278064Sume	else if (sin6_mask)
257378064Sume		np->rip6_plen = sin6mask2len(sin6_mask);
257478064Sume	else
257555163Sshin		np->rip6_plen = 0;
257655163Sshin
257778064Sume	orrt = rtsearch(np, NULL);
257878064Sume	if (orrt && orrt->rrt_info.rip6_metric != HOPCNT_INFINITY6) {
257955163Sshin		/* Already found */
258055163Sshin		if (!again) {
258155163Sshin			trace(1, "route: %s/%d flags %s: already registered\n",
258255163Sshin				inet6_n2p(&np->rip6_dest), np->rip6_plen,
258355163Sshin				rtflags(rtm));
258455163Sshin		}
258555163Sshin		free(rrt);
258655163Sshin		return;
258755163Sshin	}
258855163Sshin	/* Gateway */
258955163Sshin	if (!sin6_gw)
259055163Sshin		memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
259155163Sshin	else {
259255163Sshin		if (sin6_gw->sin6_family == AF_INET6)
259355163Sshin			rrt->rrt_gw = sin6_gw->sin6_addr;
259455163Sshin		else if (sin6_gw->sin6_family == AF_LINK) {
259555163Sshin			/* XXX in case ppp link? */
259655163Sshin			rrt->rrt_gw = in6addr_loopback;
259755163Sshin		} else
259855163Sshin			memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
259955163Sshin	}
260055163Sshin	trace(1, "route: %s/%d flags %s",
260155163Sshin		inet6_n2p(&np->rip6_dest), np->rip6_plen, rtflags(rtm));
260255163Sshin	trace(1, " gw %s", inet6_n2p(&rrt->rrt_gw));
260355163Sshin
260455163Sshin	/* Interface */
260555163Sshin	s = rtm->rtm_index;
260655163Sshin	if (s < nindex2ifc && index2ifc[s])
260755163Sshin		ifname = index2ifc[s]->ifc_name;
260858070Sshin	else {
260958070Sshin		trace(1, " not configured\n");
261062607Sitojun		free(rrt);
261158070Sshin		return;
261258070Sshin	}
261362607Sitojun	trace(1, " if %s sock %d", ifname, s);
261455163Sshin	rrt->rrt_index = s;
261555163Sshin
261662607Sitojun	trace(1, "\n");
261762607Sitojun
261855163Sshin	/* Check gateway */
261955163Sshin	if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_gw) &&
262055163Sshin	    !IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)
262155163Sshin#ifdef __FreeBSD__
262255163Sshin	 && (rrt->rrt_flags & RTF_LOCAL) == 0
262355163Sshin#endif
262455163Sshin	    ) {
262555163Sshin		trace(0, "***** Gateway %s is not a link-local address.\n",
262655163Sshin			inet6_n2p(&rrt->rrt_gw));
262755163Sshin		trace(0, "*****     dest(%s) if(%s) -- Not optimized.\n",
262862607Sitojun			inet6_n2p(&rrt->rrt_info.rip6_dest), ifname);
262962607Sitojun		rrt->rrt_rflags |= RRTF_NH_NOT_LLADDR;
263055163Sshin	}
263155163Sshin
263255163Sshin	/* Put it to the route list */
263378064Sume	if (orrt && orrt->rrt_info.rip6_metric == HOPCNT_INFINITY6) {
263478064Sume		/* replace route list */
263578064Sume		rrt->rrt_next = orrt->rrt_next;
263678064Sume		*orrt = *rrt;
263778064Sume		trace(1, "route: %s/%d flags %s: replace new route\n",
263878064Sume		    inet6_n2p(&np->rip6_dest), np->rip6_plen,
263978064Sume		    rtflags(rtm));
264078064Sume		free(rrt);
264178064Sume	} else {
264278064Sume		rrt->rrt_next = riprt;
264378064Sume		riprt = rrt;
264478064Sume	}
264555163Sshin}
264655163Sshin
264755163Sshinint
264855163Sshinaddroute(rrt, gw, ifcp)
264955163Sshin	struct riprt *rrt;
265055163Sshin	const struct in6_addr *gw;
265155163Sshin	struct ifc *ifcp;
265255163Sshin{
265355163Sshin	struct	netinfo6 *np;
265455163Sshin	u_char	buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ];
265555163Sshin	struct	rt_msghdr	*rtm;
2656119031Sume	struct	sockaddr_in6	*sin6;
265755163Sshin	int	len;
265855163Sshin
265955163Sshin	np = &rrt->rrt_info;
266078064Sume	inet_ntop(AF_INET6, (const void *)gw, (char *)buf1, sizeof(buf1));
266155163Sshin	inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2));
266255163Sshin	tracet(1, "ADD: %s/%d gw %s [%d] ifa %s\n",
266355163Sshin		inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1,
266455163Sshin		np->rip6_metric - 1, buf2);
266555163Sshin	if (rtlog)
266655163Sshin		fprintf(rtlog, "%s: ADD: %s/%d gw %s [%d] ifa %s\n", hms(),
266755163Sshin			inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1,
266855163Sshin			np->rip6_metric - 1, buf2);
266955163Sshin	if (nflag)
267055163Sshin		return 0;
267155163Sshin
267255163Sshin	memset(buf, 0, sizeof(buf));
267355163Sshin	rtm = (struct rt_msghdr *)buf;
267455163Sshin	rtm->rtm_type = RTM_ADD;
267555163Sshin	rtm->rtm_version = RTM_VERSION;
267655163Sshin	rtm->rtm_seq = ++seq;
267755163Sshin	rtm->rtm_pid = pid;
267862607Sitojun	rtm->rtm_flags = rrt->rrt_flags;
267955163Sshin	rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
268055163Sshin	rtm->rtm_rmx.rmx_hopcount = np->rip6_metric - 1;
268155163Sshin	rtm->rtm_inits = RTV_HOPCOUNT;
2682119031Sume	sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
268355163Sshin	/* Destination */
2684119031Sume	sin6->sin6_len = sizeof(struct sockaddr_in6);
2685119031Sume	sin6->sin6_family = AF_INET6;
2686119031Sume	sin6->sin6_addr = np->rip6_dest;
2687119031Sume	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
268855163Sshin	/* Gateway */
2689119031Sume	sin6->sin6_len = sizeof(struct sockaddr_in6);
2690119031Sume	sin6->sin6_family = AF_INET6;
2691119031Sume	sin6->sin6_addr = *gw;
2692119031Sume	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
269355163Sshin	/* Netmask */
2694119031Sume	sin6->sin6_len = sizeof(struct sockaddr_in6);
2695119031Sume	sin6->sin6_family = AF_INET6;
2696119031Sume	sin6->sin6_addr = *(plen2mask(np->rip6_plen));
2697119031Sume	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
269855163Sshin
2699119031Sume	len = (char *)sin6 - (char *)buf;
270055163Sshin	rtm->rtm_msglen = len;
270155163Sshin	if (write(rtsock, buf, len) > 0)
270255163Sshin		return 0;
270355163Sshin
270455163Sshin	if (errno == EEXIST) {
270555163Sshin		trace(0, "ADD: Route already exists %s/%d gw %s\n",
2706119035Sume		    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1);
270755163Sshin		if (rtlog)
270855163Sshin			fprintf(rtlog, "ADD: Route already exists %s/%d gw %s\n",
2709119035Sume			    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1);
271055163Sshin	} else {
271155163Sshin		trace(0, "Can not write to rtsock (addroute): %s\n",
2712119035Sume		    strerror(errno));
271355163Sshin		if (rtlog)
271455163Sshin			fprintf(rtlog, "\tCan not write to rtsock: %s\n",
2715119035Sume			    strerror(errno));
271655163Sshin	}
271755163Sshin	return -1;
271855163Sshin}
271955163Sshin
272055163Sshinint
272155163Sshindelroute(np, gw)
272255163Sshin	struct netinfo6 *np;
272355163Sshin	struct in6_addr *gw;
272455163Sshin{
272555163Sshin	u_char	buf[BUFSIZ], buf2[BUFSIZ];
272655163Sshin	struct	rt_msghdr	*rtm;
2727119031Sume	struct	sockaddr_in6	*sin6;
272855163Sshin	int	len;
272955163Sshin
273055163Sshin	inet_ntop(AF_INET6, (void *)gw, (char *)buf2, sizeof(buf2));
273155163Sshin	tracet(1, "DEL: %s/%d gw %s\n", inet6_n2p(&np->rip6_dest),
273255163Sshin		np->rip6_plen, buf2);
273355163Sshin	if (rtlog)
273455163Sshin		fprintf(rtlog, "%s: DEL: %s/%d gw %s\n",
273555163Sshin			hms(), inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
273655163Sshin	if (nflag)
273755163Sshin		return 0;
273855163Sshin
273955163Sshin	memset(buf, 0, sizeof(buf));
274055163Sshin	rtm = (struct rt_msghdr *)buf;
274155163Sshin	rtm->rtm_type = RTM_DELETE;
274255163Sshin	rtm->rtm_version = RTM_VERSION;
274355163Sshin	rtm->rtm_seq = ++seq;
274455163Sshin	rtm->rtm_pid = pid;
274555163Sshin	rtm->rtm_flags = RTF_UP | RTF_GATEWAY;
274678064Sume	if (np->rip6_plen == sizeof(struct in6_addr) * 8)
274778064Sume		rtm->rtm_flags |= RTF_HOST;
274855163Sshin	rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
2749119031Sume	sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
275055163Sshin	/* Destination */
2751119031Sume	sin6->sin6_len = sizeof(struct sockaddr_in6);
2752119031Sume	sin6->sin6_family = AF_INET6;
2753119031Sume	sin6->sin6_addr = np->rip6_dest;
2754119031Sume	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
275555163Sshin	/* Gateway */
2756119031Sume	sin6->sin6_len = sizeof(struct sockaddr_in6);
2757119031Sume	sin6->sin6_family = AF_INET6;
2758119031Sume	sin6->sin6_addr = *gw;
2759119031Sume	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
276055163Sshin	/* Netmask */
2761119031Sume	sin6->sin6_len = sizeof(struct sockaddr_in6);
2762119031Sume	sin6->sin6_family = AF_INET6;
2763119031Sume	sin6->sin6_addr = *(plen2mask(np->rip6_plen));
2764119031Sume	sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
276555163Sshin
2766119031Sume	len = (char *)sin6 - (char *)buf;
276755163Sshin	rtm->rtm_msglen = len;
276855163Sshin	if (write(rtsock, buf, len) >= 0)
276955163Sshin		return 0;
277055163Sshin
277155163Sshin	if (errno == ESRCH) {
277255163Sshin		trace(0, "RTDEL: Route does not exist: %s/%d gw %s\n",
2773119035Sume		    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
277455163Sshin		if (rtlog)
277555163Sshin			fprintf(rtlog, "RTDEL: Route does not exist: %s/%d gw %s\n",
2776119035Sume			    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
277755163Sshin	} else {
277855163Sshin		trace(0, "Can not write to rtsock (delroute): %s\n",
2779119035Sume		    strerror(errno));
278055163Sshin		if (rtlog)
278155163Sshin			fprintf(rtlog, "\tCan not write to rtsock: %s\n",
2782119035Sume			    strerror(errno));
278355163Sshin	}
278455163Sshin	return -1;
278555163Sshin}
278655163Sshin
278755163Sshinstruct in6_addr *
278855163Sshingetroute(np, gw)
278955163Sshin	struct netinfo6 *np;
279055163Sshin	struct in6_addr *gw;
279155163Sshin{
279255163Sshin	u_char buf[BUFSIZ];
279355163Sshin	u_long myseq;
279455163Sshin	int len;
279555163Sshin	struct rt_msghdr *rtm;
2796119031Sume	struct sockaddr_in6 *sin6;
279755163Sshin
279855163Sshin	rtm = (struct rt_msghdr *)buf;
279955163Sshin	len = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6);
280055163Sshin	memset(rtm, 0, len);
280155163Sshin	rtm->rtm_type = RTM_GET;
280255163Sshin	rtm->rtm_version = RTM_VERSION;
280355163Sshin	myseq = ++seq;
280455163Sshin	rtm->rtm_seq = myseq;
280555163Sshin	rtm->rtm_addrs = RTA_DST;
280655163Sshin	rtm->rtm_msglen = len;
2807119031Sume	sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
2808119031Sume	sin6->sin6_len = sizeof(struct sockaddr_in6);
2809119031Sume	sin6->sin6_family = AF_INET6;
2810119031Sume	sin6->sin6_addr = np->rip6_dest;
281155163Sshin	if (write(rtsock, buf, len) < 0) {
281255163Sshin		if (errno == ESRCH)	/* No such route found */
281355163Sshin			return NULL;
281455163Sshin		perror("write to rtsock");
281578064Sume		exit(1);
281655163Sshin	}
281755163Sshin	do {
281855163Sshin		if ((len = read(rtsock, buf, sizeof(buf))) < 0) {
281955163Sshin			perror("read from rtsock");
282078064Sume			exit(1);
282155163Sshin		}
282255163Sshin		rtm = (struct rt_msghdr *)buf;
282355163Sshin	} while (rtm->rtm_seq != myseq || rtm->rtm_pid != pid);
2824119031Sume	sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
282555163Sshin	if (rtm->rtm_addrs & RTA_DST) {
2826119031Sume		sin6 = (struct sockaddr_in6 *)
2827119031Sume			((char *)sin6 + ROUNDUP(sin6->sin6_len));
282855163Sshin	}
282955163Sshin	if (rtm->rtm_addrs & RTA_GATEWAY) {
2830119031Sume		*gw = sin6->sin6_addr;
283155163Sshin		return gw;
283255163Sshin	}
283355163Sshin	return NULL;
283455163Sshin}
283555163Sshin
283655163Sshinconst char *
283755163Sshininet6_n2p(p)
283855163Sshin	const struct in6_addr *p;
283955163Sshin{
284055163Sshin	static char buf[BUFSIZ];
284155163Sshin
284278064Sume	return inet_ntop(AF_INET6, (const void *)p, buf, sizeof(buf));
284355163Sshin}
284455163Sshin
284555163Sshinvoid
284655163Sshinifrtdump(sig)
284755163Sshin	int sig;
284855163Sshin{
284955163Sshin
285055163Sshin	ifdump(sig);
285155163Sshin	rtdump(sig);
285255163Sshin}
285355163Sshin
285455163Sshinvoid
285555163Sshinifdump(sig)
285655163Sshin	int sig;
285755163Sshin{
285855163Sshin	struct ifc *ifcp;
285955163Sshin	FILE *dump;
286055163Sshin	int i;
286155163Sshin
286255163Sshin	if (sig == 0)
286355163Sshin		dump = stderr;
286455163Sshin	else
286555163Sshin		if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL)
286655163Sshin			dump = stderr;
286755163Sshin
286855163Sshin	fprintf(dump, "%s: Interface Table Dump\n", hms());
286955163Sshin	fprintf(dump, "  Number of interfaces: %d\n", nifc);
287055163Sshin	for (i = 0; i < 2; i++) {
287155163Sshin		fprintf(dump, "  %sadvertising interfaces:\n", i ? "non-" : "");
287255163Sshin		for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
287355163Sshin			if (i == 0) {
287455163Sshin				if ((ifcp->ifc_flags & IFF_UP) == 0)
287555163Sshin					continue;
287655163Sshin				if (iff_find(ifcp, 'N') != NULL)
287755163Sshin					continue;
287855163Sshin			} else {
287955163Sshin				if (ifcp->ifc_flags & IFF_UP)
288055163Sshin					continue;
288155163Sshin			}
288255163Sshin			ifdump0(dump, ifcp);
288355163Sshin		}
288455163Sshin	}
288555163Sshin	fprintf(dump, "\n");
288655163Sshin	if (dump != stderr)
288755163Sshin		fclose(dump);
288855163Sshin}
288955163Sshin
289055163Sshinvoid
289155163Sshinifdump0(dump, ifcp)
289255163Sshin	FILE *dump;
289355163Sshin	const struct ifc *ifcp;
289455163Sshin{
289555163Sshin	struct ifac *ifa;
289655163Sshin	struct iff *iffp;
289755163Sshin	char buf[BUFSIZ];
289855163Sshin	const char *ft;
289955163Sshin	int addr;
290055163Sshin
290155163Sshin	fprintf(dump, "    %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)\n",
290255163Sshin		ifcp->ifc_name, ifcp->ifc_index, ifflags(ifcp->ifc_flags),
290355163Sshin		inet6_n2p(&ifcp->ifc_mylladdr),
290455163Sshin		ifcp->ifc_mtu, ifcp->ifc_metric);
290555163Sshin	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
290655163Sshin		if (ifcp->ifc_flags & IFF_POINTOPOINT) {
290755163Sshin			inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr,
290855163Sshin				buf, sizeof(buf));
290955163Sshin			fprintf(dump, "\t%s/%d -- %s\n",
291055163Sshin				inet6_n2p(&ifa->ifa_addr),
291155163Sshin				ifa->ifa_plen, buf);
291255163Sshin		} else {
291355163Sshin			fprintf(dump, "\t%s/%d\n",
291455163Sshin				inet6_n2p(&ifa->ifa_addr),
291555163Sshin				ifa->ifa_plen);
291655163Sshin		}
291755163Sshin	}
291855163Sshin	if (ifcp->ifc_filter) {
291955163Sshin		fprintf(dump, "\tFilter:");
292055163Sshin		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
292155163Sshin			addr = 0;
292255163Sshin			switch (iffp->iff_type) {
292355163Sshin			case 'A':
292455163Sshin				ft = "Aggregate"; addr++; break;
292555163Sshin			case 'N':
292678064Sume				ft = "No-use"; break;
292755163Sshin			case 'O':
292855163Sshin				ft = "Advertise-only"; addr++; break;
292955163Sshin			case 'T':
293055163Sshin				ft = "Default-only"; break;
293155163Sshin			case 'L':
293255163Sshin				ft = "Listen-only"; addr++; break;
293355163Sshin			default:
293455163Sshin				snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type);
293555163Sshin				ft = buf;
293655163Sshin				addr++;
293755163Sshin				break;
293855163Sshin			}
293955163Sshin			fprintf(dump, " %s", ft);
294055163Sshin			if (addr) {
294155163Sshin				fprintf(dump, "(%s/%d)", inet6_n2p(&iffp->iff_addr),
294255163Sshin					iffp->iff_plen);
294355163Sshin			}
294455163Sshin		}
294555163Sshin		fprintf(dump, "\n");
294655163Sshin	}
294755163Sshin}
294855163Sshin
294955163Sshinvoid
295055163Sshinrtdump(sig)
295155163Sshin	int sig;
295255163Sshin{
295355163Sshin	struct	riprt *rrt;
295455163Sshin	char	buf[BUFSIZ];
295555163Sshin	FILE	*dump;
295655163Sshin	time_t	t, age;
295755163Sshin
295855163Sshin	if (sig == 0)
295955163Sshin		dump = stderr;
296055163Sshin	else
296155163Sshin		if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL)
296255163Sshin			dump = stderr;
296355163Sshin
296455163Sshin	t = time(NULL);
296555163Sshin	fprintf(dump, "\n%s: Routing Table Dump\n", hms());
296655163Sshin	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
296755163Sshin		if (rrt->rrt_t == 0)
296855163Sshin			age = 0;
296955163Sshin		else
297055163Sshin			age = t - rrt->rrt_t;
297155163Sshin		inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest,
297255163Sshin			buf, sizeof(buf));
297355163Sshin		fprintf(dump, "    %s/%d if(%d:%s) gw(%s) [%d] age(%ld)",
297455163Sshin			buf, rrt->rrt_info.rip6_plen, rrt->rrt_index,
297555163Sshin			index2ifc[rrt->rrt_index]->ifc_name,
297655163Sshin			inet6_n2p(&rrt->rrt_gw),
297755163Sshin			rrt->rrt_info.rip6_metric, (long)age);
297855163Sshin		if (rrt->rrt_info.rip6_tag) {
297955163Sshin			fprintf(dump, " tag(0x%04x)",
298055163Sshin				ntohs(rrt->rrt_info.rip6_tag) & 0xffff);
298155163Sshin		}
298262607Sitojun		if (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)
298355163Sshin			fprintf(dump, " NOT-LL");
298462607Sitojun		if (rrt->rrt_rflags & RRTF_NOADVERTISE)
298555163Sshin			fprintf(dump, " NO-ADV");
298655163Sshin		fprintf(dump, "\n");
298755163Sshin	}
298855163Sshin	fprintf(dump, "\n");
298955163Sshin	if (dump != stderr)
299055163Sshin		fclose(dump);
299155163Sshin}
299255163Sshin
299355163Sshin/*
299455163Sshin * Parse the -A (and -O) options and put corresponding filter object to the
299578064Sume * specified interface structures.  Each of the -A/O option has the following
299655163Sshin * syntax:	-A 5f09:c400::/32,ef0,ef1  (aggregate)
299755163Sshin * 		-O 5f09:c400::/32,ef0,ef1  (only when match)
299855163Sshin */
299955163Sshinvoid
300055163Sshinfilterconfig()
300155163Sshin{
300255163Sshin	int i;
300355163Sshin	char *p, *ap, *iflp, *ifname;
300478064Sume	struct iff ftmp, *iff_obj;
300578064Sume	struct ifc *ifcp;
300678064Sume	struct riprt *rrt;
300764631Sitojun#if 0
300878064Sume	struct in6_addr gw;
300964631Sitojun#endif
301055163Sshin
301155163Sshin	for (i = 0; i < nfilter; i++) {
301255163Sshin		ap = filter[i];
301355163Sshin		iflp = NULL;
301455163Sshin		ifcp = NULL;
301555163Sshin		if (filtertype[i] == 'N' || filtertype[i] == 'T') {
301655163Sshin			iflp = ap;
301755163Sshin			goto ifonly;
301855163Sshin		}
3019119038Sume		if ((p = strchr(ap, ',')) != NULL) {
302055163Sshin			*p++ = '\0';
302155163Sshin			iflp = p;
302255163Sshin		}
3023119038Sume		if ((p = strchr(ap, '/')) == NULL) {
302455163Sshin			fatal("no prefixlen specified for '%s'", ap);
302578064Sume			/*NOTREACHED*/
302678064Sume		}
302755163Sshin		*p++ = '\0';
302878064Sume		if (inet_pton(AF_INET6, ap, &ftmp.iff_addr) != 1) {
302955163Sshin			fatal("invalid prefix specified for '%s'", ap);
303078064Sume			/*NOTREACHED*/
303178064Sume		}
303255163Sshin		ftmp.iff_plen = atoi(p);
303355163Sshin		ftmp.iff_next = NULL;
303455163Sshin		applyplen(&ftmp.iff_addr, ftmp.iff_plen);
303555163Sshinifonly:
303655163Sshin		ftmp.iff_type = filtertype[i];
303778064Sume		if (iflp == NULL || *iflp == '\0') {
303855163Sshin			fatal("no interface specified for '%s'", ap);
303978064Sume			/*NOTREACHED*/
304078064Sume		}
304155163Sshin		/* parse the interface listing portion */
304255163Sshin		while (iflp) {
304355163Sshin			ifname = iflp;
3044119038Sume			if ((iflp = strchr(iflp, ',')) != NULL)
304555163Sshin				*iflp++ = '\0';
304655163Sshin			ifcp = ifc_find(ifname);
304778064Sume			if (ifcp == NULL) {
304855163Sshin				fatal("no interface %s exists", ifname);
304978064Sume				/*NOTREACHED*/
305078064Sume			}
305155163Sshin			iff_obj = (struct iff *)malloc(sizeof(struct iff));
305278064Sume			if (iff_obj == NULL) {
305355163Sshin				fatal("malloc of iff_obj");
305478064Sume				/*NOTREACHED*/
305578064Sume			}
305655163Sshin			memcpy((void *)iff_obj, (void *)&ftmp,
305778064Sume			    sizeof(struct iff));
305855163Sshin			/* link it to the interface filter */
305955163Sshin			iff_obj->iff_next = ifcp->ifc_filter;
306055163Sshin			ifcp->ifc_filter = iff_obj;
306155163Sshin		}
306278064Sume
306378064Sume		/*
306478064Sume		 * -A: aggregate configuration.
306578064Sume		 */
306655163Sshin		if (filtertype[i] != 'A')
306755163Sshin			continue;
306855163Sshin		/* put the aggregate to the kernel routing table */
306955163Sshin		rrt = (struct riprt *)malloc(sizeof(struct riprt));
307078064Sume		if (rrt == NULL) {
307155163Sshin			fatal("malloc: rrt");
307278064Sume			/*NOTREACHED*/
307378064Sume		}
307455163Sshin		memset(rrt, 0, sizeof(struct riprt));
307555163Sshin		rrt->rrt_info.rip6_dest = ftmp.iff_addr;
307655163Sshin		rrt->rrt_info.rip6_plen = ftmp.iff_plen;
307755163Sshin		rrt->rrt_info.rip6_metric = 1;
307855163Sshin		rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
307955163Sshin		rrt->rrt_gw = in6addr_loopback;
308062607Sitojun		rrt->rrt_flags = RTF_UP | RTF_REJECT;
308162607Sitojun		rrt->rrt_rflags = RRTF_AGGREGATE;
308255163Sshin		rrt->rrt_t = 0;
3083119039Sume		rrt->rrt_index = loopifcp->ifc_index;
308464631Sitojun#if 0
308564631Sitojun		if (getroute(&rrt->rrt_info, &gw)) {
308664631Sitojun#if 0
308764631Sitojun			/*
308864631Sitojun			 * When the address has already been registered in the
308964631Sitojun			 * kernel routing table, it should be removed
309064631Sitojun			 */
309164631Sitojun			delroute(&rrt->rrt_info, &gw);
309264631Sitojun#else
309378064Sume			/* it is safer behavior */
309464631Sitojun			errno = EINVAL;
309564631Sitojun			fatal("%s/%u already in routing table, "
309664631Sitojun			    "cannot aggregate",
309764631Sitojun			    inet6_n2p(&rrt->rrt_info.rip6_dest),
309864631Sitojun			    rrt->rrt_info.rip6_plen);
309978064Sume			/*NOTREACHED*/
310064631Sitojun#endif
310164631Sitojun		}
310264631Sitojun#endif
310355163Sshin		/* Put the route to the list */
310455163Sshin		rrt->rrt_next = riprt;
310555163Sshin		riprt = rrt;
310655163Sshin		trace(1, "Aggregate: %s/%d for %s\n",
310755163Sshin			inet6_n2p(&ftmp.iff_addr), ftmp.iff_plen,
310855163Sshin			ifcp->ifc_name);
310955163Sshin		/* Add this route to the kernel */
311055163Sshin		if (nflag) 	/* do not modify kernel routing table */
311155163Sshin			continue;
311255163Sshin		addroute(rrt, &in6addr_loopback, loopifcp);
311355163Sshin	}
311455163Sshin}
311555163Sshin
311655163Sshin/***************** utility functions *****************/
311755163Sshin
311855163Sshin/*
311955163Sshin * Returns a pointer to ifac whose address and prefix length matches
312055163Sshin * with the address and prefix length specified in the arguments.
312155163Sshin */
312255163Sshinstruct ifac *
312355163Sshinifa_match(ifcp, ia, plen)
312455163Sshin	const struct ifc *ifcp;
312555163Sshin	const struct in6_addr *ia;
312655163Sshin	int plen;
312755163Sshin{
312855163Sshin	struct ifac *ifa;
312955163Sshin
313055163Sshin	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
313155163Sshin		if (IN6_ARE_ADDR_EQUAL(&ifa->ifa_addr, ia) &&
313255163Sshin		    ifa->ifa_plen == plen)
313355163Sshin			break;
313455163Sshin	}
313555163Sshin	return ifa;
313655163Sshin}
313755163Sshin
313855163Sshin/*
313955163Sshin * Return a pointer to riprt structure whose address and prefix length
314055163Sshin * matches with the address and prefix length found in the argument.
314178064Sume * Note: This is not a rtalloc().  Therefore exact match is necessary.
314255163Sshin */
314355163Sshinstruct riprt *
314478064Sumertsearch(np, prev_rrt)
314555163Sshin	struct	netinfo6 *np;
314678064Sume	struct	riprt **prev_rrt;
314755163Sshin{
314855163Sshin	struct	riprt	*rrt;
314955163Sshin
315078064Sume	if (prev_rrt)
315178064Sume		*prev_rrt = NULL;
315255163Sshin	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
315355163Sshin		if (rrt->rrt_info.rip6_plen == np->rip6_plen &&
315455163Sshin		    IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
315555163Sshin				       &np->rip6_dest))
315655163Sshin			return rrt;
315778064Sume		if (prev_rrt)
315878064Sume			*prev_rrt = rrt;
315955163Sshin	}
316078064Sume	if (prev_rrt)
316178064Sume		*prev_rrt = NULL;
316255163Sshin	return 0;
316355163Sshin}
316455163Sshin
316555163Sshinint
316678064Sumesin6mask2len(sin6)
316778064Sume	const struct sockaddr_in6 *sin6;
316878064Sume{
316978064Sume
317078064Sume	return mask2len(&sin6->sin6_addr,
317178064Sume	    sin6->sin6_len - offsetof(struct sockaddr_in6, sin6_addr));
317278064Sume}
317378064Sume
317478064Sumeint
317555163Sshinmask2len(addr, lenlim)
317655163Sshin	const struct in6_addr *addr;
317755163Sshin	int lenlim;
317855163Sshin{
317955163Sshin	int i = 0, j;
318078064Sume	const u_char *p = (const u_char *)addr;
318162607Sitojun
318255163Sshin	for (j = 0; j < lenlim; j++, p++) {
318355163Sshin		if (*p != 0xff)
318455163Sshin			break;
318555163Sshin		i += 8;
318655163Sshin	}
318755163Sshin	if (j < lenlim) {
318855163Sshin		switch (*p) {
318962607Sitojun#define	MASKLEN(m, l)	case m: do { i += l; break; } while (0)
319062607Sitojun		MASKLEN(0xfe, 7); break;
319162607Sitojun		MASKLEN(0xfc, 6); break;
319262607Sitojun		MASKLEN(0xf8, 5); break;
319362607Sitojun		MASKLEN(0xf0, 4); break;
319462607Sitojun		MASKLEN(0xe0, 3); break;
319562607Sitojun		MASKLEN(0xc0, 2); break;
319662607Sitojun		MASKLEN(0x80, 1); break;
319755163Sshin#undef	MASKLEN
319855163Sshin		}
319955163Sshin	}
320055163Sshin	return i;
320155163Sshin}
320255163Sshin
320355163Sshinvoid
320455163Sshinapplymask(addr, mask)
320555163Sshin	struct in6_addr *addr, *mask;
320655163Sshin{
320755163Sshin	int	i;
320855163Sshin	u_long	*p, *q;
320955163Sshin
321055163Sshin	p = (u_long *)addr; q = (u_long *)mask;
321155163Sshin	for (i = 0; i < 4; i++)
321255163Sshin		*p++ &= *q++;
321355163Sshin}
321455163Sshin
321555163Sshinstatic const u_char plent[8] = {
321655163Sshin	0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
321755163Sshin};
321855163Sshin
321955163Sshinvoid
322055163Sshinapplyplen(ia, plen)
322155163Sshin	struct	in6_addr *ia;
322255163Sshin	int	plen;
322355163Sshin{
322455163Sshin	u_char	*p;
322555163Sshin	int	i;
322655163Sshin
322755163Sshin	p = ia->s6_addr;
322855163Sshin	for (i = 0; i < 16; i++) {
322955163Sshin		if (plen <= 0)
323055163Sshin			*p = 0;
323155163Sshin		else if (plen < 8)
323255163Sshin			*p &= plent[plen];
323355163Sshin		p++, plen -= 8;
323455163Sshin	}
323555163Sshin}
323655163Sshin
323755163Sshinstatic const int pl2m[9] = {
323855163Sshin	0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
323955163Sshin};
324055163Sshin
324155163Sshinstruct in6_addr *
324255163Sshinplen2mask(n)
324355163Sshin	int	n;
324455163Sshin{
324555163Sshin	static struct in6_addr ia;
324655163Sshin	u_char	*p;
324755163Sshin	int	i;
324855163Sshin
324955163Sshin	memset(&ia, 0, sizeof(struct in6_addr));
325055163Sshin	p = (u_char *)&ia;
325155163Sshin	for (i = 0; i < 16; i++, p++, n -= 8) {
325255163Sshin		if (n >= 8) {
325355163Sshin			*p = 0xff;
325455163Sshin			continue;
325555163Sshin		}
325655163Sshin		*p = pl2m[n];
325755163Sshin		break;
325855163Sshin	}
325955163Sshin	return &ia;
326055163Sshin}
326155163Sshin
326255163Sshinchar *
326355163Sshinallocopy(p)
326455163Sshin	char *p;
326555163Sshin{
3266119033Sume	int len = strlen(p) + 1;
3267119033Sume	char *q = (char *)malloc(len);
326855163Sshin
3269119033Sume	if (!q) {
3270119033Sume		fatal("malloc");
3271119033Sume		/*NOTREACHED*/
3272119033Sume	}
3273119033Sume
3274119033Sume	strlcpy(q, p, len);
327555163Sshin	return q;
327655163Sshin}
327755163Sshin
327855163Sshinchar *
327955163Sshinhms()
328055163Sshin{
328155163Sshin	static char buf[BUFSIZ];
328255163Sshin	time_t t;
328355163Sshin	struct	tm *tm;
328455163Sshin
328555163Sshin	t = time(NULL);
328678064Sume	if ((tm = localtime(&t)) == 0) {
328755163Sshin		fatal("localtime");
328878064Sume		/*NOTREACHED*/
328978064Sume	}
329078064Sume	snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
329178064Sume	    tm->tm_sec);
329255163Sshin	return buf;
329355163Sshin}
329455163Sshin
329555163Sshin#define	RIPRANDDEV	1.0	/* 30 +- 15, max - min = 30 */
329655163Sshin
329755163Sshinint
329855163Sshinripinterval(timer)
329955163Sshin	int timer;
330055163Sshin{
330155163Sshin	double r = rand();
330255163Sshin
330355163Sshin	interval = (int)(timer + timer * RIPRANDDEV * (r / RAND_MAX - 0.5));
330455163Sshin	nextalarm = time(NULL) + interval;
330555163Sshin	return interval;
330655163Sshin}
330755163Sshin
330855163Sshintime_t
330955163Sshinripsuptrig()
331055163Sshin{
331155163Sshin	time_t t;
331255163Sshin
331355163Sshin	double r = rand();
331462607Sitojun	t  = (int)(RIP_TRIG_INT6_MIN +
331578064Sume		(RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / RAND_MAX));
331655163Sshin	sup_trig_update = time(NULL) + t;
331755163Sshin	return t;
331855163Sshin}
331955163Sshin
332055163Sshinvoid
332155163Sshin#ifdef __STDC__
332255163Sshinfatal(const char *fmt, ...)
332355163Sshin#else
332455163Sshinfatal(fmt, va_alist)
332555163Sshin	char	*fmt;
332655163Sshin	va_dcl
332755163Sshin#endif
332855163Sshin{
332955163Sshin	va_list ap;
333055163Sshin	char buf[1024];
333155163Sshin
333255163Sshin#ifdef __STDC__
333355163Sshin	va_start(ap, fmt);
333455163Sshin#else
333555163Sshin	va_start(ap);
333655163Sshin#endif
333755163Sshin	vsnprintf(buf, sizeof(buf), fmt, ap);
333855163Sshin	perror(buf);
333955163Sshin	syslog(LOG_ERR, "%s: %s", buf, strerror(errno));
334078064Sume	rtdexit();
334155163Sshin	va_end(ap);
334255163Sshin}
334355163Sshin
334455163Sshinvoid
334555163Sshin#ifdef __STDC__
334655163Sshintracet(int level, const char *fmt, ...)
334755163Sshin#else
334855163Sshintracet(level, fmt, va_alist)
334955163Sshin	int level;
335055163Sshin	char *fmt;
335155163Sshin	va_dcl
335255163Sshin#endif
335355163Sshin{
335455163Sshin	va_list ap;
335555163Sshin
335655163Sshin#ifdef __STDC__
335755163Sshin	va_start(ap, fmt);
335855163Sshin#else
335955163Sshin	va_start(ap);
336055163Sshin#endif
336155163Sshin	if (level <= dflag) {
336255163Sshin		fprintf(stderr, "%s: ", hms());
336355163Sshin		vfprintf(stderr, fmt, ap);
336455163Sshin	}
336555163Sshin	if (dflag) {
336655163Sshin		if (level > 0)
336755163Sshin			vsyslog(LOG_DEBUG, fmt, ap);
336855163Sshin		else
336955163Sshin			vsyslog(LOG_WARNING, fmt, ap);
337055163Sshin	}
337155163Sshin	va_end(ap);
337255163Sshin}
337355163Sshin
337455163Sshinvoid
337555163Sshin#ifdef __STDC__
337655163Sshintrace(int level, const char *fmt, ...)
337755163Sshin#else
337855163Sshintrace(level, fmt, va_alist)
337955163Sshin	int level;
338055163Sshin	char *fmt;
338155163Sshin	va_dcl
338255163Sshin#endif
338355163Sshin{
338455163Sshin	va_list ap;
338555163Sshin
338655163Sshin#ifdef __STDC__
338755163Sshin	va_start(ap, fmt);
338855163Sshin#else
338955163Sshin	va_start(ap);
339055163Sshin#endif
339155163Sshin	if (level <= dflag)
339255163Sshin		vfprintf(stderr, fmt, ap);
339355163Sshin	if (dflag) {
339455163Sshin		if (level > 0)
339555163Sshin			vsyslog(LOG_DEBUG, fmt, ap);
339655163Sshin		else
339755163Sshin			vsyslog(LOG_WARNING, fmt, ap);
339855163Sshin	}
339955163Sshin	va_end(ap);
340055163Sshin}
340155163Sshin
340255163Sshinunsigned int
340355163Sshinif_maxindex()
340455163Sshin{
340555163Sshin	struct if_nameindex *p, *p0;
340655163Sshin	unsigned int max = 0;
340755163Sshin
340855163Sshin	p0 = if_nameindex();
340955163Sshin	for (p = p0; p && p->if_index && p->if_name; p++) {
341055163Sshin		if (max < p->if_index)
341155163Sshin			max = p->if_index;
341255163Sshin	}
341355163Sshin	if_freenameindex(p0);
341455163Sshin	return max;
341555163Sshin}
341655163Sshin
341755163Sshinstruct ifc *
341855163Sshinifc_find(name)
341955163Sshin	char *name;
342055163Sshin{
342155163Sshin	struct ifc *ifcp;
342255163Sshin
342355163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
342455163Sshin		if (strcmp(name, ifcp->ifc_name) == 0)
342555163Sshin			return ifcp;
342655163Sshin	}
342755163Sshin	return (struct ifc *)NULL;
342855163Sshin}
342955163Sshin
343055163Sshinstruct iff *
343155163Sshiniff_find(ifcp, type)
343255163Sshin	struct ifc *ifcp;
343355163Sshin	int type;
343455163Sshin{
343555163Sshin	struct iff *iffp;
343655163Sshin
343755163Sshin	for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
343855163Sshin		if (iffp->iff_type == type)
343955163Sshin			return iffp;
344055163Sshin	}
344155163Sshin	return NULL;
344255163Sshin}
344355163Sshin
344455163Sshinvoid
344578064Sumesetindex2ifc(idx, ifcp)
344678064Sume	int idx;
344755163Sshin	struct ifc *ifcp;
344855163Sshin{
344955163Sshin	int n;
345062607Sitojun	struct ifc **p;
345155163Sshin
345255163Sshin	if (!index2ifc) {
345355163Sshin		nindex2ifc = 5;	/*initial guess*/
345455163Sshin		index2ifc = (struct ifc **)
345555163Sshin			malloc(sizeof(*index2ifc) * nindex2ifc);
345678064Sume		if (index2ifc == NULL) {
345755163Sshin			fatal("malloc");
345878064Sume			/*NOTREACHED*/
345978064Sume		}
346055163Sshin		memset(index2ifc, 0, sizeof(*index2ifc) * nindex2ifc);
346155163Sshin	}
346255163Sshin	n = nindex2ifc;
346378064Sume	while (nindex2ifc <= idx)
346455163Sshin		nindex2ifc *= 2;
346555163Sshin	if (n != nindex2ifc) {
346662607Sitojun		p = (struct ifc **)realloc(index2ifc,
346762607Sitojun		    sizeof(*index2ifc) * nindex2ifc);
346878064Sume		if (p == NULL) {
346955163Sshin			fatal("realloc");
347078064Sume			/*NOTREACHED*/
347178064Sume		}
347278064Sume		memset(p + n, 0, sizeof(*index2ifc) * (nindex2ifc - n));
347362607Sitojun		index2ifc = p;
347455163Sshin	}
347578064Sume	index2ifc[idx] = ifcp;
347655163Sshin}
3477