route6d.c revision 55163
155163Sshin/*
255163Sshin * $Header: /cvsroot/kame/kame/kame/kame/route6d/route6d.c,v 1.6 1999/09/10 08:20:59 itojun Exp $
355163Sshin */
455163Sshin
555163Sshin/*
655163Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
755163Sshin * All rights reserved.
855163Sshin *
955163Sshin * Redistribution and use in source and binary forms, with or without
1055163Sshin * modification, are permitted provided that the following conditions
1155163Sshin * are met:
1255163Sshin * 1. Redistributions of source code must retain the above copyright
1355163Sshin *    notice, this list of conditions and the following disclaimer.
1455163Sshin * 2. Redistributions in binary form must reproduce the above copyright
1555163Sshin *    notice, this list of conditions and the following disclaimer in the
1655163Sshin *    documentation and/or other materials provided with the distribution.
1755163Sshin * 3. Neither the name of the project nor the names of its contributors
1855163Sshin *    may be used to endorse or promote products derived from this software
1955163Sshin *    without specific prior written permission.
2055163Sshin *
2155163Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2255163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2355163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2455163Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2555163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2655163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2755163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2855163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2955163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3055163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3155163Sshin * SUCH DAMAGE.
3255163Sshin *
3355163Sshin * $FreeBSD: head/usr.sbin/route6d/route6d.c 55163 1999-12-28 02:37:14Z shin $
3455163Sshin */
3555163Sshin
3655163Sshin#ifndef	lint
3755163Sshinstatic char _rcsid[] = "$Id: route6d.c,v 1.6 1999/09/10 08:20:59 itojun Exp $";
3855163Sshin#endif
3955163Sshin
4055163Sshin#include <stdio.h>
4155163Sshin
4255163Sshin#include <time.h>
4355163Sshin#include <unistd.h>
4455163Sshin#include <stdlib.h>
4555163Sshin#include <string.h>
4655163Sshin#include <signal.h>
4755163Sshin#ifdef __STDC__
4855163Sshin#include <stdarg.h>
4955163Sshin#else
5055163Sshin#include <varargs.h>
5155163Sshin#endif
5255163Sshin#include <syslog.h>
5355163Sshin#include <stddef.h>
5455163Sshin#include <err.h>
5555163Sshin
5655163Sshin#include <sys/types.h>
5755163Sshin#include <sys/param.h>
5855163Sshin#include <sys/file.h>
5955163Sshin#include <sys/socket.h>
6055163Sshin#include <sys/ioctl.h>
6155163Sshin#include <sys/sysctl.h>
6255163Sshin#include <sys/errno.h>
6355163Sshin#ifdef ADVAPI
6455163Sshin#include <sys/uio.h>
6555163Sshin#endif
6655163Sshin#include <net/if.h>
6755163Sshin#if defined(__FreeBSD__) && __FreeBSD__ >= 3
6855163Sshin#include <net/if_var.h>
6955163Sshin#endif /* __FreeBSD__ >= 3 */
7055163Sshin#define	KERNEL	1
7155163Sshin#include <net/route.h>
7255163Sshin#undef KERNEL
7355163Sshin#include <netinet/in.h>
7455163Sshin#include <netinet/in_var.h>
7555163Sshin#include <netinet/ip6.h>
7655163Sshin#include <netinet/udp.h>
7755163Sshin#include <netdb.h>
7855163Sshin
7955163Sshin#include <arpa/inet.h>
8055163Sshin
8155163Sshin#include "route6d.h"
8255163Sshin
8355163Sshin#define	MAXFILTER	40
8455163Sshin
8555163Sshin#ifdef	DEBUG
8655163Sshin#define	INIT_INTERVAL6	6
8755163Sshin#else
8855163Sshin#define	INIT_INTERVAL6	10	/* Wait to submit a initial riprequest */
8955163Sshin#endif
9055163Sshin
9155163Sshin/* alignment constraint for routing socket */
9255163Sshin#define	ROUNDUP(a) \
9355163Sshin	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
9455163Sshin#define	ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
9555163Sshin
9655163Sshin/*
9755163Sshin * Following two macros are highly depending on KAME Release
9855163Sshin */
9955163Sshin#define	IN6_LINKLOCAL_IFINDEX(addr) \
10055163Sshin	((addr).s6_addr[2] << 8 | (addr).s6_addr[3])
10155163Sshin
10255163Sshin#define	SET_IN6_LINKLOCAL_IFINDEX(addr, index) \
10355163Sshin	do { \
10455163Sshin		(addr).s6_addr[2] = ((index) >> 8) & 0xff; \
10555163Sshin		(addr).s6_addr[3] = (index) & 0xff; \
10655163Sshin	} while (0)
10755163Sshin
10855163Sshinstruct	ifc {			/* Configuration of an interface */
10955163Sshin	char	*ifc_name;			/* if name */
11055163Sshin	struct	ifc *ifc_next;
11155163Sshin	int	ifc_index;			/* if index */
11255163Sshin	int	ifc_mtu;			/* if mtu */
11355163Sshin	int	ifc_metric;			/* if metric */
11455163Sshin	short	ifc_flags;			/* flags */
11555163Sshin	struct	in6_addr ifc_mylladdr;		/* my link-local address */
11655163Sshin	struct	sockaddr_in6 ifc_ripsin;	/* rip multicast address */
11755163Sshin	struct	iff *ifc_filter;		/* filter structure */
11855163Sshin	struct	ifac *ifc_addr;			/* list of AF_INET6 addresses */
11955163Sshin	int	ifc_joined;			/* joined to ff02::9 */
12055163Sshin};
12155163Sshin
12255163Sshinstruct	ifac {			/* Adddress associated to an interface */
12355163Sshin	struct	ifc *ifa_conf;		/* back pointer */
12455163Sshin	struct	ifac *ifa_next;
12555163Sshin	struct	in6_addr ifa_addr;	/* address */
12655163Sshin	struct	in6_addr ifa_raddr;	/* remote address, valid in p2p */
12755163Sshin	int	ifa_plen;		/* prefix length */
12855163Sshin};
12955163Sshin
13055163Sshinstruct	iff {
13155163Sshin	int	iff_type;
13255163Sshin	struct	in6_addr iff_addr;
13355163Sshin	int	iff_plen;
13455163Sshin	struct	iff *iff_next;
13555163Sshin};
13655163Sshin
13755163Sshinstruct	ifc *ifc;
13855163Sshinint	nifc;		/* number of valid ifc's */
13955163Sshinstruct	ifc **index2ifc;
14055163Sshinint	nindex2ifc;
14155163Sshinstruct	ifc *loopifcp = NULL;	/* pointing to loopback */
14255163Sshinint	loopifindex = 0;	/* ditto */
14355163Sshinfd_set	sockvec;	/* vector to select() for receiving */
14455163Sshinint	rtsock;		/* the routing socket */
14555163Sshinint	ripsock;	/* socket to send/receive RIP datagram */
14655163Sshin
14755163Sshinstruct	rip6 *ripbuf;	/* packet buffer for sending */
14855163Sshin
14955163Sshin/*
15055163Sshin * Maintain the routes in a linked list. When the number of the routes
15155163Sshin * grows, somebody would like to introduce a hash based or a radix tree
15255163Sshin * based strucutre. I believe the number of routes handled by RIP is
15355163Sshin * limited and I don't have to manage a complex data structure, however.
15455163Sshin *
15555163Sshin * One of the major drawbacks of the linear linked list is the difficulty
15655163Sshin * of representing the relationship between a couple of routes. This may
15755163Sshin * be a significant problem when we have to support route aggregation with
15855163Sshin * supressing the specifices covered by the aggregate.
15955163Sshin */
16055163Sshin
16155163Sshinstruct	riprt {
16255163Sshin	struct	riprt *rrt_next;	/* next destination */
16355163Sshin	struct	riprt *rrt_same;	/* same destination - future use */
16455163Sshin	struct	netinfo6 rrt_info;	/* network info */
16555163Sshin	struct	in6_addr rrt_gw;	/* gateway */
16655163Sshin	u_long	rrt_flags;
16755163Sshin	time_t	rrt_t;			/* when the route validated */
16855163Sshin	int	rrt_index;		/* ifindex from which this route got */
16955163Sshin};
17055163Sshin
17155163Sshinstruct	riprt *riprt = 0;
17255163Sshin
17355163Sshinint	dflag = 0;	/* debug flag */
17455163Sshinint	qflag = 0;	/* quiet flag */
17555163Sshinint	nflag = 0;	/* don't update kernel routing table */
17655163Sshinint	aflag = 0;	/* age out even the statically defined routes */
17755163Sshinint	hflag = 0;	/* don't split horizon */
17855163Sshinint	lflag = 0;	/* exchange site local routes */
17955163Sshinint	sflag = 0;	/* announce static routes w/ split horizon */
18055163Sshinint	Sflag = 0;	/* announce static routes to every interface */
18155163Sshinint	routetag = 0;	/* route tag attached on originating case */
18255163Sshin
18355163Sshinchar	*filter[MAXFILTER];
18455163Sshinint	filtertype[MAXFILTER];
18555163Sshinint	nfilter = 0;
18655163Sshin
18755163Sshinpid_t	pid;
18855163Sshin
18955163Sshinstruct	sockaddr_storage ripsin;
19055163Sshin
19155163Sshinstruct	rtentry rtentry;
19255163Sshin
19355163Sshinint	interval = 1;
19455163Sshintime_t	nextalarm = 0;
19555163Sshintime_t	sup_trig_update = 0;
19655163Sshin
19755163SshinFILE	*rtlog = NULL;
19855163Sshin
19955163Sshinint logopened = 0;
20055163Sshin
20155163Sshinstatic	u_long	seq = 0;
20255163Sshin
20355163Sshin#define	RTF_AGGREGATE		0x08000000
20455163Sshin#define	RTF_NOADVERTISE		0x10000000
20555163Sshin#define	RTF_NH_NOT_LLADDR	0x20000000
20655163Sshin#define	RTF_SENDANYWAY		0x40000000
20755163Sshin#define	RTF_CHANGED		0x80000000
20855163Sshin#define	RTF_ROUTE_H		0xffff
20955163Sshin
21055163Sshinextern int errno;
21155163Sshin
21255163Sshinint main __P((int, char **));
21355163Sshinvoid ripalarm __P((int));
21455163Sshinvoid riprecv __P((void));
21555163Sshinvoid ripsend __P((struct ifc *, struct sockaddr_in6 *, int));
21655163Sshinvoid init __P((void));
21755163Sshinvoid sockopt __P((struct ifc *));
21855163Sshinvoid ifconfig __P((void));
21955163Sshinvoid ifconfig1 __P((struct ifreq *, struct ifc *, int));
22055163Sshinvoid rtrecv __P((void));
22155163Sshinint rt_del __P((const struct sockaddr_in6 *, const struct sockaddr_in6 *,
22255163Sshin	const struct sockaddr_in6 *));
22355163Sshinint rt_deladdr __P((struct ifc *, const struct sockaddr_in6 *,
22455163Sshin	const struct sockaddr_in6 *));
22555163Sshinvoid filterconfig __P((void));
22655163Sshinint getifmtu __P((int));
22755163Sshinconst char *rttypes __P((struct rt_msghdr *rtm));
22855163Sshinconst char *rtflags __P((struct rt_msghdr *rtm));
22955163Sshinconst char *ifflags __P((int flags));
23055163Sshinvoid ifrt __P((struct ifc *, int));
23155163Sshinvoid applymask __P((struct in6_addr *, struct in6_addr *));
23255163Sshinvoid applyplen __P((struct in6_addr *, int));
23355163Sshinvoid ifrtdump __P((int));
23455163Sshinvoid ifdump __P((int));
23555163Sshinvoid ifdump0 __P((FILE *, const struct ifc *));
23655163Sshinvoid rtdump __P((int));
23755163Sshinvoid rt_entry __P((struct rt_msghdr *, int));
23855163Sshinvoid rtdexit __P((int));
23955163Sshinvoid riprequest __P((struct ifc *, struct netinfo6 *, int, struct sockaddr_in6 *));
24055163Sshinvoid ripflush __P((struct ifc *, struct sockaddr_in6 *));
24155163Sshinvoid sendrequest __P((struct ifc *));
24255163Sshinint mask2len __P((const struct in6_addr *, int));
24355163Sshinint sendpacket __P((struct sockaddr_in6 *, int));
24455163Sshinint addroute __P((struct riprt *, const struct in6_addr *, struct ifc *));
24555163Sshinint delroute __P((struct netinfo6 *, struct in6_addr *));
24655163Sshinstruct in6_addr *getroute __P((struct netinfo6 *, struct in6_addr *));
24755163Sshinvoid krtread __P((int));
24855163Sshinint tobeadv __P((struct riprt *, struct ifc *));
24955163Sshinchar *allocopy __P((char *));
25055163Sshinchar *hms __P((void));
25155163Sshinconst char *inet6_n2p __P((const struct in6_addr *));
25255163Sshinstruct ifac *ifa_match __P((const struct ifc *, const struct in6_addr *, int));
25355163Sshinstruct in6_addr *plen2mask __P((int));
25455163Sshinstruct riprt *rtsearch __P((struct netinfo6 *));
25555163Sshinint ripinterval __P((int));
25655163Sshintime_t ripsuptrig __P((void));
25755163Sshinvoid fatal __P((const char *, ...));
25855163Sshinvoid trace __P((int, const char *, ...));
25955163Sshinvoid tracet __P((int, const char *, ...));
26055163Sshinunsigned int if_maxindex __P((void));
26155163Sshinstruct ifc *ifc_find __P((char *));
26255163Sshinstruct iff *iff_find __P((struct ifc *, int));
26355163Sshinvoid setindex2ifc __P((int, struct ifc *));
26455163Sshin
26555163Sshin#define	MALLOC(type)	((type *)malloc(sizeof(type)))
26655163Sshin
26755163Sshinint
26855163Sshinmain(argc, argv)
26955163Sshin	int	argc;
27055163Sshin	char	**argv;
27155163Sshin{
27255163Sshin	int	ch;
27355163Sshin	int	error = 0;
27455163Sshin	struct	ifc *ifcp;
27555163Sshin	sigset_t mask, omask;
27655163Sshin	FILE	*pidfile;
27755163Sshin	extern char *optarg;
27855163Sshin	extern int optind;
27955163Sshin	char *progname;
28055163Sshin
28155163Sshin	progname = strrchr(*argv, '/');
28255163Sshin	if (progname)
28355163Sshin		progname++;
28455163Sshin	else
28555163Sshin		progname = *argv;
28655163Sshin
28755163Sshin	pid = getpid();
28855163Sshin	while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnqsS")) != EOF) {
28955163Sshin		switch (ch) {
29055163Sshin		case 'A':
29155163Sshin		case 'N':
29255163Sshin		case 'O':
29355163Sshin		case 'T':
29455163Sshin		case 'L':
29555163Sshin			if (nfilter >= MAXFILTER)
29655163Sshin				fatal("Exceeds MAXFILTER");
29755163Sshin			filtertype[nfilter] = ch;
29855163Sshin			filter[nfilter++] = allocopy(optarg);
29955163Sshin			break;
30055163Sshin		case 't':
30155163Sshin			sscanf(optarg, "%i", &routetag);
30255163Sshin			if (routetag & ~0xffff) {
30355163Sshin				fatal("invalid route tag");
30455163Sshin				/*NOTREACHED*/
30555163Sshin			}
30655163Sshin			break;
30755163Sshin		case 'R':
30855163Sshin			if ((rtlog = fopen(optarg, "w")) == NULL)
30955163Sshin				fatal("Can not write to routelog");
31055163Sshin			break;
31155163Sshin#define	FLAG(c, flag, n)	case c: flag = n; break
31255163Sshin		FLAG('a', aflag, 1);
31355163Sshin		FLAG('d', dflag, 1);
31455163Sshin		FLAG('D', dflag, 2);
31555163Sshin		FLAG('h', hflag, 1);
31655163Sshin		FLAG('l', lflag, 1);
31755163Sshin		FLAG('n', nflag, 1);
31855163Sshin		FLAG('q', qflag, 1);
31955163Sshin		FLAG('s', sflag, 1);
32055163Sshin		FLAG('S', Sflag, 1);
32155163Sshin#undef	FLAG
32255163Sshin		default:
32355163Sshin			fatal("Invalid option specified, terminating");
32455163Sshin		}
32555163Sshin	}
32655163Sshin	argc -= optind;
32755163Sshin	argv += optind;
32855163Sshin	if (argc > 0)
32955163Sshin		fatal("bogus extra arguments");
33055163Sshin
33155163Sshin	if (geteuid()) {
33255163Sshin		nflag = 1;
33355163Sshin		fprintf(stderr, "No kernel update is allowed\n");
33455163Sshin	}
33555163Sshin	openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON);
33655163Sshin	logopened++;
33755163Sshin	init();
33855163Sshin	ifconfig();
33955163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
34055163Sshin		if (ifcp->ifc_index < 0) {
34155163Sshin			fprintf(stderr,
34255163Sshin"No ifindex found at %s (no link-local address?)\n",
34355163Sshin				ifcp->ifc_name);
34455163Sshin			error++;
34555163Sshin		}
34655163Sshin	}
34755163Sshin	if (error)
34855163Sshin		exit(1);
34955163Sshin	if (loopifcp == NULL)
35055163Sshin		fatal("No loopback found");
35155163Sshin	loopifindex = loopifcp->ifc_index;
35255163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next)
35355163Sshin		ifrt(ifcp, 0);
35455163Sshin	filterconfig();
35555163Sshin	krtread(0);
35655163Sshin	if (dflag)
35755163Sshin		ifrtdump(0);
35855163Sshin
35955163Sshin	if (dflag == 0) {
36055163Sshin#if 1
36155163Sshin		if (daemon(0, 0) < 0)
36255163Sshin			fatal("daemon");
36355163Sshin#else
36455163Sshin		if (fork())
36555163Sshin			exit(0);
36655163Sshin		if (setsid() < 0)
36755163Sshin			fatal("setid");
36855163Sshin#endif
36955163Sshin	}
37055163Sshin	pid = getpid();
37155163Sshin	if ((pidfile = fopen(ROUTE6D_PID, "w")) != NULL) {
37255163Sshin		fprintf(pidfile, "%d\n", pid);
37355163Sshin		fclose(pidfile);
37455163Sshin	}
37555163Sshin
37655163Sshin	if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL)
37755163Sshin		fatal("malloc");
37855163Sshin	ripbuf->rip6_cmd = RIP6_RESPONSE;
37955163Sshin	ripbuf->rip6_vers = RIP6_VERSION;
38055163Sshin	ripbuf->rip6_res1[0] = 0;
38155163Sshin	ripbuf->rip6_res1[1] = 0;
38255163Sshin
38355163Sshin	if (signal(SIGALRM, ripalarm) == SIG_ERR)
38455163Sshin		fatal("signal: SIGALRM");
38555163Sshin	if (signal(SIGQUIT, rtdexit) == SIG_ERR)
38655163Sshin		fatal("signal: SIGQUIT");
38755163Sshin	if (signal(SIGTERM, rtdexit) == SIG_ERR)
38855163Sshin		fatal("signal: SIGTERM");
38955163Sshin	if (signal(SIGUSR1, ifrtdump) == SIG_ERR)
39055163Sshin		fatal("signal: SIGUSR1");
39155163Sshin	if (signal(SIGHUP, ifrtdump) == SIG_ERR)
39255163Sshin		fatal("signal: SIGHUP");
39355163Sshin	if (signal(SIGINT, ifrtdump) == SIG_ERR)
39455163Sshin		fatal("signal: SIGINT");
39555163Sshin	/*
39655163Sshin	 * To avoid rip packet congestion (not on a cable but in this
39755163Sshin	 * process), wait for a moment to send the first RIP6_RESPONSE
39855163Sshin	 * packets.
39955163Sshin	 */
40055163Sshin	alarm(ripinterval(INIT_INTERVAL6));
40155163Sshin
40255163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
40355163Sshin		if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP))
40455163Sshin			sendrequest(ifcp);
40555163Sshin	}
40655163Sshin
40755163Sshin	syslog(LOG_INFO, "**** Started ****");
40855163Sshin	sigemptyset(&mask);
40955163Sshin	sigaddset(&mask, SIGALRM);
41055163Sshin	while (1) {
41155163Sshin		fd_set	recvec;
41255163Sshin
41355163Sshin		FD_COPY(&sockvec, &recvec);
41455163Sshin		switch (select(FD_SETSIZE, &recvec, 0, 0, 0)) {
41555163Sshin		case -1:
41655163Sshin			if (errno == EINTR)
41755163Sshin				continue;
41855163Sshin			fatal("select");
41955163Sshin		case 0:
42055163Sshin			continue;
42155163Sshin		default:
42255163Sshin			if (FD_ISSET(ripsock, &recvec)) {
42355163Sshin				sigprocmask(SIG_BLOCK, &mask, &omask);
42455163Sshin				riprecv();
42555163Sshin				sigprocmask(SIG_SETMASK, &omask, NULL);
42655163Sshin			}
42755163Sshin			if (FD_ISSET(rtsock, &recvec)) {
42855163Sshin				sigprocmask(SIG_BLOCK, &mask, &omask);
42955163Sshin				rtrecv();
43055163Sshin				sigprocmask(SIG_SETMASK, &omask, NULL);
43155163Sshin			}
43255163Sshin		}
43355163Sshin	}
43455163Sshin}
43555163Sshin
43655163Sshin/*
43755163Sshin * gracefully exits after resetting sockopts.
43855163Sshin */
43955163Sshin/* ARGSUSED */
44055163Sshinvoid
44155163Sshinrtdexit(sig)
44255163Sshin	int sig;
44355163Sshin{
44455163Sshin	struct	riprt *rrt;
44555163Sshin
44655163Sshin	alarm(0);
44755163Sshin	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
44855163Sshin		if (rrt->rrt_flags & RTF_AGGREGATE) {
44955163Sshin			delroute(&rrt->rrt_info, &rrt->rrt_gw);
45055163Sshin		}
45155163Sshin	}
45255163Sshin	close(ripsock);
45355163Sshin	close(rtsock);
45455163Sshin	syslog(LOG_INFO, "**** Terminated ****");
45555163Sshin	closelog();
45655163Sshin	exit(1);
45755163Sshin}
45855163Sshin
45955163Sshin/*
46055163Sshin * Called periodically:
46155163Sshin *	1. age out the learned route. remove it if necessary.
46255163Sshin *	2. submit RIP6_RESPONSE packets.
46355163Sshin * Invoked in every SUPPLY_INTERVAL6 (30) seconds. I believe we don't have
46455163Sshin * to invoke this function in every 1 or 5 or 10 seconds only to age the
46555163Sshin * routes more precisely.
46655163Sshin */
46755163Sshin/* ARGSUSED */
46855163Sshinvoid
46955163Sshinripalarm(sig)
47055163Sshin	int sig;
47155163Sshin{
47255163Sshin	struct	ifc *ifcp;
47355163Sshin	struct	riprt *rrt, *rrt_prev, *rrt_next;
47455163Sshin	time_t	t_lifetime, t_holddown;
47555163Sshin
47655163Sshin	/* age the RIP routes */
47755163Sshin	rrt_prev = 0;
47855163Sshin	t_lifetime = time(NULL) - RIP_LIFETIME;
47955163Sshin	t_holddown = t_lifetime - RIP_HOLDDOWN;
48055163Sshin	for (rrt = riprt; rrt; rrt = rrt_next) {
48155163Sshin		rrt_next = rrt->rrt_next;
48255163Sshin
48355163Sshin		if (rrt->rrt_t == 0) {
48455163Sshin			rrt_prev = rrt;
48555163Sshin			continue;
48655163Sshin		}
48755163Sshin		if (rrt->rrt_t < t_holddown) {
48855163Sshin			if (rrt_prev) {
48955163Sshin				rrt_prev->rrt_next = rrt->rrt_next;
49055163Sshin			} else {
49155163Sshin				riprt = rrt->rrt_next;
49255163Sshin			}
49355163Sshin			delroute(&rrt->rrt_info, &rrt->rrt_gw);
49455163Sshin			free(rrt);
49555163Sshin			continue;
49655163Sshin		}
49755163Sshin		if (rrt->rrt_t < t_lifetime)
49855163Sshin			rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
49955163Sshin		rrt_prev = rrt;
50055163Sshin	}
50155163Sshin	/* Supply updates */
50255163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
50355163Sshin		if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP))
50455163Sshin			ripsend(ifcp, &ifcp->ifc_ripsin, 0);
50555163Sshin	}
50655163Sshin	alarm(ripinterval(SUPPLY_INTERVAL6));
50755163Sshin}
50855163Sshin
50955163Sshinvoid
51055163Sshininit()
51155163Sshin{
51255163Sshin#ifdef ADVAPI
51355163Sshin	int	i;
51455163Sshin#endif
51555163Sshin	int	int0, int255, error;
51655163Sshin	struct	addrinfo hints, *res;
51755163Sshin	char	port[10];
51855163Sshin
51955163Sshin	ifc = (struct ifc *)NULL;
52055163Sshin	nifc = 0;
52155163Sshin	nindex2ifc = 0;	/*initial guess*/
52255163Sshin	index2ifc = NULL;
52355163Sshin	snprintf(port, sizeof(port), "%d", RIP6_PORT);
52455163Sshin
52555163Sshin	memset(&hints, 0, sizeof(hints));
52655163Sshin	hints.ai_family = PF_INET6;
52755163Sshin	hints.ai_socktype = SOCK_DGRAM;
52855163Sshin	hints.ai_flags = AI_PASSIVE;
52955163Sshin	error = getaddrinfo(NULL, port, &hints, &res);
53055163Sshin	if (error)
53155163Sshin		fatal(gai_strerror(error));
53255163Sshin	if (res->ai_next)
53355163Sshin		fatal(":: resolved to multiple address");
53455163Sshin
53555163Sshin	int0 = 0; int255 = 255;
53655163Sshin	ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
53755163Sshin	if (ripsock < 0)
53855163Sshin		fatal("rip socket");
53955163Sshin	if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0)
54055163Sshin		fatal("rip bind");
54155163Sshin	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
54255163Sshin		&int255, sizeof(int255)) < 0)
54355163Sshin		fatal("rip IPV6_MULTICAST_HOPS");
54455163Sshin	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
54555163Sshin		&int0, sizeof(int0)) < 0)
54655163Sshin		fatal("rip IPV6_MULTICAST_LOOP");
54755163Sshin#ifdef ADVAPI
54855163Sshin	i = 1;
54955163Sshin	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_PKTINFO, &i, sizeof(i)) < 0)
55055163Sshin		fatal("rip IPV6_PKTINFO");
55155163Sshin#endif /*ADVAPI*/
55255163Sshin
55355163Sshin	memset(&hints, 0, sizeof(hints));
55455163Sshin	hints.ai_family = PF_INET6;
55555163Sshin	hints.ai_socktype = SOCK_DGRAM;
55655163Sshin	error = getaddrinfo(RIP6_DEST, port, &hints, &res);
55755163Sshin	if (error)
55855163Sshin		fatal(gai_strerror(error));
55955163Sshin	if (res->ai_next)
56055163Sshin		fatal("%s resolved to multiple address", RIP6_DEST);
56155163Sshin	memcpy(&ripsin, res->ai_addr, res->ai_addrlen);
56255163Sshin
56355163Sshin#ifdef FD_ZERO
56455163Sshin	FD_ZERO(&sockvec);
56555163Sshin#else
56655163Sshin	memset(&sockvec, 0, sizeof(sockvec));
56755163Sshin#endif
56855163Sshin	FD_SET(ripsock, &sockvec);
56955163Sshin
57055163Sshin	if (nflag == 0) {
57155163Sshin		if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0)
57255163Sshin			fatal("route socket");
57355163Sshin		FD_SET(rtsock, &sockvec);
57455163Sshin	} else
57555163Sshin		rtsock = -1;	/*just for safety */
57655163Sshin}
57755163Sshin
57855163Sshin#define	RIPSIZE(n)	(sizeof(struct rip6) + (n-1) * sizeof(struct netinfo6))
57955163Sshin
58055163Sshin/*
58155163Sshin * ripflush flushes the rip datagram stored in the rip buffer
58255163Sshin */
58355163Sshinstatic int nrt;
58455163Sshinstatic struct netinfo6 *np;
58555163Sshin
58655163Sshinvoid
58755163Sshinripflush(ifcp, sin)
58855163Sshin	struct ifc *ifcp;
58955163Sshin	struct sockaddr_in6 *sin;
59055163Sshin{
59155163Sshin	int i;
59255163Sshin	int error;
59355163Sshin
59455163Sshin	if (ifcp)
59555163Sshin		tracet(1, "Send(%s): info(%d) to %s.%d\n",
59655163Sshin			ifcp->ifc_name, nrt,
59755163Sshin			inet6_n2p(&sin->sin6_addr), ntohs(sin->sin6_port));
59855163Sshin	else
59955163Sshin		tracet(1, "Send: info(%d) to %s.%d\n",
60055163Sshin			nrt, inet6_n2p(&sin->sin6_addr), ntohs(sin->sin6_port));
60155163Sshin	if (dflag >= 2) {
60255163Sshin		np = ripbuf->rip6_nets;
60355163Sshin		for (i = 0; i < nrt; i++, np++) {
60455163Sshin			if (np->rip6_metric == NEXTHOP_METRIC) {
60555163Sshin				if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest))
60655163Sshin						trace(2, "    NextHop reset");
60755163Sshin				else {
60855163Sshin					trace(2, "    NextHop %s",
60955163Sshin						inet6_n2p(&np->rip6_dest));
61055163Sshin				}
61155163Sshin			} else {
61255163Sshin				trace(2, "    %s/%d[%d]",
61355163Sshin					inet6_n2p(&np->rip6_dest),
61455163Sshin					np->rip6_plen, np->rip6_metric);
61555163Sshin			}
61655163Sshin			if (np->rip6_tag) {
61755163Sshin				trace(2, "  tag=0x%04x",
61855163Sshin					ntohs(np->rip6_tag) & 0xffff);
61955163Sshin			}
62055163Sshin			trace(2, "\n");
62155163Sshin		}
62255163Sshin	}
62355163Sshin	error = sendpacket(sin, RIPSIZE(nrt));
62455163Sshin	if (error == EAFNOSUPPORT) {
62555163Sshin		/* Protocol not supported */
62655163Sshin		tracet(1, "Could not send info to %s (%s): "
62755163Sshin			"set IFF_UP to 0\n",
62855163Sshin			ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
62955163Sshin		ifcp->ifc_flags &= ~IFF_UP;	/* As if down for AF_INET6 */
63055163Sshin	}
63155163Sshin	nrt = 0; np = ripbuf->rip6_nets;
63255163Sshin}
63355163Sshin
63455163Sshin/*
63555163Sshin * Generate RIP6_RESPONSE packets and send them.
63655163Sshin */
63755163Sshinvoid
63855163Sshinripsend(ifcp, sin, flag)
63955163Sshin	struct	ifc *ifcp;
64055163Sshin	struct	sockaddr_in6 *sin;
64155163Sshin	int flag;
64255163Sshin{
64355163Sshin	struct	riprt *rrt;
64455163Sshin	struct	in6_addr *nh;	/* next hop */
64555163Sshin	struct	in6_addr ia;
64655163Sshin	struct	iff *iffp;
64755163Sshin	int	maxrte, ok;
64855163Sshin
64955163Sshin	if (ifcp == NULL) {
65055163Sshin		/*
65155163Sshin		 * Request from non-link local address is not
65255163Sshin		 * a regular route6d update.
65355163Sshin		 */
65455163Sshin		maxrte = (IFMINMTU - sizeof(struct ip6_hdr) -
65555163Sshin				sizeof(struct udphdr) -
65655163Sshin				sizeof(struct rip6) + sizeof(struct netinfo6)) /
65755163Sshin				sizeof(struct netinfo6);
65855163Sshin		nrt = 0; np = ripbuf->rip6_nets; nh = NULL;
65955163Sshin		for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
66055163Sshin			if (rrt->rrt_flags & RTF_NOADVERTISE)
66155163Sshin				continue;
66255163Sshin			/* Put the route to the buffer */
66355163Sshin			*np = rrt->rrt_info;
66455163Sshin			np++; nrt++;
66555163Sshin			if (nrt == maxrte) {
66655163Sshin				ripflush(NULL, sin);
66755163Sshin				nh = NULL;
66855163Sshin			}
66955163Sshin		}
67055163Sshin		if (nrt)	/* Send last packet */
67155163Sshin			ripflush(NULL, sin);
67255163Sshin		return;
67355163Sshin	}
67455163Sshin
67555163Sshin	if ((flag & RTF_SENDANYWAY) == 0 &&
67655163Sshin	    (qflag || (ifcp->ifc_flags & IFF_LOOPBACK)))
67755163Sshin		return;
67855163Sshin	if (iff_find(ifcp, 'N') != NULL)
67955163Sshin		return;
68055163Sshin	if (iff_find(ifcp, 'T') != NULL) {
68155163Sshin		struct netinfo6 rrt_info;
68255163Sshin		memset(&rrt_info, 0, sizeof(struct netinfo6));
68355163Sshin		rrt_info.rip6_dest = in6addr_any;
68455163Sshin		rrt_info.rip6_plen = 0;
68555163Sshin		rrt_info.rip6_metric = 1;
68655163Sshin		rrt_info.rip6_tag = htons(routetag & 0xffff);
68755163Sshin		np = ripbuf->rip6_nets;
68855163Sshin		*np = rrt_info;
68955163Sshin		nrt = 1;
69055163Sshin		ripflush(ifcp, sin);
69155163Sshin		return;
69255163Sshin	}
69355163Sshin	maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) -
69455163Sshin			sizeof(struct udphdr) -
69555163Sshin			sizeof(struct rip6) + sizeof(struct netinfo6)) /
69655163Sshin			sizeof(struct netinfo6);
69755163Sshin	nrt = 0; np = ripbuf->rip6_nets; nh = NULL;
69855163Sshin	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
69955163Sshin		if (rrt->rrt_flags & RTF_NOADVERTISE)
70055163Sshin			continue;
70155163Sshin		/* Need to check filer here */
70255163Sshin		ok = 1;
70355163Sshin		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
70455163Sshin			if (iffp->iff_type != 'A')
70555163Sshin				continue;
70655163Sshin			if (rrt->rrt_info.rip6_plen <= iffp->iff_plen)
70755163Sshin				continue;
70855163Sshin			ia = rrt->rrt_info.rip6_dest;
70955163Sshin			applyplen(&ia, iffp->iff_plen);
71055163Sshin			if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) {
71155163Sshin				ok = 0;
71255163Sshin				break;
71355163Sshin			}
71455163Sshin		}
71555163Sshin		if (!ok)
71655163Sshin			continue;
71755163Sshin		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
71855163Sshin			if (iffp->iff_type != 'O')
71955163Sshin				continue;
72055163Sshin			ok = 0;
72155163Sshin			if (rrt->rrt_info.rip6_plen < iffp->iff_plen)
72255163Sshin				continue;
72355163Sshin			ia = rrt->rrt_info.rip6_dest;
72455163Sshin			applyplen(&ia, iffp->iff_plen);
72555163Sshin			if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) {
72655163Sshin				ok = 1;
72755163Sshin				break;
72855163Sshin			}
72955163Sshin		}
73055163Sshin		if (!ok)
73155163Sshin			continue;
73255163Sshin		/* Check split horizon and other conditions */
73355163Sshin		if (tobeadv(rrt, ifcp) == 0)
73455163Sshin			continue;
73555163Sshin		/* Only considers the routes with flag if specified */
73655163Sshin		if ((flag & RTF_CHANGED) && (rrt->rrt_flags & RTF_CHANGED) == 0)
73755163Sshin			continue;
73855163Sshin		/* Check nexthop */
73955163Sshin		if (rrt->rrt_index == ifcp->ifc_index &&
74055163Sshin		    !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) &&
74155163Sshin		    (rrt->rrt_flags & RTF_NH_NOT_LLADDR) == 0) {
74255163Sshin			if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) {
74355163Sshin				if (nrt == maxrte - 2)
74455163Sshin					ripflush(ifcp, sin);
74555163Sshin				np->rip6_dest = rrt->rrt_gw;
74655163Sshin				if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest))
74755163Sshin					SET_IN6_LINKLOCAL_IFINDEX(np->rip6_dest, 0);
74855163Sshin				np->rip6_plen = 0;
74955163Sshin				np->rip6_tag = 0;
75055163Sshin				np->rip6_metric = NEXTHOP_METRIC;
75155163Sshin				nh = &rrt->rrt_gw;
75255163Sshin				np++; nrt++;
75355163Sshin			}
75455163Sshin		} else if (nh && (rrt->rrt_index != ifcp->ifc_index ||
75555163Sshin			          !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) ||
75655163Sshin				  rrt->rrt_flags & RTF_NH_NOT_LLADDR)) {
75755163Sshin			/* Reset nexthop */
75855163Sshin			if (nrt == maxrte - 2)
75955163Sshin				ripflush(ifcp, sin);
76055163Sshin			memset(np, 0, sizeof(struct netinfo6));
76155163Sshin			np->rip6_metric = NEXTHOP_METRIC;
76255163Sshin			nh = NULL;
76355163Sshin			np++; nrt++;
76455163Sshin		}
76555163Sshin		/* Put the route to the buffer */
76655163Sshin		*np = rrt->rrt_info;
76755163Sshin		np++; nrt++;
76855163Sshin		if (nrt == maxrte) {
76955163Sshin			ripflush(ifcp, sin);
77055163Sshin			nh = NULL;
77155163Sshin		}
77255163Sshin	}
77355163Sshin	if (nrt)	/* Send last packet */
77455163Sshin		ripflush(ifcp, sin);
77555163Sshin}
77655163Sshin
77755163Sshin/*
77855163Sshin * Determine if the route is to be advertised on the specified interface.
77955163Sshin * It checks options specified in the arguments and the split horizon rule.
78055163Sshin */
78155163Sshinint
78255163Sshintobeadv(rrt, ifcp)
78355163Sshin	struct riprt *rrt;
78455163Sshin	struct ifc *ifcp;
78555163Sshin{
78655163Sshin
78755163Sshin	/* Special care for static routes */
78855163Sshin	if (rrt->rrt_flags & RTF_STATIC) {
78955163Sshin		if (Sflag)	/* Yes, advertise it anyway */
79055163Sshin			return 1;
79155163Sshin		if (sflag && rrt->rrt_index != ifcp->ifc_index)
79255163Sshin			return 1;
79355163Sshin		return 0;
79455163Sshin	}
79555163Sshin	/* Regular split horizon */
79655163Sshin	if (hflag == 0 && rrt->rrt_index == ifcp->ifc_index)
79755163Sshin		return 0;
79855163Sshin	return 1;
79955163Sshin}
80055163Sshin
80155163Sshin/*
80255163Sshin * Send a rip packet actually.
80355163Sshin */
80455163Sshinint
80555163Sshinsendpacket(sin, len)
80655163Sshin	struct	sockaddr_in6 *sin;
80755163Sshin	int	len;
80855163Sshin{
80955163Sshin	/*
81055163Sshin	 * MSG_DONTROUTE should not be specified when it responds with a
81155163Sshin	 * RIP6_REQUEST message. SO_DONTROUTE has been specified to
81255163Sshin	 * other sockets.
81355163Sshin	 */
81455163Sshin#ifdef ADVAPI
81555163Sshin	struct msghdr m;
81655163Sshin	struct cmsghdr *cm;
81755163Sshin	struct iovec iov[2];
81855163Sshin	u_char cmsgbuf[256];
81955163Sshin	struct in6_pktinfo *pi;
82055163Sshin	int index;
82155163Sshin	struct sockaddr_in6 sincopy;
82255163Sshin
82355163Sshin	/* do not overwrite the given sin */
82455163Sshin	sincopy = *sin;
82555163Sshin	sin = &sincopy;
82655163Sshin
82755163Sshin	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)
82855163Sshin	 || IN6_IS_ADDR_MULTICAST(&sin->sin6_addr)) {
82955163Sshin		index = IN6_LINKLOCAL_IFINDEX(sin->sin6_addr);
83055163Sshin		SET_IN6_LINKLOCAL_IFINDEX(sin->sin6_addr, 0);
83155163Sshin	} else
83255163Sshin		index = 0;
83355163Sshin
83455163Sshin	m.msg_name = (caddr_t)sin;
83555163Sshin	m.msg_namelen = sizeof(*sin);
83655163Sshin	iov[0].iov_base = (caddr_t)ripbuf;
83755163Sshin	iov[0].iov_len = len;
83855163Sshin	m.msg_iov = iov;
83955163Sshin	m.msg_iovlen = 1;
84055163Sshin	if (!index) {
84155163Sshin		m.msg_control = NULL;
84255163Sshin		m.msg_controllen = 0;
84355163Sshin	} else {
84455163Sshin		memset(cmsgbuf, 0, sizeof(cmsgbuf));
84555163Sshin		cm = (struct cmsghdr *)cmsgbuf;
84655163Sshin		m.msg_control = (caddr_t)cm;
84755163Sshin		m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
84855163Sshin
84955163Sshin		cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
85055163Sshin		cm->cmsg_level = IPPROTO_IPV6;
85155163Sshin		cm->cmsg_type = IPV6_PKTINFO;
85255163Sshin		pi = (struct in6_pktinfo *)CMSG_DATA(cm);
85355163Sshin		memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/
85455163Sshin		pi->ipi6_ifindex = index;
85555163Sshin	}
85655163Sshin
85755163Sshin	if (sendmsg(ripsock, &m, 0 /*MSG_DONTROUTE*/) < 0) {
85855163Sshin		trace(1, "sendmsg: %s\n", strerror(errno));
85955163Sshin		return errno;
86055163Sshin	}
86155163Sshin#else
86255163Sshin	if (sendto(ripsock, ripbuf, len, 0 /*MSG_DONTROUTE*/,
86355163Sshin		(struct sockaddr *)sin, sizeof(struct sockaddr_in6)) < 0) {
86455163Sshin		trace(1, "sendto: %s\n", strerror(errno));
86555163Sshin		return errno;
86655163Sshin	}
86755163Sshin#endif
86855163Sshin	return 0;
86955163Sshin}
87055163Sshin
87155163Sshin/*
87255163Sshin * Receive and process RIP packets. Update the routes/kernel forwarding
87355163Sshin * table if necessary.
87455163Sshin */
87555163Sshinvoid
87655163Sshinriprecv()
87755163Sshin{
87855163Sshin	struct	ifc *ifcp, *ic;
87955163Sshin	struct	sockaddr_in6 fsock;
88055163Sshin	struct	in6_addr nh;	/* next hop */
88155163Sshin	struct	rip6 *rp;
88255163Sshin	struct	netinfo6 *np, *nq;
88355163Sshin	struct	riprt *rrt;
88455163Sshin	int	len, nn, need_trigger, index;
88555163Sshin#ifndef ADVAPI
88655163Sshin	int	flen;
88755163Sshin#endif
88855163Sshin	char	buf[4 * RIP6_MAXMTU];
88955163Sshin	time_t	t;
89055163Sshin#ifdef ADVAPI
89155163Sshin	struct msghdr m;
89255163Sshin	struct cmsghdr *cm;
89355163Sshin	struct iovec iov[2];
89455163Sshin	u_char cmsgbuf[256];
89555163Sshin	struct in6_pktinfo *pi;
89655163Sshin#endif /*ADVAPI*/
89755163Sshin	struct iff *iffp;
89855163Sshin	struct in6_addr ia;
89955163Sshin	int ok;
90055163Sshin
90155163Sshin	need_trigger = 0;
90255163Sshin#ifdef ADVAPI
90355163Sshin	m.msg_name = (caddr_t)&fsock;
90455163Sshin	m.msg_namelen = sizeof(fsock);
90555163Sshin	iov[0].iov_base = (caddr_t)buf;
90655163Sshin	iov[0].iov_len = sizeof(buf);
90755163Sshin	m.msg_iov = iov;
90855163Sshin	m.msg_iovlen = 1;
90955163Sshin	cm = (struct cmsghdr *)cmsgbuf;
91055163Sshin	m.msg_control = (caddr_t)cm;
91155163Sshin	m.msg_controllen = sizeof(cmsgbuf);
91255163Sshin	if ((len = recvmsg(ripsock, &m, 0)) < 0)
91355163Sshin		fatal("recvmsg");
91455163Sshin	index = 0;
91555163Sshin	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m);
91655163Sshin	     cm;
91755163Sshin	     cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) {
91855163Sshin		if (cm->cmsg_level == IPPROTO_IPV6
91955163Sshin		 && cm->cmsg_type == IPV6_PKTINFO) {
92055163Sshin			pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
92155163Sshin			index = pi->ipi6_ifindex;
92255163Sshin			break;
92355163Sshin		}
92455163Sshin	}
92555163Sshin	if (index && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr))
92655163Sshin		SET_IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr, index);
92755163Sshin#else
92855163Sshin	flen = sizeof(struct sockaddr_in6);
92955163Sshin	if ((len = recvfrom(ripsock, buf, sizeof(buf), 0,
93055163Sshin		(struct sockaddr *)&fsock, &flen)) < 0)
93155163Sshin		fatal("recvfrom");
93255163Sshin	if (IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr))
93355163Sshin		index = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr);
93455163Sshin	else
93555163Sshin		index = 0;
93655163Sshin#endif /*ADVAPI*/
93755163Sshin
93855163Sshin	nh = fsock.sin6_addr;
93955163Sshin	nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) /
94055163Sshin		sizeof(struct netinfo6);
94155163Sshin	rp = (struct rip6 *)buf;
94255163Sshin	np = rp->rip6_nets;
94355163Sshin
94455163Sshin	if (rp->rip6_vers !=  RIP6_VERSION) {
94555163Sshin		trace(1, "Incorrect RIP version %d\n", rp->rip6_vers);
94655163Sshin		return;
94755163Sshin	}
94855163Sshin	if (rp->rip6_cmd == RIP6_REQUEST) {
94955163Sshin		if (index && index < nindex2ifc) {
95055163Sshin			ifcp = index2ifc[index];
95155163Sshin			riprequest(ifcp, np, nn, &fsock);
95255163Sshin		} else {
95355163Sshin			riprequest(NULL, np, nn, &fsock);
95455163Sshin		}
95555163Sshin		return;
95655163Sshin	}
95755163Sshin
95855163Sshin	if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) {
95955163Sshin		trace(1, "Packets from non-ll addr: %s\n",
96055163Sshin			inet6_n2p(&fsock.sin6_addr));
96155163Sshin		return;		/* Ignore packets from non-link-local addr */
96255163Sshin	}
96355163Sshin	index = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr);
96455163Sshin	ifcp = (index < nindex2ifc) ? index2ifc[index] : NULL;
96555163Sshin	if (!ifcp) {
96655163Sshin		trace(1, "Packets to unknown interface index %d\n", index);
96755163Sshin		return;		/* Ignore it */
96855163Sshin	}
96955163Sshin	if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr))
97055163Sshin		return;		/* The packet is from me; ignore */
97155163Sshin	if (rp->rip6_cmd != RIP6_RESPONSE) {
97255163Sshin		trace(1, "Invalid command %d\n", rp->rip6_cmd);
97355163Sshin		return;
97455163Sshin	}
97555163Sshin	if (iff_find(ifcp, 'N') != NULL)
97655163Sshin		return;
97755163Sshin	tracet(1, "Recv(%s): from %s.%d info(%d)\n",
97855163Sshin		ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn);
97955163Sshin
98055163Sshin	t = time(NULL);
98155163Sshin	for (; nn; nn--, np++) {
98255163Sshin		if (np->rip6_metric == NEXTHOP_METRIC) {
98355163Sshin			/* modify neighbor address */
98455163Sshin			if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) {
98555163Sshin				nh = np->rip6_dest;
98655163Sshin				SET_IN6_LINKLOCAL_IFINDEX(nh, index);
98755163Sshin				trace(1, "\tNexthop: %s\n", inet6_n2p(&nh));
98855163Sshin			} else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) {
98955163Sshin				nh = fsock.sin6_addr;
99055163Sshin				trace(1, "\tNexthop: %s\n", inet6_n2p(&nh));
99155163Sshin			} else {
99255163Sshin				nh = fsock.sin6_addr;
99355163Sshin				trace(1, "\tInvalid Nexthop: %s\n",
99455163Sshin					inet6_n2p(&np->rip6_dest));
99555163Sshin			}
99655163Sshin			continue;
99755163Sshin		}
99855163Sshin		if (IN6_IS_ADDR_MULTICAST(&np->rip6_dest)) {
99955163Sshin			trace(1, "\tMulticast netinfo6: %s/%d [%d]\n",
100055163Sshin				inet6_n2p(&np->rip6_dest),
100155163Sshin				np->rip6_plen, np->rip6_metric);
100255163Sshin			continue;
100355163Sshin		}
100455163Sshin		if (IN6_IS_ADDR_LOOPBACK(&np->rip6_dest)) {
100555163Sshin			trace(1, "\tLoopback netinfo6: %s/%d [%d]\n",
100655163Sshin				inet6_n2p(&np->rip6_dest),
100755163Sshin				np->rip6_plen, np->rip6_metric);
100855163Sshin			continue;
100955163Sshin		}
101055163Sshin		if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) {
101155163Sshin			trace(1, "\tLink Local netinfo6: %s/%d [%d]\n",
101255163Sshin				inet6_n2p(&np->rip6_dest),
101355163Sshin				np->rip6_plen, np->rip6_metric);
101455163Sshin			continue;
101555163Sshin		}
101655163Sshin		/* may need to pass sitelocal prefix in some case, however*/
101755163Sshin		if (IN6_IS_ADDR_SITELOCAL(&np->rip6_dest) && !lflag) {
101855163Sshin			trace(1, "\tSite Local netinfo6: %s/%d [%d]\n",
101955163Sshin				inet6_n2p(&np->rip6_dest),
102055163Sshin				np->rip6_plen, np->rip6_metric);
102155163Sshin			continue;
102255163Sshin		}
102355163Sshin		trace(2, "\tnetinfo6: %s/%d [%d]",
102455163Sshin			inet6_n2p(&np->rip6_dest),
102555163Sshin			np->rip6_plen, np->rip6_metric);
102655163Sshin		if (np->rip6_tag)
102755163Sshin			trace(2, "  tag=0x%04x", ntohs(np->rip6_tag) & 0xffff);
102855163Sshin
102955163Sshin		/* Listen-only filter */
103055163Sshin		ok = 1;		/* if there's no L filter, it is ok */
103155163Sshin		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
103255163Sshin			if (iffp->iff_type != 'L')
103355163Sshin				continue;
103455163Sshin			ok = 0;
103555163Sshin			if (np->rip6_plen < iffp->iff_plen)
103655163Sshin				continue;
103755163Sshin			/* special rule: ::/0 means default, not "in /0" */
103855163Sshin			if (iffp->iff_plen == 0 && np->rip6_plen > 0)
103955163Sshin				continue;
104055163Sshin			ia = np->rip6_dest;
104155163Sshin			applyplen(&ia, iffp->iff_plen);
104255163Sshin			if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) {
104355163Sshin				ok = 1;
104455163Sshin				break;
104555163Sshin			}
104655163Sshin		}
104755163Sshin		if (!ok) {
104855163Sshin			trace(2, "  (filtered)\n");
104955163Sshin			continue;
105055163Sshin		}
105155163Sshin
105255163Sshin		trace(2, "\n");
105355163Sshin		np->rip6_metric++;
105455163Sshin		np->rip6_metric += ifcp->ifc_metric;
105555163Sshin		if (np->rip6_metric > HOPCNT_INFINITY6)
105655163Sshin			np->rip6_metric = HOPCNT_INFINITY6;
105755163Sshin
105855163Sshin		applyplen(&np->rip6_dest, np->rip6_plen);
105955163Sshin		if ((rrt = rtsearch(np)) != NULL) {
106055163Sshin			if (rrt->rrt_t == 0)
106155163Sshin				continue;	/* Intf route has priority */
106255163Sshin			nq = &rrt->rrt_info;
106355163Sshin			if (nq->rip6_metric > np->rip6_metric) {
106455163Sshin				if (rrt->rrt_index == ifcp->ifc_index &&
106555163Sshin				    IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
106655163Sshin					/* Small metric from the same gateway */
106755163Sshin					nq->rip6_metric = np->rip6_metric;
106855163Sshin				} else {
106955163Sshin					/* Better route found */
107055163Sshin					rrt->rrt_index = ifcp->ifc_index;
107155163Sshin					/* Update routing table */
107255163Sshin					delroute(nq, &rrt->rrt_gw);
107355163Sshin					rrt->rrt_gw = nh;
107455163Sshin					*nq = *np;
107555163Sshin					addroute(rrt, &nh, ifcp);
107655163Sshin				}
107755163Sshin				rrt->rrt_flags |= RTF_CHANGED;
107855163Sshin				rrt->rrt_t = t;
107955163Sshin				need_trigger = 1;
108055163Sshin			} else if (nq->rip6_metric < np->rip6_metric &&
108155163Sshin				   rrt->rrt_index == ifcp->ifc_index &&
108255163Sshin				   IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
108355163Sshin				/* Got worse route from same gw */
108455163Sshin				nq->rip6_metric = np->rip6_metric;
108555163Sshin				rrt->rrt_t = t;
108655163Sshin				rrt->rrt_flags |= RTF_CHANGED;
108755163Sshin				need_trigger = 1;
108855163Sshin			} else if (nq->rip6_metric == np->rip6_metric &&
108955163Sshin				   rrt->rrt_index == ifcp->ifc_index &&
109055163Sshin				   IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw) &&
109155163Sshin				   np->rip6_metric < HOPCNT_INFINITY6) {
109255163Sshin				/* same metric, same route from same gw */
109355163Sshin				rrt->rrt_t = t;
109455163Sshin			}
109555163Sshin			/*
109655163Sshin			 * if nq->rip6_metric == HOPCNT_INFINITY6 then
109755163Sshin			 * do not update age value. Do nothing.
109855163Sshin			 */
109955163Sshin		} else if (np->rip6_metric < HOPCNT_INFINITY6) {
110055163Sshin			/* Got a new valid route */
110155163Sshin			if ((rrt = MALLOC(struct riprt)) == NULL)
110255163Sshin				fatal("malloc: struct riprt");
110355163Sshin			nq = &rrt->rrt_info;
110455163Sshin
110555163Sshin			rrt->rrt_same = NULL;
110655163Sshin			rrt->rrt_index = ifcp->ifc_index;
110755163Sshin			rrt->rrt_flags = RTF_UP|RTF_GATEWAY;
110855163Sshin			rrt->rrt_gw = nh;
110955163Sshin			*nq = *np;
111055163Sshin			applyplen(&nq->rip6_dest, nq->rip6_plen);
111155163Sshin			if (nq->rip6_plen == sizeof(struct in6_addr) * 8)
111255163Sshin				rrt->rrt_flags |= RTF_HOST;
111355163Sshin
111455163Sshin			/* Put the route to the list */
111555163Sshin			rrt->rrt_next = riprt;
111655163Sshin			riprt = rrt;
111755163Sshin			/* Update routing table */
111855163Sshin			addroute(rrt, &nh, ifcp);
111955163Sshin			rrt->rrt_flags |= RTF_CHANGED;
112055163Sshin			need_trigger = 1;
112155163Sshin			rrt->rrt_t = t;
112255163Sshin		}
112355163Sshin	}
112455163Sshin	/* XXX need to care the interval between triggered updates */
112555163Sshin	if (need_trigger) {
112655163Sshin		if (nextalarm > time(NULL) + RIP_TRIG_INT6_MAX) {
112755163Sshin			for (ic = ifc; ic; ic = ic->ifc_next) {
112855163Sshin				if (ifcp->ifc_index == ic->ifc_index)
112955163Sshin					continue;
113055163Sshin				if (ic->ifc_flags & IFF_UP)
113155163Sshin					ripsend(ic, &ic->ifc_ripsin,
113255163Sshin						RTF_CHANGED);
113355163Sshin			}
113455163Sshin		}
113555163Sshin		/* Reset the flag */
113655163Sshin		for (rrt = riprt; rrt; rrt = rrt->rrt_next)
113755163Sshin			rrt->rrt_flags &= ~RTF_CHANGED;
113855163Sshin	}
113955163Sshin}
114055163Sshin
114155163Sshin/*
114255163Sshin * Send all routes request packet to the specified interface.
114355163Sshin */
114455163Sshinvoid
114555163Sshinsendrequest(ifcp)
114655163Sshin	struct ifc *ifcp;
114755163Sshin{
114855163Sshin	struct netinfo6 *np;
114955163Sshin	int error;
115055163Sshin
115155163Sshin	if (ifcp->ifc_flags & IFF_LOOPBACK)
115255163Sshin		return;
115355163Sshin	ripbuf->rip6_cmd = RIP6_REQUEST;
115455163Sshin	np = ripbuf->rip6_nets;
115555163Sshin	memset(np, 0, sizeof(struct netinfo6));
115655163Sshin	np->rip6_metric = HOPCNT_INFINITY6;
115755163Sshin	tracet(1, "Send rtdump Request to %s (%s)\n",
115855163Sshin		ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
115955163Sshin	error = sendpacket(&ifcp->ifc_ripsin, RIPSIZE(1));
116055163Sshin	if (error == EAFNOSUPPORT) {
116155163Sshin		/* Protocol not supported */
116255163Sshin		tracet(1, "Could not send rtdump Request to %s (%s): "
116355163Sshin			"set IFF_UP to 0\n",
116455163Sshin			ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
116555163Sshin		ifcp->ifc_flags &= ~IFF_UP;	/* As if down for AF_INET6 */
116655163Sshin	}
116755163Sshin	ripbuf->rip6_cmd = RIP6_RESPONSE;
116855163Sshin}
116955163Sshin
117055163Sshin/*
117155163Sshin * Process a RIP6_REQUEST packet.
117255163Sshin */
117355163Sshinvoid
117455163Sshinriprequest(ifcp, np, nn, sin)
117555163Sshin	struct ifc *ifcp;
117655163Sshin	struct netinfo6 *np;
117755163Sshin	int nn;
117855163Sshin	struct sockaddr_in6 *sin;
117955163Sshin{
118055163Sshin	int i;
118155163Sshin	struct riprt *rrt;
118255163Sshin
118355163Sshin	if (!(nn == 1 && IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest) &&
118455163Sshin	      np->rip6_plen == 0 && np->rip6_metric == HOPCNT_INFINITY6)) {
118555163Sshin		/* Specific response, don't split-horizon */
118655163Sshin		trace(1, "\tRIP Request\n");
118755163Sshin		for (i = 0; i < nn; i++, np++) {
118855163Sshin			rrt = rtsearch(np);
118955163Sshin			if (rrt)
119055163Sshin				np->rip6_metric = rrt->rrt_info.rip6_metric;
119155163Sshin			else
119255163Sshin				np->rip6_metric = HOPCNT_INFINITY6;
119355163Sshin		}
119455163Sshin		(void)sendpacket(sin, RIPSIZE(nn));
119555163Sshin		return;
119655163Sshin	}
119755163Sshin	/* Whole routing table dump */
119855163Sshin	trace(1, "\tRIP Request -- whole routing table\n");
119955163Sshin	ripsend(ifcp, sin, RTF_SENDANYWAY);
120055163Sshin}
120155163Sshin
120255163Sshin/*
120355163Sshin * Get information of each interface.
120455163Sshin */
120555163Sshinvoid
120655163Sshinifconfig()
120755163Sshin{
120855163Sshin	int	s, i;
120955163Sshin	char	*buf;
121055163Sshin	struct	ifconf ifconf;
121155163Sshin	struct	ifreq *ifrp, ifr;
121255163Sshin	struct	ifc *ifcp;
121355163Sshin	struct	ipv6_mreq mreq;
121455163Sshin	int	bufsiz;
121555163Sshin
121655163Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
121755163Sshin		fatal("socket");
121855163Sshin
121955163Sshin	/* wild guess - v4, media, link, v6 * 3 */
122055163Sshin	bufsiz = if_maxindex() * sizeof(struct ifreq) * 6;
122155163Sshin	if ((buf = (char *)malloc(bufsiz)) == NULL)
122255163Sshin		fatal("malloc");
122355163Sshin
122455163Sshin	/*
122555163Sshin	 * ioctl(SIOCGIFCONF) does not return error on buffer size.
122655163Sshin	 * we'll try to guess the buffer size by trying it twice, with
122755163Sshin	 * different buffer size.
122855163Sshin	 */
122955163Sshin	ifconf.ifc_buf = buf;
123055163Sshin	ifconf.ifc_len = bufsiz / 2;
123155163Sshin	if (ioctl(s, SIOCGIFCONF, (char *)&ifconf) < 0)
123255163Sshin		fatal("ioctl: SIOCGIFCONF");
123355163Sshin	i = ifconf.ifc_len;
123455163Sshin	while (1) {
123555163Sshin		ifconf.ifc_buf = buf;
123655163Sshin		ifconf.ifc_len = bufsiz;
123755163Sshin		if (ioctl(s, SIOCGIFCONF, (char *)&ifconf) < 0)
123855163Sshin			fatal("ioctl: SIOCGIFCONF");
123955163Sshin		if (i == ifconf.ifc_len)
124055163Sshin			break;
124155163Sshin		i = ifconf.ifc_len;
124255163Sshin		bufsiz *= 2;
124355163Sshin		if ((buf = (char *)realloc(buf, bufsiz)) == NULL)
124455163Sshin			fatal("realloc");
124555163Sshin	}
124655163Sshin	for (i = 0; i < ifconf.ifc_len; ) {
124755163Sshin		ifrp = (struct ifreq *)(buf + i);
124855163Sshin		if (ifrp->ifr_addr.sa_family != AF_INET6)
124955163Sshin			goto skip;
125055163Sshin		ifcp = ifc_find(ifrp->ifr_name);
125155163Sshin		strcpy(ifr.ifr_name, ifrp->ifr_name);
125255163Sshin		if (ioctl(s, SIOCGIFFLAGS, (char *)&ifr) < 0)
125355163Sshin			fatal("ioctl: SIOCGIFFLAGS");
125455163Sshin		/* we are interested in multicast-capable interfaces */
125555163Sshin		if ((ifr.ifr_flags & IFF_MULTICAST) == 0)
125655163Sshin			goto skip;
125755163Sshin		if (!ifcp) {
125855163Sshin			/* new interface */
125955163Sshin			ifcp = (struct ifc *)malloc(sizeof(*ifcp));
126055163Sshin			memset(ifcp, 0, sizeof(*ifcp));
126155163Sshin			ifcp->ifc_index = -1;
126255163Sshin			ifcp->ifc_next = ifc;
126355163Sshin			ifc = ifcp;
126455163Sshin			nifc++;
126555163Sshin			ifcp->ifc_name = allocopy(ifrp->ifr_name);
126655163Sshin			ifcp->ifc_addr = 0;
126755163Sshin			ifcp->ifc_filter = 0;
126855163Sshin			ifcp->ifc_flags = ifr.ifr_flags;
126955163Sshin			trace(1, "newif %s <%s>\n", ifcp->ifc_name,
127055163Sshin				ifflags(ifcp->ifc_flags));
127155163Sshin			if (!strcmp(ifcp->ifc_name, LOOPBACK_IF))
127255163Sshin				loopifcp = ifcp;
127355163Sshin		} else {
127455163Sshin			/* update flag, this may be up again */
127555163Sshin			if (ifcp->ifc_flags != ifr.ifr_flags) {
127655163Sshin				trace(1, "%s: <%s> -> ", ifcp->ifc_name,
127755163Sshin					ifflags(ifcp->ifc_flags));
127855163Sshin				trace(1, "<%s>\n", ifflags(ifr.ifr_flags));
127955163Sshin			}
128055163Sshin			ifcp->ifc_flags = ifr.ifr_flags;
128155163Sshin		}
128255163Sshin		ifconfig1(ifrp, ifcp, s);
128355163Sshin		if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP
128455163Sshin		 && 0 < ifcp->ifc_index && !ifcp->ifc_joined) {
128555163Sshin			mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr;
128655163Sshin			mreq.ipv6mr_interface = ifcp->ifc_index;
128755163Sshin			if (setsockopt(ripsock, IPPROTO_IPV6,
128855163Sshin				IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0)
128955163Sshin				fatal("IPV6_JOIN_GROUP");
129055163Sshin			trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST);
129155163Sshin			ifcp->ifc_joined++;
129255163Sshin		}
129355163Sshinskip:
129455163Sshin		i += IFNAMSIZ;
129555163Sshin		if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr))
129655163Sshin			i += ifrp->ifr_addr.sa_len;
129755163Sshin		else
129855163Sshin			i += sizeof(struct sockaddr);
129955163Sshin	}
130055163Sshin	close(s);
130155163Sshin	free(buf);
130255163Sshin}
130355163Sshin
130455163Sshinvoid
130555163Sshinifconfig1(ifrp, ifcp, s)
130655163Sshin	struct	ifreq *ifrp;
130755163Sshin	struct	ifc *ifcp;
130855163Sshin	int	s;
130955163Sshin{
131055163Sshin	struct	in6_ifreq ifr;
131155163Sshin	struct	sockaddr_in6 *sin;
131255163Sshin	struct	ifac *ifa;
131355163Sshin	int	plen;
131455163Sshin	char	buf[BUFSIZ];
131555163Sshin
131655163Sshin	sin = (struct sockaddr_in6 *)&ifrp->ifr_addr;
131755163Sshin	ifr.ifr_addr = *sin;
131855163Sshin	strcpy(ifr.ifr_name, ifrp->ifr_name);
131955163Sshin	if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0)
132055163Sshin		fatal("ioctl: SIOCGIFNETMASK_IN6");
132155163Sshin	plen = mask2len(&ifr.ifr_addr.sin6_addr, 16);
132255163Sshin	if ((ifa = ifa_match(ifcp, &sin->sin6_addr, plen)) != NULL) {
132355163Sshin		/* same interface found */
132455163Sshin		/* need check if something changed */
132555163Sshin		/* XXX not yet implemented */
132655163Sshin		return;
132755163Sshin	}
132855163Sshin	/*
132955163Sshin	 * New address is found
133055163Sshin	 */
133155163Sshin	if ((ifa = MALLOC(struct ifac)) == NULL)
133255163Sshin		fatal("malloc: struct ifac");
133355163Sshin	ifa->ifa_conf = ifcp;
133455163Sshin	ifa->ifa_next = ifcp->ifc_addr;
133555163Sshin	ifcp->ifc_addr = ifa;
133655163Sshin	ifa->ifa_addr = sin->sin6_addr;
133755163Sshin	ifa->ifa_plen = plen;
133855163Sshin	if (ifcp->ifc_flags & IFF_POINTOPOINT) {
133955163Sshin		ifr.ifr_addr = *sin;
134055163Sshin		if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0)
134155163Sshin			fatal("ioctl: SIOCGIFDSTADDR_IN6");
134255163Sshin		ifa->ifa_raddr = ifr.ifr_dstaddr.sin6_addr;
134355163Sshin		inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, buf, sizeof(buf));
134455163Sshin		trace(1, "found address %s/%d -- %s\n",
134555163Sshin			inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen, buf);
134655163Sshin	} else {
134755163Sshin		trace(1, "found address %s/%d\n",
134855163Sshin			inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen);
134955163Sshin	}
135055163Sshin	if (ifcp->ifc_index < 0 && IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) {
135155163Sshin		ifcp->ifc_mylladdr = ifa->ifa_addr;
135255163Sshin		ifcp->ifc_index = IN6_LINKLOCAL_IFINDEX(ifa->ifa_addr);
135355163Sshin		memcpy(&ifcp->ifc_ripsin, &ripsin, ripsin.ss_len);
135455163Sshin		SET_IN6_LINKLOCAL_IFINDEX(ifcp->ifc_ripsin.sin6_addr,
135555163Sshin			ifcp->ifc_index);
135655163Sshin		setindex2ifc(ifcp->ifc_index, ifcp);
135755163Sshin		ifcp->ifc_mtu = getifmtu(ifcp->ifc_index);
135855163Sshin		if (ifcp->ifc_mtu > RIP6_MAXMTU)
135955163Sshin			ifcp->ifc_mtu = RIP6_MAXMTU;
136055163Sshin		if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0)
136155163Sshin			fatal("ioctl: SIOCGIFMETRIC");
136255163Sshin		ifcp->ifc_metric = ifr.ifr_metric;
136355163Sshin		trace(1, "\tindex: %d, mtu: %d, metric: %d\n",
136455163Sshin			ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric);
136555163Sshin	}
136655163Sshin}
136755163Sshin
136855163Sshin/*
136955163Sshin * Receive and process routing messages.
137055163Sshin * Update interface information as necesssary.
137155163Sshin */
137255163Sshinvoid
137355163Sshinrtrecv()
137455163Sshin{
137555163Sshin	char buf[BUFSIZ];
137655163Sshin	char *p, *q;
137755163Sshin	struct rt_msghdr *rtm;
137855163Sshin	struct ifa_msghdr *ifam;
137955163Sshin	struct if_msghdr *ifm;
138055163Sshin	int len;
138155163Sshin	struct ifc *ifcp;
138255163Sshin	int iface = 0, rtable = 0;
138355163Sshin	struct sockaddr_in6 *rta[RTAX_MAX];
138455163Sshin	int i, addrs;
138555163Sshin
138655163Sshin	if ((len = read(rtsock, buf, sizeof(buf))) < 0) {
138755163Sshin		perror("read from rtsock");
138855163Sshin		exit(-1);
138955163Sshin	}
139055163Sshin	if (len < sizeof(*rtm)) {
139155163Sshin		trace(1, "short read from rtsock: %d (should be > %d)\n",
139255163Sshin			len, sizeof(*rtm));
139355163Sshin		return;
139455163Sshin	}
139555163Sshin
139655163Sshin	for (p = buf; p - buf < len; p += ((struct rt_msghdr *)p)->rtm_msglen) {
139755163Sshin		/* safety against bogus message */
139855163Sshin		if (((struct rt_msghdr *)p)->rtm_msglen <= 0) {
139955163Sshin			trace(1, "bogus rtmsg: length=%d\n",
140055163Sshin				((struct rt_msghdr *)p)->rtm_msglen);
140155163Sshin			break;
140255163Sshin		}
140355163Sshin		rtm = NULL;
140455163Sshin		ifam = NULL;
140555163Sshin		ifm = NULL;
140655163Sshin		switch (((struct rt_msghdr *)p)->rtm_type) {
140755163Sshin		case RTM_NEWADDR:
140855163Sshin		case RTM_DELADDR:
140955163Sshin			ifam = (struct ifa_msghdr *)p;
141055163Sshin			addrs = ifam->ifam_addrs;
141155163Sshin			q = (char *)(ifam + 1);
141255163Sshin			break;
141355163Sshin		case RTM_IFINFO:
141455163Sshin			ifm = (struct if_msghdr *)p;
141555163Sshin			addrs = ifm->ifm_addrs;
141655163Sshin			q = (char *)(ifm + 1);
141755163Sshin			break;
141855163Sshin		default:
141955163Sshin			rtm = (struct rt_msghdr *)p;
142055163Sshin			addrs = rtm->rtm_addrs;
142155163Sshin			q = (char *)(rtm + 1);
142255163Sshin			if (rtm->rtm_version != RTM_VERSION) {
142355163Sshin				trace(1, "unexpected rtmsg version %d "
142455163Sshin					"(should be %d)\n",
142555163Sshin					rtm->rtm_version, RTM_VERSION);
142655163Sshin				continue;
142755163Sshin			}
142855163Sshin			if (rtm->rtm_pid == pid) {
142955163Sshin#if 0
143055163Sshin				trace(1, "rtmsg looped back to me, ignored\n");
143155163Sshin#endif
143255163Sshin				continue;
143355163Sshin			}
143455163Sshin			break;
143555163Sshin		}
143655163Sshin		memset(&rta, 0, sizeof(rta));
143755163Sshin		for (i = 0; i < RTAX_MAX; i++) {
143855163Sshin			if (addrs & (1 << i)) {
143955163Sshin				rta[i] = (struct sockaddr_in6 *)q;
144055163Sshin				q += ROUNDUP(rta[i]->sin6_len);
144155163Sshin			}
144255163Sshin		}
144355163Sshin
144455163Sshin		trace(1, "rtsock: %s (addrs=%x)\n",
144555163Sshin			rttypes((struct rt_msghdr *)p), addrs);
144655163Sshin		if (dflag >= 2) {
144755163Sshin			int i;
144855163Sshin			for (i = 0;
144955163Sshin			     i < ((struct rt_msghdr *)p)->rtm_msglen;
145055163Sshin			     i++) {
145155163Sshin				fprintf(stderr, "%02x ", p[i] & 0xff);
145255163Sshin				if (i % 16 == 15) fprintf(stderr, "\n");
145355163Sshin			}
145455163Sshin			fprintf(stderr, "\n");
145555163Sshin		}
145655163Sshin
145755163Sshin		/*
145855163Sshin		 * Easy ones first.
145955163Sshin		 *
146055163Sshin		 * We may be able to optimize by using ifm->ifm_index or
146155163Sshin		 * ifam->ifam_index.  For simplicity we don't do that here.
146255163Sshin		 */
146355163Sshin		switch (((struct rt_msghdr *)p)->rtm_type) {
146455163Sshin		case RTM_NEWADDR:
146555163Sshin		case RTM_IFINFO:
146655163Sshin			iface++;
146755163Sshin			continue;
146855163Sshin		case RTM_ADD:
146955163Sshin			rtable++;
147055163Sshin			continue;
147155163Sshin		case RTM_LOSING:
147255163Sshin		case RTM_MISS:
147355163Sshin		case RTM_RESOLVE:
147455163Sshin		case RTM_GET:
147555163Sshin		case RTM_LOCK:
147655163Sshin			/* nothing to be done here */
147755163Sshin			trace(1, "\tnothing to be done, ignored\n");
147855163Sshin			continue;
147955163Sshin		}
148055163Sshin
148155163Sshin#if 0
148255163Sshin		if (rta[RTAX_DST] == NULL) {
148355163Sshin			trace(1, "\tno destination, ignored\n");
148455163Sshin			continue;
148555163Sshin		}
148655163Sshin		if (rta[RTAX_DST]->sin6_family != AF_INET6) {
148755163Sshin			trace(1, "\taf mismatch, ignored\n");
148855163Sshin			continue;
148955163Sshin		}
149055163Sshin		if (IN6_IS_ADDR_LINKLOCAL(&rta[RTAX_DST]->sin6_addr)) {
149155163Sshin			trace(1, "\tlinklocal destination, ignored\n");
149255163Sshin			continue;
149355163Sshin		}
149455163Sshin		if (IN6_ARE_ADDR_EQUAL(&rta[RTAX_DST]->sin6_addr, &in6addr_loopback)) {
149555163Sshin			trace(1, "\tloopback destination, ignored\n");
149655163Sshin			continue;		/* Loopback */
149755163Sshin		}
149855163Sshin		if (IN6_IS_ADDR_MULTICAST(&rta[RTAX_DST]->sin6_addr)) {
149955163Sshin			trace(1, "\tmulticast destination, ignored\n");
150055163Sshin			continue;
150155163Sshin		}
150255163Sshin#endif
150355163Sshin
150455163Sshin		/* hard ones */
150555163Sshin		switch (((struct rt_msghdr *)p)->rtm_type) {
150655163Sshin		case RTM_NEWADDR:
150755163Sshin		case RTM_IFINFO:
150855163Sshin		case RTM_ADD:
150955163Sshin		case RTM_LOSING:
151055163Sshin		case RTM_MISS:
151155163Sshin		case RTM_RESOLVE:
151255163Sshin		case RTM_GET:
151355163Sshin		case RTM_LOCK:
151455163Sshin			/* should already be handled */
151555163Sshin			fatal("rtrecv: never reach here");
151655163Sshin		case RTM_DELETE:
151755163Sshin			if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY]
151855163Sshin			 || !rta[RTAX_NETMASK]) {
151955163Sshin				trace(1, "\tsome of dst/gw/netamsk are unavailable, ignored\n");
152055163Sshin				break;
152155163Sshin			}
152255163Sshin			if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY], rta[RTAX_NETMASK]) == 0) {
152355163Sshin				rtable++;	/*just to be sure*/
152455163Sshin			}
152555163Sshin			break;
152655163Sshin		case RTM_CHANGE:
152755163Sshin		case RTM_REDIRECT:
152855163Sshin			trace(1, "\tnot supported yet, ignored\n");
152955163Sshin			break;
153055163Sshin		case RTM_DELADDR:
153155163Sshin			if (!rta[RTAX_NETMASK] || !rta[RTAX_IFA]) {
153255163Sshin				trace(1, "\tno netmask or ifa given, ignored\n");
153355163Sshin				break;
153455163Sshin			}
153555163Sshin			if (ifam->ifam_index < nindex2ifc)
153655163Sshin				ifcp = index2ifc[ifam->ifam_index];
153755163Sshin			else
153855163Sshin				ifcp = NULL;
153955163Sshin			if (!ifcp) {
154055163Sshin				trace(1, "\tinvalid ifam_index %d, ignored\n",
154155163Sshin					ifam->ifam_index);
154255163Sshin				break;
154355163Sshin			}
154455163Sshin			rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK]);
154555163Sshin			iface++;
154655163Sshin			break;
154755163Sshin		case RTM_OLDADD:
154855163Sshin		case RTM_OLDDEL:
154955163Sshin			trace(1, "\tnot supported yet, ignored\n");
155055163Sshin			break;
155155163Sshin		}
155255163Sshin
155355163Sshin	}
155455163Sshin
155555163Sshin	if (iface) {
155655163Sshin		trace(1, "rtsock: reconfigure interfaces, refresh interface routes\n");
155755163Sshin		ifconfig();
155855163Sshin		for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next)
155955163Sshin			ifrt(ifcp, 1);
156055163Sshin	}
156155163Sshin	if (rtable) {
156255163Sshin		trace(1, "rtsock: read routing table again\n");
156355163Sshin		krtread(1);
156455163Sshin	}
156555163Sshin}
156655163Sshin
156755163Sshin/*
156855163Sshin * remove specified route from the internal routing table.
156955163Sshin */
157055163Sshinint
157155163Sshinrt_del(sdst, sgw, smask)
157255163Sshin	const struct sockaddr_in6 *sdst;
157355163Sshin	const struct sockaddr_in6 *sgw;
157455163Sshin	const struct sockaddr_in6 *smask;
157555163Sshin{
157655163Sshin	const struct in6_addr *dst = NULL;
157755163Sshin	const struct in6_addr *gw = NULL;
157855163Sshin	int prefix;
157955163Sshin	struct netinfo6 ni6;
158055163Sshin	struct riprt *rrt = NULL;
158155163Sshin	time_t t_lifetime;
158255163Sshin
158355163Sshin	if (sdst->sin6_family != AF_INET6) {
158455163Sshin		trace(1, "\tother AF, ignored\n");
158555163Sshin		return -1;
158655163Sshin	}
158755163Sshin	if (IN6_IS_ADDR_LINKLOCAL(&sdst->sin6_addr)
158855163Sshin	 || IN6_ARE_ADDR_EQUAL(&sdst->sin6_addr, &in6addr_loopback)
158955163Sshin	 || IN6_IS_ADDR_MULTICAST(&sdst->sin6_addr)) {
159055163Sshin		trace(1, "\taddress %s not interesting, ignored\n",
159155163Sshin			inet6_n2p(&sdst->sin6_addr));
159255163Sshin		return -1;
159355163Sshin	}
159455163Sshin	dst = &sdst->sin6_addr;
159555163Sshin	if (sgw->sin6_family == AF_INET6
159655163Sshin	 && smask->sin6_family == AF_INET6) {
159755163Sshin		/* easy case */
159855163Sshin		gw = &sgw->sin6_addr;
159955163Sshin		prefix = mask2len(&smask->sin6_addr, 16);
160055163Sshin	} else if (sgw->sin6_family == AF_LINK) {
160155163Sshin		/*
160255163Sshin		 * Interface route... a hard case.  We need to get the prefix
160355163Sshin		 * length from the kernel, but we now are parsing rtmsg.
160455163Sshin		 * We'll purge matching routes from my list, then get the
160555163Sshin		 * fresh list.
160655163Sshin		 */
160755163Sshin		struct riprt *longest;
160855163Sshin		trace(1, "\t%s is a interface route, guessing prefixlen\n",
160955163Sshin			inet6_n2p(dst));
161055163Sshin		longest = NULL;
161155163Sshin		for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
161255163Sshin			if (IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
161355163Sshin					&sdst->sin6_addr)
161455163Sshin			 && IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) {
161555163Sshin				if (!longest
161655163Sshin				 || longest->rrt_info.rip6_plen <
161755163Sshin						 rrt->rrt_info.rip6_plen) {
161855163Sshin					longest = rrt;
161955163Sshin				}
162055163Sshin			}
162155163Sshin		}
162255163Sshin		rrt = longest;
162355163Sshin		if (!rrt) {
162455163Sshin			trace(1, "\tno matching interface route found\n");
162555163Sshin			return -1;
162655163Sshin		}
162755163Sshin		gw = &in6addr_loopback;
162855163Sshin		prefix = rrt->rrt_info.rip6_plen;
162955163Sshin	} else {
163055163Sshin		trace(1, "\tunsupported af: (gw=%d, mask=%d)\n",
163155163Sshin			sgw->sin6_family, smask->sin6_family);
163255163Sshin		return -1;
163355163Sshin	}
163455163Sshin
163555163Sshin	trace(1, "\tdeleting %s/%d ", inet6_n2p(dst), prefix);
163655163Sshin	trace(1, "gw %s\n", inet6_n2p(gw));
163755163Sshin	t_lifetime = time(NULL) - RIP_LIFETIME;
163855163Sshin	/* age route for interface address */
163955163Sshin	memset(&ni6, 0, sizeof(ni6));
164055163Sshin	ni6.rip6_dest = *dst;
164155163Sshin	ni6.rip6_plen = prefix;
164255163Sshin	applyplen(&ni6.rip6_dest, ni6.rip6_plen);	/*to be sure*/
164355163Sshin	trace(1, "\tfind route %s/%d\n", inet6_n2p(&ni6.rip6_dest),
164455163Sshin		ni6.rip6_plen);
164555163Sshin	if (!rrt && (rrt = rtsearch(&ni6)) == NULL) {
164655163Sshin		trace(1, "\tno route found\n");
164755163Sshin		return -1;
164855163Sshin	}
164955163Sshin	if ((rrt->rrt_flags & RTF_STATIC) == 0) {
165055163Sshin		trace(1, "\tyou can delete static routes only\n");
165155163Sshin	} else if (memcmp(&rrt->rrt_gw, gw, sizeof(rrt->rrt_gw)) != 0) {
165255163Sshin		trace(1, "\tgw mismatch: %s <-> ",
165355163Sshin			inet6_n2p(&rrt->rrt_gw));
165455163Sshin		trace(1, "%s\n", inet6_n2p(gw));
165555163Sshin	} else {
165655163Sshin		trace(1, "\troute found, age it\n");
165755163Sshin		if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
165855163Sshin			rrt->rrt_t = t_lifetime;
165955163Sshin			rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
166055163Sshin		}
166155163Sshin	}
166255163Sshin	return 0;
166355163Sshin}
166455163Sshin
166555163Sshin/*
166655163Sshin * remove specified address from internal interface/routing table.
166755163Sshin */
166855163Sshinint
166955163Sshinrt_deladdr(ifcp, sifa, smask)
167055163Sshin	struct ifc *ifcp;
167155163Sshin	const struct sockaddr_in6 *sifa;
167255163Sshin	const struct sockaddr_in6 *smask;
167355163Sshin{
167455163Sshin	const struct in6_addr *addr = NULL;
167555163Sshin	int prefix;
167655163Sshin	struct ifac *ifa = NULL;
167755163Sshin	struct netinfo6 ni6;
167855163Sshin	struct riprt *rrt = NULL;
167955163Sshin	time_t t_lifetime;
168055163Sshin	int updated = 0;
168155163Sshin
168255163Sshin	if (sifa->sin6_family != AF_INET6 || smask->sin6_family != AF_INET6) {
168355163Sshin		trace(1, "\tother AF, ignored\n");
168455163Sshin		return -1;
168555163Sshin	}
168655163Sshin	addr = &sifa->sin6_addr;
168755163Sshin	prefix = mask2len(&smask->sin6_addr, 16);
168855163Sshin
168955163Sshin	trace(1, "\tdeleting %s/%d from %s\n",
169055163Sshin		inet6_n2p(addr), prefix, ifcp->ifc_name);
169155163Sshin	ifa = ifa_match(ifcp, addr, prefix);
169255163Sshin	if (!ifa) {
169355163Sshin		trace(1, "\tno matching ifa found for %s/%d on %s\n",
169455163Sshin			inet6_n2p(addr), prefix, ifcp->ifc_name);
169555163Sshin		return -1;
169655163Sshin	}
169755163Sshin	if (ifa->ifa_conf != ifcp) {
169855163Sshin		trace(1, "\taddress table corrupt: back pointer does not match "
169955163Sshin			"(%s != %s)\n",
170055163Sshin			ifcp->ifc_name, ifa->ifa_conf->ifc_name);
170155163Sshin		return -1;
170255163Sshin	}
170355163Sshin	/* remove ifa from interface */
170455163Sshin	if (ifcp->ifc_addr == ifa)
170555163Sshin		ifcp->ifc_addr = ifa->ifa_next;
170655163Sshin	else {
170755163Sshin		struct ifac *p;
170855163Sshin		for (p = ifcp->ifc_addr; p; p = p->ifa_next) {
170955163Sshin			if (p->ifa_next == ifa) {
171055163Sshin				p->ifa_next = ifa->ifa_next;
171155163Sshin				break;
171255163Sshin			}
171355163Sshin		}
171455163Sshin	}
171555163Sshin	ifa->ifa_next = NULL;
171655163Sshin	ifa->ifa_conf = NULL;
171755163Sshin	t_lifetime = time(NULL) - RIP_LIFETIME;
171855163Sshin	/* age route for interface address */
171955163Sshin	memset(&ni6, 0, sizeof(ni6));
172055163Sshin	ni6.rip6_dest = ifa->ifa_addr;
172155163Sshin	ni6.rip6_plen = ifa->ifa_plen;
172255163Sshin	applyplen(&ni6.rip6_dest, ni6.rip6_plen);
172355163Sshin	trace(1, "\tfind interface route %s/%d on %d\n",
172455163Sshin		inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index);
172555163Sshin	if ((rrt = rtsearch(&ni6)) != NULL) {
172655163Sshin		struct in6_addr none;
172755163Sshin		memset(&none, 0, sizeof(none));
172855163Sshin		if (rrt->rrt_index == ifcp->ifc_index
172955163Sshin		 && memcmp(&rrt->rrt_gw, &none, sizeof(rrt->rrt_gw)) == 0) {
173055163Sshin			trace(1, "\troute found, age it\n");
173155163Sshin			if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
173255163Sshin				rrt->rrt_t = t_lifetime;
173355163Sshin				rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
173455163Sshin			}
173555163Sshin			updated++;
173655163Sshin		} else {
173755163Sshin			trace(1, "\tnon-interface route found: %s/%d on %d\n",
173855163Sshin				inet6_n2p(&rrt->rrt_info.rip6_dest),
173955163Sshin				rrt->rrt_info.rip6_plen,
174055163Sshin				rrt->rrt_index);
174155163Sshin		}
174255163Sshin	} else
174355163Sshin		trace(1, "\tno interface route found\n");
174455163Sshin	/* age route for p2p destination */
174555163Sshin	if (ifcp->ifc_flags & IFF_POINTOPOINT) {
174655163Sshin		memset(&ni6, 0, sizeof(ni6));
174755163Sshin		ni6.rip6_dest = ifa->ifa_raddr;
174855163Sshin		ni6.rip6_plen = 128;
174955163Sshin		applyplen(&ni6.rip6_dest, ni6.rip6_plen);	/*to be sure*/
175055163Sshin		trace(1, "\tfind p2p route %s/%d on %d\n",
175155163Sshin			inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen,
175255163Sshin			ifcp->ifc_index);
175355163Sshin		if ((rrt = rtsearch(&ni6)) != NULL) {
175455163Sshin			if (rrt->rrt_index == ifcp->ifc_index
175555163Sshin			 && memcmp(&rrt->rrt_gw, &ifa->ifa_addr,
175655163Sshin					 sizeof(rrt->rrt_gw)) == 0) {
175755163Sshin				trace(1, "\troute found, age it\n");
175855163Sshin				if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
175955163Sshin					rrt->rrt_t = t_lifetime;
176055163Sshin					rrt->rrt_info.rip6_metric =
176155163Sshin						HOPCNT_INFINITY6;
176255163Sshin					updated++;
176355163Sshin				}
176455163Sshin			} else {
176555163Sshin				trace(1, "\tnon-p2p route found: %s/%d on %d\n",
176655163Sshin					inet6_n2p(&rrt->rrt_info.rip6_dest),
176755163Sshin					rrt->rrt_info.rip6_plen,
176855163Sshin					rrt->rrt_index);
176955163Sshin			}
177055163Sshin		} else
177155163Sshin			trace(1, "\tno p2p route found\n");
177255163Sshin	}
177355163Sshin	return updated ? 0 : -1;
177455163Sshin}
177555163Sshin
177655163Sshin/*
177755163Sshin * Get each interface address and put those interface routes to the route
177855163Sshin * list.
177955163Sshin */
178055163Sshinvoid
178155163Sshinifrt(ifcp, again)
178255163Sshin	struct	ifc *ifcp;
178355163Sshin	int again;
178455163Sshin{
178555163Sshin	struct	ifac *ifa;
178655163Sshin	struct	riprt *rrt;
178755163Sshin	struct	netinfo6 *np;
178855163Sshin
178955163Sshin	if (ifcp->ifc_flags & IFF_LOOPBACK)
179055163Sshin		return;			/* ignore loopback */
179155163Sshin	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
179255163Sshin		if (IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr))
179355163Sshin			continue;	/* don't advertise link local addr */
179455163Sshin		if ((rrt = MALLOC(struct riprt)) == NULL)
179555163Sshin			fatal("malloc: struct riprt");
179655163Sshin		rrt->rrt_same = NULL;
179755163Sshin		rrt->rrt_index = ifcp->ifc_index;
179855163Sshin		rrt->rrt_t = 0;	/* don't age */
179955163Sshin		rrt->rrt_info.rip6_dest = ifa->ifa_addr;
180055163Sshin		rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
180155163Sshin		rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric;
180255163Sshin		rrt->rrt_info.rip6_plen = ifa->ifa_plen;
180355163Sshin		applyplen(&rrt->rrt_info.rip6_dest, ifa->ifa_plen);
180455163Sshin		memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
180555163Sshin		np = &rrt->rrt_info;
180655163Sshin		if (rtsearch(np) == NULL) {
180755163Sshin			/* Attach the route to the list */
180855163Sshin			rrt->rrt_next = riprt;
180955163Sshin			riprt = rrt;
181055163Sshin		} else {
181155163Sshin			/* Already found */
181255163Sshin			if (!again) {
181355163Sshin				trace(1, "route: %s/%d: already registered\n",
181455163Sshin					inet6_n2p(&np->rip6_dest),
181555163Sshin					np->rip6_plen);
181655163Sshin			}
181755163Sshin			free(rrt);
181855163Sshin		}
181955163Sshin
182055163Sshin		if (ifcp->ifc_flags & IFF_POINTOPOINT) {
182155163Sshin			if ((rrt = MALLOC(struct riprt)) == NULL)
182255163Sshin				fatal("malloc: struct riprt");
182355163Sshin			rrt->rrt_same = NULL;
182455163Sshin			rrt->rrt_index = ifcp->ifc_index;
182555163Sshin			rrt->rrt_t = 0;	/* Don't age */
182655163Sshin			rrt->rrt_info.rip6_dest = ifa->ifa_raddr;
182755163Sshin			rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
182855163Sshin			rrt->rrt_info.rip6_metric = 1;
182955163Sshin			rrt->rrt_info.rip6_plen = 128;
183055163Sshin			rrt->rrt_gw = ifa->ifa_addr;
183155163Sshin			rrt->rrt_flags |= RTF_NOADVERTISE;
183255163Sshin			np = &rrt->rrt_info;
183355163Sshin			if (rtsearch(np) == NULL) {
183455163Sshin				/* Attach the route to the list */
183555163Sshin				rrt->rrt_next = riprt;
183655163Sshin				riprt = rrt;
183755163Sshin			} else {
183855163Sshin				/* Already found */
183955163Sshin				if (!again) {
184055163Sshin					trace(1, "route: %s/%d: already registered\n",
184155163Sshin						inet6_n2p(&np->rip6_dest),
184255163Sshin						np->rip6_plen);
184355163Sshin				}
184455163Sshin				free(rrt);
184555163Sshin			}
184655163Sshin		}
184755163Sshin	}
184855163Sshin}
184955163Sshin
185055163Sshinint
185155163Sshingetifmtu(ifindex)
185255163Sshin	int	ifindex;
185355163Sshin{
185455163Sshin	int	mib[6];
185555163Sshin	char	*buf;
185655163Sshin	size_t	msize;
185755163Sshin	struct	if_msghdr *ifm;
185855163Sshin	int	mtu;
185955163Sshin
186055163Sshin	mib[0] = CTL_NET;
186155163Sshin	mib[1] = PF_ROUTE;
186255163Sshin	mib[2] = 0;
186355163Sshin	mib[3] = AF_INET6;
186455163Sshin	mib[4] = NET_RT_IFLIST;
186555163Sshin	mib[5] = ifindex;
186655163Sshin	if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0)
186755163Sshin		fatal("sysctl estimate NET_RT_IFLIST");
186855163Sshin	if ((buf = malloc(msize)) == NULL)
186955163Sshin		fatal("malloc");
187055163Sshin	if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0)
187155163Sshin		fatal("sysctl NET_RT_IFLIST");
187255163Sshin	ifm = (struct if_msghdr *)buf;
187355163Sshin	mtu = ifm->ifm_data.ifi_mtu;
187455163Sshin#ifdef	__FREEBSD__
187555163Sshin	if (ifindex != ifm->ifm_index)
187655163Sshin		fatal("ifindex does not match with ifm_index");
187755163Sshin#endif	/* __FREEBSD__ */
187855163Sshin	free(buf);
187955163Sshin	return mtu;
188055163Sshin}
188155163Sshin
188255163Sshinconst char *
188355163Sshinrttypes(rtm)
188455163Sshin	struct rt_msghdr *rtm;
188555163Sshin{
188655163Sshin#define	RTTYPE(s, f)	if (rtm->rtm_type == (f)) return (s)
188755163Sshin	RTTYPE("ADD", RTM_ADD);
188855163Sshin	RTTYPE("DELETE", RTM_DELETE);
188955163Sshin	RTTYPE("CHANGE", RTM_CHANGE);
189055163Sshin	RTTYPE("GET", RTM_GET);
189155163Sshin	RTTYPE("LOSING", RTM_LOSING);
189255163Sshin	RTTYPE("REDIRECT", RTM_REDIRECT);
189355163Sshin	RTTYPE("MISS", RTM_MISS);
189455163Sshin	RTTYPE("LOCK", RTM_LOCK);
189555163Sshin	RTTYPE("OLDADD", RTM_OLDADD);
189655163Sshin	RTTYPE("OLDDEL", RTM_OLDDEL);
189755163Sshin	RTTYPE("RESOLVE", RTM_RESOLVE);
189855163Sshin	RTTYPE("NEWADDR", RTM_NEWADDR);
189955163Sshin	RTTYPE("DELADDR", RTM_DELADDR);
190055163Sshin	RTTYPE("IFINFO", RTM_IFINFO);
190155163Sshin#undef RTTYPE
190255163Sshin	return NULL;
190355163Sshin}
190455163Sshin
190555163Sshinconst char *
190655163Sshinrtflags(rtm)
190755163Sshin	struct rt_msghdr *rtm;
190855163Sshin{
190955163Sshin	static char buf[BUFSIZ];
191055163Sshin
191155163Sshin	strcpy(buf, "");
191255163Sshin#define	RTFLAG(s, f)	if (rtm->rtm_flags & (f)) strcat(buf, (s))
191355163Sshin	RTFLAG("U", RTF_UP);
191455163Sshin	RTFLAG("G", RTF_GATEWAY);
191555163Sshin	RTFLAG("H", RTF_HOST);
191655163Sshin	RTFLAG("R", RTF_REJECT);
191755163Sshin	RTFLAG("D", RTF_DYNAMIC);
191855163Sshin	RTFLAG("M", RTF_MODIFIED);
191955163Sshin	RTFLAG("d", RTF_DONE);
192055163Sshin#ifdef	RTF_MASK
192155163Sshin	RTFLAG("m", RTF_MASK);
192255163Sshin#endif
192355163Sshin	RTFLAG("C", RTF_CLONING);
192455163Sshin	RTFLAG("X", RTF_XRESOLVE);
192555163Sshin	RTFLAG("L", RTF_LLINFO);
192655163Sshin	RTFLAG("S", RTF_STATIC);
192755163Sshin	RTFLAG("B", RTF_BLACKHOLE);
192855163Sshin	RTFLAG("2", RTF_PROTO2);
192955163Sshin	RTFLAG("1", RTF_PROTO1);
193055163Sshin#undef RTFLAG
193155163Sshin	return buf;
193255163Sshin}
193355163Sshin
193455163Sshinconst char *
193555163Sshinifflags(flags)
193655163Sshin	int flags;
193755163Sshin{
193855163Sshin	static char buf[BUFSIZ];
193955163Sshin
194055163Sshin	strcpy(buf, "");
194155163Sshin#define	IFFLAG(s, f)	\
194255163Sshin	if (flags & f) { if (buf[0]) strcat(buf, ","); strcat(buf, s); }
194355163Sshin	IFFLAG("UP", IFF_UP);
194455163Sshin	IFFLAG("BROADCAST", IFF_BROADCAST);
194555163Sshin	IFFLAG("DEBUG", IFF_DEBUG);
194655163Sshin	IFFLAG("LOOPBACK", IFF_LOOPBACK);
194755163Sshin	IFFLAG("POINTOPOINT", IFF_POINTOPOINT);
194855163Sshin#ifdef IFF_NOTRAILERS
194955163Sshin	IFFLAG("NOTRAILERS", IFF_NOTRAILERS);
195055163Sshin#endif
195155163Sshin	IFFLAG("RUNNING", IFF_RUNNING);
195255163Sshin	IFFLAG("NOARP", IFF_NOARP);
195355163Sshin	IFFLAG("PROMISC", IFF_PROMISC);
195455163Sshin	IFFLAG("ALLMULTI", IFF_ALLMULTI);
195555163Sshin	IFFLAG("OACTIVE", IFF_OACTIVE);
195655163Sshin	IFFLAG("SIMPLEX", IFF_SIMPLEX);
195755163Sshin	IFFLAG("LINK0", IFF_LINK0);
195855163Sshin	IFFLAG("LINK1", IFF_LINK1);
195955163Sshin	IFFLAG("LINK2", IFF_LINK2);
196055163Sshin	IFFLAG("MULTICAST", IFF_MULTICAST);
196155163Sshin#undef IFFLAG
196255163Sshin	return buf;
196355163Sshin}
196455163Sshin
196555163Sshinvoid
196655163Sshinkrtread(again)
196755163Sshin	int again;
196855163Sshin{
196955163Sshin	int mib[6];
197055163Sshin	size_t msize;
197155163Sshin	char *buf, *p, *lim;
197255163Sshin	struct rt_msghdr *rtm;
197355163Sshin	int retry;
197455163Sshin	const char *errmsg;
197555163Sshin
197655163Sshin	retry = 0;
197755163Sshin	buf = NULL;
197855163Sshin	mib[0] = CTL_NET;
197955163Sshin	mib[1] = PF_ROUTE;
198055163Sshin	mib[2] = 0;
198155163Sshin	mib[3] = AF_INET6;	/* Address family */
198255163Sshin	mib[4] = NET_RT_DUMP;	/* Dump the kernel routing table */
198355163Sshin	mib[5] = 0;		/* No flags */
198455163Sshin	do {
198555163Sshin		retry++;
198655163Sshin		errmsg = NULL;
198755163Sshin		if (buf)
198855163Sshin			free(buf);
198955163Sshin		if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) {
199055163Sshin			errmsg = "sysctl estimate";
199155163Sshin			continue;
199255163Sshin		}
199355163Sshin		if ((buf = malloc(msize)) == NULL) {
199455163Sshin			errmsg = "malloc";
199555163Sshin			continue;
199655163Sshin		}
199755163Sshin		if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) {
199855163Sshin			errmsg = "sysctl NET_RT_DUMP";
199955163Sshin			continue;
200055163Sshin		}
200155163Sshin	} while (retry < 5 && errmsg != NULL);
200255163Sshin	if (errmsg)
200355163Sshin		fatal("%s (with %d retries, msize=%d)", errmsg, retry, msize);
200455163Sshin	else if (1 < retry)
200555163Sshin		syslog(LOG_INFO, "NET_RT_DUMP %d retires", retry);
200655163Sshin
200755163Sshin	lim = buf + msize;
200855163Sshin	for (p = buf; p < lim; p += rtm->rtm_msglen) {
200955163Sshin		rtm = (struct rt_msghdr *)p;
201055163Sshin		rt_entry(rtm, again);
201155163Sshin	}
201255163Sshin	free(buf);
201355163Sshin}
201455163Sshin
201555163Sshinvoid
201655163Sshinrt_entry(rtm, again)
201755163Sshin	struct rt_msghdr *rtm;
201855163Sshin	int again;
201955163Sshin{
202055163Sshin	struct	sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask;
202155163Sshin	struct	sockaddr_in6 *sin6_genmask, *sin6_ifp;
202255163Sshin	char	*rtmp, *ifname = NULL;
202355163Sshin	char	buf[BUFSIZ];
202455163Sshin	struct	riprt *rrt;
202555163Sshin	struct	netinfo6 *np;
202655163Sshin	int	s;
202755163Sshin
202855163Sshin	sin6_dst = sin6_gw = sin6_mask = sin6_genmask = sin6_ifp = 0;
202955163Sshin	if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags &
203055163Sshin		(RTF_CLONING|RTF_XRESOLVE|RTF_LLINFO|RTF_BLACKHOLE))
203155163Sshin		return;		/* not interested in the link route */
203255163Sshin	rtmp = (char *)(rtm + 1);
203355163Sshin	/* Destination */
203455163Sshin	if ((rtm->rtm_addrs & RTA_DST) == 0)
203555163Sshin		return;		/* ignore routes without destination address */
203655163Sshin	sin6_dst = (struct sockaddr_in6 *)rtmp;
203755163Sshin	rtmp += sin6_dst->sin6_len;
203855163Sshin	if (rtm->rtm_addrs & RTA_GATEWAY) {
203955163Sshin		sin6_gw = (struct sockaddr_in6 *)rtmp;
204055163Sshin		rtmp += ROUNDUP(sin6_gw->sin6_len);
204155163Sshin	}
204255163Sshin	if (rtm->rtm_addrs & RTA_NETMASK) {
204355163Sshin		sin6_mask = (struct sockaddr_in6 *)rtmp;
204455163Sshin		rtmp += ROUNDUP(sin6_mask->sin6_len);
204555163Sshin	}
204655163Sshin	if (rtm->rtm_addrs & RTA_GENMASK) {
204755163Sshin		sin6_genmask = (struct sockaddr_in6 *)rtmp;
204855163Sshin		rtmp += ROUNDUP(sin6_genmask->sin6_len);
204955163Sshin	}
205055163Sshin	if (rtm->rtm_addrs & RTA_IFP) {
205155163Sshin		sin6_ifp = (struct sockaddr_in6 *)rtmp;
205255163Sshin		rtmp += ROUNDUP(sin6_ifp->sin6_len);
205355163Sshin	}
205455163Sshin
205555163Sshin	/* Destination */
205655163Sshin	if (sin6_dst->sin6_family != AF_INET6)
205755163Sshin		return;
205855163Sshin	if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst->sin6_addr))
205955163Sshin		return;		/* Link-local */
206055163Sshin	if (IN6_ARE_ADDR_EQUAL(&sin6_dst->sin6_addr, &in6addr_loopback))
206155163Sshin		return;		/* Loopback */
206255163Sshin	if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr))
206355163Sshin		return;
206455163Sshin
206555163Sshin	if ((rrt = MALLOC(struct riprt)) == NULL)
206655163Sshin		fatal("malloc: struct riprt");
206755163Sshin	np = &rrt->rrt_info;
206855163Sshin	rrt->rrt_same = NULL;
206955163Sshin	rrt->rrt_t = time(NULL);
207055163Sshin	if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC))
207155163Sshin		rrt->rrt_t = 0;	/* Don't age static routes */
207255163Sshin#if 0
207355163Sshin	np->rip6_tag = htons(routetag & 0xffff);
207455163Sshin#else
207555163Sshin	np->rip6_tag = 0;
207655163Sshin#endif
207755163Sshin	np->rip6_metric = rtm->rtm_rmx.rmx_hopcount;
207855163Sshin	if (np->rip6_metric < 1)
207955163Sshin		np->rip6_metric = 1;
208055163Sshin	rrt->rrt_flags = rtm->rtm_flags;
208155163Sshin	np->rip6_dest = sin6_dst->sin6_addr;
208255163Sshin
208355163Sshin	/* Mask or plen */
208455163Sshin	if (rtm->rtm_flags & RTF_HOST)
208555163Sshin		np->rip6_plen = 128;	/* Host route */
208655163Sshin	else if (sin6_mask) {
208755163Sshin		np->rip6_plen = mask2len(&sin6_mask->sin6_addr,
208855163Sshin			sin6_mask->sin6_len - offsetof(struct sockaddr_in6, sin6_addr));
208955163Sshin	} else
209055163Sshin		np->rip6_plen = 0;
209155163Sshin
209255163Sshin	if (rtsearch(np)) {
209355163Sshin		/* Already found */
209455163Sshin		if (!again) {
209555163Sshin			trace(1, "route: %s/%d flags %s: already registered\n",
209655163Sshin				inet6_n2p(&np->rip6_dest), np->rip6_plen,
209755163Sshin				rtflags(rtm));
209855163Sshin		}
209955163Sshin		free(rrt);
210055163Sshin		return;
210155163Sshin	}
210255163Sshin	/* Gateway */
210355163Sshin	if (!sin6_gw)
210455163Sshin		memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
210555163Sshin	else {
210655163Sshin		if (sin6_gw->sin6_family == AF_INET6)
210755163Sshin			rrt->rrt_gw = sin6_gw->sin6_addr;
210855163Sshin		else if (sin6_gw->sin6_family == AF_LINK) {
210955163Sshin			/* XXX in case ppp link? */
211055163Sshin			rrt->rrt_gw = in6addr_loopback;
211155163Sshin		} else
211255163Sshin			memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
211355163Sshin	}
211455163Sshin	trace(1, "route: %s/%d flags %s",
211555163Sshin		inet6_n2p(&np->rip6_dest), np->rip6_plen, rtflags(rtm));
211655163Sshin	trace(1, " gw %s", inet6_n2p(&rrt->rrt_gw));
211755163Sshin
211855163Sshin	/* Interface */
211955163Sshin	s = rtm->rtm_index;
212055163Sshin	if (s < nindex2ifc && index2ifc[s])
212155163Sshin		ifname = index2ifc[s]->ifc_name;
212255163Sshin	else
212355163Sshin		fatal("Unknown interface %d", s);
212455163Sshin	trace(1, " if %s sock %d\n", ifname, s);
212555163Sshin	rrt->rrt_index = s;
212655163Sshin
212755163Sshin	/* Check gateway */
212855163Sshin	if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_gw) &&
212955163Sshin	    !IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)
213055163Sshin#ifdef __FreeBSD__
213155163Sshin	 && (rrt->rrt_flags & RTF_LOCAL) == 0
213255163Sshin#endif
213355163Sshin	    ) {
213455163Sshin		inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest,
213555163Sshin			buf, sizeof(buf));
213655163Sshin		trace(0, "***** Gateway %s is not a link-local address.\n",
213755163Sshin			inet6_n2p(&rrt->rrt_gw));
213855163Sshin		trace(0, "*****     dest(%s) if(%s) -- Not optimized.\n",
213955163Sshin			buf, ifname);
214055163Sshin		rrt->rrt_flags |= RTF_NH_NOT_LLADDR;
214155163Sshin	}
214255163Sshin
214355163Sshin	/* Put it to the route list */
214455163Sshin	rrt->rrt_next = riprt;
214555163Sshin	riprt = rrt;
214655163Sshin}
214755163Sshin
214855163Sshinint
214955163Sshinaddroute(rrt, gw, ifcp)
215055163Sshin	struct riprt *rrt;
215155163Sshin	const struct in6_addr *gw;
215255163Sshin	struct ifc *ifcp;
215355163Sshin{
215455163Sshin	struct	netinfo6 *np;
215555163Sshin	u_char	buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ];
215655163Sshin	struct	rt_msghdr	*rtm;
215755163Sshin	struct	sockaddr_in6	*sin;
215855163Sshin	int	len;
215955163Sshin
216055163Sshin	np = &rrt->rrt_info;
216155163Sshin	inet_ntop(AF_INET6, (void *)gw, (char *)buf1, sizeof(buf1));
216255163Sshin	inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2));
216355163Sshin	tracet(1, "ADD: %s/%d gw %s [%d] ifa %s\n",
216455163Sshin		inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1,
216555163Sshin		np->rip6_metric - 1, buf2);
216655163Sshin	if (rtlog)
216755163Sshin		fprintf(rtlog, "%s: ADD: %s/%d gw %s [%d] ifa %s\n", hms(),
216855163Sshin			inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1,
216955163Sshin			np->rip6_metric - 1, buf2);
217055163Sshin	if (nflag)
217155163Sshin		return 0;
217255163Sshin
217355163Sshin	memset(buf, 0, sizeof(buf));
217455163Sshin	rtm = (struct rt_msghdr *)buf;
217555163Sshin	rtm->rtm_type = RTM_ADD;
217655163Sshin	rtm->rtm_version = RTM_VERSION;
217755163Sshin	rtm->rtm_seq = ++seq;
217855163Sshin	rtm->rtm_pid = pid;
217955163Sshin	rtm->rtm_flags = rrt->rrt_flags & RTF_ROUTE_H;
218055163Sshin	rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
218155163Sshin	rtm->rtm_rmx.rmx_hopcount = np->rip6_metric - 1;
218255163Sshin	rtm->rtm_inits = RTV_HOPCOUNT;
218355163Sshin	sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
218455163Sshin	/* Destination */
218555163Sshin	sin->sin6_len = sizeof(struct sockaddr_in6);
218655163Sshin	sin->sin6_family = AF_INET6;
218755163Sshin	sin->sin6_addr = np->rip6_dest;
218855163Sshin	sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
218955163Sshin	/* Gateway */
219055163Sshin	sin->sin6_len = sizeof(struct sockaddr_in6);
219155163Sshin	sin->sin6_family = AF_INET6;
219255163Sshin	sin->sin6_addr = *gw;
219355163Sshin	sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
219455163Sshin	/* Netmask */
219555163Sshin	sin->sin6_len = sizeof(struct sockaddr_in6);
219655163Sshin	sin->sin6_family = AF_INET6;
219755163Sshin	sin->sin6_addr = *(plen2mask(np->rip6_plen));
219855163Sshin	sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
219955163Sshin
220055163Sshin	len = (char *)sin - (char *)buf;
220155163Sshin	rtm->rtm_msglen = len;
220255163Sshin	if (write(rtsock, buf, len) > 0)
220355163Sshin		return 0;
220455163Sshin
220555163Sshin	if (errno == EEXIST) {
220655163Sshin		trace(0, "ADD: Route already exists %s/%d gw %s\n",
220755163Sshin			inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1);
220855163Sshin		if (rtlog)
220955163Sshin			fprintf(rtlog, "ADD: Route already exists %s/%d gw %s\n",
221055163Sshin				inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1);
221155163Sshin	} else {
221255163Sshin		trace(0, "Can not write to rtsock (addroute): %s\n",
221355163Sshin			strerror(errno));
221455163Sshin		if (rtlog)
221555163Sshin			fprintf(rtlog, "\tCan not write to rtsock: %s\n",
221655163Sshin				strerror(errno));
221755163Sshin	}
221855163Sshin	return -1;
221955163Sshin}
222055163Sshin
222155163Sshinint
222255163Sshindelroute(np, gw)
222355163Sshin	struct netinfo6 *np;
222455163Sshin	struct in6_addr *gw;
222555163Sshin{
222655163Sshin	u_char	buf[BUFSIZ], buf2[BUFSIZ];
222755163Sshin	struct	rt_msghdr	*rtm;
222855163Sshin	struct	sockaddr_in6	*sin;
222955163Sshin	int	len;
223055163Sshin
223155163Sshin	inet_ntop(AF_INET6, (void *)gw, (char *)buf2, sizeof(buf2));
223255163Sshin	tracet(1, "DEL: %s/%d gw %s\n", inet6_n2p(&np->rip6_dest),
223355163Sshin		np->rip6_plen, buf2);
223455163Sshin	if (rtlog)
223555163Sshin		fprintf(rtlog, "%s: DEL: %s/%d gw %s\n",
223655163Sshin			hms(), inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
223755163Sshin	if (nflag)
223855163Sshin		return 0;
223955163Sshin
224055163Sshin	memset(buf, 0, sizeof(buf));
224155163Sshin	rtm = (struct rt_msghdr *)buf;
224255163Sshin	rtm->rtm_type = RTM_DELETE;
224355163Sshin	rtm->rtm_version = RTM_VERSION;
224455163Sshin	rtm->rtm_seq = ++seq;
224555163Sshin	rtm->rtm_pid = pid;
224655163Sshin	rtm->rtm_flags = RTF_UP | RTF_GATEWAY;
224755163Sshin	rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
224855163Sshin	sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
224955163Sshin	/* Destination */
225055163Sshin	sin->sin6_len = sizeof(struct sockaddr_in6);
225155163Sshin	sin->sin6_family = AF_INET6;
225255163Sshin	sin->sin6_addr = np->rip6_dest;
225355163Sshin	sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
225455163Sshin	/* Gateway */
225555163Sshin	sin->sin6_len = sizeof(struct sockaddr_in6);
225655163Sshin	sin->sin6_family = AF_INET6;
225755163Sshin	sin->sin6_addr = *gw;
225855163Sshin	sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
225955163Sshin	/* Netmask */
226055163Sshin	sin->sin6_len = sizeof(struct sockaddr_in6);
226155163Sshin	sin->sin6_family = AF_INET6;
226255163Sshin	sin->sin6_addr = *(plen2mask(np->rip6_plen));
226355163Sshin	sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
226455163Sshin
226555163Sshin	len = (char *)sin - (char *)buf;
226655163Sshin	rtm->rtm_msglen = len;
226755163Sshin	if (write(rtsock, buf, len) >= 0)
226855163Sshin		return 0;
226955163Sshin
227055163Sshin	if (errno == ESRCH) {
227155163Sshin		trace(0, "RTDEL: Route does not exist: %s/%d gw %s\n",
227255163Sshin			inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
227355163Sshin		if (rtlog)
227455163Sshin			fprintf(rtlog, "RTDEL: Route does not exist: %s/%d gw %s\n",
227555163Sshin				inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
227655163Sshin	} else {
227755163Sshin		trace(0, "Can not write to rtsock (delroute): %s\n",
227855163Sshin			strerror(errno));
227955163Sshin		if (rtlog)
228055163Sshin			fprintf(rtlog, "\tCan not write to rtsock: %s\n",
228155163Sshin				strerror(errno));
228255163Sshin	}
228355163Sshin	return -1;
228455163Sshin}
228555163Sshin
228655163Sshinstruct in6_addr *
228755163Sshingetroute(np, gw)
228855163Sshin	struct netinfo6 *np;
228955163Sshin	struct in6_addr *gw;
229055163Sshin{
229155163Sshin	u_char buf[BUFSIZ];
229255163Sshin	u_long myseq;
229355163Sshin	int len;
229455163Sshin	struct rt_msghdr *rtm;
229555163Sshin	struct sockaddr_in6 *sin;
229655163Sshin
229755163Sshin	rtm = (struct rt_msghdr *)buf;
229855163Sshin	len = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6);
229955163Sshin	memset(rtm, 0, len);
230055163Sshin	rtm->rtm_type = RTM_GET;
230155163Sshin	rtm->rtm_version = RTM_VERSION;
230255163Sshin	myseq = ++seq;
230355163Sshin	rtm->rtm_seq = myseq;
230455163Sshin	rtm->rtm_addrs = RTA_DST;
230555163Sshin	rtm->rtm_msglen = len;
230655163Sshin	sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
230755163Sshin	sin->sin6_len = sizeof(struct sockaddr_in6);
230855163Sshin	sin->sin6_family = AF_INET6;
230955163Sshin	sin->sin6_addr = np->rip6_dest;
231055163Sshin	if (write(rtsock, buf, len) < 0) {
231155163Sshin		if (errno == ESRCH)	/* No such route found */
231255163Sshin			return NULL;
231355163Sshin		perror("write to rtsock");
231455163Sshin		exit(-1);
231555163Sshin	}
231655163Sshin	do {
231755163Sshin		if ((len = read(rtsock, buf, sizeof(buf))) < 0) {
231855163Sshin			perror("read from rtsock");
231955163Sshin			exit(-1);
232055163Sshin		}
232155163Sshin		rtm = (struct rt_msghdr *)buf;
232255163Sshin	} while (rtm->rtm_seq != myseq || rtm->rtm_pid != pid);
232355163Sshin	sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
232455163Sshin	if (rtm->rtm_addrs & RTA_DST) {
232555163Sshin		sin = (struct sockaddr_in6 *)
232655163Sshin			((char *)sin + ROUNDUP(sin->sin6_len));
232755163Sshin	}
232855163Sshin	if (rtm->rtm_addrs & RTA_GATEWAY) {
232955163Sshin		*gw = sin->sin6_addr;
233055163Sshin		return gw;
233155163Sshin	}
233255163Sshin	return NULL;
233355163Sshin}
233455163Sshin
233555163Sshinconst char *
233655163Sshininet6_n2p(p)
233755163Sshin	const struct in6_addr *p;
233855163Sshin{
233955163Sshin	static char buf[BUFSIZ];
234055163Sshin
234155163Sshin	return inet_ntop(AF_INET6, (void *)p, buf, sizeof(buf));
234255163Sshin}
234355163Sshin
234455163Sshinvoid
234555163Sshinifrtdump(sig)
234655163Sshin	int sig;
234755163Sshin{
234855163Sshin
234955163Sshin	ifdump(sig);
235055163Sshin	rtdump(sig);
235155163Sshin}
235255163Sshin
235355163Sshinvoid
235455163Sshinifdump(sig)
235555163Sshin	int sig;
235655163Sshin{
235755163Sshin	struct ifc *ifcp;
235855163Sshin	FILE *dump;
235955163Sshin	int i;
236055163Sshin
236155163Sshin	if (sig == 0)
236255163Sshin		dump = stderr;
236355163Sshin	else
236455163Sshin		if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL)
236555163Sshin			dump = stderr;
236655163Sshin
236755163Sshin	fprintf(dump, "%s: Interface Table Dump\n", hms());
236855163Sshin	fprintf(dump, "  Number of interfaces: %d\n", nifc);
236955163Sshin	for (i = 0; i < 2; i++) {
237055163Sshin		fprintf(dump, "  %sadvertising interfaces:\n", i ? "non-" : "");
237155163Sshin		for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
237255163Sshin			if (i == 0) {
237355163Sshin				if ((ifcp->ifc_flags & IFF_UP) == 0)
237455163Sshin					continue;
237555163Sshin				if (iff_find(ifcp, 'N') != NULL)
237655163Sshin					continue;
237755163Sshin			} else {
237855163Sshin				if (ifcp->ifc_flags & IFF_UP)
237955163Sshin					continue;
238055163Sshin			}
238155163Sshin			ifdump0(dump, ifcp);
238255163Sshin		}
238355163Sshin	}
238455163Sshin	fprintf(dump, "\n");
238555163Sshin	if (dump != stderr)
238655163Sshin		fclose(dump);
238755163Sshin}
238855163Sshin
238955163Sshinvoid
239055163Sshinifdump0(dump, ifcp)
239155163Sshin	FILE *dump;
239255163Sshin	const struct ifc *ifcp;
239355163Sshin{
239455163Sshin	struct ifac *ifa;
239555163Sshin	struct iff *iffp;
239655163Sshin	char buf[BUFSIZ];
239755163Sshin	const char *ft;
239855163Sshin	int addr;
239955163Sshin
240055163Sshin	fprintf(dump, "    %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)\n",
240155163Sshin		ifcp->ifc_name, ifcp->ifc_index, ifflags(ifcp->ifc_flags),
240255163Sshin		inet6_n2p(&ifcp->ifc_mylladdr),
240355163Sshin		ifcp->ifc_mtu, ifcp->ifc_metric);
240455163Sshin	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
240555163Sshin		if (ifcp->ifc_flags & IFF_POINTOPOINT) {
240655163Sshin			inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr,
240755163Sshin				buf, sizeof(buf));
240855163Sshin			fprintf(dump, "\t%s/%d -- %s\n",
240955163Sshin				inet6_n2p(&ifa->ifa_addr),
241055163Sshin				ifa->ifa_plen, buf);
241155163Sshin		} else {
241255163Sshin			fprintf(dump, "\t%s/%d\n",
241355163Sshin				inet6_n2p(&ifa->ifa_addr),
241455163Sshin				ifa->ifa_plen);
241555163Sshin		}
241655163Sshin	}
241755163Sshin	if (ifcp->ifc_filter) {
241855163Sshin		fprintf(dump, "\tFilter:");
241955163Sshin		for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
242055163Sshin			addr = 0;
242155163Sshin			switch (iffp->iff_type) {
242255163Sshin			case 'A':
242355163Sshin				ft = "Aggregate"; addr++; break;
242455163Sshin			case 'N':
242555163Sshin				ft = "No-advertise"; break;
242655163Sshin			case 'O':
242755163Sshin				ft = "Advertise-only"; addr++; break;
242855163Sshin			case 'T':
242955163Sshin				ft = "Default-only"; break;
243055163Sshin			case 'L':
243155163Sshin				ft = "Listen-only"; addr++; break;
243255163Sshin			default:
243355163Sshin				snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type);
243455163Sshin				ft = buf;
243555163Sshin				addr++;
243655163Sshin				break;
243755163Sshin			}
243855163Sshin			fprintf(dump, " %s", ft);
243955163Sshin			if (addr) {
244055163Sshin				fprintf(dump, "(%s/%d)", inet6_n2p(&iffp->iff_addr),
244155163Sshin					iffp->iff_plen);
244255163Sshin			}
244355163Sshin		}
244455163Sshin		fprintf(dump, "\n");
244555163Sshin	}
244655163Sshin}
244755163Sshin
244855163Sshinvoid
244955163Sshinrtdump(sig)
245055163Sshin	int sig;
245155163Sshin{
245255163Sshin	struct	riprt *rrt;
245355163Sshin	char	buf[BUFSIZ];
245455163Sshin	FILE	*dump;
245555163Sshin	time_t	t, age;
245655163Sshin
245755163Sshin	if (sig == 0)
245855163Sshin		dump = stderr;
245955163Sshin	else
246055163Sshin		if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL)
246155163Sshin			dump = stderr;
246255163Sshin
246355163Sshin	t = time(NULL);
246455163Sshin	fprintf(dump, "\n%s: Routing Table Dump\n", hms());
246555163Sshin	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
246655163Sshin		if (rrt->rrt_t == 0)
246755163Sshin			age = 0;
246855163Sshin		else
246955163Sshin			age = t - rrt->rrt_t;
247055163Sshin		inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest,
247155163Sshin			buf, sizeof(buf));
247255163Sshin		fprintf(dump, "    %s/%d if(%d:%s) gw(%s) [%d] age(%ld)",
247355163Sshin			buf, rrt->rrt_info.rip6_plen, rrt->rrt_index,
247455163Sshin			index2ifc[rrt->rrt_index]->ifc_name,
247555163Sshin			inet6_n2p(&rrt->rrt_gw),
247655163Sshin			rrt->rrt_info.rip6_metric, (long)age);
247755163Sshin		if (rrt->rrt_info.rip6_tag) {
247855163Sshin			fprintf(dump, " tag(0x%04x)",
247955163Sshin				ntohs(rrt->rrt_info.rip6_tag) & 0xffff);
248055163Sshin		}
248155163Sshin		if (rrt->rrt_flags & RTF_NH_NOT_LLADDR)
248255163Sshin			fprintf(dump, " NOT-LL");
248355163Sshin		if (rrt->rrt_flags & RTF_NOADVERTISE)
248455163Sshin			fprintf(dump, " NO-ADV");
248555163Sshin		fprintf(dump, "\n");
248655163Sshin	}
248755163Sshin	fprintf(dump, "\n");
248855163Sshin	if (dump != stderr)
248955163Sshin		fclose(dump);
249055163Sshin}
249155163Sshin
249255163Sshin/*
249355163Sshin * Parse the -A (and -O) options and put corresponding filter object to the
249455163Sshin * specified interface structures. Each of the -A/O option has the following
249555163Sshin * syntax:	-A 5f09:c400::/32,ef0,ef1  (aggregate)
249655163Sshin * 		-O 5f09:c400::/32,ef0,ef1  (only when match)
249755163Sshin */
249855163Sshinvoid
249955163Sshinfilterconfig()
250055163Sshin{
250155163Sshin	int i;
250255163Sshin	char *p, *ap, *iflp, *ifname;
250355163Sshin	struct	iff ftmp, *iff_obj;
250455163Sshin	struct	ifc *ifcp;
250555163Sshin	struct	riprt *rrt;
250655163Sshin	struct	in6_addr gw;
250755163Sshin
250855163Sshin	for (i = 0; i < nfilter; i++) {
250955163Sshin		ap = filter[i];
251055163Sshin		iflp = NULL;
251155163Sshin		ifcp = NULL;
251255163Sshin		if (filtertype[i] == 'N' || filtertype[i] == 'T') {
251355163Sshin			iflp = ap;
251455163Sshin			goto ifonly;
251555163Sshin		}
251655163Sshin		if ((p = index(ap, ',')) != NULL) {
251755163Sshin			*p++ = '\0';
251855163Sshin			iflp = p;
251955163Sshin		}
252055163Sshin		if ((p = index(ap, '/')) == NULL)
252155163Sshin			fatal("no prefixlen specified for '%s'", ap);
252255163Sshin		*p++ = '\0';
252355163Sshin		if (inet_pton(AF_INET6, ap, &ftmp.iff_addr) != 1)
252455163Sshin			fatal("invalid prefix specified for '%s'", ap);
252555163Sshin		ftmp.iff_plen = atoi(p);
252655163Sshin		ftmp.iff_next = NULL;
252755163Sshin		applyplen(&ftmp.iff_addr, ftmp.iff_plen);
252855163Sshinifonly:
252955163Sshin		ftmp.iff_type = filtertype[i];
253055163Sshin		if (iflp == NULL || *iflp == '\0')
253155163Sshin			fatal("no interface specified for '%s'", ap);
253255163Sshin		/* parse the interface listing portion */
253355163Sshin		while (iflp) {
253455163Sshin			ifname = iflp;
253555163Sshin			if ((iflp = index(iflp, ',')) != NULL)
253655163Sshin				*iflp++ = '\0';
253755163Sshin			ifcp = ifc_find(ifname);
253855163Sshin			if (ifcp == NULL)
253955163Sshin				fatal("no interface %s exists", ifname);
254055163Sshin			iff_obj = (struct iff *)malloc(sizeof(struct iff));
254155163Sshin			if (iff_obj == NULL)
254255163Sshin				fatal("malloc of iff_obj");
254355163Sshin			memcpy((void *)iff_obj, (void *)&ftmp,
254455163Sshin				sizeof(struct iff));
254555163Sshin			/* link it to the interface filter */
254655163Sshin			iff_obj->iff_next = ifcp->ifc_filter;
254755163Sshin			ifcp->ifc_filter = iff_obj;
254855163Sshin		}
254955163Sshin		if (filtertype[i] != 'A')
255055163Sshin			continue;
255155163Sshin		/* put the aggregate to the kernel routing table */
255255163Sshin		rrt = (struct riprt *)malloc(sizeof(struct riprt));
255355163Sshin		if (rrt == NULL)
255455163Sshin			fatal("malloc: rrt");
255555163Sshin		memset(rrt, 0, sizeof(struct riprt));
255655163Sshin		rrt->rrt_info.rip6_dest = ftmp.iff_addr;
255755163Sshin		rrt->rrt_info.rip6_plen = ftmp.iff_plen;
255855163Sshin		rrt->rrt_info.rip6_metric = 1;
255955163Sshin		rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
256055163Sshin		rrt->rrt_gw = in6addr_loopback;
256155163Sshin		rrt->rrt_flags = RTF_UP | RTF_REJECT | RTF_AGGREGATE;
256255163Sshin		rrt->rrt_t = 0;
256355163Sshin		rrt->rrt_index = loopifindex;
256455163Sshin		/* Put the route to the list */
256555163Sshin		rrt->rrt_next = riprt;
256655163Sshin		riprt = rrt;
256755163Sshin		trace(1, "Aggregate: %s/%d for %s\n",
256855163Sshin			inet6_n2p(&ftmp.iff_addr), ftmp.iff_plen,
256955163Sshin			ifcp->ifc_name);
257055163Sshin		/* Add this route to the kernel */
257155163Sshin		if (nflag) 	/* do not modify kernel routing table */
257255163Sshin			continue;
257355163Sshin		if (getroute(&rrt->rrt_info, &gw)) {
257455163Sshin			/*
257555163Sshin			 * When the address has already been registered in the
257655163Sshin			 * kernel routing table, it should be removed
257755163Sshin			 */
257855163Sshin			delroute(&rrt->rrt_info, &gw);
257955163Sshin		}
258055163Sshin		addroute(rrt, &in6addr_loopback, loopifcp);
258155163Sshin	}
258255163Sshin}
258355163Sshin
258455163Sshin/***************** utility functions *****************/
258555163Sshin
258655163Sshin/*
258755163Sshin * Returns a pointer to ifac whose address and prefix length matches
258855163Sshin * with the address and prefix length specified in the arguments.
258955163Sshin */
259055163Sshinstruct ifac *
259155163Sshinifa_match(ifcp, ia, plen)
259255163Sshin	const struct ifc *ifcp;
259355163Sshin	const struct in6_addr *ia;
259455163Sshin	int plen;
259555163Sshin{
259655163Sshin	struct ifac *ifa;
259755163Sshin
259855163Sshin	for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
259955163Sshin		if (IN6_ARE_ADDR_EQUAL(&ifa->ifa_addr, ia) &&
260055163Sshin		    ifa->ifa_plen == plen)
260155163Sshin			break;
260255163Sshin	}
260355163Sshin	return ifa;
260455163Sshin}
260555163Sshin
260655163Sshin/*
260755163Sshin * Return a pointer to riprt structure whose address and prefix length
260855163Sshin * matches with the address and prefix length found in the argument.
260955163Sshin * Note: This is not a rtalloc(). Therefore exact match is necessary.
261055163Sshin */
261155163Sshin
261255163Sshinstruct riprt *
261355163Sshinrtsearch(np)
261455163Sshin	struct	netinfo6 *np;
261555163Sshin{
261655163Sshin	struct	riprt	*rrt;
261755163Sshin
261855163Sshin	for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
261955163Sshin		if (rrt->rrt_info.rip6_plen == np->rip6_plen &&
262055163Sshin		    IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
262155163Sshin				       &np->rip6_dest))
262255163Sshin			return rrt;
262355163Sshin	}
262455163Sshin	return 0;
262555163Sshin}
262655163Sshin
262755163Sshinint
262855163Sshinmask2len(addr, lenlim)
262955163Sshin	const struct in6_addr *addr;
263055163Sshin	int lenlim;
263155163Sshin{
263255163Sshin	int i = 0, j;
263355163Sshin	u_char *p = (u_char *)addr;
263455163Sshin
263555163Sshin	for (j = 0; j < lenlim; j++, p++) {
263655163Sshin		if (*p != 0xff)
263755163Sshin			break;
263855163Sshin		i += 8;
263955163Sshin	}
264055163Sshin	if (j < lenlim) {
264155163Sshin		switch (*p) {
264255163Sshin#define	MASKLEN(m, l)	case m: i += l; break
264355163Sshin		MASKLEN(0xfe, 7);
264455163Sshin		MASKLEN(0xfc, 6);
264555163Sshin		MASKLEN(0xf8, 5);
264655163Sshin		MASKLEN(0xf0, 4);
264755163Sshin		MASKLEN(0xe0, 3);
264855163Sshin		MASKLEN(0xc0, 2);
264955163Sshin		MASKLEN(0x80, 1);
265055163Sshin#undef	MASKLEN
265155163Sshin		}
265255163Sshin	}
265355163Sshin	return i;
265455163Sshin}
265555163Sshin
265655163Sshinvoid
265755163Sshinapplymask(addr, mask)
265855163Sshin	struct in6_addr *addr, *mask;
265955163Sshin{
266055163Sshin	int	i;
266155163Sshin	u_long	*p, *q;
266255163Sshin
266355163Sshin	p = (u_long *)addr; q = (u_long *)mask;
266455163Sshin	for (i = 0; i < 4; i++)
266555163Sshin		*p++ &= *q++;
266655163Sshin}
266755163Sshin
266855163Sshinstatic const u_char plent[8] = {
266955163Sshin	0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
267055163Sshin};
267155163Sshin
267255163Sshinvoid
267355163Sshinapplyplen(ia, plen)
267455163Sshin	struct	in6_addr *ia;
267555163Sshin	int	plen;
267655163Sshin{
267755163Sshin	u_char	*p;
267855163Sshin	int	i;
267955163Sshin
268055163Sshin	p = ia->s6_addr;
268155163Sshin	for (i = 0; i < 16; i++) {
268255163Sshin		if (plen <= 0)
268355163Sshin			*p = 0;
268455163Sshin		else if (plen < 8)
268555163Sshin			*p &= plent[plen];
268655163Sshin		p++, plen -= 8;
268755163Sshin	}
268855163Sshin}
268955163Sshin
269055163Sshinstatic const int pl2m[9] = {
269155163Sshin	0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
269255163Sshin};
269355163Sshin
269455163Sshinstruct in6_addr *
269555163Sshinplen2mask(n)
269655163Sshin	int	n;
269755163Sshin{
269855163Sshin	static struct in6_addr ia;
269955163Sshin	u_char	*p;
270055163Sshin	int	i;
270155163Sshin
270255163Sshin	memset(&ia, 0, sizeof(struct in6_addr));
270355163Sshin	p = (u_char *)&ia;
270455163Sshin	for (i = 0; i < 16; i++, p++, n -= 8) {
270555163Sshin		if (n >= 8) {
270655163Sshin			*p = 0xff;
270755163Sshin			continue;
270855163Sshin		}
270955163Sshin		*p = pl2m[n];
271055163Sshin		break;
271155163Sshin	}
271255163Sshin	return &ia;
271355163Sshin}
271455163Sshin
271555163Sshinchar *
271655163Sshinallocopy(p)
271755163Sshin	char *p;
271855163Sshin{
271955163Sshin	char *q = (char *)malloc(strlen(p) + 1);
272055163Sshin
272155163Sshin	strcpy(q, p);
272255163Sshin	return q;
272355163Sshin}
272455163Sshin
272555163Sshinchar *
272655163Sshinhms()
272755163Sshin{
272855163Sshin	static char buf[BUFSIZ];
272955163Sshin	time_t t;
273055163Sshin	struct	tm *tm;
273155163Sshin
273255163Sshin	t = time(NULL);
273355163Sshin	if ((tm = localtime(&t)) == 0)
273455163Sshin		fatal("localtime");
273555163Sshin	snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec);
273655163Sshin	return buf;
273755163Sshin}
273855163Sshin
273955163Sshin#define	RIPRANDDEV	1.0	/* 30 +- 15, max - min = 30 */
274055163Sshin
274155163Sshinint
274255163Sshinripinterval(timer)
274355163Sshin	int timer;
274455163Sshin{
274555163Sshin	double r = rand();
274655163Sshin
274755163Sshin	interval = (int)(timer + timer * RIPRANDDEV * (r / RAND_MAX - 0.5));
274855163Sshin	nextalarm = time(NULL) + interval;
274955163Sshin	return interval;
275055163Sshin}
275155163Sshin
275255163Sshintime_t
275355163Sshinripsuptrig()
275455163Sshin{
275555163Sshin	time_t t;
275655163Sshin
275755163Sshin	double r = rand();
275855163Sshin	t  = (int)(RIP_TRIG_INT6_MIN +
275955163Sshin		(RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / RAND_MAX ));
276055163Sshin	sup_trig_update = time(NULL) + t;
276155163Sshin	return t;
276255163Sshin}
276355163Sshin
276455163Sshinvoid
276555163Sshin#ifdef __STDC__
276655163Sshinfatal(const char *fmt, ...)
276755163Sshin#else
276855163Sshinfatal(fmt, va_alist)
276955163Sshin	char	*fmt;
277055163Sshin	va_dcl
277155163Sshin#endif
277255163Sshin{
277355163Sshin	va_list ap;
277455163Sshin	char buf[1024];
277555163Sshin
277655163Sshin#ifdef __STDC__
277755163Sshin	va_start(ap, fmt);
277855163Sshin#else
277955163Sshin	va_start(ap);
278055163Sshin#endif
278155163Sshin	vsnprintf(buf, sizeof(buf), fmt, ap);
278255163Sshin	perror(buf);
278355163Sshin	syslog(LOG_ERR, "%s: %s", buf, strerror(errno));
278455163Sshin	rtdexit(0);
278555163Sshin	va_end(ap);
278655163Sshin}
278755163Sshin
278855163Sshinvoid
278955163Sshin#ifdef __STDC__
279055163Sshintracet(int level, const char *fmt, ...)
279155163Sshin#else
279255163Sshintracet(level, fmt, va_alist)
279355163Sshin	int level;
279455163Sshin	char *fmt;
279555163Sshin	va_dcl
279655163Sshin#endif
279755163Sshin{
279855163Sshin	va_list ap;
279955163Sshin
280055163Sshin#ifdef __STDC__
280155163Sshin	va_start(ap, fmt);
280255163Sshin#else
280355163Sshin	va_start(ap);
280455163Sshin#endif
280555163Sshin	if (level <= dflag) {
280655163Sshin		fprintf(stderr, "%s: ", hms());
280755163Sshin		vfprintf(stderr, fmt, ap);
280855163Sshin	}
280955163Sshin	if (dflag) {
281055163Sshin		if (level > 0)
281155163Sshin			vsyslog(LOG_DEBUG, fmt, ap);
281255163Sshin		else
281355163Sshin			vsyslog(LOG_WARNING, fmt, ap);
281455163Sshin	}
281555163Sshin	va_end(ap);
281655163Sshin}
281755163Sshin
281855163Sshinvoid
281955163Sshin#ifdef __STDC__
282055163Sshintrace(int level, const char *fmt, ...)
282155163Sshin#else
282255163Sshintrace(level, fmt, va_alist)
282355163Sshin	int level;
282455163Sshin	char *fmt;
282555163Sshin	va_dcl
282655163Sshin#endif
282755163Sshin{
282855163Sshin	va_list ap;
282955163Sshin
283055163Sshin#ifdef __STDC__
283155163Sshin	va_start(ap, fmt);
283255163Sshin#else
283355163Sshin	va_start(ap);
283455163Sshin#endif
283555163Sshin	if (level <= dflag)
283655163Sshin		vfprintf(stderr, fmt, ap);
283755163Sshin	if (dflag) {
283855163Sshin		if (level > 0)
283955163Sshin			vsyslog(LOG_DEBUG, fmt, ap);
284055163Sshin		else
284155163Sshin			vsyslog(LOG_WARNING, fmt, ap);
284255163Sshin	}
284355163Sshin	va_end(ap);
284455163Sshin}
284555163Sshin
284655163Sshinunsigned int
284755163Sshinif_maxindex()
284855163Sshin{
284955163Sshin	struct if_nameindex *p, *p0;
285055163Sshin	unsigned int max = 0;
285155163Sshin
285255163Sshin	p0 = if_nameindex();
285355163Sshin	for (p = p0; p && p->if_index && p->if_name; p++) {
285455163Sshin		if (max < p->if_index)
285555163Sshin			max = p->if_index;
285655163Sshin	}
285755163Sshin	if_freenameindex(p0);
285855163Sshin	return max;
285955163Sshin}
286055163Sshin
286155163Sshinstruct ifc *
286255163Sshinifc_find(name)
286355163Sshin	char *name;
286455163Sshin{
286555163Sshin	struct ifc *ifcp;
286655163Sshin
286755163Sshin	for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
286855163Sshin		if (strcmp(name, ifcp->ifc_name) == 0)
286955163Sshin			return ifcp;
287055163Sshin	}
287155163Sshin	return (struct ifc *)NULL;
287255163Sshin}
287355163Sshin
287455163Sshinstruct iff *
287555163Sshiniff_find(ifcp, type)
287655163Sshin	struct ifc *ifcp;
287755163Sshin	int type;
287855163Sshin{
287955163Sshin	struct iff *iffp;
288055163Sshin
288155163Sshin	for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
288255163Sshin		if (iffp->iff_type == type)
288355163Sshin			return iffp;
288455163Sshin	}
288555163Sshin	return NULL;
288655163Sshin}
288755163Sshin
288855163Sshinvoid
288955163Sshinsetindex2ifc(index, ifcp)
289055163Sshin	int index;
289155163Sshin	struct ifc *ifcp;
289255163Sshin{
289355163Sshin	int n;
289455163Sshin
289555163Sshin	if (!index2ifc) {
289655163Sshin		nindex2ifc = 5;	/*initial guess*/
289755163Sshin		index2ifc = (struct ifc **)
289855163Sshin			malloc(sizeof(*index2ifc) * nindex2ifc);
289955163Sshin		if (index2ifc == NULL)
290055163Sshin			fatal("malloc");
290155163Sshin		memset(index2ifc, 0, sizeof(*index2ifc) * nindex2ifc);
290255163Sshin	}
290355163Sshin	n = nindex2ifc;
290455163Sshin	while (nindex2ifc <= index)
290555163Sshin		nindex2ifc *= 2;
290655163Sshin	if (n != nindex2ifc) {
290755163Sshin		index2ifc = (struct ifc **)
290855163Sshin			realloc(index2ifc, sizeof(*index2ifc) * nindex2ifc);
290955163Sshin		if (index2ifc == NULL)
291055163Sshin			fatal("realloc");
291155163Sshin	}
291255163Sshin	index2ifc[index] = ifcp;
291355163Sshin}
2914