ndp.c revision 122615
162590Sitojun/*	$FreeBSD: head/usr.sbin/ndp/ndp.c 122615 2003-11-13 16:02:44Z ume $	*/
2122615Sume/*	$KAME: ndp.c,v 1.104 2003/06/27 07:48:39 itojun Exp $	*/
362590Sitojun
455505Sshin/*
555505Sshin * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
655505Sshin * All rights reserved.
755505Sshin *
855505Sshin * Redistribution and use in source and binary forms, with or without
955505Sshin * modification, are permitted provided that the following conditions
1055505Sshin * are met:
1155505Sshin * 1. Redistributions of source code must retain the above copyright
1255505Sshin *    notice, this list of conditions and the following disclaimer.
1355505Sshin * 2. Redistributions in binary form must reproduce the above copyright
1455505Sshin *    notice, this list of conditions and the following disclaimer in the
1555505Sshin *    documentation and/or other materials provided with the distribution.
1655505Sshin * 3. Neither the name of the project nor the names of its contributors
1755505Sshin *    may be used to endorse or promote products derived from this software
1855505Sshin *    without specific prior written permission.
1955505Sshin *
2055505Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2155505Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2255505Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2355505Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2455505Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2555505Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2655505Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2755505Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2855505Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2955505Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3055505Sshin * SUCH DAMAGE.
3155505Sshin */
3255505Sshin/*
3355505Sshin * Copyright (c) 1984, 1993
3455505Sshin *	The Regents of the University of California.  All rights reserved.
3555505Sshin *
3655505Sshin * This code is derived from software contributed to Berkeley by
3755505Sshin * Sun Microsystems, Inc.
3855505Sshin *
3955505Sshin * Redistribution and use in source and binary forms, with or without
4055505Sshin * modification, are permitted provided that the following conditions
4155505Sshin * are met:
4255505Sshin * 1. Redistributions of source code must retain the above copyright
4355505Sshin *    notice, this list of conditions and the following disclaimer.
4455505Sshin * 2. Redistributions in binary form must reproduce the above copyright
4555505Sshin *    notice, this list of conditions and the following disclaimer in the
4655505Sshin *    documentation and/or other materials provided with the distribution.
4755505Sshin * 3. All advertising materials mentioning features or use of this software
4855505Sshin *    must display the following acknowledgement:
4955505Sshin *	This product includes software developed by the University of
5055505Sshin *	California, Berkeley and its contributors.
5155505Sshin * 4. Neither the name of the University nor the names of its contributors
5255505Sshin *    may be used to endorse or promote products derived from this software
5355505Sshin *    without specific prior written permission.
5455505Sshin *
5555505Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5655505Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5755505Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5855505Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5955505Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
6055505Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
6155505Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6255505Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6355505Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6455505Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6555505Sshin * SUCH DAMAGE.
6655505Sshin */
6755505Sshin
6855505Sshin/*
6955505Sshin * Based on:
7055505Sshin * "@(#) Copyright (c) 1984, 1993\n\
7155505Sshin *	The Regents of the University of California.  All rights reserved.\n";
7255505Sshin *
7355505Sshin * "@(#)arp.c	8.2 (Berkeley) 1/2/94";
7455505Sshin */
7555505Sshin
7655505Sshin/*
7755505Sshin * ndp - display, set, delete and flush neighbor cache
7855505Sshin */
7955505Sshin
8055505Sshin
8155505Sshin#include <sys/param.h>
8255505Sshin#include <sys/file.h>
8355505Sshin#include <sys/ioctl.h>
8455505Sshin#include <sys/socket.h>
8555505Sshin#include <sys/sysctl.h>
8655505Sshin#include <sys/time.h>
8778064Sume#include <sys/queue.h>
8855505Sshin
8955505Sshin#include <net/if.h>
9055505Sshin#include <net/if_var.h>
9155505Sshin#include <net/if_dl.h>
9255505Sshin#include <net/if_types.h>
9355505Sshin#include <net/route.h>
9455505Sshin
9555505Sshin#include <netinet/in.h>
9655505Sshin#include <netinet/if_ether.h>
9755505Sshin
9855505Sshin#include <netinet/icmp6.h>
9955505Sshin#include <netinet6/in6_var.h>
10055505Sshin#include <netinet6/nd6.h>
10155505Sshin
10255505Sshin#include <arpa/inet.h>
10355505Sshin
10455505Sshin#include <netdb.h>
10555505Sshin#include <errno.h>
10655505Sshin#include <nlist.h>
10755505Sshin#include <stdio.h>
10855505Sshin#include <string.h>
10955505Sshin#include <paths.h>
11055505Sshin#include <err.h>
11155505Sshin#include <stdlib.h>
11255505Sshin#include <fcntl.h>
11355505Sshin#include <unistd.h>
114122615Sume#include <err.h>
11555505Sshin#include "gmt2local.h"
11655505Sshin
11755505Sshin/* packing rule for routing socket */
11862590Sitojun#define ROUNDUP(a) \
11955505Sshin	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
12062590Sitojun#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
12155505Sshin
122100650Sjmallettstatic pid_t pid;
12362590Sitojunstatic int nflag;
12462590Sitojunstatic int tflag;
12562590Sitojunstatic int32_t thiszone;	/* time difference with gmt */
12662590Sitojunstatic int s = -1;
12762590Sitojunstatic int repeat = 0;
12855505Sshin
12962590Sitojunchar ntop_buf[INET6_ADDRSTRLEN];	/* inet_ntop() */
13062590Sitojunchar host_buf[NI_MAXHOST];		/* getnameinfo() */
13162590Sitojunchar ifix_buf[IFNAMSIZ];		/* if_indextoname() */
13255505Sshin
13362590Sitojunint main __P((int, char **));
13462590Sitojunint file __P((char *));
13562590Sitojunvoid getsocket __P((void));
13662590Sitojunint set __P((int, char **));
13762590Sitojunvoid get __P((char *));
13862590Sitojunint delete __P((char *));
139122615Sumevoid dump __P((struct in6_addr *, int));
140122615Sumestatic struct in6_nbrinfo *getnbrinfo __P((struct in6_addr *, int, int));
14162590Sitojunstatic char *ether_str __P((struct sockaddr_dl *));
14262590Sitojunint ndp_ether_aton __P((char *, u_char *));
14362590Sitojunvoid usage __P((void));
14462590Sitojunint rtmsg __P((int));
145122615Sumevoid ifinfo __P((char *, int, char **));
14662590Sitojunvoid rtrlist __P((void));
14762590Sitojunvoid plist __P((void));
14862590Sitojunvoid pfx_flush __P((void));
14962590Sitojunvoid rtrlist __P((void));
15062590Sitojunvoid rtr_flush __P((void));
15162590Sitojunvoid harmonize_rtr __P((void));
15262590Sitojun#ifdef SIOCSDEFIFACE_IN6	/* XXX: check SIOCGDEFIFACE_IN6 as well? */
15362590Sitojunstatic void getdefif __P((void));
15462590Sitojunstatic void setdefif __P((char *));
15562590Sitojun#endif
156122615Sumestatic char *sec2str __P((time_t));
157122615Sumestatic char *ether_str __P((struct sockaddr_dl *));
15862590Sitojunstatic void ts_print __P((const struct timeval *));
15955505Sshin
160122615Sume#ifdef ICMPV6CTL_ND6_DRLIST
16178064Sumestatic char *rtpref_str[] = {
16278064Sume	"medium",		/* 00 */
16378064Sume	"high",			/* 01 */
16478064Sume	"rsv",			/* 10 */
16578064Sume	"low"			/* 11 */
16678064Sume};
167122615Sume#endif
16878064Sume
169122615Sumeint mode = 0;
170122615Sumechar *arg = NULL;
171122615Sume
17255505Sshinint
17355505Sshinmain(argc, argv)
17455505Sshin	int argc;
17555505Sshin	char **argv;
17655505Sshin{
17755505Sshin	int ch;
17855505Sshin
17955505Sshin	pid = getpid();
18055505Sshin	thiszone = gmt2local(0);
181122615Sume	while ((ch = getopt(argc, argv, "acd:f:Ii:nprstA:HPR")) != -1)
182121156Sume		switch (ch) {
18355505Sshin		case 'a':
18455505Sshin		case 'c':
185122615Sume		case 'p':
186122615Sume		case 'r':
187122615Sume		case 'H':
188122615Sume		case 'P':
189122615Sume		case 'R':
190122615Sume		case 's':
191122615Sume		case 'I':
192122615Sume			if (mode) {
193122615Sume				usage();
194122615Sume				/*NOTREACHED*/
195122615Sume			}
196122615Sume			mode = ch;
197122615Sume			arg = NULL;
19855505Sshin			break;
19955505Sshin		case 'd':
200122615Sume		case 'f':
20155505Sshin		case 'i' :
202122615Sume			if (mode) {
20355505Sshin				usage();
204122615Sume				/*NOTREACHED*/
205122615Sume			}
206122615Sume			mode = ch;
207122615Sume			arg = optarg;
208122615Sume			break;
20955505Sshin		case 'n':
21055505Sshin			nflag = 1;
21155505Sshin			break;
21255505Sshin		case 't':
21355505Sshin			tflag = 1;
21455505Sshin			break;
21555505Sshin		case 'A':
216122615Sume			if (mode) {
217122615Sume				usage();
218122615Sume				/*NOTREACHED*/
219122615Sume			}
220122615Sume			mode = 'a';
22155505Sshin			repeat = atoi(optarg);
222122615Sume			if (repeat < 0) {
22355505Sshin				usage();
224122615Sume				/*NOTREACHED*/
225122615Sume			}
22655505Sshin			break;
22755505Sshin		default:
22855505Sshin			usage();
22955505Sshin		}
23055505Sshin
23155505Sshin	argc -= optind;
23255505Sshin	argv += optind;
23355505Sshin
234122615Sume	switch (mode) {
235122615Sume	case 'a':
236122615Sume	case 'c':
237122615Sume		if (argc != 0) {
23855505Sshin			usage();
239122615Sume			/*NOTREACHED*/
240122615Sume		}
241122615Sume		dump(0, mode == 'c');
242122615Sume		break;
243122615Sume	case 'd':
244122615Sume		if (argc != 0) {
245122615Sume			usage();
246122615Sume			/*NOTREACHED*/
247122615Sume		}
248122615Sume		delete(arg);
249122615Sume		break;
250122615Sume	case 'I':
251122615Sume#ifdef SIOCSDEFIFACE_IN6	/* XXX: check SIOCGDEFIFACE_IN6 as well? */
252122615Sume		if (argc > 1) {
253122615Sume			usage();
254122615Sume			/*NOTREACHED*/
255122615Sume		} else if (argc == 1) {
256122615Sume			if (strcmp(*argv, "delete") == 0 ||
257122615Sume			    if_nametoindex(*argv))
258122615Sume				setdefif(*argv);
259122615Sume			else
260122615Sume				errx(1, "invalid interface %s", *argv);
261122615Sume		}
262122615Sume		getdefif(); /* always call it to print the result */
263122615Sume		break;
264122615Sume#else
265122615Sume		errx(1, "not supported yet");
266122615Sume		/*NOTREACHED*/
267122615Sume#endif
268122615Sume	case 'p':
269122615Sume		if (argc != 0) {
270122615Sume			usage();
271122615Sume			/*NOTREACHED*/
272122615Sume		}
27355505Sshin		plist();
274122615Sume		break;
275122615Sume	case 'i':
276122615Sume		ifinfo(arg, argc, argv);
277122615Sume		break;
278122615Sume	case 'r':
279122615Sume		if (argc != 0) {
280122615Sume			usage();
281122615Sume			/*NOTREACHED*/
282122615Sume		}
28355505Sshin		rtrlist();
284122615Sume		break;
285122615Sume	case 's':
28655505Sshin		if (argc < 2 || argc > 4)
28755505Sshin			usage();
28855505Sshin		exit(set(argc, argv) ? 1 : 0);
289122615Sume	case 'H':
290122615Sume		if (argc != 0) {
291122615Sume			usage();
292122615Sume			/*NOTREACHED*/
293122615Sume		}
29455505Sshin		harmonize_rtr();
295122615Sume		break;
296122615Sume	case 'P':
297122615Sume		if (argc != 0) {
298122615Sume			usage();
299122615Sume			/*NOTREACHED*/
300122615Sume		}
30155505Sshin		pfx_flush();
302122615Sume		break;
303122615Sume	case 'R':
304122615Sume		if (argc != 0) {
305122615Sume			usage();
306122615Sume			/*NOTREACHED*/
307122615Sume		}
30855505Sshin		rtr_flush();
309122615Sume		break;
310122615Sume	case 0:
311122615Sume		if (argc != 1) {
312122615Sume			usage();
313122615Sume			/*NOTREACHED*/
314122615Sume		}
315122615Sume		get(argv[0]);
316122615Sume		break;
31755505Sshin	}
31855505Sshin	exit(0);
31955505Sshin}
32055505Sshin
32155505Sshin/*
32255505Sshin * Process a file to set standard ndp entries
32355505Sshin */
32455505Sshinint
32555505Sshinfile(name)
32655505Sshin	char *name;
32755505Sshin{
32855505Sshin	FILE *fp;
32955505Sshin	int i, retval;
33055505Sshin	char line[100], arg[5][50], *args[5];
33155505Sshin
33255505Sshin	if ((fp = fopen(name, "r")) == NULL) {
33355505Sshin		fprintf(stderr, "ndp: cannot open %s\n", name);
33455505Sshin		exit(1);
33555505Sshin	}
33655505Sshin	args[0] = &arg[0][0];
33755505Sshin	args[1] = &arg[1][0];
33855505Sshin	args[2] = &arg[2][0];
33955505Sshin	args[3] = &arg[3][0];
34055505Sshin	args[4] = &arg[4][0];
34155505Sshin	retval = 0;
342121156Sume	while (fgets(line, 100, fp) != NULL) {
343122615Sume		i = sscanf(line, "%49s %49s %49s %49s %49s",
344122615Sume		    arg[0], arg[1], arg[2], arg[3], arg[4]);
34555505Sshin		if (i < 2) {
34655505Sshin			fprintf(stderr, "ndp: bad line: %s\n", line);
34755505Sshin			retval = 1;
34855505Sshin			continue;
34955505Sshin		}
35055505Sshin		if (set(i, args))
35155505Sshin			retval = 1;
35255505Sshin	}
35355505Sshin	fclose(fp);
35455505Sshin	return (retval);
35555505Sshin}
35655505Sshin
35755505Sshinvoid
35855505Sshingetsocket()
35955505Sshin{
36055505Sshin	if (s < 0) {
36155505Sshin		s = socket(PF_ROUTE, SOCK_RAW, 0);
36255505Sshin		if (s < 0) {
363121156Sume			err(1, "socket");
364121156Sume			/* NOTREACHED */
36555505Sshin		}
36655505Sshin	}
36755505Sshin}
36855505Sshin
36962590Sitojunstruct	sockaddr_in6 so_mask = {sizeof(so_mask), AF_INET6 };
37055505Sshinstruct	sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET6 }, sin_m;
37155505Sshinstruct	sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m;
37255505Sshinint	expire_time, flags, found_entry;
37355505Sshinstruct	{
37455505Sshin	struct	rt_msghdr m_rtm;
37555505Sshin	char	m_space[512];
37655505Sshin}	m_rtmsg;
37755505Sshin
37855505Sshin/*
37955505Sshin * Set an individual neighbor cache entry
38055505Sshin */
38155505Sshinint
38255505Sshinset(argc, argv)
38355505Sshin	int argc;
38455505Sshin	char **argv;
38555505Sshin{
38655505Sshin	register struct sockaddr_in6 *sin = &sin_m;
38755505Sshin	register struct sockaddr_dl *sdl;
38855505Sshin	register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
38955505Sshin	struct addrinfo hints, *res;
39055505Sshin	int gai_error;
39155505Sshin	u_char *ea;
39255505Sshin	char *host = argv[0], *eaddr = argv[1];
39355505Sshin
39455505Sshin	getsocket();
39555505Sshin	argc -= 2;
39655505Sshin	argv += 2;
39755505Sshin	sdl_m = blank_sdl;
39855505Sshin	sin_m = blank_sin;
39955505Sshin
40055505Sshin	bzero(&hints, sizeof(hints));
40155505Sshin	hints.ai_family = AF_INET6;
40255505Sshin	gai_error = getaddrinfo(host, NULL, &hints, &res);
40355505Sshin	if (gai_error) {
40455505Sshin		fprintf(stderr, "ndp: %s: %s\n", host,
40555505Sshin			gai_strerror(gai_error));
40655505Sshin		return 1;
40755505Sshin	}
40855505Sshin	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
40962590Sitojun#ifdef __KAME__
41062590Sitojun	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
41162590Sitojun		*(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
412121156Sume		    htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
41362590Sitojun	}
41462590Sitojun#endif
41555505Sshin	ea = (u_char *)LLADDR(&sdl_m);
41655505Sshin	if (ndp_ether_aton(eaddr, ea) == 0)
41755505Sshin		sdl_m.sdl_alen = 6;
41855505Sshin	flags = expire_time = 0;
41955505Sshin	while (argc-- > 0) {
42055505Sshin		if (strncmp(argv[0], "temp", 4) == 0) {
42155505Sshin			struct timeval time;
422121156Sume
42355505Sshin			gettimeofday(&time, 0);
42455505Sshin			expire_time = time.tv_sec + 20 * 60;
42562590Sitojun		} else if (strncmp(argv[0], "proxy", 5) == 0)
42662590Sitojun			flags |= RTF_ANNOUNCE;
42755505Sshin		argv++;
42855505Sshin	}
42955505Sshin	if (rtmsg(RTM_GET) < 0) {
430121156Sume		errx(1, "RTM_GET(%s) failed", host);
431121156Sume		/* NOTREACHED */
43255505Sshin	}
43355505Sshin	sin = (struct sockaddr_in6 *)(rtm + 1);
43455505Sshin	sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
43555505Sshin	if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
43655505Sshin		if (sdl->sdl_family == AF_LINK &&
43755505Sshin		    (rtm->rtm_flags & RTF_LLINFO) &&
438122615Sume		    !(rtm->rtm_flags & RTF_GATEWAY)) {
439122615Sume			switch (sdl->sdl_type) {
440122615Sume			case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
441122615Sume			case IFT_ISO88024: case IFT_ISO88025:
442122615Sume				goto overwrite;
443122615Sume			}
44455505Sshin		}
44562590Sitojun		/*
44662590Sitojun		 * IPv4 arp command retries with sin_other = SIN_PROXY here.
44762590Sitojun		 */
44862590Sitojun		fprintf(stderr, "set: cannot configure a new entry\n");
44962590Sitojun		return 1;
45055505Sshin	}
45162590Sitojun
45255505Sshinoverwrite:
45355505Sshin	if (sdl->sdl_family != AF_LINK) {
45455505Sshin		printf("cannot intuit interface index and type for %s\n", host);
45555505Sshin		return (1);
45655505Sshin	}
45755505Sshin	sdl_m.sdl_type = sdl->sdl_type;
45855505Sshin	sdl_m.sdl_index = sdl->sdl_index;
45955505Sshin	return (rtmsg(RTM_ADD));
46055505Sshin}
46155505Sshin
46255505Sshin/*
46355505Sshin * Display an individual neighbor cache entry
46455505Sshin */
46555505Sshinvoid
46655505Sshinget(host)
46755505Sshin	char *host;
46855505Sshin{
46955505Sshin	struct sockaddr_in6 *sin = &sin_m;
47055505Sshin	struct addrinfo hints, *res;
47155505Sshin	int gai_error;
47255505Sshin
47355505Sshin	sin_m = blank_sin;
47455505Sshin	bzero(&hints, sizeof(hints));
47555505Sshin	hints.ai_family = AF_INET6;
47655505Sshin	gai_error = getaddrinfo(host, NULL, &hints, &res);
47755505Sshin	if (gai_error) {
47855505Sshin		fprintf(stderr, "ndp: %s: %s\n", host,
479121156Sume		    gai_strerror(gai_error));
48055505Sshin		return;
48155505Sshin	}
48255505Sshin	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
48362590Sitojun#ifdef __KAME__
48462590Sitojun	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
48562590Sitojun		*(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
486121156Sume		    htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
48762590Sitojun	}
48862590Sitojun#endif
489122615Sume	dump(&sin->sin6_addr, 0);
49055505Sshin	if (found_entry == 0) {
49155505Sshin		getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
492121156Sume		    sizeof(host_buf), NULL ,0,
493121156Sume		    (nflag ? NI_NUMERICHOST : 0));
49455505Sshin		printf("%s (%s) -- no entry\n", host, host_buf);
49555505Sshin		exit(1);
49655505Sshin	}
49755505Sshin}
49855505Sshin
49955505Sshin/*
50055505Sshin * Delete a neighbor cache entry
50155505Sshin */
50255505Sshinint
50355505Sshindelete(host)
50455505Sshin	char *host;
50555505Sshin{
50655505Sshin	struct sockaddr_in6 *sin = &sin_m;
50755505Sshin	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
50855505Sshin	struct sockaddr_dl *sdl;
50955505Sshin	struct addrinfo hints, *res;
51055505Sshin	int gai_error;
51155505Sshin
51255505Sshin	getsocket();
51355505Sshin	sin_m = blank_sin;
51455505Sshin
51555505Sshin	bzero(&hints, sizeof(hints));
51655505Sshin	hints.ai_family = AF_INET6;
51755505Sshin	gai_error = getaddrinfo(host, NULL, &hints, &res);
51855505Sshin	if (gai_error) {
51955505Sshin		fprintf(stderr, "ndp: %s: %s\n", host,
520121156Sume		    gai_strerror(gai_error));
52155505Sshin		return 1;
52255505Sshin	}
52355505Sshin	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
52462590Sitojun#ifdef __KAME__
52562590Sitojun	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
52662590Sitojun		*(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
527121156Sume		    htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
52862590Sitojun	}
52962590Sitojun#endif
53055505Sshin	if (rtmsg(RTM_GET) < 0) {
531121156Sume		errx(1, "RTM_GET(%s) failed", host);
532121156Sume		/* NOTREACHED */
53355505Sshin	}
53455505Sshin	sin = (struct sockaddr_in6 *)(rtm + 1);
53555505Sshin	sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
53655505Sshin	if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
53755505Sshin		if (sdl->sdl_family == AF_LINK &&
53855505Sshin		    (rtm->rtm_flags & RTF_LLINFO) &&
53962590Sitojun		    !(rtm->rtm_flags & RTF_GATEWAY)) {
54078064Sume			goto delete;
54155505Sshin		}
54262590Sitojun		/*
54362590Sitojun		 * IPv4 arp command retries with sin_other = SIN_PROXY here.
54462590Sitojun		 */
54562590Sitojun		fprintf(stderr, "delete: cannot delete non-NDP entry\n");
54662590Sitojun		return 1;
54755505Sshin	}
54862590Sitojun
54955505Sshindelete:
55055505Sshin	if (sdl->sdl_family != AF_LINK) {
55155505Sshin		printf("cannot locate %s\n", host);
55255505Sshin		return (1);
55355505Sshin	}
55455505Sshin	if (rtmsg(RTM_DELETE) == 0) {
55562590Sitojun		struct sockaddr_in6 s6 = *sin; /* XXX: for safety */
55662590Sitojun
55762590Sitojun#ifdef __KAME__
55862590Sitojun		if (IN6_IS_ADDR_LINKLOCAL(&s6.sin6_addr)) {
55962590Sitojun			s6.sin6_scope_id = ntohs(*(u_int16_t *)&s6.sin6_addr.s6_addr[2]);
56062590Sitojun			*(u_int16_t *)&s6.sin6_addr.s6_addr[2] = 0;
56162590Sitojun		}
56262590Sitojun#endif
56362590Sitojun		getnameinfo((struct sockaddr *)&s6,
564121156Sume		    s6.sin6_len, host_buf,
565121156Sume		    sizeof(host_buf), NULL, 0,
566121156Sume		    (nflag ? NI_NUMERICHOST : 0));
56755505Sshin		printf("%s (%s) deleted\n", host, host_buf);
56855505Sshin	}
56955505Sshin
57055505Sshin	return 0;
57155505Sshin}
57255505Sshin
573122615Sume#define W_ADDR	36
57478064Sume#define W_LL	17
57578064Sume#define W_IF	6
57678064Sume
57755505Sshin/*
57855505Sshin * Dump the entire neighbor cache
57955505Sshin */
58055505Sshinvoid
581122615Sumedump(addr, cflag)
58255505Sshin	struct in6_addr *addr;
583122615Sume	int cflag;
58455505Sshin{
58555505Sshin	int mib[6];
58655505Sshin	size_t needed;
58762590Sitojun	char *lim, *buf, *next;
58855505Sshin	struct rt_msghdr *rtm;
58955505Sshin	struct sockaddr_in6 *sin;
59055505Sshin	struct sockaddr_dl *sdl;
59155505Sshin	extern int h_errno;
59255505Sshin	struct in6_nbrinfo *nbi;
59355505Sshin	struct timeval time;
59455505Sshin	int addrwidth;
59578064Sume	int llwidth;
59678064Sume	int ifwidth;
59762590Sitojun	char flgbuf[8];
59878064Sume	char *ifname;
59955505Sshin
60055505Sshin	/* Print header */
60166865Ssumikawa	if (!tflag && !cflag)
602122615Sume		printf("%-*.*s %-*.*s %*.*s %-9.9s %1s %5s\n",
60378064Sume		    W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address",
604122615Sume		    W_IF, W_IF, "Netif", "Expire", "S", "Flags");
60555505Sshin
60655505Sshinagain:;
60755505Sshin	mib[0] = CTL_NET;
60855505Sshin	mib[1] = PF_ROUTE;
60955505Sshin	mib[2] = 0;
61055505Sshin	mib[3] = AF_INET6;
61155505Sshin	mib[4] = NET_RT_FLAGS;
61255505Sshin	mib[5] = RTF_LLINFO;
61355505Sshin	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
61455505Sshin		err(1, "sysctl(PF_ROUTE estimate)");
61555505Sshin	if (needed > 0) {
61655505Sshin		if ((buf = malloc(needed)) == NULL)
617121156Sume			err(1, "malloc");
61855505Sshin		if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
61955505Sshin			err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
62055505Sshin		lim = buf + needed;
62155505Sshin	} else
62255505Sshin		buf = lim = NULL;
62355505Sshin
62455505Sshin	for (next = buf; next && next < lim; next += rtm->rtm_msglen) {
62555505Sshin		int isrouter = 0, prbs = 0;
62655505Sshin
62755505Sshin		rtm = (struct rt_msghdr *)next;
62855505Sshin		sin = (struct sockaddr_in6 *)(rtm + 1);
62955505Sshin		sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len));
63078064Sume
63178064Sume		/*
63278064Sume		 * Some OSes can produce a route that has the LINK flag but
63378064Sume		 * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD
63478064Sume		 * and BSD/OS, where xx is not the interface identifier on
63578064Sume		 * lo0).  Such routes entry would annoy getnbrinfo() below,
63678064Sume		 * so we skip them.
63778064Sume		 * XXX: such routes should have the GATEWAY flag, not the
638121156Sume		 * LINK flag.  However, there is rotten routing software
63978064Sume		 * that advertises all routes that have the GATEWAY flag.
64078064Sume		 * Thus, KAME kernel intentionally does not set the LINK flag.
64178064Sume		 * What is to be fixed is not ndp, but such routing software
64278064Sume		 * (and the kernel workaround)...
64378064Sume		 */
64478064Sume		if (sdl->sdl_family != AF_LINK)
64578064Sume			continue;
64678064Sume
647122615Sume		if (!(rtm->rtm_flags & RTF_HOST))
648122615Sume			continue;
649122615Sume
65055505Sshin		if (addr) {
65155505Sshin			if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr))
65255505Sshin				continue;
65355505Sshin			found_entry = 1;
65455505Sshin		} else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
65555505Sshin			continue;
65655505Sshin		if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) ||
65755505Sshin		    IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) {
65855505Sshin			/* XXX: should scope id be filled in the kernel? */
65955505Sshin			if (sin->sin6_scope_id == 0)
66055505Sshin				sin->sin6_scope_id = sdl->sdl_index;
66166865Ssumikawa#ifdef __KAME__
66266865Ssumikawa			/* KAME specific hack; removed the embedded id */
66355505Sshin			*(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0;
66466865Ssumikawa#endif
66555505Sshin		}
66655505Sshin		getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
667121156Sume		    sizeof(host_buf), NULL, 0, (nflag ? NI_NUMERICHOST : 0));
668122615Sume		if (cflag) {
66981366Ssumikawa#ifdef RTF_WASCLONED
67081366Ssumikawa			if (rtm->rtm_flags & RTF_WASCLONED)
67181366Ssumikawa				delete(host_buf);
672122615Sume#elif defined(RTF_CLONED)
673122615Sume			if (rtm->rtm_flags & RTF_CLONED)
674122615Sume				delete(host_buf);
67581366Ssumikawa#else
67666865Ssumikawa			delete(host_buf);
67781366Ssumikawa#endif
67866865Ssumikawa			continue;
67966865Ssumikawa		}
68055505Sshin		gettimeofday(&time, 0);
68155505Sshin		if (tflag)
68255505Sshin			ts_print(&time);
68355505Sshin
68478064Sume		addrwidth = strlen(host_buf);
68578064Sume		if (addrwidth < W_ADDR)
68678064Sume			addrwidth = W_ADDR;
68778064Sume		llwidth = strlen(ether_str(sdl));
68878064Sume		if (W_ADDR + W_LL - addrwidth > llwidth)
68978064Sume			llwidth = W_ADDR + W_LL - addrwidth;
69078064Sume		ifname = if_indextoname(sdl->sdl_index, ifix_buf);
69178064Sume		if (!ifname)
69278064Sume			ifname = "?";
69378064Sume		ifwidth = strlen(ifname);
69478064Sume		if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth)
69578064Sume			ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth;
69655505Sshin
69778064Sume		printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf,
69878064Sume		    llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname);
69955505Sshin
70055505Sshin		/* Print neighbor discovery specific informations */
70162590Sitojun		nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1);
70255505Sshin		if (nbi) {
70355505Sshin			if (nbi->expire > time.tv_sec) {
70455505Sshin				printf(" %-9.9s",
705121156Sume				    sec2str(nbi->expire - time.tv_sec));
70678064Sume			} else if (nbi->expire == 0)
70755505Sshin				printf(" %-9.9s", "permanent");
70855505Sshin			else
70955505Sshin				printf(" %-9.9s", "expired");
71055505Sshin
711121156Sume			switch (nbi->state) {
712121156Sume			case ND6_LLINFO_NOSTATE:
71355505Sshin				 printf(" N");
71455505Sshin				 break;
71578064Sume#ifdef ND6_LLINFO_WAITDELETE
716121156Sume			case ND6_LLINFO_WAITDELETE:
71755505Sshin				 printf(" W");
71855505Sshin				 break;
71978064Sume#endif
720121156Sume			case ND6_LLINFO_INCOMPLETE:
72155505Sshin				 printf(" I");
72255505Sshin				 break;
723121156Sume			case ND6_LLINFO_REACHABLE:
72455505Sshin				 printf(" R");
72555505Sshin				 break;
726121156Sume			case ND6_LLINFO_STALE:
72755505Sshin				 printf(" S");
72855505Sshin				 break;
729121156Sume			case ND6_LLINFO_DELAY:
73055505Sshin				 printf(" D");
73155505Sshin				 break;
732121156Sume			case ND6_LLINFO_PROBE:
73355505Sshin				 printf(" P");
73455505Sshin				 break;
735121156Sume			default:
73655505Sshin				 printf(" ?");
73755505Sshin				 break;
73855505Sshin			}
73955505Sshin
74055505Sshin			isrouter = nbi->isrouter;
74155505Sshin			prbs = nbi->asked;
74278064Sume		} else {
74355505Sshin			warnx("failed to get neighbor information");
74455505Sshin			printf("  ");
74555505Sshin		}
74655505Sshin
74762590Sitojun		/*
74862590Sitojun		 * other flags. R: router, P: proxy, W: ??
74962590Sitojun		 */
75062590Sitojun		if ((rtm->rtm_addrs & RTA_NETMASK) == 0) {
75162590Sitojun			snprintf(flgbuf, sizeof(flgbuf), "%s%s",
752121156Sume			    isrouter ? "R" : "",
753121156Sume			    (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
75462590Sitojun		} else {
75562590Sitojun			sin = (struct sockaddr_in6 *)
756121156Sume			    (sdl->sdl_len + (char *)sdl);
757122615Sume#if 0	/* W and P are mystery even for us */
75862590Sitojun			snprintf(flgbuf, sizeof(flgbuf), "%s%s%s%s",
759121156Sume			    isrouter ? "R" : "",
760121156Sume			    !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr) ? "P" : "",
761121156Sume			    (sin->sin6_len != sizeof(struct sockaddr_in6)) ? "W" : "",
762121156Sume			    (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
763122615Sume#else
764122615Sume			snprintf(flgbuf, sizeof(flgbuf), "%s%s",
765122615Sume			    isrouter ? "R" : "",
766122615Sume			    (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
767122615Sume#endif
76855505Sshin		}
769122615Sume		printf(" %s", flgbuf);
77055505Sshin
77155505Sshin		if (prbs)
772122615Sume			printf(" %d", prbs);
77355505Sshin
77455505Sshin		printf("\n");
77555505Sshin	}
77678064Sume	if (buf != NULL)
77778064Sume		free(buf);
77855505Sshin
77955505Sshin	if (repeat) {
78055505Sshin		printf("\n");
78155505Sshin		sleep(repeat);
78255505Sshin		goto again;
78355505Sshin	}
78455505Sshin}
78555505Sshin
78655505Sshinstatic struct in6_nbrinfo *
78762590Sitojungetnbrinfo(addr, ifindex, warning)
78855505Sshin	struct in6_addr *addr;
78955505Sshin	int ifindex;
79062590Sitojun	int warning;
79155505Sshin{
79255505Sshin	static struct in6_nbrinfo nbi;
79355505Sshin	int s;
79455505Sshin
79555505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
79655505Sshin		err(1, "socket");
79755505Sshin
79855505Sshin	bzero(&nbi, sizeof(nbi));
79955505Sshin	if_indextoname(ifindex, nbi.ifname);
80055505Sshin	nbi.addr = *addr;
80155505Sshin	if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) {
80262590Sitojun		if (warning)
80362590Sitojun			warn("ioctl(SIOCGNBRINFO_IN6)");
80455505Sshin		close(s);
80555505Sshin		return(NULL);
80655505Sshin	}
80755505Sshin
80855505Sshin	close(s);
80955505Sshin	return(&nbi);
81055505Sshin}
81155505Sshin
81255505Sshinstatic char *
81355505Sshinether_str(sdl)
81455505Sshin	struct sockaddr_dl *sdl;
81555505Sshin{
816121156Sume	static char hbuf[NI_MAXHOST];
81755505Sshin	u_char *cp;
81855505Sshin
81955505Sshin	if (sdl->sdl_alen) {
82055505Sshin		cp = (u_char *)LLADDR(sdl);
821121156Sume		snprintf(hbuf, sizeof(hbuf), "%x:%x:%x:%x:%x:%x",
822121156Sume		    cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
823121156Sume	} else
824121156Sume		snprintf(hbuf, sizeof(hbuf), "(incomplete)");
82555505Sshin
826121156Sume	return(hbuf);
82755505Sshin}
82855505Sshin
82955505Sshinint
83055505Sshinndp_ether_aton(a, n)
83155505Sshin	char *a;
83255505Sshin	u_char *n;
83355505Sshin{
83455505Sshin	int i, o[6];
83555505Sshin
83655505Sshin	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
837121156Sume	    &o[3], &o[4], &o[5]);
83855505Sshin	if (i != 6) {
83955505Sshin		fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a);
84055505Sshin		return (1);
84155505Sshin	}
842121156Sume	for (i = 0; i < 6; i++)
84355505Sshin		n[i] = o[i];
84455505Sshin	return (0);
84555505Sshin}
84655505Sshin
84755505Sshinvoid
84855505Sshinusage()
84955505Sshin{
850122615Sume	printf("usage: ndp [-nt] hostname\n");
851122615Sume	printf("       ndp [-nt] -a | -c | -p | -r | -H | -P | -R\n");
85278064Sume	printf("       ndp [-nt] -A wait\n");
853122615Sume	printf("       ndp [-nt] -d hostname\n");
854122615Sume	printf("       ndp [-nt] -f filename\n");
855122615Sume	printf("       ndp [-nt] -i interface [flags...]\n");
85662590Sitojun#ifdef SIOCSDEFIFACE_IN6
857122615Sume	printf("       ndp [-nt] -I [interface|delete]\n");
85862590Sitojun#endif
859122615Sume	printf("       ndp [-nt] -s nodename etheraddr [temp] [proxy]\n");
86055505Sshin	exit(1);
86155505Sshin}
86255505Sshin
86355505Sshinint
86455505Sshinrtmsg(cmd)
86555505Sshin	int cmd;
86655505Sshin{
86755505Sshin	static int seq;
86855505Sshin	int rlen;
86955505Sshin	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
87055505Sshin	register char *cp = m_rtmsg.m_space;
87155505Sshin	register int l;
87255505Sshin
87355505Sshin	errno = 0;
87455505Sshin	if (cmd == RTM_DELETE)
87555505Sshin		goto doit;
87655505Sshin	bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
87755505Sshin	rtm->rtm_flags = flags;
87855505Sshin	rtm->rtm_version = RTM_VERSION;
87955505Sshin
88055505Sshin	switch (cmd) {
88155505Sshin	default:
88255505Sshin		fprintf(stderr, "ndp: internal wrong cmd\n");
88355505Sshin		exit(1);
88455505Sshin	case RTM_ADD:
88555505Sshin		rtm->rtm_addrs |= RTA_GATEWAY;
886122615Sume		if (expire_time) {
887122615Sume			rtm->rtm_rmx.rmx_expire = expire_time;
888122615Sume			rtm->rtm_inits = RTV_EXPIRE;
889122615Sume		}
89055505Sshin		rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
89162590Sitojun		if (rtm->rtm_flags & RTF_ANNOUNCE) {
89262590Sitojun			rtm->rtm_flags &= ~RTF_HOST;
89362590Sitojun			rtm->rtm_flags |= RTA_NETMASK;
89462590Sitojun		}
89555505Sshin		/* FALLTHROUGH */
89655505Sshin	case RTM_GET:
89755505Sshin		rtm->rtm_addrs |= RTA_DST;
89855505Sshin	}
89962590Sitojun#define NEXTADDR(w, s) \
90055505Sshin	if (rtm->rtm_addrs & (w)) { \
90155505Sshin		bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);}
90255505Sshin
90355505Sshin	NEXTADDR(RTA_DST, sin_m);
90455505Sshin	NEXTADDR(RTA_GATEWAY, sdl_m);
90562590Sitojun	memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr));
90655505Sshin	NEXTADDR(RTA_NETMASK, so_mask);
90755505Sshin
90855505Sshin	rtm->rtm_msglen = cp - (char *)&m_rtmsg;
90955505Sshindoit:
91055505Sshin	l = rtm->rtm_msglen;
91155505Sshin	rtm->rtm_seq = ++seq;
91255505Sshin	rtm->rtm_type = cmd;
91355505Sshin	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
91455505Sshin		if (errno != ESRCH || cmd != RTM_DELETE) {
915121156Sume			err(1, "writing to routing socket");
916121156Sume			/* NOTREACHED */
91755505Sshin		}
91855505Sshin	}
91955505Sshin	do {
92055505Sshin		l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
92155505Sshin	} while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
92255505Sshin	if (l < 0)
92355505Sshin		(void) fprintf(stderr, "ndp: read from routing socket: %s\n",
92455505Sshin		    strerror(errno));
92555505Sshin	return (0);
92655505Sshin}
92755505Sshin
92855505Sshinvoid
929122615Sumeifinfo(ifname, argc, argv)
930122615Sume	char *ifname;
93162590Sitojun	int argc;
93262590Sitojun	char **argv;
93355505Sshin{
93455505Sshin	struct in6_ndireq nd;
93562590Sitojun	int i, s;
93662590Sitojun	u_int32_t newflags;
93778064Sume#ifdef IPV6CTL_USETEMPADDR
93878064Sume	u_int8_t nullbuf[8];
93978064Sume#endif
94055505Sshin
94155505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
942121156Sume		err(1, "socket");
943121156Sume		/* NOTREACHED */
94455505Sshin	}
94555505Sshin	bzero(&nd, sizeof(nd));
946121156Sume	strlcpy(nd.ifname, ifname, sizeof(nd.ifname));
94755505Sshin	if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
948121156Sume		err(1, "ioctl(SIOCGIFINFO_IN6)");
949121156Sume		/* NOTREACHED */
950122615Sume	}
95162590Sitojun#define ND nd.ndi
95262590Sitojun	newflags = ND.flags;
953122615Sume	for (i = 0; i < argc; i++) {
95462590Sitojun		int clear = 0;
95562590Sitojun		char *cp = argv[i];
95662590Sitojun
95762590Sitojun		if (*cp == '-') {
95862590Sitojun			clear = 1;
95962590Sitojun			cp++;
96062590Sitojun		}
96162590Sitojun
96262590Sitojun#define SETFLAG(s, f) \
96362590Sitojun	do {\
96462590Sitojun		if (strcmp(cp, (s)) == 0) {\
96562590Sitojun			if (clear)\
96662590Sitojun				newflags &= ~(f);\
96762590Sitojun			else\
96862590Sitojun				newflags |= (f);\
96962590Sitojun		}\
97062590Sitojun	} while (0)
97162590Sitojun		SETFLAG("nud", ND6_IFF_PERFORMNUD);
972118498Sume#ifdef ND6_IFF_ACCEPT_RTADV
973118498Sume		SETFLAG("accept_rtadv", ND6_IFF_ACCEPT_RTADV);
974118498Sume#endif
975122615Sume#ifdef ND6_IFF_PREFER_SOURCE
976122615Sume		SETFLAG("prefer_source", ND6_IFF_PREFER_SOURCE);
977122615Sume#endif
97862590Sitojun
97962590Sitojun		ND.flags = newflags;
98062590Sitojun		if (ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd) < 0) {
981121156Sume			err(1, "ioctl(SIOCSIFINFO_FLAGS)");
982121156Sume			/* NOTREACHED */
98362590Sitojun		}
98462590Sitojun#undef SETFLAG
98562590Sitojun	}
98662590Sitojun
987121162Sume	if (!ND.initialized) {
988121162Sume		errx(1, "%s: not initialized yet", ifname);
989121162Sume		/* NOTREACHED */
990121162Sume	}
991121162Sume
99255505Sshin	printf("linkmtu=%d", ND.linkmtu);
993121471Sume	printf(", maxmtu=%d", ND.maxmtu);
99455505Sshin	printf(", curhlim=%d", ND.chlim);
99555505Sshin	printf(", basereachable=%ds%dms",
996121156Sume	    ND.basereachable / 1000, ND.basereachable % 1000);
99755505Sshin	printf(", reachable=%ds", ND.reachable);
99862590Sitojun	printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000);
99978064Sume#ifdef IPV6CTL_USETEMPADDR
100078064Sume	memset(nullbuf, 0, sizeof(nullbuf));
100178064Sume	if (memcmp(nullbuf, ND.randomid, sizeof(nullbuf)) != 0) {
100278064Sume		int j;
100378064Sume		u_int8_t *rbuf;
100478064Sume
100578064Sume		for (i = 0; i < 3; i++) {
1006121156Sume			switch (i) {
100778064Sume			case 0:
100878064Sume				printf("\nRandom seed(0): ");
100978064Sume				rbuf = ND.randomseed0;
101078064Sume				break;
101178064Sume			case 1:
101278064Sume				printf("\nRandom seed(1): ");
101378064Sume				rbuf = ND.randomseed1;
101478064Sume				break;
101578064Sume			case 2:
101678064Sume				printf("\nRandom ID:      ");
101778064Sume				rbuf = ND.randomid;
101878064Sume				break;
101978064Sume			}
102078064Sume			for (j = 0; j < 8; j++)
102178064Sume				printf("%02x", rbuf[j]);
102278064Sume		}
102378064Sume	}
102478064Sume#endif
102562590Sitojun	if (ND.flags) {
102662590Sitojun		printf("\nFlags: ");
1027118498Sume		if ((ND.flags & ND6_IFF_PERFORMNUD))
1028118498Sume			printf("nud ");
1029118498Sume#ifdef ND6_IFF_ACCEPT_RTADV
1030118498Sume		if ((ND.flags & ND6_IFF_ACCEPT_RTADV))
1031118498Sume			printf("accept_rtadv ");
1032118498Sume#endif
1033122615Sume#ifdef ND6_IFF_PREFER_SOURCE
1034122615Sume		if ((ND.flags & ND6_IFF_PREFER_SOURCE))
1035122615Sume			printf("prefer_source ");
1036122615Sume#endif
1037122615Sume	}
103862590Sitojun	putc('\n', stdout);
103955505Sshin#undef ND
1040121156Sume
104155505Sshin	close(s);
104255505Sshin}
104355505Sshin
104478064Sume#ifndef ND_RA_FLAG_RTPREF_MASK	/* XXX: just for compilation on *BSD release */
104578064Sume#define ND_RA_FLAG_RTPREF_MASK	0x18 /* 00011000 */
104678064Sume#endif
104778064Sume
104855505Sshinvoid
104955505Sshinrtrlist()
105055505Sshin{
105178064Sume#ifdef ICMPV6CTL_ND6_DRLIST
105278064Sume	int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST };
105378064Sume	char *buf;
105478064Sume	struct in6_defrouter *p, *ep;
105578064Sume	size_t l;
105678064Sume	struct timeval time;
105778064Sume
105878064Sume	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
105978064Sume		err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
106078064Sume		/*NOTREACHED*/
106178064Sume	}
106278064Sume	buf = malloc(l);
106378064Sume	if (!buf) {
1064121156Sume		err(1, "malloc");
106578064Sume		/*NOTREACHED*/
106678064Sume	}
106778064Sume	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
106878064Sume		err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
106978064Sume		/*NOTREACHED*/
107078064Sume	}
107178064Sume
107278064Sume	ep = (struct in6_defrouter *)(buf + l);
107378064Sume	for (p = (struct in6_defrouter *)buf; p < ep; p++) {
107478064Sume		int rtpref;
107578064Sume
107678064Sume		if (getnameinfo((struct sockaddr *)&p->rtaddr,
107778064Sume		    p->rtaddr.sin6_len, host_buf, sizeof(host_buf), NULL, 0,
1078121156Sume		    (nflag ? NI_NUMERICHOST : 0)) != 0)
107978064Sume			strlcpy(host_buf, "?", sizeof(host_buf));
1080121156Sume
108178064Sume		printf("%s if=%s", host_buf,
1082121156Sume		    if_indextoname(p->if_index, ifix_buf));
108378064Sume		printf(", flags=%s%s",
1084121156Sume		    p->flags & ND_RA_FLAG_MANAGED ? "M" : "",
1085121156Sume		    p->flags & ND_RA_FLAG_OTHER   ? "O" : "");
108678064Sume		rtpref = ((p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff;
108778064Sume		printf(", pref=%s", rtpref_str[rtpref]);
1088121156Sume
108978064Sume		gettimeofday(&time, 0);
109078064Sume		if (p->expire == 0)
109178064Sume			printf(", expire=Never\n");
109278064Sume		else
109378064Sume			printf(", expire=%s\n",
1094121156Sume			    sec2str(p->expire - time.tv_sec));
109578064Sume	}
109678064Sume	free(buf);
109778064Sume#else
109855505Sshin	struct in6_drlist dr;
109955505Sshin	int s, i;
110055505Sshin	struct timeval time;
110155505Sshin
110255505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1103121156Sume		err(1, "socket");
1104121156Sume		/* NOTREACHED */
110555505Sshin	}
110655505Sshin	bzero(&dr, sizeof(dr));
1107121156Sume	strlcpy(dr.ifname, "lo0", sizeof(dr.ifname)); /* dummy */
110855505Sshin	if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) {
1109121156Sume		err(1, "ioctl(SIOCGDRLST_IN6)");
1110121156Sume		/* NOTREACHED */
1111121156Sume	}
111262590Sitojun#define DR dr.defrouter[i]
111378064Sume	for (i = 0 ; DR.if_index && i < DRLSTSIZ ; i++) {
111455505Sshin		struct sockaddr_in6 sin6;
111555505Sshin
111655505Sshin		bzero(&sin6, sizeof(sin6));
111755505Sshin		sin6.sin6_family = AF_INET6;
111855505Sshin		sin6.sin6_len = sizeof(sin6);
111955505Sshin		sin6.sin6_addr = DR.rtaddr;
112055505Sshin		getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf,
1121121156Sume		    sizeof(host_buf), NULL, 0,
1122121156Sume		    (nflag ? NI_NUMERICHOST : 0));
1123121156Sume
112455505Sshin		printf("%s if=%s", host_buf,
1125121156Sume		    if_indextoname(DR.if_index, ifix_buf));
112655505Sshin		printf(", flags=%s%s",
1127121156Sume		    DR.flags & ND_RA_FLAG_MANAGED ? "M" : "",
1128121156Sume		    DR.flags & ND_RA_FLAG_OTHER   ? "O" : "");
112955505Sshin		gettimeofday(&time, 0);
113055505Sshin		if (DR.expire == 0)
113155505Sshin			printf(", expire=Never\n");
113255505Sshin		else
113355505Sshin			printf(", expire=%s\n",
1134121156Sume			    sec2str(DR.expire - time.tv_sec));
113555505Sshin	}
113655505Sshin#undef DR
113755505Sshin	close(s);
113878064Sume#endif
113955505Sshin}
114055505Sshin
114155505Sshinvoid
114255505Sshinplist()
114355505Sshin{
114478064Sume#ifdef ICMPV6CTL_ND6_PRLIST
114578064Sume	int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST };
114678064Sume	char *buf;
114778064Sume	struct in6_prefix *p, *ep, *n;
114878064Sume	struct sockaddr_in6 *advrtr;
114978064Sume	size_t l;
115078064Sume	struct timeval time;
115178064Sume	const int niflags = NI_NUMERICHOST;
115278064Sume	int ninflags = nflag ? NI_NUMERICHOST : 0;
115378064Sume	char namebuf[NI_MAXHOST];
115478064Sume
115578064Sume	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
115678064Sume		err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
115778064Sume		/*NOTREACHED*/
115878064Sume	}
115978064Sume	buf = malloc(l);
116078064Sume	if (!buf) {
1161121156Sume		err(1, "malloc");
116278064Sume		/*NOTREACHED*/
116378064Sume	}
116478064Sume	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
116578064Sume		err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
116678064Sume		/*NOTREACHED*/
116778064Sume	}
116878064Sume
116978064Sume	ep = (struct in6_prefix *)(buf + l);
117078064Sume	for (p = (struct in6_prefix *)buf; p < ep; p = n) {
117178064Sume		advrtr = (struct sockaddr_in6 *)(p + 1);
117278064Sume		n = (struct in6_prefix *)&advrtr[p->advrtrs];
117378064Sume
117478064Sume		if (getnameinfo((struct sockaddr *)&p->prefix,
117578064Sume		    p->prefix.sin6_len, namebuf, sizeof(namebuf),
117678064Sume		    NULL, 0, niflags) != 0)
117778064Sume			strlcpy(namebuf, "?", sizeof(namebuf));
117878064Sume		printf("%s/%d if=%s\n", namebuf, p->prefixlen,
1179121156Sume		    if_indextoname(p->if_index, ifix_buf));
118078064Sume
118178064Sume		gettimeofday(&time, 0);
118278064Sume		/*
118378064Sume		 * meaning of fields, especially flags, is very different
118478064Sume		 * by origin.  notify the difference to the users.
118578064Sume		 */
118678064Sume		printf("flags=%s%s%s%s%s",
1187121156Sume		    p->raflags.onlink ? "L" : "",
1188121156Sume		    p->raflags.autonomous ? "A" : "",
1189121156Sume		    (p->flags & NDPRF_ONLINK) != 0 ? "O" : "",
1190121156Sume		    (p->flags & NDPRF_DETACHED) != 0 ? "D" : "",
119178064Sume#ifdef NDPRF_HOME
1192121156Sume		    (p->flags & NDPRF_HOME) != 0 ? "H" : ""
119378064Sume#else
1194121156Sume		    ""
119578064Sume#endif
1196121156Sume		    );
119778064Sume		if (p->vltime == ND6_INFINITE_LIFETIME)
119878064Sume			printf(" vltime=infinity");
119978064Sume		else
1200122615Sume			printf(" vltime=%lu", (unsigned long)p->vltime);
120178064Sume		if (p->pltime == ND6_INFINITE_LIFETIME)
120278064Sume			printf(", pltime=infinity");
120378064Sume		else
1204122615Sume			printf(", pltime=%lu", (unsigned long)p->pltime);
120578064Sume		if (p->expire == 0)
120678064Sume			printf(", expire=Never");
120778064Sume		else if (p->expire >= time.tv_sec)
120878064Sume			printf(", expire=%s",
1209121156Sume			    sec2str(p->expire - time.tv_sec));
121078064Sume		else
121178064Sume			printf(", expired");
121278064Sume		printf(", ref=%d", p->refcnt);
121378064Sume		printf("\n");
121478064Sume		/*
121578064Sume		 * "advertising router" list is meaningful only if the prefix
121678064Sume		 * information is from RA.
121778064Sume		 */
121878064Sume		if (p->advrtrs) {
121978064Sume			int j;
122078064Sume			struct sockaddr_in6 *sin6;
122178064Sume
1222122615Sume			sin6 = advrtr;
122378064Sume			printf("  advertised by\n");
122478064Sume			for (j = 0; j < p->advrtrs; j++) {
122578064Sume				struct in6_nbrinfo *nbi;
122678064Sume
122778064Sume				if (getnameinfo((struct sockaddr *)sin6,
122878064Sume				    sin6->sin6_len, namebuf, sizeof(namebuf),
122978064Sume				    NULL, 0, ninflags) != 0)
123078064Sume					strlcpy(namebuf, "?", sizeof(namebuf));
123178064Sume				printf("    %s", namebuf);
123278064Sume
1233121156Sume				nbi = getnbrinfo(&sin6->sin6_addr,
1234121156Sume				    p->if_index, 0);
123578064Sume				if (nbi) {
1236121156Sume					switch (nbi->state) {
123778064Sume					case ND6_LLINFO_REACHABLE:
123878064Sume					case ND6_LLINFO_STALE:
123978064Sume					case ND6_LLINFO_DELAY:
124078064Sume					case ND6_LLINFO_PROBE:
124178064Sume						printf(" (reachable)\n");
124278064Sume						break;
124378064Sume					default:
124478064Sume						printf(" (unreachable)\n");
124578064Sume					}
124678064Sume				} else
124778064Sume					printf(" (no neighbor state)\n");
124878064Sume				sin6++;
124978064Sume			}
125078064Sume		} else
125178064Sume			printf("  No advertising router\n");
125278064Sume	}
125378064Sume	free(buf);
125478064Sume#else
125555505Sshin	struct in6_prlist pr;
125655505Sshin	int s, i;
125755505Sshin	struct timeval time;
125855505Sshin
125955505Sshin	gettimeofday(&time, 0);
126055505Sshin
126155505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1262121156Sume		err(1, "socket");
1263121156Sume		/* NOTREACHED */
126455505Sshin	}
126555505Sshin	bzero(&pr, sizeof(pr));
1266121156Sume	strlcpy(pr.ifname, "lo0", sizeof(pr.ifname)); /* dummy */
126755505Sshin	if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) {
1268121156Sume		err(1, "ioctl(SIOCGPRLST_IN6)");
1269121156Sume		/* NOTREACHED */
1270121156Sume	}
127162590Sitojun#define PR pr.prefix[i]
127255505Sshin	for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) {
127378064Sume		struct sockaddr_in6 p6;
127478064Sume		char namebuf[NI_MAXHOST];
127578064Sume		int niflags;
127678064Sume
127778064Sume#ifdef NDPRF_ONLINK
127878064Sume		p6 = PR.prefix;
127978064Sume#else
128078064Sume		memset(&p6, 0, sizeof(p6));
128178064Sume		p6.sin6_family = AF_INET6;
128278064Sume		p6.sin6_len = sizeof(p6);
128378064Sume		p6.sin6_addr = PR.prefix;
128478064Sume#endif
128578064Sume
128678064Sume		/*
128778064Sume		 * copy link index to sin6_scope_id field.
128878064Sume		 * XXX: KAME specific.
128978064Sume		 */
129078064Sume		if (IN6_IS_ADDR_LINKLOCAL(&p6.sin6_addr)) {
129178064Sume			u_int16_t linkid;
129278064Sume
129378064Sume			memcpy(&linkid, &p6.sin6_addr.s6_addr[2],
1294121156Sume			    sizeof(linkid));
129578064Sume			linkid = ntohs(linkid);
129678064Sume			p6.sin6_scope_id = linkid;
129778064Sume			p6.sin6_addr.s6_addr[2] = 0;
129878064Sume			p6.sin6_addr.s6_addr[3] = 0;
129978064Sume		}
130078064Sume
130178064Sume		niflags = NI_NUMERICHOST;
130278064Sume		if (getnameinfo((struct sockaddr *)&p6,
1303121156Sume		    sizeof(p6), namebuf, sizeof(namebuf),
1304121156Sume		    NULL, 0, niflags)) {
130578064Sume			warnx("getnameinfo failed");
130678064Sume			continue;
130778064Sume		}
130878064Sume		printf("%s/%d if=%s\n", namebuf, PR.prefixlen,
1309121156Sume		    if_indextoname(PR.if_index, ifix_buf));
131078064Sume
131155505Sshin		gettimeofday(&time, 0);
131262590Sitojun		/*
131362590Sitojun		 * meaning of fields, especially flags, is very different
131462590Sitojun		 * by origin.  notify the difference to the users.
131562590Sitojun		 */
131678064Sume#if 0
131778064Sume		printf("  %s",
1318121156Sume		    PR.origin == PR_ORIG_RA ? "" : "advertise: ");
131978064Sume#endif
132078064Sume#ifdef NDPRF_ONLINK
132178064Sume		printf("flags=%s%s%s%s%s",
1322121156Sume		    PR.raflags.onlink ? "L" : "",
1323121156Sume		    PR.raflags.autonomous ? "A" : "",
1324121156Sume		    (PR.flags & NDPRF_ONLINK) != 0 ? "O" : "",
1325121156Sume		    (PR.flags & NDPRF_DETACHED) != 0 ? "D" : "",
132678064Sume#ifdef NDPRF_HOME
1327121156Sume		    (PR.flags & NDPRF_HOME) != 0 ? "H" : ""
132878064Sume#else
1329121156Sume		    ""
133078064Sume#endif
1331121156Sume		    );
133278064Sume#else
133362590Sitojun		printf("flags=%s%s",
1334121156Sume		    PR.raflags.onlink ? "L" : "",
1335121156Sume		    PR.raflags.autonomous ? "A" : "");
133678064Sume#endif
133755505Sshin		if (PR.vltime == ND6_INFINITE_LIFETIME)
133855505Sshin			printf(" vltime=infinity");
133955505Sshin		else
1340122615Sume			printf(" vltime=%lu", PR.vltime);
134155505Sshin		if (PR.pltime == ND6_INFINITE_LIFETIME)
134255505Sshin			printf(", pltime=infinity");
134355505Sshin		else
1344122615Sume			printf(", pltime=%lu", PR.pltime);
134555505Sshin		if (PR.expire == 0)
134662590Sitojun			printf(", expire=Never");
134755505Sshin		else if (PR.expire >= time.tv_sec)
134862590Sitojun			printf(", expire=%s",
1349121156Sume			    sec2str(PR.expire - time.tv_sec));
135055505Sshin		else
135162590Sitojun			printf(", expired");
135278064Sume#ifdef NDPRF_ONLINK
135378064Sume		printf(", ref=%d", PR.refcnt);
135478064Sume#endif
135578064Sume#if 0
135662590Sitojun		switch (PR.origin) {
135762590Sitojun		case PR_ORIG_RA:
135862590Sitojun			printf(", origin=RA");
135962590Sitojun			break;
136062590Sitojun		case PR_ORIG_RR:
136162590Sitojun			printf(", origin=RR");
136262590Sitojun			break;
136362590Sitojun		case PR_ORIG_STATIC:
136462590Sitojun			printf(", origin=static");
136562590Sitojun			break;
136662590Sitojun		case PR_ORIG_KERNEL:
136762590Sitojun			printf(", origin=kernel");
136862590Sitojun			break;
136962590Sitojun		default:
137062590Sitojun			printf(", origin=?");
137162590Sitojun			break;
137262590Sitojun		}
137378064Sume#endif
137462590Sitojun		printf("\n");
137562590Sitojun		/*
137662590Sitojun		 * "advertising router" list is meaningful only if the prefix
137762590Sitojun		 * information is from RA.
137862590Sitojun		 */
137978064Sume		if (0 &&	/* prefix origin is almost obsolted */
138078064Sume		    PR.origin != PR_ORIG_RA)
138162590Sitojun			;
138262590Sitojun		else if (PR.advrtrs) {
138355505Sshin			int j;
138455505Sshin			printf("  advertised by\n");
138555505Sshin			for (j = 0; j < PR.advrtrs; j++) {
138655505Sshin				struct sockaddr_in6 sin6;
138762590Sitojun				struct in6_nbrinfo *nbi;
138855505Sshin
138955505Sshin				bzero(&sin6, sizeof(sin6));
139055505Sshin				sin6.sin6_family = AF_INET6;
139155505Sshin				sin6.sin6_len = sizeof(sin6);
139255505Sshin				sin6.sin6_addr = PR.advrtr[j];
139362590Sitojun				sin6.sin6_scope_id = PR.if_index; /* XXX */
139455505Sshin				getnameinfo((struct sockaddr *)&sin6,
1395121156Sume				    sin6.sin6_len, host_buf,
1396121156Sume				    sizeof(host_buf), NULL, 0,
1397121156Sume				    (nflag ? NI_NUMERICHOST : 0));
139862590Sitojun				printf("    %s", host_buf);
139955505Sshin
1400121156Sume				nbi = getnbrinfo(&sin6.sin6_addr,
1401121156Sume				    PR.if_index, 0);
140262590Sitojun				if (nbi) {
1403121156Sume					switch (nbi->state) {
1404121156Sume					case ND6_LLINFO_REACHABLE:
1405121156Sume					case ND6_LLINFO_STALE:
1406121156Sume					case ND6_LLINFO_DELAY:
1407121156Sume					case ND6_LLINFO_PROBE:
140862590Sitojun						 printf(" (reachable)\n");
140962590Sitojun						 break;
1410121156Sume					default:
141162590Sitojun						 printf(" (unreachable)\n");
141262590Sitojun					}
141378064Sume				} else
141462590Sitojun					printf(" (no neighbor state)\n");
141555505Sshin			}
141655505Sshin			if (PR.advrtrs > DRLSTSIZ)
141755505Sshin				printf("    and %d routers\n",
1418121156Sume				    PR.advrtrs - DRLSTSIZ);
141962590Sitojun		} else
142055505Sshin			printf("  No advertising router\n");
142155505Sshin	}
142255505Sshin#undef PR
142355505Sshin	close(s);
142478064Sume#endif
142555505Sshin}
142655505Sshin
142755505Sshinvoid
142855505Sshinpfx_flush()
142955505Sshin{
143055505Sshin	char dummyif[IFNAMSIZ+8];
143155505Sshin	int s;
143255505Sshin
143355505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
143455505Sshin		err(1, "socket");
1435121156Sume	strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
143655505Sshin	if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0)
1437121156Sume		err(1, "ioctl(SIOCSPFXFLUSH_IN6)");
143855505Sshin}
143955505Sshin
144055505Sshinvoid
144155505Sshinrtr_flush()
144255505Sshin{
144355505Sshin	char dummyif[IFNAMSIZ+8];
144455505Sshin	int s;
144555505Sshin
144655505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
144755505Sshin		err(1, "socket");
1448121156Sume	strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
144955505Sshin	if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0)
1450121156Sume		err(1, "ioctl(SIOCSRTRFLUSH_IN6)");
145162590Sitojun
145262590Sitojun	close(s);
145355505Sshin}
145455505Sshin
145555505Sshinvoid
145655505Sshinharmonize_rtr()
145755505Sshin{
145855505Sshin	char dummyif[IFNAMSIZ+8];
145955505Sshin	int s;
146055505Sshin
146162590Sitojun	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
146262590Sitojun		err(1, "socket");
1463121156Sume	strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
146462590Sitojun	if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0)
1465121156Sume		err(1, "ioctl(SIOCSNDFLUSH_IN6)");
146662590Sitojun
146762590Sitojun	close(s);
146855505Sshin}
146955505Sshin
147062590Sitojun#ifdef SIOCSDEFIFACE_IN6	/* XXX: check SIOCGDEFIFACE_IN6 as well? */
147162590Sitojunstatic void
147262590Sitojunsetdefif(ifname)
147362590Sitojun	char *ifname;
147462590Sitojun{
147562590Sitojun	struct in6_ndifreq ndifreq;
147662590Sitojun	unsigned int ifindex;
147762590Sitojun
147862590Sitojun	if (strcasecmp(ifname, "delete") == 0)
147962590Sitojun		ifindex = 0;
148062590Sitojun	else {
148162590Sitojun		if ((ifindex = if_nametoindex(ifname)) == 0)
148262590Sitojun			err(1, "failed to resolve i/f index for %s", ifname);
148362590Sitojun	}
148462590Sitojun
148562590Sitojun	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
148662590Sitojun		err(1, "socket");
148762590Sitojun
1488121156Sume	strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */
148962590Sitojun	ndifreq.ifindex = ifindex;
149062590Sitojun
149162590Sitojun	if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1492121156Sume		err(1, "ioctl(SIOCSDEFIFACE_IN6)");
149362590Sitojun
149462590Sitojun	close(s);
149562590Sitojun}
149662590Sitojun
149762590Sitojunstatic void
149862590Sitojungetdefif()
149962590Sitojun{
150062590Sitojun	struct in6_ndifreq ndifreq;
150162590Sitojun	char ifname[IFNAMSIZ+8];
150262590Sitojun
150362590Sitojun	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
150462590Sitojun		err(1, "socket");
150562590Sitojun
150662590Sitojun	memset(&ndifreq, 0, sizeof(ndifreq));
1507121156Sume	strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */
150862590Sitojun
150962590Sitojun	if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1510121156Sume		err(1, "ioctl(SIOCGDEFIFACE_IN6)");
151162590Sitojun
151262590Sitojun	if (ndifreq.ifindex == 0)
151362590Sitojun		printf("No default interface.\n");
151462590Sitojun	else {
151562590Sitojun		if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL)
151662590Sitojun			err(1, "failed to resolve ifname for index %lu",
151762590Sitojun			    ndifreq.ifindex);
151862590Sitojun		printf("ND default interface = %s\n", ifname);
151962590Sitojun	}
152062590Sitojun
152162590Sitojun	close(s);
152262590Sitojun}
152362590Sitojun#endif
152462590Sitojun
152555505Sshinstatic char *
152655505Sshinsec2str(total)
152755505Sshin	time_t total;
152855505Sshin{
152955505Sshin	static char result[256];
153055505Sshin	int days, hours, mins, secs;
153155505Sshin	int first = 1;
153255505Sshin	char *p = result;
1533121156Sume	char *ep = &result[sizeof(result)];
1534121156Sume	int n;
153555505Sshin
153655505Sshin	days = total / 3600 / 24;
153755505Sshin	hours = (total / 3600) % 24;
153855505Sshin	mins = (total / 60) % 60;
153955505Sshin	secs = total % 60;
154055505Sshin
154155505Sshin	if (days) {
154255505Sshin		first = 0;
1543121156Sume		n = snprintf(p, ep - p, "%dd", days);
1544121156Sume		if (n < 0 || n >= ep - p)
1545121156Sume			return "?";
1546121156Sume		p += n;
154755505Sshin	}
154855505Sshin	if (!first || hours) {
154955505Sshin		first = 0;
1550121156Sume		n = snprintf(p, ep - p, "%dh", hours);
1551121156Sume		if (n < 0 || n >= ep - p)
1552121156Sume			return "?";
1553121156Sume		p += n;
155455505Sshin	}
155555505Sshin	if (!first || mins) {
155655505Sshin		first = 0;
1557121156Sume		n = snprintf(p, ep - p, "%dm", mins);
1558121156Sume		if (n < 0 || n >= ep - p)
1559121156Sume			return "?";
1560121156Sume		p += n;
156155505Sshin	}
1562121156Sume	snprintf(p, ep - p, "%ds", secs);
156355505Sshin
156455505Sshin	return(result);
156555505Sshin}
156655505Sshin
156755505Sshin/*
156855505Sshin * Print the timestamp
156955505Sshin * from tcpdump/util.c
157055505Sshin */
157155505Sshinstatic void
157255505Sshints_print(tvp)
157355505Sshin	const struct timeval *tvp;
157455505Sshin{
157555505Sshin	int s;
157655505Sshin
157755505Sshin	/* Default */
157855505Sshin	s = (tvp->tv_sec + thiszone) % 86400;
157955505Sshin	(void)printf("%02d:%02d:%02d.%06u ",
158055505Sshin	    s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec);
158155505Sshin}
1582