1168404Spjd/*	$KAME: route6d.c,v 1.104 2003/10/31 00:30:20 itojun Exp $	*/
2168404Spjd
3168404Spjd/*-
4168404Spjd * SPDX-License-Identifier: BSD-3-Clause
5168404Spjd *
6168404Spjd * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7168404Spjd * All rights reserved.
8168404Spjd *
9168404Spjd * Redistribution and use in source and binary forms, with or without
10168404Spjd * modification, are permitted provided that the following conditions
11168404Spjd * are met:
12168404Spjd * 1. Redistributions of source code must retain the above copyright
13168404Spjd *    notice, this list of conditions and the following disclaimer.
14168404Spjd * 2. Redistributions in binary form must reproduce the above copyright
15168404Spjd *    notice, this list of conditions and the following disclaimer in the
16168404Spjd *    documentation and/or other materials provided with the distribution.
17168404Spjd * 3. Neither the name of the project nor the names of its contributors
18168404Spjd *    may be used to endorse or promote products derived from this software
19168404Spjd *    without specific prior written permission.
20168404Spjd *
21168404Spjd * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22168404Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23219089Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24264670Sdelphij * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25268126Sdelphij * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26247265Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27168404Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28168404Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29168404Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30251629Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31251629Sdelphij * SUCH DAMAGE.
32168404Spjd */
33168404Spjd
34168404Spjd
35168404Spjd#include <sys/param.h>
36168404Spjd#include <sys/file.h>
37168404Spjd#include <sys/ioctl.h>
38168404Spjd#include <sys/queue.h>
39168404Spjd#include <sys/socket.h>
40168404Spjd#include <sys/sysctl.h>
41168404Spjd#include <sys/uio.h>
42168404Spjd#include <arpa/inet.h>
43168404Spjd#include <net/if.h>
44168404Spjd#include <net/route.h>
45168404Spjd#include <netinet/in.h>
46219089Spjd#include <netinet/in_var.h>
47168404Spjd#include <netinet/ip6.h>
48168404Spjd#include <netinet/udp.h>
49219089Spjd#include <err.h>
50168404Spjd#include <errno.h>
51168404Spjd#include <fnmatch.h>
52168404Spjd#include <ifaddrs.h>
53168404Spjd#include <netdb.h>
54168404Spjd#ifdef HAVE_POLL_H
55168404Spjd#include <poll.h>
56168404Spjd#endif
57168404Spjd#include <signal.h>
58168404Spjd#include <stdio.h>
59168404Spjd#include <stdarg.h>
60168404Spjd#include <stddef.h>
61168404Spjd#include <stdlib.h>
62185029Spjd#include <string.h>
63168404Spjd#include <syslog.h>
64185029Spjd#include <time.h>
65219089Spjd#include <unistd.h>
66219089Spjd
67248571Smm#include "route6d.h"
68248571Smm
69248571Smm#define	MAXFILTER	40
70236884Smm#define RT_DUMP_MAXRETRY	15
71219089Spjd
72240868Spjd#ifdef	DEBUG
73168404Spjd#define	INIT_INTERVAL6	6
74219089Spjd#else
75219089Spjd#define	INIT_INTERVAL6	10	/* Wait to submit an initial riprequest */
76219089Spjd#endif
77219089Spjd
78219089Spjd/* alignment constraint for routing socket */
79219089Spjd#define ROUNDUP(a) \
80185029Spjd	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
81185029Spjd#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
82168404Spjd
83204073Spjdstruct ifc {			/* Configuration of an interface */
84204073Spjd	TAILQ_ENTRY(ifc) ifc_next;
85204073Spjd
86204073Spjd	char	ifc_name[IFNAMSIZ];		/* if name */
87267992Shselasky	int	ifc_index;			/* if index */
88204073Spjd	int	ifc_mtu;			/* if mtu */
89204073Spjd	int	ifc_metric;			/* if metric */
90251636Sdelphij	u_int	ifc_flags;			/* flags */
91251636Sdelphij	short	ifc_cflags;			/* IFC_XXX */
92251636Sdelphij	struct	in6_addr ifc_mylladdr;		/* my link-local address */
93251636Sdelphij	struct	sockaddr_in6 ifc_ripsin;	/* rip multicast address */
94251636Sdelphij	TAILQ_HEAD(, ifac) ifc_ifac_head;	/* list of AF_INET6 addrs */
95251636Sdelphij	TAILQ_HEAD(, iff) ifc_iff_head;		/* list of filters */
96219089Spjd	int	ifc_joined;			/* joined to ff02::9 */
97258631Savg};
98258631Savgstatic TAILQ_HEAD(, ifc) ifc_head = TAILQ_HEAD_INITIALIZER(ifc_head);
99258631Savg
100258631Savgstruct ifac {			/* Address associated to an interface */
101219089Spjd	TAILQ_ENTRY(ifac) ifac_next;
102168712Spjd
103258631Savg	struct	ifc *ifac_ifc;		/* back pointer */
104258631Savg	struct	in6_addr ifac_addr;	/* address */
105258631Savg	struct	in6_addr ifac_raddr;	/* remote address, valid in p2p */
106209962Smm	int	ifac_scope_id;		/* scope id */
107258631Savg	int	ifac_plen;		/* prefix length */
108258631Savg};
109209962Smm
110209962Smmstruct iff {			/* Filters for an interface */
111258631Savg	TAILQ_ENTRY(iff) iff_next;
112211931Smm
113258631Savg	int	iff_type;
114209962Smm	struct	in6_addr iff_addr;
115209962Smm	int	iff_plen;
116209962Smm};
117219089Spjd
118209962Smmstatic struct	ifc **index2ifc;
119209962Smmstatic unsigned int	nindex2ifc;
120211931Smmstatic struct	ifc *loopifcp = NULL;	/* pointing to loopback */
121258631Savg#ifdef HAVE_POLL_H
122258631Savgstatic struct	pollfd set[2];
123258631Savg#else
124258631Savgstatic fd_set	*sockvecp;	/* vector to select() for receiving */
125258631Savgstatic fd_set	*recvecp;
126258631Savgstatic int	fdmasks;
127258631Savgstatic int	maxfd;		/* maximum fd for select() */
128258631Savg#endif
129258631Savgstatic int	rtsock;		/* the routing socket */
130258631Savgstatic int	ripsock;	/* socket to send/receive RIP datagram */
131258631Savg
132258631Savgstatic struct	rip6 *ripbuf;	/* packet buffer for sending */
133258631Savg
134258631Savg/*
135258631Savg * Maintain the routes in a linked list.  When the number of the routes
136211931Smm * grows, somebody would like to introduce a hash based or a radix tree
137211931Smm * based structure.  I believe the number of routes handled by RIP is
138211931Smm * limited and I don't have to manage a complex data structure, however.
139258631Savg *
140264670Sdelphij * One of the major drawbacks of the linear linked list is the difficulty
141258631Savg * of representing the relationship between a couple of routes.  This may
142258631Savg * be a significant problem when we have to support route aggregation with
143258631Savg * suppressing the specifics covered by the aggregate.
144258631Savg */
145209962Smm
146209962Smmstruct riprt {
147248571Smm	TAILQ_ENTRY(riprt) rrt_next;	/* next destination */
148248571Smm
149185029Spjd	struct	riprt *rrt_same;	/* same destination - future use */
150219089Spjd	struct	netinfo6 rrt_info;	/* network info */
151219089Spjd	struct	in6_addr rrt_gw;	/* gateway */
152219089Spjd	u_long	rrt_flags;		/* kernel routing table flags */
153219089Spjd	u_long	rrt_rflags;		/* route6d routing table flags */
154185029Spjd	time_t	rrt_t;			/* when the route validated */
155258632Savg	int	rrt_index;		/* ifindex from which this route got */
156219089Spjd};
157219089Spjdstatic TAILQ_HEAD(, riprt) riprt_head = TAILQ_HEAD_INITIALIZER(riprt_head);
158219089Spjd
159219089Spjdstatic int	dflag = 0;	/* debug flag */
160219089Spjdstatic int	qflag = 0;	/* quiet flag */
161219089Spjdstatic int	nflag = 0;	/* don't update kernel routing table */
162219089Spjdstatic int	aflag = 0;	/* age out even the statically defined routes */
163219089Spjdstatic int	hflag = 0;	/* don't split horizon */
164219089Spjdstatic int	lflag = 0;	/* exchange site local routes */
165243503Smmstatic int	Pflag = 0;	/* don't age out routes with RTF_PROTO[123] */
166219089Spjdstatic int	Qflag = RTF_PROTO2;	/* set RTF_PROTO[123] flag to routes by RIPng */
167247265Smmstatic int	sflag = 0;	/* announce static routes w/ split horizon */
168247265Smmstatic int	Sflag = 0;	/* announce static routes to every interface */
169247265Smmstatic unsigned long routetag = 0;	/* route tag attached on originating case */
170247265Smm
171168404Spjdstatic char	*filter[MAXFILTER];
172219089Spjdstatic int	filtertype[MAXFILTER];
173219089Spjdstatic int	nfilter = 0;
174219089Spjd
175219089Spjdstatic pid_t	pid;
176219089Spjd
177219089Spjdstatic struct	sockaddr_storage ripsin;
178168404Spjd
179185029Spjdstatic int	interval = 1;
180185029Spjdstatic time_t	nextalarm = 0;
181185029Spjd#if 0
182185029Spjdstatic time_t	sup_trig_update = 0;
183185029Spjd#endif
184185029Spjd
185185029Spjdstatic FILE	*rtlog = NULL;
186185029Spjd
187185029Spjdstatic int logopened = 0;
188185029Spjd
189185029Spjdstatic	int	seq = 0;
190185029Spjd
191185029Spjdstatic volatile sig_atomic_t seenalrm;
192185029Spjdstatic volatile sig_atomic_t seenquit;
193185029Spjdstatic volatile sig_atomic_t seenusr1;
194185029Spjd
195185029Spjd#define	RRTF_AGGREGATE		0x08000000
196185029Spjd#define	RRTF_NOADVERTISE	0x10000000
197185029Spjd#define	RRTF_NH_NOT_LLADDR	0x20000000
198185029Spjd#define RRTF_SENDANYWAY		0x40000000
199185029Spjd#define	RRTF_CHANGED		0x80000000
200185029Spjd
201185029Spjdstatic void sighandler(int);
202185029Spjdstatic void ripalarm(void);
203185029Spjdstatic void riprecv(void);
204185029Spjdstatic void ripsend(struct ifc *, struct sockaddr_in6 *, int);
205185029Spjdstatic int out_filter(struct riprt *, struct ifc *);
206185029Spjdstatic void init(void);
207185029Spjdstatic void ifconfig(void);
208185029Spjdstatic int ifconfig1(const char *, const struct sockaddr *, struct ifc *, int);
209185029Spjdstatic void rtrecv(void);
210185029Spjdstatic int rt_del(const struct sockaddr_in6 *, const struct sockaddr_in6 *,
211236155Smm	const struct sockaddr_in6 *);
212236884Smmstatic int rt_deladdr(struct ifc *, const struct sockaddr_in6 *,
213269118Sdelphij	const struct sockaddr_in6 *);
214185029Spjdstatic void filterconfig(void);
215185029Spjdstatic int getifmtu(int);
216269118Sdelphijstatic const char *rttypes(struct rt_msghdr *);
217185029Spjdstatic const char *rtflags(struct rt_msghdr *);
218185029Spjdstatic const char *ifflags(int);
219185029Spjdstatic int ifrt(struct ifc *, int);
220236155Smmstatic void ifrt_p2p(struct ifc *, int);
221219089Spjdstatic void applyplen(struct in6_addr *, int);
222219089Spjdstatic void ifrtdump(int);
223209962Smmstatic void ifdump(int);
224209962Smmstatic void ifdump0(FILE *, const struct ifc *);
225219089Spjdstatic void ifremove(int);
226219089Spjdstatic void rtdump(int);
227219089Spjdstatic void rt_entry(struct rt_msghdr *, int);
228236155Smmstatic void rtdexit(void);
229269118Sdelphijstatic void riprequest(struct ifc *, struct netinfo6 *, int,
230269118Sdelphij	struct sockaddr_in6 *);
231269118Sdelphijstatic void ripflush(struct ifc *, struct sockaddr_in6 *, int, struct netinfo6 *np);
232269118Sdelphijstatic void sendrequest(struct ifc *);
233219089Spjdstatic int sin6mask2len(const struct sockaddr_in6 *);
234219089Spjdstatic int mask2len(const struct in6_addr *, int);
235185029Spjdstatic int sendpacket(struct sockaddr_in6 *, int);
236219089Spjdstatic int addroute(struct riprt *, const struct in6_addr *, struct ifc *);
237209962Smmstatic int delroute(struct netinfo6 *, struct in6_addr *);
238185029Spjd#if 0
239219089Spjdstatic struct in6_addr *getroute(struct netinfo6 *, struct in6_addr *);
240219089Spjd#endif
241219089Spjdstatic void krtread(int);
242209962Smmstatic int tobeadv(struct riprt *, struct ifc *);
243236155Smmstatic char *allocopy(char *);
244209962Smmstatic char *hms(void);
245209962Smmstatic const char *inet6_n2p(const struct in6_addr *);
246209962Smmstatic struct ifac *ifa_match(const struct ifc *, const struct in6_addr *, int);
247209962Smmstatic struct in6_addr *plen2mask(int);
248209962Smmstatic struct riprt *rtsearch(struct netinfo6 *);
249209962Smmstatic int ripinterval(int);
250209962Smm#if 0
251209962Smmstatic time_t ripsuptrig(void);
252209962Smm#endif
253236884Smmstatic void fatal(const char *, ...)
254236884Smm	__attribute__((__format__(__printf__, 1, 2)));
255236884Smmstatic void trace(int, const char *, ...)
256236884Smm	__attribute__((__format__(__printf__, 2, 3)));
257236884Smmstatic void tracet(int, const char *, ...)
258268079Sdelphij	__attribute__((__format__(__printf__, 2, 3)));
259236884Smmstatic struct ifc *ifc_find(char *);
260268079Sdelphijstatic struct iff *iff_find(struct ifc *, int);
261236884Smmstatic void setindex2ifc(int, struct ifc *);
262236884Smm
263236884Smm#define	MALLOC(type)	((type *)malloc(sizeof(type)))
264236884Smm
265268079Sdelphij#define IFIL_TYPE_ANY	0x0
266268079Sdelphij#define IFIL_TYPE_A	'A'
267268079Sdelphij#define IFIL_TYPE_N	'N'
268268079Sdelphij#define IFIL_TYPE_T	'T'
269268079Sdelphij#define IFIL_TYPE_O	'O'
270268079Sdelphij#define IFIL_TYPE_L	'L'
271268079Sdelphij
272268079Sdelphijint
273236884Smmmain(int argc, char *argv[])
274236884Smm{
275185029Spjd	int	ch;
276185029Spjd	int	error = 0;
277228103Smm	unsigned long proto;
278228103Smm	struct	ifc *ifcp;
279228103Smm	sigset_t mask, omask;
280228103Smm	const char *pidfile = ROUTE6D_PID;
281228103Smm	FILE *pidfh;
282185029Spjd	char *progname;
283185029Spjd	char *ep;
284185029Spjd
285185029Spjd	progname = strrchr(*argv, '/');
286185029Spjd	if (progname)
287185029Spjd		progname++;
288185029Spjd	else
289185029Spjd		progname = *argv;
290185029Spjd
291185029Spjd	pid = getpid();
292185029Spjd	while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnp:P:Q:qsS")) != -1) {
293185029Spjd		switch (ch) {
294185029Spjd		case 'A':
295185029Spjd		case 'N':
296185029Spjd		case 'O':
297185029Spjd		case 'T':
298185029Spjd		case 'L':
299185029Spjd			if (nfilter >= MAXFILTER) {
300185029Spjd				fatal("Exceeds MAXFILTER");
301185029Spjd				/*NOTREACHED*/
302185029Spjd			}
303219089Spjd			filtertype[nfilter] = ch;
304185029Spjd			filter[nfilter++] = allocopy(optarg);
305185029Spjd			break;
306185029Spjd		case 't':
307185029Spjd			ep = NULL;
308185029Spjd			routetag = strtoul(optarg, &ep, 0);
309185029Spjd			if (!ep || *ep != '\0' || (routetag & ~0xffff) != 0) {
310185029Spjd				fatal("invalid route tag");
311185029Spjd				/*NOTREACHED*/
312185029Spjd			}
313185029Spjd			break;
314185029Spjd		case 'p':
315185029Spjd			pidfile = optarg;
316185029Spjd			break;
317185029Spjd		case 'P':
318219089Spjd			ep = NULL;
319185029Spjd			proto = strtoul(optarg, &ep, 0);
320185029Spjd			if (!ep || *ep != '\0' || 3 < proto) {
321185029Spjd				fatal("invalid P flag");
322185029Spjd				/*NOTREACHED*/
323185029Spjd			}
324185029Spjd			if (proto == 0)
325185029Spjd				Pflag = 0;
326185029Spjd			if (proto == 1)
327185029Spjd				Pflag |= RTF_PROTO1;
328185029Spjd			if (proto == 2)
329185029Spjd				Pflag |= RTF_PROTO2;
330185029Spjd			if (proto == 3)
331185029Spjd				Pflag |= RTF_PROTO3;
332185029Spjd			break;
333185029Spjd		case 'Q':
334185029Spjd			ep = NULL;
335185029Spjd			proto = strtoul(optarg, &ep, 0);
336185029Spjd			if (!ep || *ep != '\0' || 3 < proto) {
337185029Spjd				fatal("invalid Q flag");
338185029Spjd				/*NOTREACHED*/
339185029Spjd			}
340185029Spjd			if (proto == 0)
341185029Spjd				Qflag = 0;
342185029Spjd			if (proto == 1)
343185029Spjd				Qflag |= RTF_PROTO1;
344185029Spjd			if (proto == 2)
345185029Spjd				Qflag |= RTF_PROTO2;
346185029Spjd			if (proto == 3)
347185029Spjd				Qflag |= RTF_PROTO3;
348185029Spjd			break;
349248571Smm		case 'R':
350185029Spjd			if ((rtlog = fopen(optarg, "w")) == NULL) {
351185029Spjd				fatal("Can not write to routelog");
352248571Smm				/*NOTREACHED*/
353185029Spjd			}
354185029Spjd			break;
355185029Spjd#define	FLAG(c, flag, n)	case c: do { flag = n; break; } while(0)
356185029Spjd		FLAG('a', aflag, 1); break;
357185029Spjd		FLAG('d', dflag, 1); break;
358185029Spjd		FLAG('D', dflag, 2); break;
359185029Spjd		FLAG('h', hflag, 1); break;
360185029Spjd		FLAG('l', lflag, 1); break;
361248571Smm		FLAG('n', nflag, 1); break;
362185029Spjd		FLAG('q', qflag, 1); break;
363185029Spjd		FLAG('s', sflag, 1); break;
364185029Spjd		FLAG('S', Sflag, 1); break;
365185029Spjd#undef	FLAG
366185029Spjd		default:
367185029Spjd			fatal("Invalid option specified, terminating");
368185029Spjd			/*NOTREACHED*/
369185029Spjd		}
370185029Spjd	}
371185029Spjd	argc -= optind;
372185029Spjd	argv += optind;
373185029Spjd	if (argc > 0) {
374185029Spjd		fatal("bogus extra arguments");
375185029Spjd		/*NOTREACHED*/
376185029Spjd	}
377185029Spjd
378185029Spjd	if (geteuid()) {
379185029Spjd		nflag = 1;
380185029Spjd		fprintf(stderr, "No kernel update is allowed\n");
381185029Spjd	}
382185029Spjd
383185029Spjd	if (dflag == 0) {
384185029Spjd		if (daemon(0, 0) < 0) {
385185029Spjd			fatal("daemon");
386185029Spjd			/*NOTREACHED*/
387185029Spjd		}
388185029Spjd	}
389185029Spjd
390185029Spjd	openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON);
391185029Spjd	logopened++;
392185029Spjd
393185029Spjd	if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL)
394185029Spjd		fatal("malloc");
395185029Spjd	memset(ripbuf, 0, RIP6_MAXMTU);
396185029Spjd	ripbuf->rip6_cmd = RIP6_RESPONSE;
397185029Spjd	ripbuf->rip6_vers = RIP6_VERSION;
398185029Spjd	ripbuf->rip6_res1[0] = 0;
399185029Spjd	ripbuf->rip6_res1[1] = 0;
400185029Spjd
401185029Spjd	init();
402185029Spjd	ifconfig();
403185029Spjd	TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) {
404185029Spjd		if (ifcp->ifc_index < 0) {
405185029Spjd			fprintf(stderr, "No ifindex found at %s "
406185029Spjd			    "(no link-local address?)\n", ifcp->ifc_name);
407185029Spjd			error++;
408185029Spjd		}
409185029Spjd	}
410185029Spjd	if (error)
411185029Spjd		exit(1);
412185029Spjd	if (loopifcp == NULL) {
413247187Smm		fatal("No loopback found");
414236884Smm		/*NOTREACHED*/
415185029Spjd	}
416185029Spjd	TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) {
417185029Spjd		ifrt(ifcp, 0);
418185029Spjd	}
419236884Smm	filterconfig();
420236884Smm	krtread(0);
421236884Smm	if (dflag)
422185029Spjd		ifrtdump(0);
423236884Smm
424236884Smm	pid = getpid();
425236884Smm	if ((pidfh = fopen(pidfile, "w")) != NULL) {
426249195Smm		fprintf(pidfh, "%d\n", pid);
427236884Smm		fclose(pidfh);
428236884Smm	}
429185029Spjd
430236884Smm	if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) {
431236884Smm		fatal("malloc");
432236884Smm		/*NOTREACHED*/
433236884Smm	}
434249195Smm	memset(ripbuf, 0, RIP6_MAXMTU);
435236884Smm	ripbuf->rip6_cmd = RIP6_RESPONSE;
436236884Smm	ripbuf->rip6_vers = RIP6_VERSION;
437185029Spjd	ripbuf->rip6_res1[0] = 0;
438236884Smm	ripbuf->rip6_res1[1] = 0;
439249195Smm
440236884Smm	if (signal(SIGALRM, sighandler) == SIG_ERR ||
441236884Smm	    signal(SIGQUIT, sighandler) == SIG_ERR ||
442236884Smm	    signal(SIGTERM, sighandler) == SIG_ERR ||
443236884Smm	    signal(SIGUSR1, sighandler) == SIG_ERR ||
444249195Smm	    signal(SIGHUP, sighandler) == SIG_ERR ||
445236884Smm	    signal(SIGINT, sighandler) == SIG_ERR) {
446236884Smm		fatal("signal");
447236884Smm		/*NOTREACHED*/
448236884Smm	}
449236884Smm	/*
450249195Smm	 * To avoid rip packet congestion (not on a cable but in this
451236884Smm	 * process), wait for a moment to send the first RIP6_RESPONSE
452236884Smm	 * packets.
453236884Smm	 */
454236884Smm	alarm(ripinterval(INIT_INTERVAL6));
455236884Smm
456236884Smm	TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) {
457185029Spjd		if (iff_find(ifcp, IFIL_TYPE_N) != NULL)
458185029Spjd			continue;
459185029Spjd		if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP))
460236884Smm			sendrequest(ifcp);
461236884Smm	}
462236884Smm
463249195Smm	syslog(LOG_INFO, "**** Started ****");
464185029Spjd	sigemptyset(&mask);
465185029Spjd	sigaddset(&mask, SIGALRM);
466185029Spjd	while (1) {
467185029Spjd		if (seenalrm) {
468185029Spjd			ripalarm();
469219089Spjd			seenalrm = 0;
470185029Spjd			continue;
471185029Spjd		}
472249195Smm		if (seenquit) {
473185029Spjd			rtdexit();
474185029Spjd			seenquit = 0;
475185029Spjd			continue;
476209962Smm		}
477209962Smm		if (seenusr1) {
478209962Smm			ifrtdump(SIGUSR1);
479209962Smm			seenusr1 = 0;
480209962Smm			continue;
481185029Spjd		}
482249195Smm
483185029Spjd#ifdef HAVE_POLL_H
484185029Spjd		switch (poll(set, 2, INFTIM))
485185029Spjd#else
486185029Spjd		memcpy(recvecp, sockvecp, fdmasks);
487185029Spjd		switch (select(maxfd + 1, recvecp, 0, 0, 0))
488185029Spjd#endif
489185029Spjd		{
490249195Smm		case -1:
491185029Spjd			if (errno != EINTR) {
492185029Spjd				fatal("select");
493185029Spjd				/*NOTREACHED*/
494185029Spjd			}
495185029Spjd			continue;
496185029Spjd		case 0:
497185029Spjd			continue;
498185029Spjd		default:
499236884Smm#ifdef HAVE_POLL_H
500185029Spjd			if (set[0].revents & POLLIN)
501185029Spjd#else
502185029Spjd			if (FD_ISSET(ripsock, recvecp))
503185029Spjd#endif
504185029Spjd			{
505185029Spjd				sigprocmask(SIG_BLOCK, &mask, &omask);
506185029Spjd				riprecv();
507185029Spjd				sigprocmask(SIG_SETMASK, &omask, NULL);
508219089Spjd			}
509185029Spjd#ifdef HAVE_POLL_H
510185029Spjd			if (set[1].revents & POLLIN)
511219089Spjd#else
512219089Spjd			if (FD_ISSET(rtsock, recvecp))
513219089Spjd#endif
514249195Smm			{
515248571Smm				sigprocmask(SIG_BLOCK, &mask, &omask);
516248571Smm				rtrecv();
517185029Spjd				sigprocmask(SIG_SETMASK, &omask, NULL);
518248571Smm			}
519185029Spjd		}
520249195Smm	}
521185029Spjd}
522185029Spjd
523185029Spjdstatic void
524219089Spjdsighandler(int signo)
525185029Spjd{
526185029Spjd
527185029Spjd	switch (signo) {
528185029Spjd	case SIGALRM:
529185029Spjd		seenalrm++;
530185029Spjd		break;
531185029Spjd	case SIGQUIT:
532249195Smm	case SIGTERM:
533185029Spjd		seenquit++;
534185029Spjd		break;
535185029Spjd	case SIGUSR1:
536185029Spjd	case SIGHUP:
537185029Spjd	case SIGINT:
538185029Spjd		seenusr1++;
539185029Spjd		break;
540185029Spjd	}
541185029Spjd}
542185029Spjd
543185029Spjd/*
544185029Spjd * gracefully exits after resetting sockopts.
545185029Spjd */
546249195Smm/* ARGSUSED */
547185029Spjdstatic void
548185029Spjdrtdexit(void)
549185029Spjd{
550185029Spjd	struct	riprt *rrt;
551185029Spjd
552185029Spjd	alarm(0);
553185029Spjd	TAILQ_FOREACH(rrt, &riprt_head, rrt_next) {
554185029Spjd		if (rrt->rrt_rflags & RRTF_AGGREGATE) {
555185029Spjd			delroute(&rrt->rrt_info, &rrt->rrt_gw);
556185029Spjd		}
557185029Spjd	}
558185029Spjd	close(ripsock);
559185029Spjd	close(rtsock);
560185029Spjd	syslog(LOG_INFO, "**** Terminated ****");
561249195Smm	closelog();
562185029Spjd	exit(1);
563185029Spjd}
564185029Spjd
565185029Spjd/*
566185029Spjd * Called periodically:
567185029Spjd *	1. age out the learned route. remove it if necessary.
568185029Spjd *	2. submit RIP6_RESPONSE packets.
569185029Spjd * Invoked in every SUPPLY_INTERVAL6 (30) seconds.  I believe we don't have
570249195Smm * to invoke this function in every 1 or 5 or 10 seconds only to age the
571185029Spjd * routes more precisely.
572219089Spjd */
573228103Smm/* ARGSUSED */
574228103Smmstatic void
575228103Smmripalarm(void)
576228103Smm{
577228103Smm	struct	ifc *ifcp;
578228103Smm	struct	riprt *rrt, *rrt_tmp;
579228103Smm	time_t	t_lifetime, t_holddown;
580228103Smm
581228103Smm	/* age the RIP routes */
582228103Smm	t_lifetime = time(NULL) - RIP_LIFETIME;
583228103Smm	t_holddown = t_lifetime - RIP_HOLDDOWN;
584249195Smm	TAILQ_FOREACH_SAFE(rrt, &riprt_head, rrt_next, rrt_tmp) {
585228103Smm		if (rrt->rrt_t == 0)
586228103Smm			continue;
587228103Smm		else if (rrt->rrt_t < t_holddown) {
588228103Smm			TAILQ_REMOVE(&riprt_head, rrt, rrt_next);
589228103Smm			delroute(&rrt->rrt_info, &rrt->rrt_gw);
590228103Smm			free(rrt);
591228103Smm		} else if (rrt->rrt_t < t_lifetime)
592228103Smm			rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
593219089Spjd	}
594219089Spjd	/* Supply updates */
595249195Smm	TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) {
596219089Spjd		if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP))
597219089Spjd			ripsend(ifcp, &ifcp->ifc_ripsin, 0);
598219089Spjd	}
599219089Spjd	alarm(ripinterval(SUPPLY_INTERVAL6));
600249195Smm}
601219089Spjd
602185029Spjdstatic void
603185029Spjdinit(void)
604185029Spjd{
605185029Spjd	int	error;
606185029Spjd	const int int0 = 0, int1 = 1, int255 = 255;
607185029Spjd	struct	addrinfo hints, *res;
608185029Spjd	char	port[NI_MAXSERV];
609185029Spjd
610185029Spjd	TAILQ_INIT(&ifc_head);
611185029Spjd	nindex2ifc = 0;	/*initial guess*/
612185029Spjd	index2ifc = NULL;
613185029Spjd	snprintf(port, sizeof(port), "%u", RIP6_PORT);
614185029Spjd
615185029Spjd	memset(&hints, 0, sizeof(hints));
616185029Spjd	hints.ai_family = PF_INET6;
617185029Spjd	hints.ai_socktype = SOCK_DGRAM;
618185029Spjd	hints.ai_protocol = IPPROTO_UDP;
619185029Spjd	hints.ai_flags = AI_PASSIVE;
620185029Spjd	error = getaddrinfo(NULL, port, &hints, &res);
621209962Smm	if (error) {
622209962Smm		fatal("%s", gai_strerror(error));
623209962Smm		/*NOTREACHED*/
624209962Smm	}
625209962Smm	if (res->ai_next) {
626209962Smm		fatal(":: resolved to multiple address");
627209962Smm		/*NOTREACHED*/
628209962Smm	}
629209962Smm
630209962Smm	ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
631209962Smm	if (ripsock < 0) {
632209962Smm		fatal("rip socket");
633209962Smm		/*NOTREACHED*/
634209962Smm	}
635209962Smm#ifdef IPV6_V6ONLY
636209962Smm	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_V6ONLY,
637209962Smm	    &int1, sizeof(int1)) < 0) {
638209962Smm		fatal("rip IPV6_V6ONLY");
639209962Smm		/*NOTREACHED*/
640209962Smm	}
641209962Smm#endif
642209962Smm	if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0) {
643209962Smm		fatal("rip bind");
644209962Smm		/*NOTREACHED*/
645209962Smm	}
646185029Spjd	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
647185029Spjd	    &int255, sizeof(int255)) < 0) {
648185029Spjd		fatal("rip IPV6_MULTICAST_HOPS");
649185029Spjd		/*NOTREACHED*/
650236884Smm	}
651209962Smm	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
652185029Spjd	    &int0, sizeof(int0)) < 0) {
653185029Spjd		fatal("rip IPV6_MULTICAST_LOOP");
654185029Spjd		/*NOTREACHED*/
655185029Spjd	}
656209962Smm
657236884Smm#ifdef IPV6_RECVPKTINFO
658209962Smm	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
659219089Spjd	    &int1, sizeof(int1)) < 0) {
660219089Spjd		fatal("rip IPV6_RECVPKTINFO");
661219089Spjd		/*NOTREACHED*/
662209962Smm	}
663209962Smm#else  /* old adv. API */
664236884Smm	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_PKTINFO,
665236884Smm	    &int1, sizeof(int1)) < 0) {
666236884Smm		fatal("rip IPV6_PKTINFO");
667236884Smm		/*NOTREACHED*/
668236884Smm	}
669236884Smm#endif
670236884Smm
671236884Smm#ifdef IPV6_RECVPKTINFO
672236884Smm	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
673236884Smm	    &int1, sizeof(int1)) < 0) {
674236884Smm		fatal("rip IPV6_RECVHOPLIMIT");
675236884Smm		/*NOTREACHED*/
676236884Smm	}
677236884Smm#else  /* old adv. API */
678236884Smm	if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_HOPLIMIT,
679236884Smm	    &int1, sizeof(int1)) < 0) {
680236884Smm		fatal("rip IPV6_HOPLIMIT");
681236884Smm		/*NOTREACHED*/
682236884Smm	}
683236884Smm#endif
684236884Smm	freeaddrinfo(res);
685248571Smm
686268473Sdelphij	memset(&hints, 0, sizeof(hints));
687268473Sdelphij	hints.ai_family = PF_INET6;
688236884Smm	hints.ai_socktype = SOCK_DGRAM;
689236884Smm	hints.ai_protocol = IPPROTO_UDP;
690236884Smm	error = getaddrinfo(RIP6_DEST, port, &hints, &res);
691236884Smm	if (error) {
692236884Smm		fatal("%s", gai_strerror(error));
693209962Smm		/*NOTREACHED*/
694209962Smm	}
695209962Smm	if (res->ai_next) {
696209962Smm		fatal("%s resolved to multiple address", RIP6_DEST);
697236884Smm		/*NOTREACHED*/
698248571Smm	}
699268473Sdelphij	memcpy(&ripsin, res->ai_addr, res->ai_addrlen);
700236884Smm	freeaddrinfo(res);
701236884Smm
702236884Smm#ifdef HAVE_POLL_H
703185029Spjd	set[0].fd = ripsock;
704185029Spjd	set[0].events = POLLIN;
705185029Spjd#else
706185029Spjd	maxfd = ripsock;
707185029Spjd#endif
708185029Spjd
709185029Spjd	if (nflag == 0) {
710185029Spjd		if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
711185029Spjd			fatal("route socket");
712185029Spjd			/*NOTREACHED*/
713185029Spjd		}
714185029Spjd#ifdef HAVE_POLL_H
715185029Spjd		set[1].fd = rtsock;
716185029Spjd		set[1].events = POLLIN;
717185029Spjd#else
718185029Spjd		if (rtsock > maxfd)
719239620Smm			maxfd = rtsock;
720239620Smm#endif
721248571Smm	} else {
722239620Smm#ifdef HAVE_POLL_H
723248571Smm		set[1].fd = -1;
724248571Smm#else
725239620Smm		rtsock = -1;	/*just for safety */
726239620Smm#endif
727239620Smm	}
728239620Smm
729239620Smm#ifndef HAVE_POLL_H
730239620Smm	fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask);
731239620Smm	if ((sockvecp = malloc(fdmasks)) == NULL) {
732239620Smm		fatal("malloc");
733249195Smm		/*NOTREACHED*/
734239620Smm	}
735239620Smm	if ((recvecp = malloc(fdmasks)) == NULL) {
736239620Smm		fatal("malloc");
737239620Smm		/*NOTREACHED*/
738239620Smm	}
739239620Smm	memset(sockvecp, 0, fdmasks);
740239620Smm	FD_SET(ripsock, sockvecp);
741248571Smm	if (rtsock >= 0)
742239620Smm		FD_SET(rtsock, sockvecp);
743248571Smm#endif
744248571Smm}
745239620Smm
746239620Smm#define	RIPSIZE(n) \
747239620Smm	(sizeof(struct rip6) + ((n)-1) * sizeof(struct netinfo6))
748239620Smm
749239620Smm/*
750239620Smm * ripflush flushes the rip datagram stored in the rip buffer
751239620Smm */
752239620Smmstatic void
753239620Smmripflush(struct ifc *ifcp, struct sockaddr_in6 *sin6, int nrt, struct netinfo6 *np)
754239620Smm{
755239620Smm	int i;
756248571Smm	int error;
757239620Smm
758239620Smm	if (ifcp)
759239620Smm		tracet(1, "Send(%s): info(%d) to %s.%d\n",
760185029Spjd			ifcp->ifc_name, nrt,
761228103Smm			inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port));
762228103Smm	else
763228103Smm		tracet(1, "Send: info(%d) to %s.%d\n",
764228103Smm			nrt, inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port));
765228103Smm	if (dflag >= 2) {
766228103Smm		np = ripbuf->rip6_nets;
767228103Smm		for (i = 0; i < nrt; i++, np++) {
768228103Smm			if (np->rip6_metric == NEXTHOP_METRIC) {
769228103Smm				if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest))
770228103Smm					trace(2, "    NextHop reset");
771228103Smm				else {
772239620Smm					trace(2, "    NextHop %s",
773239620Smm						inet6_n2p(&np->rip6_dest));
774228103Smm				}
775254074Sdelphij			} else {
776239620Smm				trace(2, "    %s/%d[%d]",
777239620Smm					inet6_n2p(&np->rip6_dest),
778228103Smm					np->rip6_plen, np->rip6_metric);
779248571Smm			}
780268473Sdelphij			if (np->rip6_tag) {
781228103Smm				trace(2, "  tag=0x%04x",
782239620Smm					ntohs(np->rip6_tag) & 0xffff);
783239620Smm			}
784239620Smm			trace(2, "\n");
785239620Smm		}
786228103Smm	}
787239620Smm	error = sendpacket(sin6, RIPSIZE(nrt));
788254074Sdelphij	if (error == EAFNOSUPPORT) {
789228103Smm		/* Protocol not supported */
790239620Smm		if (ifcp != NULL) {
791228103Smm			tracet(1, "Could not send info to %s (%s): "
792228103Smm			    "set IFF_UP to 0\n",
793228103Smm			    ifcp->ifc_name,
794185029Spjd			    inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
795168404Spjd			/* As if down for AF_INET6 */
796168404Spjd			ifcp->ifc_flags &= ~IFF_UP;
797168404Spjd		} else {
798168404Spjd			tracet(1, "Could not send info to %s\n",
799168404Spjd			    inet6_n2p(&sin6->sin6_addr));
800168404Spjd		}
801168404Spjd	}
802168404Spjd}
803168404Spjd
804168404Spjd/*
805168404Spjd * Generate RIP6_RESPONSE packets and send them.
806168404Spjd */
807268123Sdelphijstatic void
808168404Spjdripsend(struct	ifc *ifcp, struct sockaddr_in6 *sin6, int flag)
809168404Spjd{
810168404Spjd	struct	riprt *rrt;
811168404Spjd	struct	in6_addr *nh;	/* next hop */
812168404Spjd	struct netinfo6 *np;
813168404Spjd	int	maxrte;
814168404Spjd	int nrt;
815168404Spjd
816168404Spjd	if (qflag)
817168404Spjd		return;
818168404Spjd
819168404Spjd	if (ifcp == NULL) {
820168404Spjd		/*
821168404Spjd		 * Request from non-link local address is not
822168404Spjd		 * a regular route6d update.
823168404Spjd		 */
824168404Spjd		maxrte = (IFMINMTU - sizeof(struct ip6_hdr) -
825168404Spjd				sizeof(struct udphdr) -
826168404Spjd				sizeof(struct rip6) + sizeof(struct netinfo6)) /
827168404Spjd				sizeof(struct netinfo6);
828168404Spjd		nh = NULL;
829168404Spjd		nrt = 0;
830168404Spjd		np = ripbuf->rip6_nets;
831168404Spjd		TAILQ_FOREACH(rrt, &riprt_head, rrt_next) {
832168404Spjd			if (rrt->rrt_rflags & RRTF_NOADVERTISE)
833168404Spjd				continue;
834168404Spjd			/* Put the route to the buffer */
835168404Spjd			*np = rrt->rrt_info;
836168404Spjd			np++; nrt++;
837258631Savg			if (nrt == maxrte) {
838258631Savg				ripflush(NULL, sin6, nrt, np);
839168404Spjd				nh = NULL;
840258631Savg				nrt = 0;
841258631Savg				np = ripbuf->rip6_nets;
842258631Savg			}
843258631Savg		}
844258631Savg		if (nrt)	/* Send last packet */
845258631Savg			ripflush(NULL, sin6, nrt, np);
846258630Savg		return;
847219089Spjd	}
848168404Spjd
849258631Savg	if ((flag & RRTF_SENDANYWAY) == 0 &&
850258631Savg	    (qflag || (ifcp->ifc_flags & IFF_LOOPBACK)))
851258631Savg		return;
852258631Savg
853258631Savg	/* -N: no use */
854168404Spjd	if (iff_find(ifcp, IFIL_TYPE_N) != NULL)
855258631Savg		return;
856168404Spjd
857258631Savg	/* -T: generate default route only */
858258631Savg	if (iff_find(ifcp, IFIL_TYPE_T) != NULL) {
859219089Spjd		struct netinfo6 rrt_info;
860258632Savg		memset(&rrt_info, 0, sizeof(struct netinfo6));
861258632Savg		rrt_info.rip6_dest = in6addr_any;
862258632Savg		rrt_info.rip6_plen = 0;
863258632Savg		rrt_info.rip6_metric = 1;
864258632Savg		rrt_info.rip6_metric += ifcp->ifc_metric;
865219089Spjd		rrt_info.rip6_tag = htons(routetag & 0xffff);
866258632Savg		np = ripbuf->rip6_nets;
867258632Savg		*np = rrt_info;
868258632Savg		nrt = 1;
869258632Savg		ripflush(ifcp, sin6, nrt, np);
870258632Savg		return;
871219089Spjd	}
872258632Savg
873258632Savg	maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) -
874258632Savg			sizeof(struct udphdr) -
875258632Savg			sizeof(struct rip6) + sizeof(struct netinfo6)) /
876258632Savg			sizeof(struct netinfo6);
877258632Savg
878258631Savg	nrt = 0; np = ripbuf->rip6_nets; nh = NULL;
879258632Savg	TAILQ_FOREACH(rrt, &riprt_head, rrt_next) {
880258632Savg		if (rrt->rrt_rflags & RRTF_NOADVERTISE)
881258631Savg			continue;
882258631Savg
883258631Savg		/* Need to check filter here */
884258631Savg		if (out_filter(rrt, ifcp) == 0)
885258631Savg			continue;
886258631Savg
887258631Savg		/* Check split horizon and other conditions */
888258631Savg		if (tobeadv(rrt, ifcp) == 0)
889258631Savg			continue;
890219089Spjd
891258631Savg		/* Only considers the routes with flag if specified */
892258631Savg		if ((flag & RRTF_CHANGED) &&
893258631Savg		    (rrt->rrt_rflags & RRTF_CHANGED) == 0)
894219089Spjd			continue;
895258631Savg
896258631Savg		/* Check nexthop */
897258631Savg		if (rrt->rrt_index == ifcp->ifc_index &&
898258631Savg		    !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) &&
899258632Savg		    (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) == 0) {
900258632Savg			if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) {
901258632Savg				if (nrt == maxrte - 2) {
902258632Savg					ripflush(ifcp, sin6, nrt, np);
903258632Savg					nh = NULL;
904258632Savg					nrt = 0;
905258632Savg					np = ripbuf->rip6_nets;
906258632Savg				}
907258632Savg
908258632Savg				np->rip6_dest = rrt->rrt_gw;
909258631Savg				np->rip6_plen = 0;
910258631Savg				np->rip6_tag = 0;
911258631Savg				np->rip6_metric = NEXTHOP_METRIC;
912258631Savg				nh = &rrt->rrt_gw;
913258631Savg				np++; nrt++;
914258631Savg			}
915219089Spjd		} else if (nh && (rrt->rrt_index != ifcp->ifc_index ||
916219089Spjd			          !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) ||
917219089Spjd				  rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)) {
918219089Spjd			/* Reset nexthop */
919258631Savg			if (nrt == maxrte - 2) {
920258631Savg				ripflush(ifcp, sin6, nrt, np);
921258631Savg				nh = NULL;
922258631Savg				nrt = 0;
923258631Savg				np = ripbuf->rip6_nets;
924258631Savg			}
925258631Savg			memset(np, 0, sizeof(struct netinfo6));
926258631Savg			np->rip6_metric = NEXTHOP_METRIC;
927258631Savg			nh = NULL;
928258631Savg			np++; nrt++;
929258631Savg		}
930258631Savg
931258631Savg		/* Put the route to the buffer */
932258631Savg		*np = rrt->rrt_info;
933258631Savg		np++; nrt++;
934258631Savg		if (nrt == maxrte) {
935258631Savg			ripflush(ifcp, sin6, nrt, np);
936258631Savg			nh = NULL;
937258631Savg			nrt = 0;
938258631Savg			np = ripbuf->rip6_nets;
939258631Savg		}
940258631Savg	}
941258631Savg	if (nrt)	/* Send last packet */
942258631Savg		ripflush(ifcp, sin6, nrt, np);
943258631Savg}
944258631Savg
945258631Savg/*
946258631Savg * outbound filter logic, per-route/interface.
947258631Savg */
948258631Savgstatic int
949258631Savgout_filter(struct riprt *rrt, struct ifc *ifcp)
950258631Savg{
951258631Savg	struct iff *iffp;
952258631Savg	struct in6_addr ia;
953258631Savg	int ok;
954258631Savg
955258631Savg	/*
956267038Sbdrewery	 * -A: filter out less specific routes, if we have aggregated
957267029Smav	 * route configured.
958267038Sbdrewery	 */
959267038Sbdrewery	TAILQ_FOREACH(iffp, &ifcp->ifc_iff_head, iff_next) {
960267038Sbdrewery		if (iffp->iff_type != 'A')
961258631Savg			continue;
962258631Savg		if (rrt->rrt_info.rip6_plen <= iffp->iff_plen)
963258631Savg			continue;
964258631Savg		ia = rrt->rrt_info.rip6_dest;
965258631Savg		applyplen(&ia, iffp->iff_plen);
966258631Savg		if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr))
967219089Spjd			return 0;
968219089Spjd	}
969185029Spjd
970185029Spjd	/*
971258631Savg	 * if it is an aggregated route, advertise it only to the
972219089Spjd	 * interfaces specified on -A.
973219089Spjd	 */
974219089Spjd	if ((rrt->rrt_rflags & RRTF_AGGREGATE) != 0) {
975209962Smm		ok = 0;
976219089Spjd		TAILQ_FOREACH(iffp, &ifcp->ifc_iff_head, iff_next) {
977219089Spjd			if (iffp->iff_type != 'A')
978219089Spjd				continue;
979219089Spjd			if (rrt->rrt_info.rip6_plen == iffp->iff_plen &&
980219089Spjd			    IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
981219089Spjd			    &iffp->iff_addr)) {
982209962Smm				ok = 1;
983219089Spjd				break;
984219089Spjd			}
985209962Smm		}
986219089Spjd		if (!ok)
987219089Spjd			return 0;
988209962Smm	}
989219089Spjd
990219089Spjd	/*
991219089Spjd	 * -O: advertise only if prefix matches the configured prefix.
992219089Spjd	 */
993211931Smm	if (iff_find(ifcp, IFIL_TYPE_O) != NULL) {
994219089Spjd		ok = 0;
995219089Spjd		TAILQ_FOREACH(iffp, &ifcp->ifc_iff_head, iff_next) {
996219089Spjd			if (iffp->iff_type != 'O')
997219089Spjd				continue;
998219089Spjd			if (rrt->rrt_info.rip6_plen < iffp->iff_plen)
999219089Spjd				continue;
1000219089Spjd			ia = rrt->rrt_info.rip6_dest;
1001219089Spjd			applyplen(&ia, iffp->iff_plen);
1002219089Spjd			if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) {
1003219089Spjd				ok = 1;
1004219089Spjd				break;
1005219089Spjd			}
1006219089Spjd		}
1007219089Spjd		if (!ok)
1008219089Spjd			return 0;
1009219089Spjd	}
1010219089Spjd
1011219089Spjd	/* the prefix should be advertised */
1012219089Spjd	return 1;
1013219089Spjd}
1014219089Spjd
1015219089Spjd/*
1016219089Spjd * Determine if the route is to be advertised on the specified interface.
1017219089Spjd * It checks options specified in the arguments and the split horizon rule.
1018219089Spjd */
1019219089Spjdstatic int
1020219089Spjdtobeadv(struct riprt *rrt, struct ifc *ifcp)
1021219089Spjd{
1022219089Spjd
1023219089Spjd	/* Special care for static routes */
1024219089Spjd	if (rrt->rrt_flags & RTF_STATIC) {
1025219089Spjd		/* XXX don't advertise reject/blackhole routes */
1026219089Spjd		if (rrt->rrt_flags & (RTF_REJECT | RTF_BLACKHOLE))
1027219089Spjd			return 0;
1028219089Spjd
1029219089Spjd		if (Sflag)	/* Yes, advertise it anyway */
1030219089Spjd			return 1;
1031219089Spjd		if (sflag && rrt->rrt_index != ifcp->ifc_index)
1032219089Spjd			return 1;
1033219089Spjd		return 0;
1034219089Spjd	}
1035219089Spjd	/* Regular split horizon */
1036219089Spjd	if (hflag == 0 && rrt->rrt_index == ifcp->ifc_index)
1037219089Spjd		return 0;
1038219089Spjd	return 1;
1039219089Spjd}
1040219089Spjd
1041219089Spjd/*
1042219089Spjd * Send a rip packet actually.
1043219089Spjd */
1044219089Spjdstatic int
1045219089Spjdsendpacket(struct sockaddr_in6 *sin6, int len)
1046219089Spjd{
1047219089Spjd	struct msghdr m;
1048219089Spjd	struct cmsghdr *cm;
1049219089Spjd	struct iovec iov[2];
1050219089Spjd	struct in6_pktinfo *pi;
1051219089Spjd	u_char cmsgbuf[256];
1052219089Spjd	int idx;
1053219089Spjd	struct sockaddr_in6 sincopy;
1054219089Spjd
1055219089Spjd	/* do not overwrite the given sin */
1056219089Spjd	sincopy = *sin6;
1057219089Spjd	sin6 = &sincopy;
1058219089Spjd
1059219089Spjd	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
1060219089Spjd	    IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
1061219089Spjd		idx = sin6->sin6_scope_id;
1062219089Spjd	else
1063219089Spjd		idx = 0;
1064219089Spjd
1065219089Spjd	m.msg_name = (caddr_t)sin6;
1066219089Spjd	m.msg_namelen = sizeof(*sin6);
1067219089Spjd	iov[0].iov_base = (caddr_t)ripbuf;
1068219089Spjd	iov[0].iov_len = len;
1069219089Spjd	m.msg_iov = iov;
1070219089Spjd	m.msg_iovlen = 1;
1071219089Spjd	m.msg_flags = 0;
1072219089Spjd	if (!idx) {
1073219089Spjd		m.msg_control = NULL;
1074219089Spjd		m.msg_controllen = 0;
1075219089Spjd	} else {
1076219089Spjd		memset(cmsgbuf, 0, sizeof(cmsgbuf));
1077219089Spjd		cm = (struct cmsghdr *)(void *)cmsgbuf;
1078219089Spjd		m.msg_control = (caddr_t)cm;
1079219089Spjd		m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
1080219089Spjd
1081209962Smm		cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
1082219089Spjd		cm->cmsg_level = IPPROTO_IPV6;
1083219089Spjd		cm->cmsg_type = IPV6_PKTINFO;
1084219089Spjd		pi = (struct in6_pktinfo *)(void *)CMSG_DATA(cm);
1085219089Spjd		memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/
1086219089Spjd		pi->ipi6_ifindex = idx;
1087219089Spjd	}
1088219089Spjd
1089219089Spjd	if (sendmsg(ripsock, &m, 0 /*MSG_DONTROUTE*/) < 0) {
1090219089Spjd		trace(1, "sendmsg: %s\n", strerror(errno));
1091185029Spjd		return errno;
1092168404Spjd	}
1093219089Spjd
1094219089Spjd	return 0;
1095168404Spjd}
1096219089Spjd
1097219089Spjd/*
1098219089Spjd * Receive and process RIP packets.  Update the routes/kernel forwarding
1099219089Spjd * table if necessary.
1100219089Spjd */
1101219089Spjdstatic void
1102240868Spjdriprecv(void)
1103240868Spjd{
1104240868Spjd	struct	ifc *ifcp, *ic;
1105240868Spjd	struct	sockaddr_in6 fsock;
1106240868Spjd	struct	in6_addr nh;	/* next hop */
1107185029Spjd	struct	rip6 *rp;
1108185029Spjd	struct	netinfo6 *np, *nq;
1109185029Spjd	struct	riprt *rrt;
1110185029Spjd	ssize_t	len, nn;
1111168404Spjd	unsigned int need_trigger, idx;
1112168404Spjd	char	buf[4 * RIP6_MAXMTU];
1113168404Spjd	time_t	t;
1114168404Spjd	struct msghdr m;
1115168404Spjd	struct cmsghdr *cm;
1116168404Spjd	struct iovec iov[2];
1117168404Spjd	u_char cmsgbuf[256];
1118168404Spjd	struct in6_pktinfo *pi = NULL;
1119168404Spjd	int *hlimp = NULL;
1120168404Spjd	struct iff *iffp;
1121168404Spjd	struct in6_addr ia;
1122168404Spjd	int ok;
1123168404Spjd	time_t t_half_lifetime;
1124168404Spjd
1125168404Spjd	need_trigger = 0;
1126168404Spjd
1127168404Spjd	m.msg_name = (caddr_t)&fsock;
1128168404Spjd	m.msg_namelen = sizeof(fsock);
1129168404Spjd	iov[0].iov_base = (caddr_t)buf;
1130168404Spjd	iov[0].iov_len = sizeof(buf);
1131168404Spjd	m.msg_iov = iov;
1132209962Smm	m.msg_iovlen = 1;
1133168404Spjd	cm = (struct cmsghdr *)(void *)cmsgbuf;
1134168404Spjd	m.msg_control = (caddr_t)cm;
1135240868Spjd	m.msg_controllen = sizeof(cmsgbuf);
1136240868Spjd	m.msg_flags = 0;
1137240868Spjd	if ((len = recvmsg(ripsock, &m, 0)) < 0) {
1138240868Spjd		fatal("recvmsg");
1139240868Spjd		/*NOTREACHED*/
1140240868Spjd	}
1141168404Spjd	idx = 0;
1142168404Spjd	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m);
1143185029Spjd	     cm;
1144185029Spjd	     cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) {
1145168404Spjd		if (cm->cmsg_level != IPPROTO_IPV6)
1146185029Spjd		    continue;
1147185029Spjd		switch (cm->cmsg_type) {
1148258631Savg		case IPV6_PKTINFO:
1149185029Spjd			if (cm->cmsg_len != CMSG_LEN(sizeof(*pi))) {
1150168404Spjd				trace(1,
1151168404Spjd				    "invalid cmsg length for IPV6_PKTINFO\n");
1152168404Spjd				return;
1153168404Spjd			}
1154168404Spjd			pi = (struct in6_pktinfo *)(void *)CMSG_DATA(cm);
1155185029Spjd			idx = pi->ipi6_ifindex;
1156185029Spjd			break;
1157185029Spjd		case IPV6_HOPLIMIT:
1158168404Spjd			if (cm->cmsg_len != CMSG_LEN(sizeof(int))) {
1159168404Spjd				trace(1,
1160168404Spjd				    "invalid cmsg length for IPV6_HOPLIMIT\n");
1161168404Spjd				return;
1162168404Spjd			}
1163168404Spjd			hlimp = (int *)(void *)CMSG_DATA(cm);
1164168404Spjd			break;
1165168404Spjd		}
1166168404Spjd	}
1167168404Spjd
1168219089Spjd	if ((size_t)len < sizeof(struct rip6)) {
1169219089Spjd		trace(1, "Packet too short\n");
1170219089Spjd		return;
1171219089Spjd	}
1172219089Spjd
1173219089Spjd	if (pi == NULL || hlimp == NULL) {
1174219089Spjd		/*
1175219089Spjd		 * This can happen when the kernel failed to allocate memory
1176219089Spjd		 * for the ancillary data.  Although we might be able to handle
1177219089Spjd		 * some cases without this info, those are minor and not so
1178219089Spjd		 * important, so it's better to discard the packet for safer
1179219089Spjd		 * operation.
1180219089Spjd		 */
1181219089Spjd		trace(1, "IPv6 packet information cannot be retrieved\n");
1182219089Spjd		return;
1183219089Spjd	}
1184219089Spjd
1185219089Spjd	nh = fsock.sin6_addr;
1186219089Spjd	nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) /
1187219089Spjd		sizeof(struct netinfo6);
1188219089Spjd	rp = (struct rip6 *)(void *)buf;
1189219089Spjd	np = rp->rip6_nets;
1190219089Spjd
1191219089Spjd	if (rp->rip6_vers != RIP6_VERSION) {
1192219089Spjd		trace(1, "Incorrect RIP version %d\n", rp->rip6_vers);
1193219089Spjd		return;
1194219089Spjd	}
1195168404Spjd	if (rp->rip6_cmd == RIP6_REQUEST) {
1196168404Spjd		if (idx && idx < nindex2ifc) {
1197168404Spjd			ifcp = index2ifc[idx];
1198168404Spjd			riprequest(ifcp, np, nn, &fsock);
1199168404Spjd		} else {
1200168404Spjd			riprequest(NULL, np, nn, &fsock);
1201168404Spjd		}
1202168404Spjd		return;
1203168404Spjd	}
1204168404Spjd
1205168404Spjd	if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) {
1206168404Spjd		trace(1, "Response from non-ll addr: %s\n",
1207168404Spjd		    inet6_n2p(&fsock.sin6_addr));
1208219089Spjd		return;		/* Ignore packets from non-link-local addr */
1209168404Spjd	}
1210168404Spjd	if (ntohs(fsock.sin6_port) != RIP6_PORT) {
1211168404Spjd		trace(1, "Response from non-rip port from %s\n",
1212168404Spjd		    inet6_n2p(&fsock.sin6_addr));
1213168404Spjd		return;
1214168404Spjd	}
1215168404Spjd	if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) && *hlimp != 255) {
1216168404Spjd		trace(1,
1217185029Spjd		    "Response packet with a smaller hop limit (%d) from %s\n",
1218185029Spjd		    *hlimp, inet6_n2p(&fsock.sin6_addr));
1219185029Spjd		return;
1220185029Spjd	}
1221185029Spjd	/*
1222185029Spjd	 * Further validation: since this program does not send off-link
1223185029Spjd	 * requests, an incoming response must always come from an on-link
1224168404Spjd	 * node.  Although this is normally ensured by the source address
1225168404Spjd	 * check above, it may not 100% be safe because there are router
1226249195Smm	 * implementations that (invalidly) allow a packet with a link-local
1227168404Spjd	 * source address to be forwarded to a different link.
1228168404Spjd	 * So we also check whether the destination address is a link-local
1229219089Spjd	 * address or the hop limit is 255.  Note that RFC2080 does not require
1230168404Spjd	 * the specific hop limit for a unicast response, so we cannot assume
1231168404Spjd	 * the limitation.
1232168404Spjd	 */
1233168404Spjd	if (!IN6_IS_ADDR_LINKLOCAL(&pi->ipi6_addr) && *hlimp != 255) {
1234168404Spjd		trace(1,
1235168404Spjd		    "Response packet possibly from an off-link node: "
1236168404Spjd		    "from %s to %s hlim=%d\n",
1237168404Spjd		    inet6_n2p(&fsock.sin6_addr),
1238168404Spjd		    inet6_n2p(&pi->ipi6_addr), *hlimp);
1239168404Spjd		return;
1240168404Spjd	}
1241168404Spjd
1242168404Spjd	idx = fsock.sin6_scope_id;
1243168404Spjd	ifcp = (idx < nindex2ifc) ? index2ifc[idx] : NULL;
1244168404Spjd	if (!ifcp) {
1245168404Spjd		trace(1, "Packets to unknown interface index %d\n", idx);
1246168404Spjd		return;		/* Ignore it */
1247168404Spjd	}
1248168404Spjd	if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr))
1249168404Spjd		return;		/* The packet is from me; ignore */
1250168404Spjd	if (rp->rip6_cmd != RIP6_RESPONSE) {
1251168404Spjd		trace(1, "Invalid command %d\n", rp->rip6_cmd);
1252185029Spjd		return;
1253185029Spjd	}
1254168404Spjd
1255240868Spjd	/* -N: no use */
1256240868Spjd	if (iff_find(ifcp, IFIL_TYPE_N) != NULL)
1257240868Spjd		return;
1258240868Spjd
1259240868Spjd	tracet(1, "Recv(%s): from %s.%d info(%zd)\n",
1260168404Spjd	    ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn);
1261168404Spjd
1262168404Spjd	t = time(NULL);
1263168404Spjd	t_half_lifetime = t - (RIP_LIFETIME/2);
1264168404Spjd	for (; nn; nn--, np++) {
1265168404Spjd		if (np->rip6_metric == NEXTHOP_METRIC) {
1266168404Spjd			/* modify neighbor address */
1267168404Spjd			if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) {
1268168404Spjd				nh = np->rip6_dest;
1269168404Spjd				trace(1, "\tNexthop: %s\n", inet6_n2p(&nh));
1270168404Spjd			} else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) {
1271168404Spjd				nh = fsock.sin6_addr;
1272168404Spjd				trace(1, "\tNexthop: %s\n", inet6_n2p(&nh));
1273185029Spjd			} else {
1274168404Spjd				nh = fsock.sin6_addr;
1275209962Smm				trace(1, "\tInvalid Nexthop: %s\n",
1276209962Smm				    inet6_n2p(&np->rip6_dest));
1277209962Smm			}
1278209962Smm			continue;
1279168404Spjd		}
1280219089Spjd		if (IN6_IS_ADDR_MULTICAST(&np->rip6_dest)) {
1281219089Spjd			trace(1, "\tMulticast netinfo6: %s/%d [%d]\n",
1282258717Savg				inet6_n2p(&np->rip6_dest),
1283258717Savg				np->rip6_plen, np->rip6_metric);
1284168404Spjd			continue;
1285258717Savg		}
1286258717Savg		if (IN6_IS_ADDR_LOOPBACK(&np->rip6_dest)) {
1287258717Savg			trace(1, "\tLoopback netinfo6: %s/%d [%d]\n",
1288258717Savg				inet6_n2p(&np->rip6_dest),
1289258717Savg				np->rip6_plen, np->rip6_metric);
1290258717Savg			continue;
1291258717Savg		}
1292168404Spjd		if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) {
1293168404Spjd			trace(1, "\tLink Local netinfo6: %s/%d [%d]\n",
1294168404Spjd				inet6_n2p(&np->rip6_dest),
1295168404Spjd				np->rip6_plen, np->rip6_metric);
1296168404Spjd			continue;
1297219089Spjd		}
1298168404Spjd		/* may need to pass sitelocal prefix in some case, however*/
1299168404Spjd		if (IN6_IS_ADDR_SITELOCAL(&np->rip6_dest) && !lflag) {
1300219089Spjd			trace(1, "\tSite Local netinfo6: %s/%d [%d]\n",
1301219089Spjd				inet6_n2p(&np->rip6_dest),
1302209962Smm				np->rip6_plen, np->rip6_metric);
1303168404Spjd			continue;
1304209962Smm		}
1305209962Smm		trace(2, "\tnetinfo6: %s/%d [%d]",
1306209962Smm			inet6_n2p(&np->rip6_dest),
1307209962Smm			np->rip6_plen, np->rip6_metric);
1308185029Spjd		if (np->rip6_tag)
1309185029Spjd			trace(2, "  tag=0x%04x", ntohs(np->rip6_tag) & 0xffff);
1310185029Spjd		if (dflag >= 2) {
1311185029Spjd			ia = np->rip6_dest;
1312185029Spjd			applyplen(&ia, np->rip6_plen);
1313185029Spjd			if (!IN6_ARE_ADDR_EQUAL(&ia, &np->rip6_dest))
1314168404Spjd				trace(2, " [junk outside prefix]");
1315185029Spjd		}
1316185029Spjd
1317185029Spjd		/*
1318168404Spjd		 * -L: listen only if the prefix matches the configuration
1319185029Spjd		 */
1320168404Spjd                ok = 1;	/* if there's no L filter, it is ok */
1321230514Smm                TAILQ_FOREACH(iffp, &ifcp->ifc_iff_head, iff_next) {
1322230514Smm                        if (iffp->iff_type != IFIL_TYPE_L)
1323185029Spjd                                continue;
1324230514Smm                        ok = 0;
1325185029Spjd                        if (np->rip6_plen < iffp->iff_plen)
1326185029Spjd                                continue;
1327185029Spjd                        /* special rule: ::/0 means default, not "in /0" */
1328185029Spjd                        if (iffp->iff_plen == 0 && np->rip6_plen > 0)
1329185029Spjd                                continue;
1330185029Spjd                        ia = np->rip6_dest;
1331185029Spjd                        applyplen(&ia, iffp->iff_plen);
1332185029Spjd                        if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) {
1333185029Spjd                                ok = 1;
1334185029Spjd                                break;
1335185029Spjd                        }
1336168404Spjd                }
1337209962Smm		if (!ok) {
1338228103Smm			trace(2, "  (filtered)\n");
1339228103Smm			continue;
1340228103Smm		}
1341228103Smm
1342228103Smm		trace(2, "\n");
1343209962Smm		np->rip6_metric++;
1344168404Spjd		np->rip6_metric += ifcp->ifc_metric;
1345168404Spjd		if (np->rip6_metric > HOPCNT_INFINITY6)
1346168404Spjd			np->rip6_metric = HOPCNT_INFINITY6;
1347168404Spjd
1348168404Spjd		applyplen(&np->rip6_dest, np->rip6_plen);
1349185029Spjd		if ((rrt = rtsearch(np)) != NULL) {
1350185029Spjd			if (rrt->rrt_t == 0)
1351168404Spjd				continue;	/* Intf route has priority */
1352168404Spjd			nq = &rrt->rrt_info;
1353168404Spjd			if (nq->rip6_metric > np->rip6_metric) {
1354168404Spjd				if (rrt->rrt_index == ifcp->ifc_index &&
1355168404Spjd				    IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
1356168404Spjd					/* Small metric from the same gateway */
1357168404Spjd					nq->rip6_metric = np->rip6_metric;
1358168404Spjd				} else {
1359168404Spjd					/* Better route found */
1360185029Spjd					rrt->rrt_index = ifcp->ifc_index;
1361185029Spjd					/* Update routing table */
1362168404Spjd					delroute(nq, &rrt->rrt_gw);
1363168404Spjd					rrt->rrt_gw = nh;
1364168404Spjd					*nq = *np;
1365185029Spjd					addroute(rrt, &nh, ifcp);
1366185029Spjd				}
1367168404Spjd				rrt->rrt_rflags |= RRTF_CHANGED;
1368168404Spjd				rrt->rrt_t = t;
1369185029Spjd				need_trigger = 1;
1370185029Spjd			} else if (nq->rip6_metric < np->rip6_metric &&
1371168404Spjd				   rrt->rrt_index == ifcp->ifc_index &&
1372168404Spjd				   IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
1373168404Spjd				/* Got worse route from same gw */
1374168404Spjd				nq->rip6_metric = np->rip6_metric;
1375168404Spjd				rrt->rrt_t = t;
1376185029Spjd				rrt->rrt_rflags |= RRTF_CHANGED;
1377185029Spjd				need_trigger = 1;
1378185029Spjd			} else if (nq->rip6_metric == np->rip6_metric &&
1379168404Spjd				   np->rip6_metric < HOPCNT_INFINITY6) {
1380185029Spjd				if (rrt->rrt_index == ifcp->ifc_index &&
1381168404Spjd				   IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
1382168404Spjd					/* same metric, same route from same gw */
1383185029Spjd					rrt->rrt_t = t;
1384168404Spjd				} else if (rrt->rrt_t < t_half_lifetime) {
1385168404Spjd					/* Better route found */
1386185029Spjd					rrt->rrt_index = ifcp->ifc_index;
1387185029Spjd					/* Update routing table */
1388168404Spjd					delroute(nq, &rrt->rrt_gw);
1389168404Spjd					rrt->rrt_gw = nh;
1390168404Spjd					*nq = *np;
1391168404Spjd					addroute(rrt, &nh, ifcp);
1392168404Spjd					rrt->rrt_rflags |= RRTF_CHANGED;
1393168404Spjd					rrt->rrt_t = t;
1394168404Spjd				}
1395168404Spjd			}
1396168404Spjd			/*
1397168404Spjd			 * if nq->rip6_metric == HOPCNT_INFINITY6 then
1398168404Spjd			 * do not update age value.  Do nothing.
1399168404Spjd			 */
1400168404Spjd		} else if (np->rip6_metric < HOPCNT_INFINITY6) {
1401185029Spjd			/* Got a new valid route */
1402185029Spjd			if ((rrt = MALLOC(struct riprt)) == NULL) {
1403185029Spjd				fatal("malloc: struct riprt");
1404168404Spjd				/*NOTREACHED*/
1405168404Spjd			}
1406168404Spjd			memset(rrt, 0, sizeof(*rrt));
1407168404Spjd			nq = &rrt->rrt_info;
1408185029Spjd
1409168404Spjd			rrt->rrt_same = NULL;
1410185029Spjd			rrt->rrt_index = ifcp->ifc_index;
1411185029Spjd			rrt->rrt_flags = RTF_UP|RTF_GATEWAY;
1412168404Spjd			rrt->rrt_gw = nh;
1413168404Spjd			*nq = *np;
1414168404Spjd			applyplen(&nq->rip6_dest, nq->rip6_plen);
1415168404Spjd			if (nq->rip6_plen == sizeof(struct in6_addr) * 8)
1416168404Spjd				rrt->rrt_flags |= RTF_HOST;
1417168404Spjd
1418168404Spjd			/* Update routing table */
1419168404Spjd			addroute(rrt, &nh, ifcp);
1420168404Spjd			rrt->rrt_rflags |= RRTF_CHANGED;
1421168404Spjd			need_trigger = 1;
1422168404Spjd			rrt->rrt_t = t;
1423168404Spjd
1424168404Spjd			/* Put the route to the list */
1425168404Spjd			TAILQ_INSERT_HEAD(&riprt_head, rrt, rrt_next);
1426168404Spjd		}
1427168404Spjd	}
1428168404Spjd	/* XXX need to care the interval between triggered updates */
1429168404Spjd	if (need_trigger) {
1430168404Spjd		if (nextalarm > time(NULL) + RIP_TRIG_INT6_MAX) {
1431168404Spjd			TAILQ_FOREACH(ic, &ifc_head, ifc_next) {
1432185029Spjd				if (ifcp->ifc_index == ic->ifc_index)
1433209962Smm					continue;
1434185029Spjd				if (ic->ifc_flags & IFF_UP)
1435168404Spjd					ripsend(ic, &ic->ifc_ripsin,
1436168404Spjd						RRTF_CHANGED);
1437168404Spjd			}
1438185029Spjd		}
1439185029Spjd		/* Reset the flag */
1440168404Spjd		TAILQ_FOREACH(rrt, &riprt_head, rrt_next) {
1441168404Spjd			rrt->rrt_rflags &= ~RRTF_CHANGED;
1442168404Spjd		}
1443168404Spjd	}
1444168404Spjd}
1445168404Spjd
1446185029Spjd/*
1447168404Spjd * Send all routes request packet to the specified interface.
1448168404Spjd */
1449185029Spjdstatic void
1450185029Spjdsendrequest(struct ifc *ifcp)
1451185029Spjd{
1452185029Spjd	struct netinfo6 *np;
1453219089Spjd	int error;
1454185029Spjd
1455185029Spjd	if (ifcp->ifc_flags & IFF_LOOPBACK)
1456185029Spjd		return;
1457168404Spjd	ripbuf->rip6_cmd = RIP6_REQUEST;
1458185029Spjd	np = ripbuf->rip6_nets;
1459168404Spjd	memset(np, 0, sizeof(struct netinfo6));
1460168404Spjd	np->rip6_metric = HOPCNT_INFINITY6;
1461185029Spjd	tracet(1, "Send rtdump Request to %s (%s)\n",
1462185029Spjd		ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
1463185029Spjd	error = sendpacket(&ifcp->ifc_ripsin, RIPSIZE(1));
1464185029Spjd	if (error == EAFNOSUPPORT) {
1465185029Spjd		/* Protocol not supported */
1466185029Spjd		tracet(1, "Could not send rtdump Request to %s (%s): "
1467185029Spjd			"set IFF_UP to 0\n",
1468185029Spjd			ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
1469185029Spjd		ifcp->ifc_flags &= ~IFF_UP;	/* As if down for AF_INET6 */
1470185029Spjd	}
1471185029Spjd	ripbuf->rip6_cmd = RIP6_RESPONSE;
1472185029Spjd}
1473185029Spjd
1474185029Spjd/*
1475219089Spjd * Process a RIP6_REQUEST packet.
1476185029Spjd */
1477185029Spjdstatic void
1478185029Spjdriprequest(struct ifc *ifcp,
1479185029Spjd	struct netinfo6 *np,
1480185029Spjd	int nn,
1481185029Spjd	struct sockaddr_in6 *sin6)
1482185029Spjd{
1483185029Spjd	int i;
1484185029Spjd	struct riprt *rrt;
1485185029Spjd
1486185029Spjd	if (!(nn == 1 && IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest) &&
1487247187Smm	      np->rip6_plen == 0 && np->rip6_metric == HOPCNT_INFINITY6)) {
1488185029Spjd		/* Specific response, don't split-horizon */
1489185029Spjd		trace(1, "\tRIP Request\n");
1490185029Spjd		for (i = 0; i < nn; i++, np++) {
1491185029Spjd			rrt = rtsearch(np);
1492185029Spjd			if (rrt)
1493185029Spjd				np->rip6_metric = rrt->rrt_info.rip6_metric;
1494185029Spjd			else
1495185029Spjd				np->rip6_metric = HOPCNT_INFINITY6;
1496185029Spjd		}
1497185029Spjd		(void)sendpacket(sin6, RIPSIZE(nn));
1498185029Spjd		return;
1499185029Spjd	}
1500185029Spjd	/* Whole routing table dump */
1501185029Spjd	trace(1, "\tRIP Request -- whole routing table\n");
1502185029Spjd	ripsend(ifcp, sin6, RRTF_SENDANYWAY);
1503185029Spjd}
1504185029Spjd
1505185029Spjd/*
1506185029Spjd * Get information of each interface.
1507185029Spjd */
1508185029Spjdstatic void
1509185029Spjdifconfig(void)
1510185029Spjd{
1511185029Spjd	struct ifaddrs *ifap, *ifa;
1512185029Spjd	struct ifc *ifcp;
1513185029Spjd	struct ipv6_mreq mreq;
1514185029Spjd	int s;
1515185029Spjd
1516185029Spjd	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1517185029Spjd		fatal("socket");
1518185029Spjd		/*NOTREACHED*/
1519185029Spjd	}
1520185029Spjd
1521185029Spjd	if (getifaddrs(&ifap) != 0) {
1522185029Spjd		fatal("getifaddrs");
1523185029Spjd		/*NOTREACHED*/
1524185029Spjd	}
1525185029Spjd
1526185029Spjd	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1527185029Spjd		if (ifa->ifa_addr->sa_family != AF_INET6)
1528185029Spjd			continue;
1529185029Spjd		ifcp = ifc_find(ifa->ifa_name);
1530185029Spjd		/* we are interested in multicast-capable interfaces */
1531185029Spjd		if ((ifa->ifa_flags & IFF_MULTICAST) == 0)
1532185029Spjd			continue;
1533185029Spjd		if (!ifcp) {
1534185029Spjd			/* new interface */
1535185029Spjd			if ((ifcp = MALLOC(struct ifc)) == NULL) {
1536185029Spjd				fatal("malloc: struct ifc");
1537185029Spjd				/*NOTREACHED*/
1538185029Spjd			}
1539185029Spjd			memset(ifcp, 0, sizeof(*ifcp));
1540219089Spjd
1541219089Spjd			ifcp->ifc_index = -1;
1542185029Spjd			strlcpy(ifcp->ifc_name, ifa->ifa_name,
1543185029Spjd			    sizeof(ifcp->ifc_name));
1544185029Spjd			TAILQ_INIT(&ifcp->ifc_ifac_head);
1545185029Spjd			TAILQ_INIT(&ifcp->ifc_iff_head);
1546185029Spjd			ifcp->ifc_flags = ifa->ifa_flags;
1547185029Spjd			TAILQ_INSERT_HEAD(&ifc_head, ifcp, ifc_next);
1548185029Spjd			trace(1, "newif %s <%s>\n", ifcp->ifc_name,
1549185029Spjd				ifflags(ifcp->ifc_flags));
1550185029Spjd			if (!strcmp(ifcp->ifc_name, LOOPBACK_IF))
1551185029Spjd				loopifcp = ifcp;
1552185029Spjd		} else {
1553230514Smm			/* update flag, this may be up again */
1554230514Smm			if (ifcp->ifc_flags != ifa->ifa_flags) {
1555209962Smm				trace(1, "%s: <%s> -> ", ifcp->ifc_name,
1556209962Smm					ifflags(ifcp->ifc_flags));
1557185029Spjd				trace(1, "<%s>\n", ifflags(ifa->ifa_flags));
1558230514Smm				ifcp->ifc_cflags |= IFC_CHANGED;
1559230514Smm			}
1560185029Spjd			ifcp->ifc_flags = ifa->ifa_flags;
1561185029Spjd		}
1562185029Spjd		if (ifconfig1(ifa->ifa_name, ifa->ifa_addr, ifcp, s) < 0) {
1563185029Spjd			/* maybe temporary failure */
1564185029Spjd			continue;
1565185029Spjd		}
1566185029Spjd		if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP
1567185029Spjd		 && 0 < ifcp->ifc_index && !ifcp->ifc_joined) {
1568185029Spjd			mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr;
1569185029Spjd			mreq.ipv6mr_interface = ifcp->ifc_index;
1570185029Spjd			if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
1571185029Spjd			    &mreq, sizeof(mreq)) < 0) {
1572185029Spjd				fatal("IPV6_JOIN_GROUP");
1573185029Spjd				/*NOTREACHED*/
1574185029Spjd			}
1575185029Spjd			trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST);
1576185029Spjd			ifcp->ifc_joined++;
1577185029Spjd		}
1578185029Spjd	}
1579185029Spjd	close(s);
1580185029Spjd	freeifaddrs(ifap);
1581185029Spjd}
1582219089Spjd
1583185029Spjdstatic int
1584185029Spjdifconfig1(const char *name,
1585185029Spjd	const struct sockaddr *sa,
1586185029Spjd	struct ifc *ifcp,
1587185029Spjd	int s)
1588185029Spjd{
1589185029Spjd	struct	in6_ifreq ifr;
1590185029Spjd	const struct sockaddr_in6 *sin6;
1591185029Spjd	struct	ifac *ifac;
1592168404Spjd	int	plen;
1593168404Spjd	char	buf[BUFSIZ];
1594168404Spjd
1595168404Spjd	sin6 = (const struct sockaddr_in6 *)(const void *)sa;
1596168404Spjd	if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) && !lflag)
1597168404Spjd		return (-1);
1598168404Spjd	ifr.ifr_addr = *sin6;
1599168404Spjd	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1600168404Spjd	if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0) {
1601262676Sdelphij		syslog(LOG_INFO, "ioctl: SIOCGIFNETMASK_IN6");
1602262676Sdelphij		return (-1);
1603262676Sdelphij	}
1604168404Spjd	plen = sin6mask2len(&ifr.ifr_addr);
1605168404Spjd	if ((ifac = ifa_match(ifcp, &sin6->sin6_addr, plen)) != NULL) {
1606168404Spjd		/* same interface found */
1607168404Spjd		/* need check if something changed */
1608209962Smm		/* XXX not yet implemented */
1609209962Smm		return (-1);
1610168404Spjd	}
1611168404Spjd	/*
1612168404Spjd	 * New address is found
1613168404Spjd	 */
1614168404Spjd	if ((ifac = MALLOC(struct ifac)) == NULL) {
1615168404Spjd		fatal("malloc: struct ifac");
1616168404Spjd		/*NOTREACHED*/
1617168404Spjd	}
1618185029Spjd	memset(ifac, 0, sizeof(*ifac));
1619185029Spjd
1620185029Spjd	ifac->ifac_ifc = ifcp;
1621185029Spjd	ifac->ifac_addr = sin6->sin6_addr;
1622185029Spjd	ifac->ifac_plen = plen;
1623185029Spjd	ifac->ifac_scope_id = sin6->sin6_scope_id;
1624219089Spjd	if (ifcp->ifc_flags & IFF_POINTOPOINT) {
1625185029Spjd		ifr.ifr_addr = *sin6;
1626185029Spjd		if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0) {
1627249188Smm			fatal("ioctl: SIOCGIFDSTADDR_IN6");
1628249188Smm			/*NOTREACHED*/
1629185029Spjd		}
1630185029Spjd		ifac->ifac_raddr = ifr.ifr_dstaddr.sin6_addr;
1631185029Spjd		inet_ntop(AF_INET6, (void *)&ifac->ifac_raddr, buf,
1632185029Spjd		    sizeof(buf));
1633185029Spjd		trace(1, "found address %s/%d -- %s\n",
1634185029Spjd			inet6_n2p(&ifac->ifac_addr), ifac->ifac_plen, buf);
1635219089Spjd	} else {
1636213197Smm		trace(1, "found address %s/%d\n",
1637219089Spjd			inet6_n2p(&ifac->ifac_addr), ifac->ifac_plen);
1638219089Spjd	}
1639213197Smm	if (ifcp->ifc_index < 0 && IN6_IS_ADDR_LINKLOCAL(&ifac->ifac_addr)) {
1640219089Spjd		ifcp->ifc_mylladdr = ifac->ifac_addr;
1641219089Spjd		ifcp->ifc_index = ifac->ifac_scope_id;
1642213197Smm		memcpy(&ifcp->ifc_ripsin, &ripsin, ripsin.ss_len);
1643219089Spjd		ifcp->ifc_ripsin.sin6_scope_id = ifcp->ifc_index;
1644213197Smm		setindex2ifc(ifcp->ifc_index, ifcp);
1645219089Spjd		ifcp->ifc_mtu = getifmtu(ifcp->ifc_index);
1646219089Spjd		if (ifcp->ifc_mtu > RIP6_MAXMTU)
1647219089Spjd			ifcp->ifc_mtu = RIP6_MAXMTU;
1648219089Spjd		if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0) {
1649219089Spjd			fatal("ioctl: SIOCGIFMETRIC");
1650219089Spjd			/*NOTREACHED*/
1651219089Spjd		}
1652219089Spjd		ifcp->ifc_metric = ifr.ifr_metric;
1653219089Spjd		trace(1, "\tindex: %d, mtu: %d, metric: %d\n",
1654219089Spjd			ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric);
1655219089Spjd	} else
1656219089Spjd		ifcp->ifc_cflags |= IFC_CHANGED;
1657219089Spjd
1658219089Spjd	TAILQ_INSERT_HEAD(&ifcp->ifc_ifac_head, ifac, ifac_next);
1659219089Spjd
1660219089Spjd	return 0;
1661219089Spjd}
1662219089Spjd
1663219089Spjdstatic void
1664219089Spjdifremove(int ifindex)
1665219089Spjd{
1666219089Spjd	struct ifc *ifcp;
1667219089Spjd	struct riprt *rrt;
1668219089Spjd
1669219089Spjd	TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) {
1670219089Spjd		if (ifcp->ifc_index == ifindex)
1671219089Spjd			break;
1672219089Spjd	}
1673219089Spjd	if (ifcp == NULL)
1674219089Spjd		return;
1675219089Spjd
1676219089Spjd	tracet(1, "ifremove: %s is departed.\n", ifcp->ifc_name);
1677219089Spjd	TAILQ_REMOVE(&ifc_head, ifcp, ifc_next);
1678219089Spjd
1679219089Spjd	TAILQ_FOREACH(rrt, &riprt_head, rrt_next) {
1680219089Spjd		if (rrt->rrt_index == ifcp->ifc_index &&
1681219089Spjd		    rrt->rrt_rflags & RRTF_AGGREGATE)
1682219089Spjd			delroute(&rrt->rrt_info, &rrt->rrt_gw);
1683219089Spjd	}
1684219089Spjd	free(ifcp);
1685219089Spjd}
1686219089Spjd
1687219089Spjd/*
1688219089Spjd * Receive and process routing messages.
1689219089Spjd * Update interface information as necessary.
1690219089Spjd */
1691219089Spjdstatic void
1692219089Spjdrtrecv(void)
1693213197Smm{
1694219089Spjd	char buf[BUFSIZ];
1695213197Smm	char *p, *q = NULL;
1696219089Spjd	struct rt_msghdr *rtm;
1697219089Spjd	struct ifa_msghdr *ifam;
1698219089Spjd	struct if_msghdr *ifm;
1699219089Spjd	struct if_announcemsghdr *ifan;
1700219089Spjd	int len;
1701219089Spjd	struct ifc *ifcp, *ic;
1702219089Spjd	int iface = 0, rtable = 0;
1703219089Spjd	struct sockaddr_in6 *rta[RTAX_MAX];
1704219089Spjd	struct sockaddr_in6 mask;
1705219089Spjd	int i, addrs = 0;
1706219089Spjd	struct riprt *rrt;
1707219089Spjd
1708219089Spjd	if ((len = read(rtsock, buf, sizeof(buf))) < 0) {
1709219089Spjd		perror("read from rtsock");
1710219089Spjd		exit(1);
1711219089Spjd	}
1712219089Spjd	if (len == 0)
1713219089Spjd		return;
1714219089Spjd#if 0
1715219089Spjd	if (len < sizeof(*rtm)) {
1716219089Spjd		trace(1, "short read from rtsock: %d (should be > %lu)\n",
1717219089Spjd			len, (u_long)sizeof(*rtm));
1718219089Spjd		return;
1719219089Spjd	}
1720219089Spjd#endif
1721219089Spjd	if (dflag >= 2) {
1722219089Spjd		fprintf(stderr, "rtmsg:\n");
1723219089Spjd		for (i = 0; i < len; i++) {
1724219089Spjd			fprintf(stderr, "%02x ", buf[i] & 0xff);
1725219089Spjd			if (i % 16 == 15) fprintf(stderr, "\n");
1726219089Spjd		}
1727219089Spjd		fprintf(stderr, "\n");
1728219089Spjd	}
1729219089Spjd
1730219089Spjd	for (p = buf; p - buf < len; p +=
1731219089Spjd	    ((struct rt_msghdr *)(void *)p)->rtm_msglen) {
1732219089Spjd		if (((struct rt_msghdr *)(void *)p)->rtm_version != RTM_VERSION)
1733219089Spjd			continue;
1734219089Spjd
1735219089Spjd		/* safety against bogus message */
1736219089Spjd		if (((struct rt_msghdr *)(void *)p)->rtm_msglen <= 0) {
1737219089Spjd			trace(1, "bogus rtmsg: length=%d\n",
1738219089Spjd				((struct rt_msghdr *)(void *)p)->rtm_msglen);
1739219089Spjd			break;
1740219089Spjd		}
1741219089Spjd		rtm = NULL;
1742219089Spjd		ifam = NULL;
1743219089Spjd		ifm = NULL;
1744219089Spjd		switch (((struct rt_msghdr *)(void *)p)->rtm_type) {
1745219089Spjd		case RTM_NEWADDR:
1746213197Smm		case RTM_DELADDR:
1747219089Spjd			ifam = (struct ifa_msghdr *)(void *)p;
1748219089Spjd			addrs = ifam->ifam_addrs;
1749219089Spjd			q = (char *)(ifam + 1);
1750219089Spjd			break;
1751219089Spjd		case RTM_IFINFO:
1752219089Spjd			ifm = (struct if_msghdr *)(void *)p;
1753219089Spjd			addrs = ifm->ifm_addrs;
1754213197Smm			q = (char *)(ifm + 1);
1755213197Smm			break;
1756213197Smm		case RTM_IFANNOUNCE:
1757185029Spjd			ifan = (struct if_announcemsghdr *)(void *)p;
1758185029Spjd			switch (ifan->ifan_what) {
1759248571Smm			case IFAN_ARRIVAL:
1760185029Spjd				iface++;
1761185029Spjd				break;
1762248571Smm			case IFAN_DEPARTURE:
1763248571Smm				ifremove(ifan->ifan_index);
1764185029Spjd				iface++;
1765185029Spjd				break;
1766185029Spjd			}
1767185029Spjd			break;
1768248571Smm		default:
1769248571Smm			rtm = (struct rt_msghdr *)(void *)p;
1770248571Smm			if (rtm->rtm_version != RTM_VERSION) {
1771219089Spjd				trace(1, "unexpected rtmsg version %d "
1772185029Spjd					"(should be %d)\n",
1773185029Spjd					rtm->rtm_version, RTM_VERSION);
1774248571Smm				continue;
1775185029Spjd			}
1776185029Spjd			/*
1777219089Spjd			 * Only messages that use the struct rt_msghdr
1778219089Spjd			 * format are allowed beyond this point.
1779219089Spjd			 */
1780219089Spjd			if (rtm->rtm_type > RTM_RESOLVE) {
1781219089Spjd				trace(1, "rtmsg type %d ignored\n",
1782219089Spjd					rtm->rtm_type);
1783219089Spjd				continue;
1784219089Spjd			}
1785219089Spjd			addrs = rtm->rtm_addrs;
1786219089Spjd			q = (char *)(rtm + 1);
1787219089Spjd			if (rtm->rtm_pid == pid) {
1788219089Spjd#if 0
1789219089Spjd				trace(1, "rtmsg looped back to me, ignored\n");
1790219089Spjd#endif
1791219089Spjd				continue;
1792219089Spjd			}
1793219089Spjd			break;
1794219089Spjd		}
1795219089Spjd		memset(&rta, 0, sizeof(rta));
1796219089Spjd		for (i = 0; i < RTAX_MAX; i++) {
1797219089Spjd			if (addrs & (1 << i)) {
1798219089Spjd				rta[i] = (struct sockaddr_in6 *)(void *)q;
1799219089Spjd				q += ROUNDUP(rta[i]->sin6_len);
1800219089Spjd			}
1801219089Spjd		}
1802219089Spjd
1803219089Spjd		trace(1, "rtsock: %s (addrs=%x)\n",
1804219089Spjd			rttypes((struct rt_msghdr *)(void *)p), addrs);
1805219089Spjd		if (dflag >= 2) {
1806219089Spjd			for (i = 0;
1807219089Spjd			     i < ((struct rt_msghdr *)(void *)p)->rtm_msglen;
1808219089Spjd			     i++) {
1809219089Spjd				fprintf(stderr, "%02x ", p[i] & 0xff);
1810219089Spjd				if (i % 16 == 15) fprintf(stderr, "\n");
1811219089Spjd			}
1812219089Spjd			fprintf(stderr, "\n");
1813219089Spjd		}
1814219089Spjd
1815219089Spjd		/*
1816219089Spjd		 * Easy ones first.
1817219089Spjd		 *
1818219089Spjd		 * We may be able to optimize by using ifm->ifm_index or
1819219089Spjd		 * ifam->ifam_index.  For simplicity we don't do that here.
1820248571Smm		 */
1821219089Spjd		switch (((struct rt_msghdr *)(void *)p)->rtm_type) {
1822248571Smm		case RTM_NEWADDR:
1823248571Smm		case RTM_IFINFO:
1824248571Smm			iface++;
1825219089Spjd			continue;
1826219089Spjd		case RTM_ADD:
1827219089Spjd			rtable++;
1828219089Spjd			continue;
1829219089Spjd		case RTM_LOSING:
1830219089Spjd		case RTM_MISS:
1831219089Spjd		case RTM_GET:
1832219089Spjd		case RTM_LOCK:
1833219089Spjd			/* nothing to be done here */
1834219089Spjd			trace(1, "\tnothing to be done, ignored\n");
1835219089Spjd			continue;
1836219089Spjd		}
1837219089Spjd
1838219089Spjd#if 0
1839219089Spjd		if (rta[RTAX_DST] == NULL) {
1840219089Spjd			trace(1, "\tno destination, ignored\n");
1841219089Spjd			continue;
1842219089Spjd		}
1843219089Spjd		if (rta[RTAX_DST]->sin6_family != AF_INET6) {
1844219089Spjd			trace(1, "\taf mismatch, ignored\n");
1845219089Spjd			continue;
1846219089Spjd		}
1847219089Spjd		if (IN6_IS_ADDR_LINKLOCAL(&rta[RTAX_DST]->sin6_addr)) {
1848219089Spjd			trace(1, "\tlinklocal destination, ignored\n");
1849219089Spjd			continue;
1850219089Spjd		}
1851219089Spjd		if (IN6_ARE_ADDR_EQUAL(&rta[RTAX_DST]->sin6_addr, &in6addr_loopback)) {
1852219089Spjd			trace(1, "\tloopback destination, ignored\n");
1853219089Spjd			continue;		/* Loopback */
1854219089Spjd		}
1855219089Spjd		if (IN6_IS_ADDR_MULTICAST(&rta[RTAX_DST]->sin6_addr)) {
1856219089Spjd			trace(1, "\tmulticast destination, ignored\n");
1857219089Spjd			continue;
1858219089Spjd		}
1859219089Spjd#endif
1860219089Spjd
1861219089Spjd		/* hard ones */
1862219089Spjd		switch (((struct rt_msghdr *)(void *)p)->rtm_type) {
1863219089Spjd		case RTM_NEWADDR:
1864219089Spjd		case RTM_IFINFO:
1865219089Spjd		case RTM_ADD:
1866219089Spjd		case RTM_LOSING:
1867219089Spjd		case RTM_MISS:
1868219089Spjd		case RTM_GET:
1869219089Spjd		case RTM_LOCK:
1870268720Sdelphij			/* should already be handled */
1871219089Spjd			fatal("rtrecv: never reach here");
1872219089Spjd			/*NOTREACHED*/
1873236884Smm		case RTM_DELETE:
1874219089Spjd			if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY]) {
1875219089Spjd				trace(1, "\tsome of dst/gw/netamsk are "
1876219089Spjd				    "unavailable, ignored\n");
1877219089Spjd				break;
1878219089Spjd			}
1879219089Spjd			if ((rtm->rtm_flags & RTF_HOST) != 0) {
1880268720Sdelphij				mask.sin6_len = sizeof(mask);
1881268720Sdelphij				memset(&mask.sin6_addr, 0xff,
1882268720Sdelphij				    sizeof(mask.sin6_addr));
1883268720Sdelphij				rta[RTAX_NETMASK] = &mask;
1884268720Sdelphij			} else if (!rta[RTAX_NETMASK]) {
1885219089Spjd				trace(1, "\tsome of dst/gw/netamsk are "
1886219089Spjd				    "unavailable, ignored\n");
1887268720Sdelphij				break;
1888268720Sdelphij			}
1889268720Sdelphij			if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY],
1890268720Sdelphij			    rta[RTAX_NETMASK]) == 0) {
1891268720Sdelphij				rtable++;	/*just to be sure*/
1892268720Sdelphij			}
1893268720Sdelphij			break;
1894268720Sdelphij		case RTM_CHANGE:
1895268720Sdelphij		case RTM_REDIRECT:
1896268720Sdelphij			trace(1, "\tnot supported yet, ignored\n");
1897268720Sdelphij			break;
1898268720Sdelphij		case RTM_DELADDR:
1899268720Sdelphij			if (!rta[RTAX_NETMASK] || !rta[RTAX_IFA]) {
1900268720Sdelphij				trace(1, "\tno netmask or ifa given, ignored\n");
1901268720Sdelphij				break;
1902268720Sdelphij			}
1903268720Sdelphij			if (ifam->ifam_index < nindex2ifc)
1904268720Sdelphij				ifcp = index2ifc[ifam->ifam_index];
1905268720Sdelphij			else
1906268720Sdelphij				ifcp = NULL;
1907268720Sdelphij			if (!ifcp) {
1908219089Spjd				trace(1, "\tinvalid ifam_index %d, ignored\n",
1909219089Spjd					ifam->ifam_index);
1910219089Spjd				break;
1911268123Sdelphij			}
1912219089Spjd			if (!rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK]))
1913268720Sdelphij				iface++;
1914268720Sdelphij			break;
1915268720Sdelphij		}
1916268720Sdelphij
1917268720Sdelphij	}
1918268720Sdelphij
1919268720Sdelphij	if (iface) {
1920268720Sdelphij		trace(1, "rtsock: reconfigure interfaces, refresh interface routes\n");
1921268720Sdelphij		ifconfig();
1922268720Sdelphij		TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) {
1923268720Sdelphij			if (ifcp->ifc_cflags & IFC_CHANGED) {
1924219089Spjd				if (ifrt(ifcp, 1)) {
1925268720Sdelphij					TAILQ_FOREACH(ic, &ifc_head, ifc_next) {
1926268720Sdelphij						if (ifcp->ifc_index == ic->ifc_index)
1927268720Sdelphij							continue;
1928268720Sdelphij						if (ic->ifc_flags & IFF_UP)
1929268720Sdelphij							ripsend(ic, &ic->ifc_ripsin,
1930268720Sdelphij							RRTF_CHANGED);
1931268720Sdelphij					}
1932268720Sdelphij					/* Reset the flag */
1933268720Sdelphij					TAILQ_FOREACH(rrt, &riprt_head, rrt_next) {
1934268720Sdelphij						rrt->rrt_rflags &= ~RRTF_CHANGED;
1935268720Sdelphij					}
1936268720Sdelphij				}
1937268720Sdelphij				ifcp->ifc_cflags &= ~IFC_CHANGED;
1938268720Sdelphij			}
1939219089Spjd		}
1940219089Spjd	}
1941219089Spjd	if (rtable) {
1942219089Spjd		trace(1, "rtsock: read routing table again\n");
1943219089Spjd		krtread(1);
1944219089Spjd	}
1945219089Spjd}
1946219089Spjd
1947219089Spjd/*
1948219089Spjd * remove specified route from the internal routing table.
1949268720Sdelphij */
1950219089Spjdstatic int
1951219089Spjdrt_del(const struct sockaddr_in6 *sdst,
1952219089Spjd	const struct sockaddr_in6 *sgw,
1953219089Spjd	const struct sockaddr_in6 *smask)
1954219089Spjd{
1955219089Spjd	const struct in6_addr *dst = NULL;
1956219089Spjd	const struct in6_addr *gw = NULL;
1957219089Spjd	int prefix;
1958219089Spjd	struct netinfo6 ni6;
1959268720Sdelphij	struct riprt *rrt = NULL;
1960268720Sdelphij	time_t t_lifetime;
1961268720Sdelphij
1962268720Sdelphij	if (sdst->sin6_family != AF_INET6) {
1963268720Sdelphij		trace(1, "\tother AF, ignored\n");
1964219089Spjd		return -1;
1965219089Spjd	}
1966219089Spjd	if (IN6_IS_ADDR_LINKLOCAL(&sdst->sin6_addr)
1967219089Spjd	 || IN6_ARE_ADDR_EQUAL(&sdst->sin6_addr, &in6addr_loopback)
1968219089Spjd	 || IN6_IS_ADDR_MULTICAST(&sdst->sin6_addr)) {
1969219089Spjd		trace(1, "\taddress %s not interesting, ignored\n",
1970219089Spjd			inet6_n2p(&sdst->sin6_addr));
1971219089Spjd		return -1;
1972219089Spjd	}
1973219089Spjd	dst = &sdst->sin6_addr;
1974219089Spjd	if (sgw->sin6_family == AF_INET6) {
1975219089Spjd		/* easy case */
1976219089Spjd		gw = &sgw->sin6_addr;
1977219089Spjd		prefix = sin6mask2len(smask);
1978219089Spjd	} else if (sgw->sin6_family == AF_LINK) {
1979219089Spjd		/*
1980219089Spjd		 * Interface route... a hard case.  We need to get the prefix
1981219089Spjd		 * length from the kernel, but we now are parsing rtmsg.
1982219089Spjd		 * We'll purge matching routes from my list, then get the
1983219089Spjd		 * fresh list.
1984219089Spjd		 */
1985219089Spjd		struct riprt *longest;
1986219089Spjd		trace(1, "\t%s is an interface route, guessing prefixlen\n",
1987219089Spjd			inet6_n2p(dst));
1988219089Spjd		longest = NULL;
1989219089Spjd		TAILQ_FOREACH(rrt, &riprt_head, rrt_next) {
1990219089Spjd			if (IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
1991249195Smm					&sdst->sin6_addr)
1992219089Spjd			 && IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) {
1993219089Spjd				if (!longest
1994219089Spjd				 || longest->rrt_info.rip6_plen <
1995219089Spjd						 rrt->rrt_info.rip6_plen) {
1996219089Spjd					longest = rrt;
1997219089Spjd				}
1998185029Spjd			}
1999219089Spjd		}
2000168404Spjd		rrt = longest;
2001219089Spjd		if (!rrt) {
2002219089Spjd			trace(1, "\tno matching interface route found\n");
2003219089Spjd			return -1;
2004219089Spjd		}
2005219089Spjd		gw = &in6addr_loopback;
2006219089Spjd		prefix = rrt->rrt_info.rip6_plen;
2007219089Spjd	} else {
2008219089Spjd		trace(1, "\tunsupported af: (gw=%d)\n", sgw->sin6_family);
2009219089Spjd		return -1;
2010219089Spjd	}
2011168404Spjd
2012219089Spjd	trace(1, "\tdeleting %s/%d ", inet6_n2p(dst), prefix);
2013168404Spjd	trace(1, "gw %s\n", inet6_n2p(gw));
2014219089Spjd	t_lifetime = time(NULL) - RIP_LIFETIME;
2015219089Spjd	/* age route for interface address */
2016219089Spjd	memset(&ni6, 0, sizeof(ni6));
2017168404Spjd	ni6.rip6_dest = *dst;
2018219089Spjd	ni6.rip6_plen = prefix;
2019219089Spjd	applyplen(&ni6.rip6_dest, ni6.rip6_plen);	/*to be sure*/
2020219089Spjd	trace(1, "\tfind route %s/%d\n", inet6_n2p(&ni6.rip6_dest),
2021219089Spjd		ni6.rip6_plen);
2022219089Spjd	if (!rrt && (rrt = rtsearch(&ni6)) == NULL) {
2023219089Spjd		trace(1, "\tno route found\n");
2024219089Spjd		return -1;
2025219089Spjd	}
2026219089Spjd#if 0
2027219089Spjd	if ((rrt->rrt_flags & RTF_STATIC) == 0) {
2028219089Spjd		trace(1, "\tyou can delete static routes only\n");
2029219089Spjd	} else
2030219089Spjd#endif
2031219089Spjd	if (!IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, gw)) {
2032219089Spjd		trace(1, "\tgw mismatch: %s <-> ",
2033219089Spjd			inet6_n2p(&rrt->rrt_gw));
2034219089Spjd		trace(1, "%s\n", inet6_n2p(gw));
2035219089Spjd	} else {
2036219089Spjd		trace(1, "\troute found, age it\n");
2037219089Spjd		if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
2038219089Spjd			rrt->rrt_t = t_lifetime;
2039219089Spjd			rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
2040219089Spjd		}
2041219089Spjd	}
2042219089Spjd	return 0;
2043219089Spjd}
2044219089Spjd
2045219089Spjd/*
2046219089Spjd * remove specified address from internal interface/routing table.
2047219089Spjd */
2048219089Spjdstatic int
2049219089Spjdrt_deladdr(struct ifc *ifcp,
2050219089Spjd	const struct sockaddr_in6 *sifa,
2051219089Spjd	const struct sockaddr_in6 *smask)
2052219089Spjd{
2053219089Spjd	const struct in6_addr *addr = NULL;
2054219089Spjd	int prefix;
2055219089Spjd	struct ifac *ifac = NULL;
2056219089Spjd	struct netinfo6 ni6;
2057219089Spjd	struct riprt *rrt = NULL;
2058219089Spjd	time_t t_lifetime;
2059219089Spjd	int updated = 0;
2060219089Spjd
2061219089Spjd	if (sifa->sin6_family != AF_INET6) {
2062219089Spjd		trace(1, "\tother AF, ignored\n");
2063219089Spjd		return -1;
2064219089Spjd	}
2065219089Spjd	addr = &sifa->sin6_addr;
2066219089Spjd	prefix = sin6mask2len(smask);
2067219089Spjd
2068219089Spjd	trace(1, "\tdeleting %s/%d from %s\n",
2069219089Spjd		inet6_n2p(addr), prefix, ifcp->ifc_name);
2070219089Spjd	ifac = ifa_match(ifcp, addr, prefix);
2071219089Spjd	if (!ifac) {
2072219089Spjd		trace(1, "\tno matching ifa found for %s/%d on %s\n",
2073219089Spjd			inet6_n2p(addr), prefix, ifcp->ifc_name);
2074219089Spjd		return -1;
2075219089Spjd	}
2076219089Spjd	if (ifac->ifac_ifc != ifcp) {
2077219089Spjd		trace(1, "\taddress table corrupt: back pointer does not match "
2078219089Spjd			"(%s != %s)\n",
2079219089Spjd			ifcp->ifc_name, ifac->ifac_ifc->ifc_name);
2080219089Spjd		return -1;
2081219089Spjd	}
2082219089Spjd	TAILQ_REMOVE(&ifcp->ifc_ifac_head, ifac, ifac_next);
2083219089Spjd	t_lifetime = time(NULL) - RIP_LIFETIME;
2084219089Spjd	/* age route for interface address */
2085219089Spjd	memset(&ni6, 0, sizeof(ni6));
2086219089Spjd	ni6.rip6_dest = ifac->ifac_addr;
2087219089Spjd	ni6.rip6_plen = ifac->ifac_plen;
2088219089Spjd	applyplen(&ni6.rip6_dest, ni6.rip6_plen);
2089219089Spjd	trace(1, "\tfind interface route %s/%d on %d\n",
2090219089Spjd		inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index);
2091219089Spjd	if ((rrt = rtsearch(&ni6)) != NULL) {
2092209962Smm		struct in6_addr none;
2093219089Spjd		memset(&none, 0, sizeof(none));
2094219089Spjd		if (rrt->rrt_index == ifcp->ifc_index &&
2095219089Spjd		    (IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &none) ||
2096209962Smm		     IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw))) {
2097219089Spjd			trace(1, "\troute found, age it\n");
2098219089Spjd			if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
2099219089Spjd				rrt->rrt_t = t_lifetime;
2100219089Spjd				rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
2101219089Spjd			}
2102219089Spjd			updated++;
2103209962Smm		} else {
2104219089Spjd			trace(1, "\tnon-interface route found: %s/%d on %d\n",
2105219089Spjd				inet6_n2p(&rrt->rrt_info.rip6_dest),
2106185029Spjd				rrt->rrt_info.rip6_plen,
2107219089Spjd				rrt->rrt_index);
2108219089Spjd		}
2109219089Spjd	} else
2110219089Spjd		trace(1, "\tno interface route found\n");
2111219089Spjd	/* age route for p2p destination */
2112219089Spjd	if (ifcp->ifc_flags & IFF_POINTOPOINT) {
2113228103Smm		memset(&ni6, 0, sizeof(ni6));
2114219089Spjd		ni6.rip6_dest = ifac->ifac_raddr;
2115219089Spjd		ni6.rip6_plen = 128;
2116219089Spjd		applyplen(&ni6.rip6_dest, ni6.rip6_plen);	/*to be sure*/
2117168404Spjd		trace(1, "\tfind p2p route %s/%d on %d\n",
2118219089Spjd			inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen,
2119249195Smm			ifcp->ifc_index);
2120168404Spjd		if ((rrt = rtsearch(&ni6)) != NULL) {
2121228103Smm			if (rrt->rrt_index == ifcp->ifc_index &&
2122228103Smm			    IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw,
2123228103Smm			    &ifac->ifac_addr)) {
2124228103Smm				trace(1, "\troute found, age it\n");
2125168404Spjd				if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
2126168404Spjd					rrt->rrt_t = t_lifetime;
2127168404Spjd					rrt->rrt_info.rip6_metric =
2128168404Spjd					    HOPCNT_INFINITY6;
2129219089Spjd					updated++;
2130219089Spjd				}
2131219089Spjd			} else {
2132168404Spjd				trace(1, "\tnon-p2p route found: %s/%d on %d\n",
2133168404Spjd					inet6_n2p(&rrt->rrt_info.rip6_dest),
2134168404Spjd					rrt->rrt_info.rip6_plen,
2135168404Spjd					rrt->rrt_index);
2136168404Spjd			}
2137168404Spjd		} else
2138249195Smm			trace(1, "\tno p2p route found\n");
2139219089Spjd	}
2140228103Smm	free(ifac);
2141219089Spjd
2142219089Spjd	return ((updated) ? 0 : -1);
2143219089Spjd}
2144219089Spjd
2145219089Spjd/*
2146219089Spjd * Get each interface address and put those interface routes to the route
2147219089Spjd * list.
2148236884Smm */
2149236884Smmstatic int
2150236884Smmifrt(struct ifc *ifcp, int again)
2151219089Spjd{
2152219089Spjd	struct ifac *ifac;
2153219089Spjd	struct riprt *rrt = NULL, *search_rrt, *loop_rrt;
2154168404Spjd	struct netinfo6 *np;
2155168404Spjd	time_t t_lifetime;
2156219089Spjd	int need_trigger = 0;
2157219089Spjd
2158219089Spjd#if 0
2159219089Spjd	if (ifcp->ifc_flags & IFF_LOOPBACK)
2160219089Spjd		return 0;			/* ignore loopback */
2161219089Spjd#endif
2162219089Spjd
2163219089Spjd	if (ifcp->ifc_flags & IFF_POINTOPOINT) {
2164219089Spjd		ifrt_p2p(ifcp, again);
2165219089Spjd		return 0;
2166219089Spjd	}
2167219089Spjd
2168168404Spjd	TAILQ_FOREACH(ifac, &ifcp->ifc_ifac_head, ifac_next) {
2169219089Spjd		if (IN6_IS_ADDR_LINKLOCAL(&ifac->ifac_addr)) {
2170219089Spjd#if 0
2171219089Spjd			trace(1, "route: %s on %s: "
2172219089Spjd			    "skip linklocal interface address\n",
2173219089Spjd			    inet6_n2p(&ifac->ifac_addr), ifcp->ifc_name);
2174219089Spjd#endif
2175219089Spjd			continue;
2176219089Spjd		}
2177219089Spjd		if (IN6_IS_ADDR_UNSPECIFIED(&ifac->ifac_addr)) {
2178219089Spjd#if 0
2179219089Spjd			trace(1, "route: %s: skip unspec interface address\n",
2180219089Spjd			    ifcp->ifc_name);
2181219089Spjd#endif
2182219089Spjd			continue;
2183236884Smm		}
2184219089Spjd		if (IN6_IS_ADDR_LOOPBACK(&ifac->ifac_addr)) {
2185219089Spjd#if 0
2186219089Spjd			trace(1, "route: %s: skip loopback address\n",
2187219089Spjd			    ifcp->ifc_name);
2188219089Spjd#endif
2189219089Spjd			continue;
2190236884Smm		}
2191219089Spjd		if (ifcp->ifc_flags & IFF_UP) {
2192168404Spjd			if ((rrt = MALLOC(struct riprt)) == NULL)
2193219089Spjd				fatal("malloc: struct riprt");
2194219089Spjd			memset(rrt, 0, sizeof(*rrt));
2195219089Spjd			rrt->rrt_same = NULL;
2196219089Spjd			rrt->rrt_index = ifcp->ifc_index;
2197219089Spjd			rrt->rrt_t = 0;	/* don't age */
2198219089Spjd			rrt->rrt_info.rip6_dest = ifac->ifac_addr;
2199219089Spjd			rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
2200219089Spjd			rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric;
2201219089Spjd			rrt->rrt_info.rip6_plen = ifac->ifac_plen;
2202219089Spjd			rrt->rrt_flags = RTF_HOST;
2203219089Spjd			rrt->rrt_rflags |= RRTF_CHANGED;
2204249195Smm			applyplen(&rrt->rrt_info.rip6_dest, ifac->ifac_plen);
2205219089Spjd			memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
2206219089Spjd			rrt->rrt_gw = ifac->ifac_addr;
2207219089Spjd			np = &rrt->rrt_info;
2208219089Spjd			search_rrt = rtsearch(np);
2209219089Spjd			if (search_rrt != NULL) {
2210209962Smm				if (search_rrt->rrt_info.rip6_metric <=
2211209962Smm				    rrt->rrt_info.rip6_metric) {
2212209962Smm					/* Already have better route */
2213209962Smm					if (!again) {
2214209962Smm						trace(1, "route: %s/%d: "
2215209962Smm						    "already registered (%s)\n",
2216168404Spjd						    inet6_n2p(&np->rip6_dest), np->rip6_plen,
2217168404Spjd						    ifcp->ifc_name);
2218168404Spjd					}
2219168404Spjd					goto next;
2220185029Spjd				}
2221219089Spjd
2222185029Spjd				TAILQ_REMOVE(&riprt_head, search_rrt, rrt_next);
2223168404Spjd				delroute(&search_rrt->rrt_info,
2224168404Spjd				    &search_rrt->rrt_gw);
2225219089Spjd				free(search_rrt);
2226168404Spjd			}
2227168404Spjd			/* Attach the route to the list */
2228168404Spjd			trace(1, "route: %s/%d: register route (%s)\n",
2229219089Spjd			    inet6_n2p(&np->rip6_dest), np->rip6_plen,
2230219089Spjd			    ifcp->ifc_name);
2231219089Spjd			TAILQ_INSERT_HEAD(&riprt_head, rrt, rrt_next);
2232219089Spjd			addroute(rrt, &rrt->rrt_gw, ifcp);
2233168404Spjd			rrt = NULL;
2234168404Spjd			sendrequest(ifcp);
2235168404Spjd			ripsend(ifcp, &ifcp->ifc_ripsin, 0);
2236185029Spjd			need_trigger = 1;
2237168926Spjd		} else {
2238185029Spjd			TAILQ_FOREACH(loop_rrt, &riprt_head, rrt_next) {
2239168926Spjd				if (loop_rrt->rrt_index == ifcp->ifc_index) {
2240219089Spjd					t_lifetime = time(NULL) - RIP_LIFETIME;
2241168404Spjd					if (loop_rrt->rrt_t == 0 || loop_rrt->rrt_t > t_lifetime) {
2242168404Spjd						loop_rrt->rrt_t = t_lifetime;
2243209962Smm						loop_rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
2244209962Smm						loop_rrt->rrt_rflags |= RRTF_CHANGED;
2245209962Smm						need_trigger = 1;
2246219089Spjd					}
2247209962Smm				}
2248209962Smm			}
2249209962Smm                }
2250219089Spjd	next:
2251219089Spjd		if (rrt)
2252219089Spjd			free(rrt);
2253219089Spjd	}
2254168404Spjd	return need_trigger;
2255219089Spjd}
2256219089Spjd
2257230514Smm/*
2258219089Spjd * there are couple of p2p interface routing models.  "behavior" lets
2259168404Spjd * you pick one.  it looks that gated behavior fits best with BSDs,
2260219089Spjd * since BSD kernels do not look at prefix length on p2p interfaces.
2261219089Spjd */
2262219089Spjdstatic void
2263219089Spjdifrt_p2p(struct ifc *ifcp, int again)
2264249195Smm{
2265168404Spjd	struct ifac *ifac;
2266168404Spjd	struct riprt *rrt, *orrt;
2267168404Spjd	struct netinfo6 *np;
2268168404Spjd	struct in6_addr addr, dest;
2269168404Spjd	int advert, ignore, i;
2270236884Smm#define P2PADVERT_NETWORK	1
2271168404Spjd#define P2PADVERT_ADDR		2
2272168404Spjd#define P2PADVERT_DEST		4
2273168404Spjd#define P2PADVERT_MAX		4
2274168404Spjd	const enum { CISCO, GATED, ROUTE6D } behavior = GATED;
2275236884Smm	const char *category = "";
2276236884Smm	const char *noadv;
2277219089Spjd
2278236884Smm	TAILQ_FOREACH(ifac, &ifcp->ifc_ifac_head, ifac_next) {
2279168404Spjd		addr = ifac->ifac_addr;
2280168404Spjd		dest = ifac->ifac_raddr;
2281236884Smm		applyplen(&addr, ifac->ifac_plen);
2282168404Spjd		applyplen(&dest, ifac->ifac_plen);
2283236884Smm		advert = ignore = 0;
2284236884Smm		switch (behavior) {
2285219089Spjd		case CISCO:
2286236884Smm			/*
2287168404Spjd			 * honor addr/plen, just like normal shared medium
2288236884Smm			 * interface.  this may cause trouble if you reuse
2289236884Smm			 * addr/plen on other interfaces.
2290236884Smm			 *
2291236884Smm			 * advertise addr/plen.
2292236884Smm			 */
2293236884Smm			advert |= P2PADVERT_NETWORK;
2294236884Smm			break;
2295236884Smm		case GATED:
2296236884Smm			/*
2297236884Smm			 * prefixlen on p2p interface is meaningless.
2298236884Smm			 * advertise addr/128 and dest/128.
2299236884Smm			 *
2300236884Smm			 * do not install network route to route6d routing
2301236884Smm			 * table (if we do, it would prevent route installation
2302236884Smm			 * for other p2p interface that shares addr/plen).
2303236884Smm			 *
2304236884Smm			 * XXX what should we do if dest is ::?  it will not
2305236884Smm			 * get announced anyways (see following filter),
2306236884Smm			 * but we need to think.
2307236884Smm			 */
2308236884Smm			advert |= P2PADVERT_ADDR;
2309236884Smm			advert |= P2PADVERT_DEST;
2310236884Smm			ignore |= P2PADVERT_NETWORK;
2311236884Smm			break;
2312168404Spjd		case ROUTE6D:
2313236884Smm			/*
2314236884Smm			 * just for testing.  actually the code is redundant
2315236884Smm			 * given the current p2p interface address assignment
2316236884Smm			 * rule for kame kernel.
2317236884Smm			 *
2318236884Smm			 * intent:
2319236884Smm			 *	A/n -> announce A/n
2320236884Smm			 *	A B/n, A and B share prefix -> A/n (= B/n)
2321236884Smm			 *	A B/n, do not share prefix -> A/128 and B/128
2322236884Smm			 * actually, A/64 and A B/128 are the only cases
2323236884Smm			 * permitted by the kernel:
2324236884Smm			 *	A/64 -> A/64
2325236884Smm			 *	A B/128 -> A/128 and B/128
2326236884Smm			 */
2327236884Smm			if (!IN6_IS_ADDR_UNSPECIFIED(&ifac->ifac_raddr)) {
2328236884Smm				if (IN6_ARE_ADDR_EQUAL(&addr, &dest))
2329236884Smm					advert |= P2PADVERT_NETWORK;
2330236884Smm				else {
2331236884Smm					advert |= P2PADVERT_ADDR;
2332236884Smm					advert |= P2PADVERT_DEST;
2333236884Smm					ignore |= P2PADVERT_NETWORK;
2334236884Smm				}
2335236884Smm			} else
2336236884Smm				advert |= P2PADVERT_NETWORK;
2337236884Smm			break;
2338236884Smm		}
2339236884Smm
2340236884Smm		for (i = 1; i <= P2PADVERT_MAX; i *= 2) {
2341236884Smm			if ((ignore & i) != 0)
2342236884Smm				continue;
2343236884Smm			if ((rrt = MALLOC(struct riprt)) == NULL) {
2344168404Spjd				fatal("malloc: struct riprt");
2345219089Spjd				/*NOTREACHED*/
2346219089Spjd			}
2347219089Spjd			memset(rrt, 0, sizeof(*rrt));
2348219089Spjd			rrt->rrt_same = NULL;
2349168404Spjd			rrt->rrt_index = ifcp->ifc_index;
2350219089Spjd			rrt->rrt_t = 0;	/* don't age */
2351219089Spjd			switch (i) {
2352219089Spjd			case P2PADVERT_NETWORK:
2353219089Spjd				rrt->rrt_info.rip6_dest = ifac->ifac_addr;
2354219089Spjd				rrt->rrt_info.rip6_plen = ifac->ifac_plen;
2355219089Spjd				applyplen(&rrt->rrt_info.rip6_dest,
2356219089Spjd				    ifac->ifac_plen);
2357219089Spjd				category = "network";
2358219089Spjd				break;
2359219089Spjd			case P2PADVERT_ADDR:
2360219089Spjd				rrt->rrt_info.rip6_dest = ifac->ifac_addr;
2361168404Spjd				rrt->rrt_info.rip6_plen = 128;
2362168404Spjd				rrt->rrt_gw = in6addr_loopback;
2363168404Spjd				category = "addr";
2364168404Spjd				break;
2365168404Spjd			case P2PADVERT_DEST:
2366168404Spjd				rrt->rrt_info.rip6_dest = ifac->ifac_raddr;
2367168404Spjd				rrt->rrt_info.rip6_plen = 128;
2368219089Spjd				rrt->rrt_gw = ifac->ifac_addr;
2369219089Spjd				category = "dest";
2370219089Spjd				break;
2371219089Spjd			}
2372219089Spjd			if (IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_info.rip6_dest) ||
2373219089Spjd			    IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_info.rip6_dest)) {
2374219089Spjd#if 0
2375236884Smm				trace(1, "route: %s: skip unspec/linklocal "
2376219089Spjd				    "(%s on %s)\n", category, ifcp->ifc_name);
2377219089Spjd#endif
2378168404Spjd				free(rrt);
2379168404Spjd				continue;
2380219089Spjd			}
2381219089Spjd			if ((advert & i) == 0) {
2382168404Spjd				rrt->rrt_rflags |= RRTF_NOADVERTISE;
2383236884Smm				noadv = ", NO-ADV";
2384236884Smm			} else
2385238926Smm				noadv = "";
2386236884Smm			rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
2387236884Smm			rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric;
2388236884Smm			np = &rrt->rrt_info;
2389236884Smm			orrt = rtsearch(np);
2390236884Smm			if (!orrt) {
2391236884Smm				/* Attach the route to the list */
2392236884Smm				trace(1, "route: %s/%d: register route "
2393236884Smm				    "(%s on %s%s)\n",
2394236884Smm				    inet6_n2p(&np->rip6_dest), np->rip6_plen,
2395236884Smm				    category, ifcp->ifc_name, noadv);
2396236884Smm				TAILQ_INSERT_HEAD(&riprt_head, rrt, rrt_next);
2397236884Smm			} else if (rrt->rrt_index != orrt->rrt_index ||
2398236884Smm			    rrt->rrt_info.rip6_metric != orrt->rrt_info.rip6_metric) {
2399236884Smm				/* replace route */
2400236884Smm				TAILQ_INSERT_BEFORE(orrt, rrt, rrt_next);
2401236884Smm				TAILQ_REMOVE(&riprt_head, orrt, rrt_next);
2402238926Smm				free(orrt);
2403238926Smm
2404236884Smm				trace(1, "route: %s/%d: update (%s on %s%s)\n",
2405259813Sdelphij				    inet6_n2p(&np->rip6_dest), np->rip6_plen,
2406238926Smm				    category, ifcp->ifc_name, noadv);
2407236884Smm			} else {
2408236884Smm				/* Already found */
2409236884Smm				if (!again) {
2410259813Sdelphij					trace(1, "route: %s/%d: "
2411238926Smm					    "already registered (%s on %s%s)\n",
2412236884Smm					    inet6_n2p(&np->rip6_dest),
2413238926Smm					    np->rip6_plen, category,
2414236884Smm					    ifcp->ifc_name, noadv);
2415236884Smm				}
2416238926Smm				free(rrt);
2417238926Smm			}
2418238926Smm		}
2419236884Smm	}
2420238926Smm#undef P2PADVERT_NETWORK
2421238926Smm#undef P2PADVERT_ADDR
2422236884Smm#undef P2PADVERT_DEST
2423236884Smm#undef P2PADVERT_MAX
2424238926Smm}
2425238926Smm
2426236884Smmstatic int
2427236884Smmgetifmtu(int ifindex)
2428236884Smm{
2429236884Smm	int	mib[6];
2430236884Smm	char	*buf;
2431236884Smm	size_t	msize;
2432236884Smm	struct	if_msghdr *ifm;
2433236884Smm	int	mtu;
2434236884Smm
2435236884Smm	mib[0] = CTL_NET;
2436236884Smm	mib[1] = PF_ROUTE;
2437236884Smm	mib[2] = 0;
2438236884Smm	mib[3] = AF_INET6;
2439236884Smm	mib[4] = NET_RT_IFLIST;
2440236884Smm	mib[5] = ifindex;
2441236884Smm	if (sysctl(mib, nitems(mib), NULL, &msize, NULL, 0) < 0) {
2442236884Smm		fatal("sysctl estimate NET_RT_IFLIST");
2443236884Smm		/*NOTREACHED*/
2444236884Smm	}
2445236884Smm	if ((buf = malloc(msize)) == NULL) {
2446236884Smm		fatal("malloc");
2447236884Smm		/*NOTREACHED*/
2448236884Smm	}
2449236884Smm	if (sysctl(mib, nitems(mib), buf, &msize, NULL, 0) < 0) {
2450236884Smm		fatal("sysctl NET_RT_IFLIST");
2451236884Smm		/*NOTREACHED*/
2452236884Smm	}
2453236884Smm	ifm = (struct if_msghdr *)(void *)buf;
2454236884Smm	mtu = ifm->ifm_data.ifi_mtu;
2455236884Smm	if (ifindex != ifm->ifm_index) {
2456260150Sdelphij		fatal("ifindex does not match with ifm_index");
2457260150Sdelphij		/*NOTREACHED*/
2458260150Sdelphij	}
2459260150Sdelphij	free(buf);
2460260150Sdelphij	return mtu;
2461260150Sdelphij}
2462260150Sdelphij
2463260150Sdelphijstatic const char *
2464260150Sdelphijrttypes(struct rt_msghdr *rtm)
2465260150Sdelphij{
2466260150Sdelphij#define	RTTYPE(s, f) \
2467260150Sdelphijdo { \
2468260150Sdelphij	if (rtm->rtm_type == (f)) \
2469260150Sdelphij		return (s); \
2470260150Sdelphij} while (0)
2471260150Sdelphij	RTTYPE("ADD", RTM_ADD);
2472260150Sdelphij	RTTYPE("DELETE", RTM_DELETE);
2473260150Sdelphij	RTTYPE("CHANGE", RTM_CHANGE);
2474260150Sdelphij	RTTYPE("GET", RTM_GET);
2475260150Sdelphij	RTTYPE("LOSING", RTM_LOSING);
2476236884Smm	RTTYPE("REDIRECT", RTM_REDIRECT);
2477236884Smm	RTTYPE("MISS", RTM_MISS);
2478260150Sdelphij	RTTYPE("LOCK", RTM_LOCK);
2479260150Sdelphij	RTTYPE("NEWADDR", RTM_NEWADDR);
2480268075Sdelphij	RTTYPE("DELADDR", RTM_DELADDR);
2481260150Sdelphij	RTTYPE("IFINFO", RTM_IFINFO);
2482260150Sdelphij#ifdef RTM_OIFINFO
2483260150Sdelphij	RTTYPE("OIFINFO", RTM_OIFINFO);
2484236884Smm#endif
2485236884Smm#ifdef RTM_IFANNOUNCE
2486236884Smm	RTTYPE("IFANNOUNCE", RTM_IFANNOUNCE);
2487236884Smm#endif
2488236884Smm#ifdef RTM_NEWMADDR
2489236884Smm	RTTYPE("NEWMADDR", RTM_NEWMADDR);
2490168404Spjd#endif
2491168498Spjd#ifdef RTM_DELMADDR
2492219089Spjd	RTTYPE("DELMADDR", RTM_DELMADDR);
2493168404Spjd#endif
2494219089Spjd#undef RTTYPE
2495219089Spjd	return NULL;
2496168404Spjd}
2497219089Spjd
2498185029Spjdstatic const char *
2499168498Spjdrtflags(struct rt_msghdr *rtm)
2500168498Spjd{
2501168498Spjd	static char buf[BUFSIZ];
2502219089Spjd
2503168498Spjd	/*
2504168498Spjd	 * letter conflict should be okay.  painful when *BSD diverges...
2505219089Spjd	 */
2506219089Spjd	strlcpy(buf, "", sizeof(buf));
2507219089Spjd#define	RTFLAG(s, f) \
2508219089Spjddo { \
2509219089Spjd	if (rtm->rtm_flags & (f)) \
2510219089Spjd		strlcat(buf, (s), sizeof(buf)); \
2511219089Spjd} while (0)
2512168498Spjd	RTFLAG("U", RTF_UP);
2513219089Spjd	RTFLAG("G", RTF_GATEWAY);
2514204073Spjd	RTFLAG("H", RTF_HOST);
2515219089Spjd	RTFLAG("R", RTF_REJECT);
2516219089Spjd	RTFLAG("D", RTF_DYNAMIC);
2517168498Spjd	RTFLAG("M", RTF_MODIFIED);
2518168498Spjd	RTFLAG("d", RTF_DONE);
2519185029Spjd#ifdef	RTF_MASK
2520236146Smm	RTFLAG("m", RTF_MASK);
2521185029Spjd#endif
2522168498Spjd#ifdef RTF_CLONED
2523249195Smm	RTFLAG("c", RTF_CLONED);
2524168498Spjd#endif
2525168498Spjd	RTFLAG("X", RTF_XRESOLVE);
2526219089Spjd#ifdef RTF_LLINFO
2527219089Spjd	RTFLAG("L", RTF_LLINFO);
2528219089Spjd#endif
2529219089Spjd	RTFLAG("S", RTF_STATIC);
2530168498Spjd	RTFLAG("B", RTF_BLACKHOLE);
2531219089Spjd#ifdef RTF_PROTO3
2532168404Spjd	RTFLAG("3", RTF_PROTO3);
2533168404Spjd#endif
2534209962Smm	RTFLAG("2", RTF_PROTO2);
2535168404Spjd	RTFLAG("1", RTF_PROTO1);
2536219089Spjd#ifdef RTF_BROADCAST
2537168404Spjd	RTFLAG("b", RTF_BROADCAST);
2538168404Spjd#endif
2539219089Spjd#ifdef RTF_DEFAULT
2540219089Spjd	RTFLAG("d", RTF_DEFAULT);
2541219089Spjd#endif
2542219089Spjd#ifdef RTF_ISAROUTER
2543219089Spjd	RTFLAG("r", RTF_ISAROUTER);
2544168404Spjd#endif
2545168404Spjd#ifdef RTF_TUNNEL
2546168404Spjd	RTFLAG("T", RTF_TUNNEL);
2547168404Spjd#endif
2548168404Spjd#ifdef RTF_AUTH
2549168404Spjd	RTFLAG("A", RTF_AUTH);
2550219089Spjd#endif
2551219089Spjd#ifdef RTF_CRYPT
2552219089Spjd	RTFLAG("E", RTF_CRYPT);
2553168404Spjd#endif
2554219089Spjd#undef RTFLAG
2555219089Spjd	return buf;
2556219089Spjd}
2557219089Spjd
2558219089Spjdstatic const char *
2559168404Spjdifflags(int flags)
2560168404Spjd{
2561168404Spjd	static char buf[BUFSIZ];
2562168404Spjd
2563219089Spjd	strlcpy(buf, "", sizeof(buf));
2564219089Spjd#define	IFFLAG(s, f) \
2565219089Spjddo { \
2566168404Spjd	if (flags & (f)) { \
2567219089Spjd		if (buf[0]) \
2568219089Spjd			strlcat(buf, ",", sizeof(buf)); \
2569219089Spjd		strlcat(buf, (s), sizeof(buf)); \
2570219089Spjd	} \
2571168404Spjd} while (0)
2572168404Spjd	IFFLAG("UP", IFF_UP);
2573168404Spjd	IFFLAG("BROADCAST", IFF_BROADCAST);
2574168404Spjd	IFFLAG("DEBUG", IFF_DEBUG);
2575168404Spjd	IFFLAG("LOOPBACK", IFF_LOOPBACK);
2576219089Spjd	IFFLAG("POINTOPOINT", IFF_POINTOPOINT);
2577219089Spjd#ifdef IFF_NOTRAILERS
2578219089Spjd	IFFLAG("NOTRAILERS", IFF_NOTRAILERS);
2579168404Spjd#endif
2580168404Spjd	IFFLAG("RUNNING", IFF_RUNNING);
2581219089Spjd	IFFLAG("NOARP", IFF_NOARP);
2582219089Spjd	IFFLAG("PROMISC", IFF_PROMISC);
2583219089Spjd	IFFLAG("ALLMULTI", IFF_ALLMULTI);
2584219089Spjd	IFFLAG("OACTIVE", IFF_OACTIVE);
2585219089Spjd	IFFLAG("SIMPLEX", IFF_SIMPLEX);
2586219089Spjd	IFFLAG("LINK0", IFF_LINK0);
2587168404Spjd	IFFLAG("LINK1", IFF_LINK1);
2588168404Spjd	IFFLAG("LINK2", IFF_LINK2);
2589219089Spjd	IFFLAG("MULTICAST", IFF_MULTICAST);
2590219089Spjd#undef IFFLAG
2591219089Spjd	return buf;
2592219089Spjd}
2593185029Spjd
2594185029Spjdstatic void
2595219089Spjdkrtread(int again)
2596219089Spjd{
2597168404Spjd	int mib[6];
2598185029Spjd	size_t msize;
2599168404Spjd	char *buf, *p, *lim;
2600185029Spjd	struct rt_msghdr *rtm;
2601219089Spjd	int retry;
2602219089Spjd	const char *errmsg;
2603168404Spjd
2604168404Spjd	retry = 0;
2605185029Spjd	buf = NULL;
2606185029Spjd	mib[0] = CTL_NET;
2607185029Spjd	mib[1] = PF_ROUTE;
2608219089Spjd	mib[2] = 0;
2609185029Spjd	mib[3] = AF_INET6;	/* Address family */
2610219089Spjd	mib[4] = NET_RT_DUMP;	/* Dump the kernel routing table */
2611219089Spjd	mib[5] = 0;		/* No flags */
2612219089Spjd	do {
2613185029Spjd		if (retry)
2614185029Spjd			sleep(1);
2615219089Spjd		retry++;
2616219089Spjd		errmsg = NULL;
2617185029Spjd		if (buf) {
2618185029Spjd			free(buf);
2619185029Spjd			buf = NULL;
2620185029Spjd		}
2621219089Spjd		if (sysctl(mib, nitems(mib), NULL, &msize, NULL, 0) < 0) {
2622219089Spjd			errmsg = "sysctl estimate";
2623185029Spjd			continue;
2624185029Spjd		}
2625219089Spjd		if ((buf = malloc(msize)) == NULL) {
2626213197Smm			errmsg = "malloc";
2627219089Spjd			continue;
2628219089Spjd		}
2629219089Spjd		if (sysctl(mib, nitems(mib), buf, &msize, NULL, 0) < 0) {
2630185029Spjd			errmsg = "sysctl NET_RT_DUMP";
2631219089Spjd			continue;
2632219089Spjd		}
2633185029Spjd	} while (retry < RT_DUMP_MAXRETRY && errmsg != NULL);
2634219089Spjd	if (errmsg) {
2635219089Spjd		fatal("%s (with %d retries, msize=%lu)", errmsg, retry,
2636219089Spjd		    (u_long)msize);
2637219089Spjd		/*NOTREACHED*/
2638219089Spjd	} else if (1 < retry)
2639219089Spjd		syslog(LOG_INFO, "NET_RT_DUMP %d retires", retry);
2640219089Spjd
2641185029Spjd	lim = buf + msize;
2642219089Spjd	for (p = buf; p < lim; p += rtm->rtm_msglen) {
2643168404Spjd		rtm = (struct rt_msghdr *)(void *)p;
2644168404Spjd		rt_entry(rtm, again);
2645168404Spjd	}
2646185029Spjd	free(buf);
2647185029Spjd}
2648185029Spjd
2649185029Spjdstatic void
2650185029Spjdrt_entry(struct rt_msghdr *rtm, int again)
2651185029Spjd{
2652219089Spjd	struct	sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask;
2653185029Spjd	struct	sockaddr_in6 *sin6_genmask, *sin6_ifp;
2654219089Spjd	char	*rtmp, *ifname = NULL;
2655219089Spjd	struct	riprt *rrt, *orrt;
2656219089Spjd	struct	netinfo6 *np;
2657219089Spjd	int ifindex;
2658219089Spjd
2659219089Spjd	sin6_dst = sin6_gw = sin6_mask = sin6_genmask = sin6_ifp = 0;
2660219089Spjd	if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags &
2661219089Spjd		(RTF_XRESOLVE|RTF_BLACKHOLE)) {
2662219089Spjd		return;		/* not interested in the link route */
2663219089Spjd	}
2664185029Spjd	/* do not look at cloned routes */
2665185029Spjd#ifdef RTF_WASCLONED
2666168404Spjd	if (rtm->rtm_flags & RTF_WASCLONED)
2667168404Spjd		return;
2668168404Spjd#endif
2669168404Spjd#ifdef RTF_CLONED
2670168404Spjd	if (rtm->rtm_flags & RTF_CLONED)
2671168404Spjd		return;
2672168404Spjd#endif
2673185029Spjd	/* XXX: Ignore connected routes. */
2674168404Spjd	if (!(rtm->rtm_flags & (RTF_GATEWAY|RTF_HOST|RTF_STATIC)))
2675185029Spjd		return;
2676168404Spjd	/*
2677168404Spjd	 * do not look at dynamic routes.
2678219089Spjd	 * netbsd/openbsd cloned routes have UGHD.
2679168404Spjd	 */
2680219089Spjd	if (rtm->rtm_flags & RTF_DYNAMIC)
2681219089Spjd		return;
2682219089Spjd	rtmp = (char *)(rtm + 1);
2683219089Spjd	/* Destination */
2684219089Spjd	if ((rtm->rtm_addrs & RTA_DST) == 0)
2685219089Spjd		return;		/* ignore routes without destination address */
2686219089Spjd	sin6_dst = (struct sockaddr_in6 *)(void *)rtmp;
2687219089Spjd	rtmp += ROUNDUP(sin6_dst->sin6_len);
2688219089Spjd	if (rtm->rtm_addrs & RTA_GATEWAY) {
2689219089Spjd		sin6_gw = (struct sockaddr_in6 *)(void *)rtmp;
2690219089Spjd		rtmp += ROUNDUP(sin6_gw->sin6_len);
2691219089Spjd	}
2692219089Spjd	if (rtm->rtm_addrs & RTA_NETMASK) {
2693219089Spjd		sin6_mask = (struct sockaddr_in6 *)(void *)rtmp;
2694219089Spjd		rtmp += ROUNDUP(sin6_mask->sin6_len);
2695219089Spjd	}
2696219089Spjd	if (rtm->rtm_addrs & RTA_GENMASK) {
2697219089Spjd		sin6_genmask = (struct sockaddr_in6 *)(void *)rtmp;
2698219089Spjd		rtmp += ROUNDUP(sin6_genmask->sin6_len);
2699219089Spjd	}
2700219089Spjd	if (rtm->rtm_addrs & RTA_IFP) {
2701219089Spjd		sin6_ifp = (struct sockaddr_in6 *)(void *)rtmp;
2702219089Spjd		rtmp += ROUNDUP(sin6_ifp->sin6_len);
2703219089Spjd	}
2704219089Spjd
2705219089Spjd	/* Destination */
2706219089Spjd	if (sin6_dst->sin6_family != AF_INET6)
2707236884Smm		return;
2708219089Spjd	if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst->sin6_addr))
2709219089Spjd		return;		/* Link-local */
2710219089Spjd	if (IN6_ARE_ADDR_EQUAL(&sin6_dst->sin6_addr, &in6addr_loopback))
2711219089Spjd		return;		/* Loopback */
2712249195Smm	if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr))
2713219089Spjd		return;
2714219089Spjd
2715219089Spjd	if ((rrt = MALLOC(struct riprt)) == NULL) {
2716219089Spjd		fatal("malloc: struct riprt");
2717219089Spjd		/*NOTREACHED*/
2718168404Spjd	}
2719168404Spjd	memset(rrt, 0, sizeof(*rrt));
2720236884Smm	np = &rrt->rrt_info;
2721236884Smm	rrt->rrt_same = NULL;
2722236884Smm	rrt->rrt_t = time(NULL);
2723236884Smm	if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC))
2724236884Smm		rrt->rrt_t = 0;	/* Don't age static routes */
2725236884Smm	if (rtm->rtm_flags & Pflag)
2726236884Smm		rrt->rrt_t = 0;	/* Don't age PROTO[123] routes */
2727236884Smm	if ((rtm->rtm_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST)
2728236884Smm		rrt->rrt_t = 0;	/* Don't age non-gateway host routes */
2729236884Smm	np->rip6_tag = 0;
2730236884Smm	np->rip6_metric = rtm->rtm_rmx.rmx_hopcount;
2731219089Spjd	if (np->rip6_metric < 1)
2732219089Spjd		np->rip6_metric = 1;
2733219089Spjd	rrt->rrt_flags = rtm->rtm_flags;
2734219089Spjd	np->rip6_dest = sin6_dst->sin6_addr;
2735219089Spjd
2736219089Spjd	/* Mask or plen */
2737219089Spjd	if (rtm->rtm_flags & RTF_HOST)
2738219089Spjd		np->rip6_plen = 128;	/* Host route */
2739219089Spjd	else if (sin6_mask)
2740219089Spjd		np->rip6_plen = sin6mask2len(sin6_mask);
2741219089Spjd	else
2742219089Spjd		np->rip6_plen = 0;
2743168404Spjd
2744168404Spjd	orrt = rtsearch(np);
2745168404Spjd	if (orrt && orrt->rrt_info.rip6_metric != HOPCNT_INFINITY6) {
2746209962Smm		/* Already found */
2747209962Smm		if (!again) {
2748168404Spjd			trace(1, "route: %s/%d flags %s: already registered\n",
2749168404Spjd				inet6_n2p(&np->rip6_dest), np->rip6_plen,
2750168404Spjd				rtflags(rtm));
2751219089Spjd		}
2752219089Spjd		free(rrt);
2753219089Spjd		return;
2754168404Spjd	}
2755219089Spjd	/* Gateway */
2756219089Spjd	if (!sin6_gw)
2757168404Spjd		memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
2758168404Spjd	else {
2759185029Spjd		if (sin6_gw->sin6_family == AF_INET6)
2760168404Spjd			rrt->rrt_gw = sin6_gw->sin6_addr;
2761168404Spjd		else if (sin6_gw->sin6_family == AF_LINK) {
2762168404Spjd			/* XXX in case ppp link? */
2763219089Spjd			rrt->rrt_gw = in6addr_loopback;
2764219089Spjd		} else
2765219089Spjd			memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
2766168404Spjd	}
2767168404Spjd	trace(1, "route: %s/%d flags %s",
2768168404Spjd		inet6_n2p(&np->rip6_dest), np->rip6_plen, rtflags(rtm));
2769168404Spjd	trace(1, " gw %s", inet6_n2p(&rrt->rrt_gw));
2770219089Spjd
2771219089Spjd	/* Interface */
2772219089Spjd	ifindex = rtm->rtm_index;
2773219089Spjd	if ((unsigned int)ifindex < nindex2ifc && index2ifc[ifindex])
2774219089Spjd		ifname = index2ifc[ifindex]->ifc_name;
2775168404Spjd	else {
2776219089Spjd		trace(1, " not configured\n");
2777168404Spjd		free(rrt);
2778168404Spjd		return;
2779168404Spjd	}
2780168404Spjd	trace(1, " if %s sock %d", ifname, ifindex);
2781209962Smm	rrt->rrt_index = ifindex;
2782219089Spjd
2783209962Smm	trace(1, "\n");
2784168404Spjd
2785168404Spjd	/* Check gateway */
2786219089Spjd	if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_gw) &&
2787219089Spjd	    !IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw) &&
2788219089Spjd	    (rrt->rrt_flags & RTF_LOCAL) == 0) {
2789168404Spjd		trace(0, "***** Gateway %s is not a link-local address.\n",
2790168404Spjd			inet6_n2p(&rrt->rrt_gw));
2791209962Smm		trace(0, "*****     dest(%s) if(%s) -- Not optimized.\n",
2792168404Spjd			inet6_n2p(&rrt->rrt_info.rip6_dest), ifname);
2793168404Spjd		rrt->rrt_rflags |= RRTF_NH_NOT_LLADDR;
2794168404Spjd	}
2795168404Spjd
2796168404Spjd	/* Put it to the route list */
2797168404Spjd	if (orrt && orrt->rrt_info.rip6_metric == HOPCNT_INFINITY6) {
2798168404Spjd		/* replace route list */
2799168404Spjd		TAILQ_INSERT_BEFORE(orrt, rrt, rrt_next);
2800168404Spjd		TAILQ_REMOVE(&riprt_head, orrt, rrt_next);
2801208683Spjd
2802208683Spjd		trace(1, "route: %s/%d flags %s: replace new route\n",
2803208683Spjd		    inet6_n2p(&np->rip6_dest), np->rip6_plen,
2804208683Spjd		    rtflags(rtm));
2805219089Spjd		free(orrt);
2806219089Spjd	} else
2807208683Spjd		TAILQ_INSERT_HEAD(&riprt_head, rrt, rrt_next);
2808219089Spjd}
2809219089Spjd
2810248571Smmstatic int
2811248571Smmaddroute(struct riprt *rrt,
2812248571Smm	const struct in6_addr *gw,
2813248571Smm	struct ifc *ifcp)
2814248571Smm{
2815248571Smm	struct	netinfo6 *np;
2816219089Spjd	u_char	buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ];
2817219089Spjd	struct	rt_msghdr	*rtm;
2818219089Spjd	struct	sockaddr_in6	*sin6;
2819219089Spjd	int	len;
2820219089Spjd
2821219089Spjd	np = &rrt->rrt_info;
2822219089Spjd	inet_ntop(AF_INET6, (const void *)gw, (char *)buf1, sizeof(buf1));
2823219089Spjd	inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2));
2824219089Spjd	tracet(1, "ADD: %s/%d gw %s [%d] ifa %s\n",
2825168404Spjd		inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1,
2826168404Spjd		np->rip6_metric - 1, buf2);
2827219089Spjd	if (rtlog)
2828219089Spjd		fprintf(rtlog, "%s: ADD: %s/%d gw %s [%d] ifa %s\n", hms(),
2829168404Spjd			inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1,
2830219089Spjd			np->rip6_metric - 1, buf2);
2831219089Spjd	if (nflag)
2832219089Spjd		return 0;
2833219089Spjd
2834219089Spjd	memset(buf, 0, sizeof(buf));
2835219089Spjd	rtm = (struct rt_msghdr *)(void *)buf;
2836219089Spjd	rtm->rtm_type = RTM_ADD;
2837219089Spjd	rtm->rtm_version = RTM_VERSION;
2838268720Sdelphij	rtm->rtm_seq = ++seq;
2839219089Spjd	rtm->rtm_pid = pid;
2840219089Spjd	rtm->rtm_flags = rrt->rrt_flags;
2841219089Spjd	rtm->rtm_flags |= Qflag;
2842219089Spjd	rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
2843219089Spjd	rtm->rtm_rmx.rmx_hopcount = np->rip6_metric - 1;
2844168404Spjd	rtm->rtm_inits = RTV_HOPCOUNT;
2845168404Spjd	sin6 = (struct sockaddr_in6 *)(void *)&buf[sizeof(struct rt_msghdr)];
2846236884Smm	/* Destination */
2847236884Smm	sin6->sin6_len = sizeof(struct sockaddr_in6);
2848236884Smm	sin6->sin6_family = AF_INET6;
2849236884Smm	sin6->sin6_addr = np->rip6_dest;
2850236884Smm	sin6 = (struct sockaddr_in6 *)(void *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
2851236884Smm	/* Gateway */
2852236884Smm	sin6->sin6_len = sizeof(struct sockaddr_in6);
2853219089Spjd	sin6->sin6_family = AF_INET6;
2854219089Spjd	sin6->sin6_addr = *gw;
2855219089Spjd	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
2856219089Spjd		sin6->sin6_scope_id = ifcp->ifc_index;
2857236884Smm	sin6 = (struct sockaddr_in6 *)(void *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
2858219089Spjd	/* Netmask */
2859219089Spjd	sin6->sin6_len = sizeof(struct sockaddr_in6);
2860219089Spjd	sin6->sin6_family = AF_INET6;
2861219089Spjd	sin6->sin6_addr = *(plen2mask(np->rip6_plen));
2862219089Spjd	sin6 = (struct sockaddr_in6 *)(void *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
2863219089Spjd
2864219089Spjd	len = (char *)sin6 - (char *)buf;
2865219089Spjd	rtm->rtm_msglen = len;
2866219089Spjd	if (write(rtsock, buf, len) > 0)
2867219089Spjd		return 0;
2868268720Sdelphij
2869268720Sdelphij	if (errno == EEXIST) {
2870219089Spjd		trace(0, "ADD: Route already exists %s/%d gw %s\n",
2871219089Spjd		    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1);
2872219089Spjd		if (rtlog)
2873219089Spjd			fprintf(rtlog, "ADD: Route already exists %s/%d gw %s\n",
2874219089Spjd			    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1);
2875219089Spjd	} else {
2876219089Spjd		trace(0, "Can not write to rtsock (addroute): %s\n",
2877219089Spjd		    strerror(errno));
2878219089Spjd		if (rtlog)
2879219089Spjd			fprintf(rtlog, "\tCan not write to rtsock: %s\n",
2880219089Spjd			    strerror(errno));
2881219089Spjd	}
2882219089Spjd	return -1;
2883219089Spjd}
2884219089Spjd
2885219089Spjdstatic int
2886219089Spjddelroute(struct netinfo6 *np, struct in6_addr *gw)
2887219089Spjd{
2888236884Smm	u_char	buf[BUFSIZ], buf2[BUFSIZ];
2889236884Smm	struct	rt_msghdr	*rtm;
2890219089Spjd	struct	sockaddr_in6	*sin6;
2891236884Smm	int	len;
2892236884Smm
2893236884Smm	inet_ntop(AF_INET6, (void *)gw, (char *)buf2, sizeof(buf2));
2894236884Smm	tracet(1, "DEL: %s/%d gw %s\n", inet6_n2p(&np->rip6_dest),
2895236884Smm		np->rip6_plen, buf2);
2896236884Smm	if (rtlog)
2897236884Smm		fprintf(rtlog, "%s: DEL: %s/%d gw %s\n",
2898236884Smm			hms(), inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
2899236884Smm	if (nflag)
2900219089Spjd		return 0;
2901219089Spjd
2902219089Spjd	memset(buf, 0, sizeof(buf));
2903219089Spjd	rtm = (struct rt_msghdr *)(void *)buf;
2904219089Spjd	rtm->rtm_type = RTM_DELETE;
2905219089Spjd	rtm->rtm_version = RTM_VERSION;
2906219089Spjd	rtm->rtm_seq = ++seq;
2907219089Spjd	rtm->rtm_pid = pid;
2908219089Spjd	rtm->rtm_flags = RTF_UP | RTF_GATEWAY;
2909219089Spjd	rtm->rtm_flags |= Qflag;
2910219089Spjd	if (np->rip6_plen == sizeof(struct in6_addr) * 8)
2911219089Spjd		rtm->rtm_flags |= RTF_HOST;
2912219089Spjd	rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
2913219089Spjd	sin6 = (struct sockaddr_in6 *)(void *)&buf[sizeof(struct rt_msghdr)];
2914219089Spjd	/* Destination */
2915219089Spjd	sin6->sin6_len = sizeof(struct sockaddr_in6);
2916219089Spjd	sin6->sin6_family = AF_INET6;
2917219089Spjd	sin6->sin6_addr = np->rip6_dest;
2918219089Spjd	sin6 = (struct sockaddr_in6 *)(void *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
2919219089Spjd	/* Gateway */
2920219089Spjd	sin6->sin6_len = sizeof(struct sockaddr_in6);
2921219089Spjd	sin6->sin6_family = AF_INET6;
2922219089Spjd	sin6->sin6_addr = *gw;
2923236884Smm	sin6 = (struct sockaddr_in6 *)(void *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
2924236884Smm	/* Netmask */
2925236884Smm	sin6->sin6_len = sizeof(struct sockaddr_in6);
2926236884Smm	sin6->sin6_family = AF_INET6;
2927236884Smm	sin6->sin6_addr = *(plen2mask(np->rip6_plen));
2928236884Smm	sin6 = (struct sockaddr_in6 *)(void *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
2929236884Smm
2930236884Smm	len = (char *)sin6 - (char *)buf;
2931236884Smm	rtm->rtm_msglen = len;
2932236884Smm	if (write(rtsock, buf, len) >= 0)
2933236884Smm		return 0;
2934236884Smm
2935236884Smm	if (errno == ESRCH) {
2936236884Smm		trace(0, "RTDEL: Route does not exist: %s/%d gw %s\n",
2937219089Spjd		    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
2938219089Spjd		if (rtlog)
2939168404Spjd			fprintf(rtlog, "RTDEL: Route does not exist: %s/%d gw %s\n",
2940168404Spjd			    inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
2941168404Spjd	} else {
2942168404Spjd		trace(0, "Can not write to rtsock (delroute): %s\n",
2943168404Spjd		    strerror(errno));
2944168404Spjd		if (rtlog)
2945185029Spjd			fprintf(rtlog, "\tCan not write to rtsock: %s\n",
2946168404Spjd			    strerror(errno));
2947168404Spjd	}
2948168404Spjd	return -1;
2949168404Spjd}
2950168404Spjd
2951168404Spjd#if 0
2952219089Spjdstatic struct in6_addr *
2953219089Spjdgetroute(struct netinfo6 *np, struct in6_addr *gw)
2954168404Spjd{
2955168404Spjd	u_char buf[BUFSIZ];
2956219089Spjd	int myseq;
2957168404Spjd	int len;
2958168404Spjd	struct rt_msghdr *rtm;
2959219089Spjd	struct sockaddr_in6 *sin6;
2960168404Spjd
2961168404Spjd	rtm = (struct rt_msghdr *)(void *)buf;
2962168404Spjd	len = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6);
2963168404Spjd	memset(rtm, 0, len);
2964168404Spjd	rtm->rtm_type = RTM_GET;
2965168404Spjd	rtm->rtm_version = RTM_VERSION;
2966168404Spjd	myseq = ++seq;
2967168404Spjd	rtm->rtm_seq = myseq;
2968168404Spjd	rtm->rtm_addrs = RTA_DST;
2969168404Spjd	rtm->rtm_msglen = len;
2970168404Spjd	sin6 = (struct sockaddr_in6 *)(void *)&buf[sizeof(struct rt_msghdr)];
2971168404Spjd	sin6->sin6_len = sizeof(struct sockaddr_in6);
2972168404Spjd	sin6->sin6_family = AF_INET6;
2973168404Spjd	sin6->sin6_addr = np->rip6_dest;
2974168404Spjd	if (write(rtsock, buf, len) < 0) {
2975168404Spjd		if (errno == ESRCH)	/* No such route found */
2976168404Spjd			return NULL;
2977249195Smm		perror("write to rtsock");
2978168404Spjd		exit(1);
2979219089Spjd	}
2980168404Spjd	do {
2981219089Spjd		if ((len = read(rtsock, buf, sizeof(buf))) < 0) {
2982168404Spjd			perror("read from rtsock");
2983219089Spjd			exit(1);
2984219089Spjd		}
2985219089Spjd		rtm = (struct rt_msghdr *)(void *)buf;
2986219089Spjd	} while (rtm->rtm_type != RTM_GET || rtm->rtm_seq != myseq ||
2987219089Spjd	    rtm->rtm_pid != pid);
2988219089Spjd	sin6 = (struct sockaddr_in6 *)(void *)&buf[sizeof(struct rt_msghdr)];
2989219089Spjd	if (rtm->rtm_addrs & RTA_DST) {
2990209962Smm		sin6 = (struct sockaddr_in6 *)(void *)
2991168404Spjd			((char *)sin6 + ROUNDUP(sin6->sin6_len));
2992219089Spjd	}
2993219089Spjd	if (rtm->rtm_addrs & RTA_GATEWAY) {
2994168404Spjd		*gw = sin6->sin6_addr;
2995219089Spjd		return gw;
2996219089Spjd	}
2997219089Spjd	return NULL;
2998168404Spjd}
2999168404Spjd#endif
3000168404Spjd
3001168404Spjdstatic const char *
3002168404Spjdinet6_n2p(const struct in6_addr *p)
3003168404Spjd{
3004168404Spjd	static char buf[BUFSIZ];
3005168404Spjd
3006168404Spjd	return inet_ntop(AF_INET6, (const void *)p, buf, sizeof(buf));
3007168404Spjd}
3008185029Spjd
3009168404Spjdstatic void
3010168404Spjdifrtdump(int sig)
3011168404Spjd{
3012249195Smm
3013168404Spjd	ifdump(sig);
3014168404Spjd	rtdump(sig);
3015168404Spjd}
3016168404Spjd
3017168404Spjdstatic void
3018168404Spjdifdump(int sig)
3019168404Spjd{
3020168404Spjd	struct ifc *ifcp;
3021219089Spjd	FILE *dump;
3022219089Spjd	int nifc = 0;
3023219089Spjd
3024219089Spjd	if (sig == 0)
3025219089Spjd		dump = stderr;
3026219089Spjd	else
3027219089Spjd		if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL)
3028168404Spjd			dump = stderr;
3029168404Spjd
3030219089Spjd	fprintf(dump, "%s: Interface Table Dump\n", hms());
3031168404Spjd	TAILQ_FOREACH(ifcp, &ifc_head, ifc_next)
3032168404Spjd		nifc++;
3033168404Spjd	fprintf(dump, "  Number of interfaces: %d\n", nifc);
3034168404Spjd
3035168404Spjd	fprintf(dump, "  advertising interfaces:\n");
3036168404Spjd	TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) {
3037168404Spjd		if ((ifcp->ifc_flags & IFF_UP) == 0)
3038168404Spjd			continue;
3039185029Spjd		if (iff_find(ifcp, IFIL_TYPE_N) != NULL)
3040219089Spjd			continue;
3041219089Spjd		ifdump0(dump, ifcp);
3042219089Spjd	}
3043219089Spjd	fprintf(dump, "\n");
3044219089Spjd	fprintf(dump, "  non-advertising interfaces:\n");
3045219089Spjd	TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) {
3046219089Spjd		if ((ifcp->ifc_flags & IFF_UP) &&
3047219089Spjd		    (iff_find(ifcp, IFIL_TYPE_N) == NULL))
3048219089Spjd			continue;
3049219089Spjd		ifdump0(dump, ifcp);
3050219089Spjd	}
3051219089Spjd	fprintf(dump, "\n");
3052219089Spjd	if (dump != stderr)
3053219089Spjd		fclose(dump);
3054219089Spjd}
3055219089Spjd
3056168404Spjdstatic void
3057219089Spjdifdump0(FILE *dump, const struct ifc *ifcp)
3058219089Spjd{
3059219089Spjd	struct ifac *ifac;
3060249047Savg	struct iff *iffp;
3061219089Spjd	char buf[BUFSIZ];
3062219089Spjd	const char *ft;
3063219089Spjd	int addr;
3064168404Spjd
3065168404Spjd	fprintf(dump, "    %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)\n",
3066168404Spjd		ifcp->ifc_name, ifcp->ifc_index, ifflags(ifcp->ifc_flags),
3067168404Spjd		inet6_n2p(&ifcp->ifc_mylladdr),
3068168404Spjd		ifcp->ifc_mtu, ifcp->ifc_metric);
3069168404Spjd	TAILQ_FOREACH(ifac, &ifcp->ifc_ifac_head, ifac_next) {
3070168404Spjd		if (ifcp->ifc_flags & IFF_POINTOPOINT) {
3071219089Spjd			inet_ntop(AF_INET6, (void *)&ifac->ifac_raddr,
3072219089Spjd				buf, sizeof(buf));
3073219089Spjd			fprintf(dump, "\t%s/%d -- %s\n",
3074219089Spjd				inet6_n2p(&ifac->ifac_addr),
3075219089Spjd				ifac->ifac_plen, buf);
3076219089Spjd		} else {
3077219089Spjd			fprintf(dump, "\t%s/%d\n",
3078168404Spjd				inet6_n2p(&ifac->ifac_addr),
3079168404Spjd				ifac->ifac_plen);
3080219089Spjd		}
3081168404Spjd	}
3082168404Spjd
3083168404Spjd	fprintf(dump, "\tFilter:\n");
3084168404Spjd	TAILQ_FOREACH(iffp, &ifcp->ifc_iff_head, iff_next) {
3085168404Spjd		addr = 0;
3086168404Spjd		switch (iffp->iff_type) {
3087168404Spjd		case IFIL_TYPE_A:
3088168404Spjd			ft = "Aggregate"; addr++; break;
3089168404Spjd		case IFIL_TYPE_N:
3090168404Spjd			ft = "No-use"; break;
3091168404Spjd		case IFIL_TYPE_O:
3092168404Spjd			ft = "Advertise-only"; addr++; break;
3093168404Spjd		case IFIL_TYPE_T:
3094168404Spjd			ft = "Default-only"; break;
3095168404Spjd		case IFIL_TYPE_L:
3096168404Spjd			ft = "Listen-only"; addr++; break;
3097168404Spjd		default:
3098168404Spjd			snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type);
3099168404Spjd			ft = buf;
3100168404Spjd			addr++;
3101168404Spjd			break;
3102168404Spjd		}
3103168404Spjd		fprintf(dump, "\t\t%s", ft);
3104168404Spjd		if (addr)
3105168404Spjd			fprintf(dump, "(%s/%d)", inet6_n2p(&iffp->iff_addr),
3106168404Spjd				iffp->iff_plen);
3107168404Spjd		fprintf(dump, "\n");
3108168404Spjd	}
3109168404Spjd	fprintf(dump, "\n");
3110168404Spjd}
3111185029Spjd
3112185029Spjdstatic void
3113185029Spjdrtdump(int sig)
3114168404Spjd{
3115168404Spjd	struct	riprt *rrt;
3116168404Spjd	char	buf[BUFSIZ];
3117168404Spjd	FILE	*dump;
3118168404Spjd	time_t	t, age;
3119168404Spjd
3120168404Spjd	if (sig == 0)
3121168404Spjd		dump = stderr;
3122168404Spjd	else
3123168404Spjd		if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL)
3124168404Spjd			dump = stderr;
3125209962Smm
3126209962Smm	t = time(NULL);
3127185029Spjd	fprintf(dump, "\n%s: Routing Table Dump\n", hms());
3128168404Spjd	TAILQ_FOREACH(rrt, &riprt_head, rrt_next) {
3129168404Spjd		if (rrt->rrt_t == 0)
3130168404Spjd			age = 0;
3131168404Spjd		else
3132185029Spjd			age = t - rrt->rrt_t;
3133168404Spjd		inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest,
3134168404Spjd			buf, sizeof(buf));
3135168404Spjd		fprintf(dump, "    %s/%d if(%d:%s) gw(%s) [%d] age(%ld)",
3136168404Spjd			buf, rrt->rrt_info.rip6_plen, rrt->rrt_index,
3137168404Spjd			index2ifc[rrt->rrt_index]->ifc_name,
3138168404Spjd			inet6_n2p(&rrt->rrt_gw),
3139168404Spjd			rrt->rrt_info.rip6_metric, (long)age);
3140168404Spjd		if (rrt->rrt_info.rip6_tag) {
3141168404Spjd			fprintf(dump, " tag(0x%04x)",
3142168404Spjd				ntohs(rrt->rrt_info.rip6_tag) & 0xffff);
3143168404Spjd		}
3144168404Spjd		if (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)
3145168404Spjd			fprintf(dump, " NOT-LL");
3146168404Spjd		if (rrt->rrt_rflags & RRTF_NOADVERTISE)
3147168404Spjd			fprintf(dump, " NO-ADV");
3148185029Spjd		fprintf(dump, "\n");
3149185029Spjd	}
3150168404Spjd	fprintf(dump, "\n");
3151219089Spjd	if (dump != stderr)
3152168404Spjd		fclose(dump);
3153168404Spjd}
3154168404Spjd
3155168404Spjd/*
3156168404Spjd * Parse the -A (and -O) options and put corresponding filter object to the
3157168404Spjd * specified interface structures.  Each of the -A/O option has the following
3158168404Spjd * syntax:	-A 5f09:c400::/32,ef0,ef1  (aggregate)
3159168404Spjd * 		-O 5f09:c400::/32,ef0,ef1  (only when match)
3160185029Spjd */
3161185029Spjdstatic void
3162185029Spjdfilterconfig(void)
3163185029Spjd{
3164185029Spjd	int i;
3165185029Spjd	char *p, *ap, *iflp, *ifname, *ep;
3166185029Spjd	struct iff iff, *iffp;
3167185029Spjd	struct ifc *ifcp;
3168185029Spjd	struct riprt *rrt;
3169185029Spjd#if 0
3170185029Spjd	struct in6_addr gw;
3171185029Spjd#endif
3172185029Spjd	u_long plen;
3173185029Spjd
3174209962Smm	for (i = 0; i < nfilter; i++) {
3175209962Smm		ap = filter[i];
3176185029Spjd		iflp = NULL;
3177185029Spjd		iffp = &iff;
3178185029Spjd		memset(iffp, 0, sizeof(*iffp));
3179185029Spjd		if (filtertype[i] == 'N' || filtertype[i] == 'T') {
3180185029Spjd			iflp = ap;
3181185029Spjd			goto ifonly;
3182185029Spjd		}
3183185029Spjd		if ((p = strchr(ap, ',')) != NULL) {
3184185029Spjd			*p++ = '\0';
3185185029Spjd			iflp = p;
3186185029Spjd		}
3187185029Spjd		if ((p = strchr(ap, '/')) == NULL) {
3188185029Spjd			fatal("no prefixlen specified for '%s'", ap);
3189185029Spjd			/*NOTREACHED*/
3190185029Spjd		}
3191185029Spjd		*p++ = '\0';
3192185029Spjd		if (inet_pton(AF_INET6, ap, &iffp->iff_addr) != 1) {
3193185029Spjd			fatal("invalid prefix specified for '%s'", ap);
3194185029Spjd			/*NOTREACHED*/
3195185029Spjd		}
3196185029Spjd		errno = 0;
3197185029Spjd		ep = NULL;
3198185029Spjd		plen = strtoul(p, &ep, 10);
3199185029Spjd		if (errno || !*p || *ep || plen > sizeof(iffp->iff_addr) * 8) {
3200185029Spjd			fatal("invalid prefix length specified for '%s'", ap);
3201185029Spjd			/*NOTREACHED*/
3202185029Spjd		}
3203185029Spjd		iffp->iff_plen = plen;
3204185029Spjd		applyplen(&iffp->iff_addr, iffp->iff_plen);
3205185029Spjdifonly:
3206185029Spjd		iffp->iff_type = filtertype[i];
3207185029Spjd		if (iflp == NULL || *iflp == '\0') {
3208219089Spjd			fatal("no interface specified for '%s'", ap);
3209219089Spjd			/*NOTREACHED*/
3210185029Spjd		}
3211185029Spjd		/* parse the interface listing portion */
3212185029Spjd		while (iflp) {
3213185029Spjd			ifname = iflp;
3214185029Spjd			if ((iflp = strchr(iflp, ',')) != NULL)
3215236884Smm				*iflp++ = '\0';
3216236884Smm
3217236884Smm			TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) {
3218236884Smm				if (fnmatch(ifname, ifcp->ifc_name, 0) != 0)
3219236884Smm					continue;
3220236884Smm
3221236884Smm				iffp = malloc(sizeof(*iffp));
3222236884Smm				if (iffp == NULL) {
3223236884Smm					fatal("malloc of iff");
3224236884Smm					/*NOTREACHED*/
3225253993Smav				}
3226253993Smav				memcpy(iffp, &iff, sizeof(*iffp));
3227253993Smav#if 0
3228253993Smav				syslog(LOG_INFO, "Add filter: type %d, ifname %s.", iffp->iff_type, ifname);
3229236884Smm#endif
3230236884Smm				TAILQ_INSERT_HEAD(&ifcp->ifc_iff_head, iffp, iff_next);
3231236884Smm			}
3232236884Smm		}
3233236884Smm
3234236884Smm		/*
3235236884Smm		 * -A: aggregate configuration.
3236236884Smm		 */
3237236884Smm		if (filtertype[i] != IFIL_TYPE_A)
3238236884Smm			continue;
3239236884Smm		/* put the aggregate to the kernel routing table */
3240236884Smm		rrt = (struct riprt *)malloc(sizeof(struct riprt));
3241236884Smm		if (rrt == NULL) {
3242236884Smm			fatal("malloc: rrt");
3243236884Smm			/*NOTREACHED*/
3244236884Smm		}
3245236884Smm		memset(rrt, 0, sizeof(struct riprt));
3246236884Smm		rrt->rrt_info.rip6_dest = iff.iff_addr;
3247236884Smm		rrt->rrt_info.rip6_plen = iff.iff_plen;
3248236884Smm		rrt->rrt_info.rip6_metric = 1;
3249236884Smm		rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
3250236884Smm		rrt->rrt_gw = in6addr_loopback;
3251236884Smm		rrt->rrt_flags = RTF_UP | RTF_REJECT;
3252236884Smm		rrt->rrt_rflags = RRTF_AGGREGATE;
3253236884Smm		rrt->rrt_t = 0;
3254236884Smm		rrt->rrt_index = loopifcp->ifc_index;
3255253993Smav#if 0
3256236884Smm		if (getroute(&rrt->rrt_info, &gw)) {
3257236884Smm#if 0
3258236884Smm			/*
3259236884Smm			 * When the address has already been registered in the
3260236884Smm			 * kernel routing table, it should be removed
3261168404Spjd			 */
3262236884Smm			delroute(&rrt->rrt_info, &gw);
3263236884Smm#else
3264168404Spjd			/* it is safer behavior */
3265168404Spjd			errno = EINVAL;
3266168404Spjd			fatal("%s/%u already in routing table, "
3267168404Spjd			    "cannot aggregate",
3268168404Spjd			    inet6_n2p(&rrt->rrt_info.rip6_dest),
3269219089Spjd			    rrt->rrt_info.rip6_plen);
3270168404Spjd			/*NOTREACHED*/
3271209962Smm#endif
3272209962Smm		}
3273209962Smm#endif
3274209962Smm		/* Put the route to the list */
3275209962Smm		TAILQ_INSERT_HEAD(&riprt_head, rrt, rrt_next);
3276209962Smm		trace(1, "Aggregate: %s/%d for %s\n",
3277209962Smm			inet6_n2p(&iff.iff_addr), iff.iff_plen,
3278168404Spjd			loopifcp->ifc_name);
3279209962Smm		/* Add this route to the kernel */
3280219089Spjd		if (nflag) 	/* do not modify kernel routing table */
3281219089Spjd			continue;
3282219089Spjd		addroute(rrt, &in6addr_loopback, loopifcp);
3283219089Spjd	}
3284219089Spjd}
3285219089Spjd
3286219089Spjd/***************** utility functions *****************/
3287185029Spjd
3288209962Smm/*
3289209962Smm * Returns a pointer to ifac whose address and prefix length matches
3290185029Spjd * with the address and prefix length specified in the arguments.
3291209962Smm */
3292209962Smmstatic struct ifac *
3293209962Smmifa_match(const struct ifc *ifcp,
3294209962Smm	const struct in6_addr *ia,
3295209962Smm	int plen)
3296209962Smm{
3297209962Smm	struct ifac *ifac;
3298236884Smm
3299209962Smm	TAILQ_FOREACH(ifac, &ifcp->ifc_ifac_head, ifac_next) {
3300168404Spjd		if (IN6_ARE_ADDR_EQUAL(&ifac->ifac_addr, ia) &&
3301168404Spjd		    ifac->ifac_plen == plen)
3302168404Spjd			break;
3303168404Spjd	}
3304168404Spjd
3305168404Spjd	return (ifac);
3306168404Spjd}
3307168404Spjd
3308168404Spjd/*
3309168404Spjd * Return a pointer to riprt structure whose address and prefix length
3310168404Spjd * matches with the address and prefix length found in the argument.
3311168404Spjd * Note: This is not a rtalloc().  Therefore exact match is necessary.
3312168404Spjd */
3313168404Spjdstatic struct riprt *
3314168404Spjdrtsearch(struct netinfo6 *np)
3315168404Spjd{
3316168404Spjd	struct	riprt	*rrt;
3317168404Spjd
3318168404Spjd	TAILQ_FOREACH(rrt, &riprt_head, rrt_next) {
3319168404Spjd		if (rrt->rrt_info.rip6_plen == np->rip6_plen &&
3320168404Spjd		    IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
3321209962Smm				       &np->rip6_dest))
3322209962Smm			break;
3323168404Spjd	}
3324209962Smm
3325168404Spjd	return (rrt);
3326168404Spjd}
3327168404Spjd
3328168404Spjdstatic int
3329168404Spjdsin6mask2len(const struct sockaddr_in6 *sin6)
3330185029Spjd{
3331185029Spjd
3332185029Spjd	return mask2len(&sin6->sin6_addr,
3333185029Spjd	    sin6->sin6_len - offsetof(struct sockaddr_in6, sin6_addr));
3334168404Spjd}
3335168404Spjd
3336185029Spjdstatic int
3337185029Spjdmask2len(const struct in6_addr *addr, int lenlim)
3338185029Spjd{
3339168404Spjd	int i = 0, j;
3340185029Spjd	const u_char *p = (const u_char *)addr;
3341185029Spjd
3342168404Spjd	for (j = 0; j < lenlim; j++, p++) {
3343168404Spjd		if (*p != 0xff)
3344168404Spjd			break;
3345185029Spjd		i += 8;
3346185029Spjd	}
3347168404Spjd	if (j < lenlim) {
3348185029Spjd		switch (*p) {
3349168404Spjd#define	MASKLEN(m, l)	case m: do { i += l; break; } while (0)
3350185029Spjd		MASKLEN(0xfe, 7); break;
3351168404Spjd		MASKLEN(0xfc, 6); break;
3352168404Spjd		MASKLEN(0xf8, 5); break;
3353185029Spjd		MASKLEN(0xf0, 4); break;
3354249195Smm		MASKLEN(0xe0, 3); break;
3355168404Spjd		MASKLEN(0xc0, 2); break;
3356168404Spjd		MASKLEN(0x80, 1); break;
3357185029Spjd#undef	MASKLEN
3358185029Spjd		}
3359168404Spjd	}
3360185029Spjd	return i;
3361249195Smm}
3362168404Spjd
3363168404Spjdstatic const u_char plent[8] = {
3364185029Spjd	0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
3365168404Spjd};
3366168404Spjd
3367185029Spjdstatic void
3368185029Spjdapplyplen(struct in6_addr *ia, int plen)
3369168404Spjd{
3370185029Spjd	u_char	*p;
3371185029Spjd	int	i;
3372168404Spjd
3373168404Spjd	p = ia->s6_addr;
3374168404Spjd	for (i = 0; i < 16; i++) {
3375168404Spjd		if (plen <= 0)
3376168404Spjd			*p = 0;
3377249195Smm		else if (plen < 8)
3378168404Spjd			*p &= plent[plen];
3379168404Spjd		p++, plen -= 8;
3380168404Spjd	}
3381185029Spjd}
3382185029Spjd
3383185029Spjdstatic const int pl2m[9] = {
3384185029Spjd	0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
3385185029Spjd};
3386185029Spjd
3387185029Spjdstatic struct in6_addr *
3388249195Smmplen2mask(int n)
3389230514Smm{
3390185029Spjd	static struct in6_addr ia;
3391185029Spjd	u_char	*p;
3392185029Spjd	int	i;
3393168404Spjd
3394168404Spjd	memset(&ia, 0, sizeof(struct in6_addr));
3395168404Spjd	p = (u_char *)&ia;
3396185029Spjd	for (i = 0; i < 16; i++, p++, n -= 8) {
3397185029Spjd		if (n >= 8) {
3398168404Spjd			*p = 0xff;
3399168404Spjd			continue;
3400168404Spjd		}
3401168404Spjd		*p = pl2m[n];
3402168404Spjd		break;
3403185029Spjd	}
3404185029Spjd	return &ia;
3405168404Spjd}
3406168404Spjd
3407168404Spjdstatic char *
3408168404Spjdallocopy(char *p)
3409168404Spjd{
3410168404Spjd	int len = strlen(p) + 1;
3411185029Spjd	char *q = (char *)malloc(len);
3412185029Spjd
3413168404Spjd	if (!q) {
3414168404Spjd		fatal("malloc");
3415168404Spjd		/*NOTREACHED*/
3416185029Spjd	}
3417185029Spjd
3418185029Spjd	strlcpy(q, p, len);
3419185029Spjd	return q;
3420185029Spjd}
3421185029Spjd
3422185029Spjdstatic char *
3423185029Spjdhms(void)
3424185029Spjd{
3425185029Spjd	static char buf[BUFSIZ];
3426185029Spjd	time_t t;
3427185029Spjd	struct	tm *tm;
3428185029Spjd
3429185029Spjd	t = time(NULL);
3430185029Spjd	if ((tm = localtime(&t)) == 0) {
3431185029Spjd		fatal("localtime");
3432185029Spjd		/*NOTREACHED*/
3433185029Spjd	}
3434185029Spjd	snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
3435185029Spjd	    tm->tm_sec);
3436185029Spjd	return buf;
3437185029Spjd}
3438185029Spjd
3439185029Spjd#define	RIPRANDDEV	1.0	/* 30 +- 15, max - min = 30 */
3440185029Spjd
3441185029Spjdstatic int
3442185029Spjdripinterval(int timer)
3443185029Spjd{
3444185029Spjd	double r = rand();
3445185029Spjd
3446185029Spjd	interval = (int)(timer + timer * RIPRANDDEV * (r / RAND_MAX - 0.5));
3447185029Spjd	nextalarm = time(NULL) + interval;
3448185029Spjd	return interval;
3449185029Spjd}
3450185029Spjd
3451185029Spjd#if 0
3452185029Spjdstatic time_t
3453185029Spjdripsuptrig(void)
3454185029Spjd{
3455185029Spjd	time_t t;
3456185029Spjd
3457185029Spjd	double r = rand();
3458185029Spjd	t  = (int)(RIP_TRIG_INT6_MIN +
3459185029Spjd		(RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / RAND_MAX));
3460185029Spjd	sup_trig_update = time(NULL) + t;
3461185029Spjd	return t;
3462185029Spjd}
3463185029Spjd#endif
3464185029Spjd
3465185029Spjdstatic void
3466185029Spjdfatal(const char *fmt, ...)
3467185029Spjd{
3468185029Spjd	va_list ap;
3469185029Spjd	char buf[1024];
3470185029Spjd
3471185029Spjd	va_start(ap, fmt);
3472185029Spjd	vsnprintf(buf, sizeof(buf), fmt, ap);
3473185029Spjd	va_end(ap);
3474185029Spjd	perror(buf);
3475185029Spjd	if (errno)
3476185029Spjd		syslog(LOG_ERR, "%s: %s", buf, strerror(errno));
3477185029Spjd	else
3478185029Spjd		syslog(LOG_ERR, "%s", buf);
3479185029Spjd	rtdexit();
3480168404Spjd}
3481185029Spjd
3482185029Spjdstatic void
3483185029Spjdtracet(int level, const char *fmt, ...)
3484185029Spjd{
3485185029Spjd	va_list ap;
3486185029Spjd
3487185029Spjd	if (level <= dflag) {
3488185029Spjd		va_start(ap, fmt);
3489185029Spjd		fprintf(stderr, "%s: ", hms());
3490185029Spjd		vfprintf(stderr, fmt, ap);
3491185029Spjd		va_end(ap);
3492185029Spjd	}
3493185029Spjd	if (dflag) {
3494185029Spjd		va_start(ap, fmt);
3495185029Spjd		if (level > 0)
3496209962Smm			vsyslog(LOG_DEBUG, fmt, ap);
3497209962Smm		else
3498185029Spjd			vsyslog(LOG_WARNING, fmt, ap);
3499185029Spjd		va_end(ap);
3500185029Spjd	}
3501185029Spjd}
3502185029Spjd
3503168404Spjdstatic void
3504168404Spjdtrace(int level, const char *fmt, ...)
3505168404Spjd{
3506185029Spjd	va_list ap;
3507248571Smm
3508168404Spjd	if (level <= dflag) {
3509168404Spjd		va_start(ap, fmt);
3510185029Spjd		vfprintf(stderr, fmt, ap);
3511168404Spjd		va_end(ap);
3512168404Spjd	}
3513168404Spjd	if (dflag) {
3514219089Spjd		va_start(ap, fmt);
3515168404Spjd		if (level > 0)
3516185029Spjd			vsyslog(LOG_DEBUG, fmt, ap);
3517185029Spjd		else
3518219089Spjd			vsyslog(LOG_WARNING, fmt, ap);
3519236884Smm		va_end(ap);
3520168404Spjd	}
3521168404Spjd}
3522168404Spjd
3523168404Spjdstatic struct ifc *
3524168404Spjdifc_find(char *name)
3525168404Spjd{
3526168404Spjd	struct ifc *ifcp;
3527249195Smm
3528168404Spjd	TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) {
3529168404Spjd		if (strcmp(name, ifcp->ifc_name) == 0)
3530168404Spjd			break;
3531168404Spjd	}
3532168404Spjd	return (ifcp);
3533185029Spjd}
3534185029Spjd
3535219089Spjdstatic struct iff *
3536209962Smmiff_find(struct ifc *ifcp, int type)
3537168404Spjd{
3538185029Spjd	struct iff *iffp;
3539185029Spjd
3540185029Spjd	TAILQ_FOREACH(iffp, &ifcp->ifc_iff_head, iff_next) {
3541185029Spjd		if (type == IFIL_TYPE_ANY ||
3542185029Spjd		    type == iffp->iff_type)
3543185029Spjd			break;
3544185029Spjd	}
3545236884Smm
3546236884Smm	return (iffp);
3547236884Smm}
3548236884Smm
3549236884Smmstatic void
3550236884Smmsetindex2ifc(int idx, struct ifc *ifcp)
3551236884Smm{
3552236884Smm	int n, nsize;
3553236884Smm	struct ifc **p;
3554185029Spjd
3555236884Smm	if (!index2ifc) {
3556236884Smm		nindex2ifc = 5;	/*initial guess*/
3557219089Spjd		index2ifc = (struct ifc **)
3558219089Spjd			malloc(sizeof(*index2ifc) * nindex2ifc);
3559219089Spjd		if (index2ifc == NULL) {
3560185029Spjd			fatal("malloc");
3561168404Spjd			/*NOTREACHED*/
3562168404Spjd		}
3563168404Spjd		memset(index2ifc, 0, sizeof(*index2ifc) * nindex2ifc);
3564209962Smm	}
3565209962Smm	n = nindex2ifc;
3566209962Smm	for (nsize = nindex2ifc; nsize <= idx; nsize *= 2)
3567209962Smm		;
3568209962Smm	if (n != nsize) {
3569209962Smm		p = (struct ifc **)realloc(index2ifc,
3570168404Spjd		    sizeof(*index2ifc) * nsize);
3571168404Spjd		if (p == NULL) {
3572185029Spjd			fatal("realloc");
3573168404Spjd			/*NOTREACHED*/
3574168404Spjd		}
3575168404Spjd		memset(p + n, 0, sizeof(*index2ifc) * (nindex2ifc - n));
3576168404Spjd		index2ifc = p;
3577168404Spjd		nindex2ifc = nsize;
3578168404Spjd	}
3579185029Spjd	index2ifc[idx] = ifcp;
3580249195Smm}
3581168404Spjd