ndp.c revision 121162
162590Sitojun/*	$FreeBSD: head/usr.sbin/ndp/ndp.c 121162 2003-10-17 16:17:47Z ume $	*/
278064Sume/*	$KAME: ndp.c,v 1.65 2001/05/08 04:36:34 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>
11455505Sshin#include "gmt2local.h"
11555505Sshin
11655505Sshin/* packing rule for routing socket */
11762590Sitojun#define ROUNDUP(a) \
11855505Sshin	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
11962590Sitojun#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
12055505Sshin
121100650Sjmallettstatic pid_t pid;
12266865Ssumikawastatic int cflag;
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 *));
13962590Sitojunvoid dump __P((struct in6_addr *));
14062590Sitojunstatic struct in6_nbrinfo *getnbrinfo __P((struct in6_addr *addr,
14162590Sitojun					   int ifindex, int));
14262590Sitojunstatic char *ether_str __P((struct sockaddr_dl *));
14362590Sitojunint ndp_ether_aton __P((char *, u_char *));
14462590Sitojunvoid usage __P((void));
14562590Sitojunint rtmsg __P((int));
14662590Sitojunvoid ifinfo __P((int, char **));
14762590Sitojunvoid rtrlist __P((void));
14862590Sitojunvoid plist __P((void));
14962590Sitojunvoid pfx_flush __P((void));
15062590Sitojunvoid rtrlist __P((void));
15162590Sitojunvoid rtr_flush __P((void));
15262590Sitojunvoid harmonize_rtr __P((void));
15362590Sitojun#ifdef SIOCSDEFIFACE_IN6	/* XXX: check SIOCGDEFIFACE_IN6 as well? */
15462590Sitojunstatic void getdefif __P((void));
15562590Sitojunstatic void setdefif __P((char *));
15662590Sitojun#endif
15762590Sitojunstatic char *sec2str __P((time_t t));
15862590Sitojunstatic char *ether_str __P((struct sockaddr_dl *sdl));
15962590Sitojunstatic void ts_print __P((const struct timeval *));
16055505Sshin
16178064Sumestatic char *rtpref_str[] = {
16278064Sume	"medium",		/* 00 */
16378064Sume	"high",			/* 01 */
16478064Sume	"rsv",			/* 10 */
16578064Sume	"low"			/* 11 */
16678064Sume};
16778064Sume
16855505Sshinint
16955505Sshinmain(argc, argv)
17055505Sshin	int argc;
17155505Sshin	char **argv;
17255505Sshin{
17355505Sshin	int ch;
17466865Ssumikawa	int aflag = 0, dflag = 0, sflag = 0, Hflag = 0,
17555505Sshin		pflag = 0, rflag = 0, Pflag = 0, Rflag = 0;
17655505Sshin
17755505Sshin	pid = getpid();
17855505Sshin	thiszone = gmt2local(0);
17978064Sume	while ((ch = getopt(argc, argv, "acndfIilprstA:HPR")) != -1)
180121156Sume		switch (ch) {
18155505Sshin		case 'a':
18255505Sshin			aflag = 1;
18355505Sshin			break;
18455505Sshin		case 'c':
18555505Sshin			cflag = 1;
18655505Sshin			break;
18755505Sshin		case 'd':
18855505Sshin			dflag = 1;
18955505Sshin			break;
19062590Sitojun		case 'I':
19162590Sitojun#ifdef SIOCSDEFIFACE_IN6	/* XXX: check SIOCGDEFIFACE_IN6 as well? */
19262590Sitojun			if (argc > 2)
19362590Sitojun				setdefif(argv[2]);
19462590Sitojun			getdefif(); /* always call it to print the result */
19562590Sitojun			exit(0);
19662590Sitojun#else
19762590Sitojun			errx(1, "not supported yet");
19862590Sitojun			/*NOTREACHED*/
19962590Sitojun#endif
20055505Sshin		case 'i' :
20162590Sitojun			argc -= optind;
20262590Sitojun			argv += optind;
20362590Sitojun			if (argc < 1)
20455505Sshin				usage();
20562590Sitojun			ifinfo(argc, argv);
20655505Sshin			exit(0);
20755505Sshin		case 'n':
20855505Sshin			nflag = 1;
20955505Sshin			continue;
21055505Sshin		case 'p':
21155505Sshin			pflag = 1;
21255505Sshin			break;
21355505Sshin		case 'f' :
21455505Sshin			if (argc != 3)
21555505Sshin				usage();
21655505Sshin			file(argv[2]);
21755505Sshin			exit(0);
21855505Sshin		case 'l' :
21978064Sume			/* obsolete, ignored */
22055505Sshin			break;
22155505Sshin		case 'r' :
22255505Sshin			rflag = 1;
22355505Sshin			break;
22455505Sshin		case 's':
22555505Sshin			sflag = 1;
22655505Sshin			break;
22755505Sshin		case 't':
22855505Sshin			tflag = 1;
22955505Sshin			break;
23055505Sshin		case 'A':
23155505Sshin			aflag = 1;
23255505Sshin			repeat = atoi(optarg);
23355505Sshin			if (repeat < 0)
23455505Sshin				usage();
23555505Sshin			break;
23655505Sshin		case 'H' :
23755505Sshin			Hflag = 1;
23855505Sshin			break;
23955505Sshin		case 'P':
24055505Sshin			Pflag = 1;
24155505Sshin			break;
24255505Sshin		case 'R':
24355505Sshin			Rflag = 1;
24455505Sshin			break;
24555505Sshin		default:
24655505Sshin			usage();
24755505Sshin		}
24855505Sshin
24955505Sshin	argc -= optind;
25055505Sshin	argv += optind;
25155505Sshin
25255505Sshin	if (aflag || cflag) {
25355505Sshin		dump(0);
25455505Sshin		exit(0);
25555505Sshin	}
25655505Sshin	if (dflag) {
25755505Sshin		if (argc != 1)
25855505Sshin			usage();
25955505Sshin		delete(argv[0]);
26062590Sitojun		exit(0);
26155505Sshin	}
26255505Sshin	if (pflag) {
26355505Sshin		plist();
26455505Sshin		exit(0);
26555505Sshin	}
26655505Sshin	if (rflag) {
26755505Sshin		rtrlist();
26855505Sshin		exit(0);
26955505Sshin	}
27055505Sshin	if (sflag) {
27155505Sshin		if (argc < 2 || argc > 4)
27255505Sshin			usage();
27355505Sshin		exit(set(argc, argv) ? 1 : 0);
27455505Sshin	}
27555505Sshin	if (Hflag) {
27655505Sshin		harmonize_rtr();
27755505Sshin		exit(0);
27855505Sshin	}
27955505Sshin	if (Pflag) {
28055505Sshin		pfx_flush();
28155505Sshin		exit(0);
28255505Sshin	}
28355505Sshin	if (Rflag) {
28455505Sshin		rtr_flush();
28555505Sshin		exit(0);
28655505Sshin	}
28755505Sshin
28855505Sshin	if (argc != 1)
28955505Sshin		usage();
29055505Sshin	get(argv[0]);
29155505Sshin	exit(0);
29255505Sshin}
29355505Sshin
29455505Sshin/*
29555505Sshin * Process a file to set standard ndp entries
29655505Sshin */
29755505Sshinint
29855505Sshinfile(name)
29955505Sshin	char *name;
30055505Sshin{
30155505Sshin	FILE *fp;
30255505Sshin	int i, retval;
30355505Sshin	char line[100], arg[5][50], *args[5];
30455505Sshin
30555505Sshin	if ((fp = fopen(name, "r")) == NULL) {
30655505Sshin		fprintf(stderr, "ndp: cannot open %s\n", name);
30755505Sshin		exit(1);
30855505Sshin	}
30955505Sshin	args[0] = &arg[0][0];
31055505Sshin	args[1] = &arg[1][0];
31155505Sshin	args[2] = &arg[2][0];
31255505Sshin	args[3] = &arg[3][0];
31355505Sshin	args[4] = &arg[4][0];
31455505Sshin	retval = 0;
315121156Sume	while (fgets(line, 100, fp) != NULL) {
31655505Sshin		i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2],
31755505Sshin		    arg[3], arg[4]);
31855505Sshin		if (i < 2) {
31955505Sshin			fprintf(stderr, "ndp: bad line: %s\n", line);
32055505Sshin			retval = 1;
32155505Sshin			continue;
32255505Sshin		}
32355505Sshin		if (set(i, args))
32455505Sshin			retval = 1;
32555505Sshin	}
32655505Sshin	fclose(fp);
32755505Sshin	return (retval);
32855505Sshin}
32955505Sshin
33055505Sshinvoid
33155505Sshingetsocket()
33255505Sshin{
33355505Sshin	if (s < 0) {
33455505Sshin		s = socket(PF_ROUTE, SOCK_RAW, 0);
33555505Sshin		if (s < 0) {
336121156Sume			err(1, "socket");
337121156Sume			/* NOTREACHED */
33855505Sshin		}
33955505Sshin	}
34055505Sshin}
34155505Sshin
34262590Sitojunstruct	sockaddr_in6 so_mask = {sizeof(so_mask), AF_INET6 };
34355505Sshinstruct	sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET6 }, sin_m;
34455505Sshinstruct	sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m;
34555505Sshinint	expire_time, flags, found_entry;
34655505Sshinstruct	{
34755505Sshin	struct	rt_msghdr m_rtm;
34855505Sshin	char	m_space[512];
34955505Sshin}	m_rtmsg;
35055505Sshin
35155505Sshin/*
35255505Sshin * Set an individual neighbor cache entry
35355505Sshin */
35455505Sshinint
35555505Sshinset(argc, argv)
35655505Sshin	int argc;
35755505Sshin	char **argv;
35855505Sshin{
35955505Sshin	register struct sockaddr_in6 *sin = &sin_m;
36055505Sshin	register struct sockaddr_dl *sdl;
36155505Sshin	register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
36255505Sshin	struct addrinfo hints, *res;
36355505Sshin	int gai_error;
36455505Sshin	u_char *ea;
36555505Sshin	char *host = argv[0], *eaddr = argv[1];
36655505Sshin
36755505Sshin	getsocket();
36855505Sshin	argc -= 2;
36955505Sshin	argv += 2;
37055505Sshin	sdl_m = blank_sdl;
37155505Sshin	sin_m = blank_sin;
37255505Sshin
37355505Sshin	bzero(&hints, sizeof(hints));
37455505Sshin	hints.ai_family = AF_INET6;
37555505Sshin	gai_error = getaddrinfo(host, NULL, &hints, &res);
37655505Sshin	if (gai_error) {
37755505Sshin		fprintf(stderr, "ndp: %s: %s\n", host,
37855505Sshin			gai_strerror(gai_error));
37955505Sshin		return 1;
38055505Sshin	}
38155505Sshin	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
38262590Sitojun#ifdef __KAME__
38362590Sitojun	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
38462590Sitojun		*(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
385121156Sume		    htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
38662590Sitojun	}
38762590Sitojun#endif
38855505Sshin	ea = (u_char *)LLADDR(&sdl_m);
38955505Sshin	if (ndp_ether_aton(eaddr, ea) == 0)
39055505Sshin		sdl_m.sdl_alen = 6;
39155505Sshin	flags = expire_time = 0;
39255505Sshin	while (argc-- > 0) {
39355505Sshin		if (strncmp(argv[0], "temp", 4) == 0) {
39455505Sshin			struct timeval time;
395121156Sume
39655505Sshin			gettimeofday(&time, 0);
39755505Sshin			expire_time = time.tv_sec + 20 * 60;
39862590Sitojun		} else if (strncmp(argv[0], "proxy", 5) == 0)
39962590Sitojun			flags |= RTF_ANNOUNCE;
40055505Sshin		argv++;
40155505Sshin	}
40255505Sshin	if (rtmsg(RTM_GET) < 0) {
403121156Sume		errx(1, "RTM_GET(%s) failed", host);
404121156Sume		/* NOTREACHED */
40555505Sshin	}
40655505Sshin	sin = (struct sockaddr_in6 *)(rtm + 1);
40755505Sshin	sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
40855505Sshin	if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
40955505Sshin		if (sdl->sdl_family == AF_LINK &&
41055505Sshin		    (rtm->rtm_flags & RTF_LLINFO) &&
41155505Sshin		    !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
41255505Sshin		case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
41355505Sshin		case IFT_ISO88024: case IFT_ISO88025:
41455505Sshin			goto overwrite;
41555505Sshin		}
41662590Sitojun		/*
41762590Sitojun		 * IPv4 arp command retries with sin_other = SIN_PROXY here.
41862590Sitojun		 */
41962590Sitojun		fprintf(stderr, "set: cannot configure a new entry\n");
42062590Sitojun		return 1;
42155505Sshin	}
42262590Sitojun
42355505Sshinoverwrite:
42455505Sshin	if (sdl->sdl_family != AF_LINK) {
42555505Sshin		printf("cannot intuit interface index and type for %s\n", host);
42655505Sshin		return (1);
42755505Sshin	}
42855505Sshin	sdl_m.sdl_type = sdl->sdl_type;
42955505Sshin	sdl_m.sdl_index = sdl->sdl_index;
43055505Sshin	return (rtmsg(RTM_ADD));
43155505Sshin}
43255505Sshin
43355505Sshin/*
43455505Sshin * Display an individual neighbor cache entry
43555505Sshin */
43655505Sshinvoid
43755505Sshinget(host)
43855505Sshin	char *host;
43955505Sshin{
44055505Sshin	struct sockaddr_in6 *sin = &sin_m;
44155505Sshin	struct addrinfo hints, *res;
44255505Sshin	int gai_error;
44355505Sshin
44455505Sshin	sin_m = blank_sin;
44555505Sshin	bzero(&hints, sizeof(hints));
44655505Sshin	hints.ai_family = AF_INET6;
44755505Sshin	gai_error = getaddrinfo(host, NULL, &hints, &res);
44855505Sshin	if (gai_error) {
44955505Sshin		fprintf(stderr, "ndp: %s: %s\n", host,
450121156Sume		    gai_strerror(gai_error));
45155505Sshin		return;
45255505Sshin	}
45355505Sshin	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
45462590Sitojun#ifdef __KAME__
45562590Sitojun	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
45662590Sitojun		*(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
457121156Sume		    htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
45862590Sitojun	}
45962590Sitojun#endif
46055505Sshin	dump(&sin->sin6_addr);
46155505Sshin	if (found_entry == 0) {
46255505Sshin		getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
463121156Sume		    sizeof(host_buf), NULL ,0,
464121156Sume		    (nflag ? NI_NUMERICHOST : 0));
46555505Sshin		printf("%s (%s) -- no entry\n", host, host_buf);
46655505Sshin		exit(1);
46755505Sshin	}
46855505Sshin}
46955505Sshin
47055505Sshin/*
47155505Sshin * Delete a neighbor cache entry
47255505Sshin */
47355505Sshinint
47455505Sshindelete(host)
47555505Sshin	char *host;
47655505Sshin{
47755505Sshin	struct sockaddr_in6 *sin = &sin_m;
47855505Sshin	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
47955505Sshin	struct sockaddr_dl *sdl;
48055505Sshin	struct addrinfo hints, *res;
48155505Sshin	int gai_error;
48255505Sshin
48355505Sshin	getsocket();
48455505Sshin	sin_m = blank_sin;
48555505Sshin
48655505Sshin	bzero(&hints, sizeof(hints));
48755505Sshin	hints.ai_family = AF_INET6;
48855505Sshin	gai_error = getaddrinfo(host, NULL, &hints, &res);
48955505Sshin	if (gai_error) {
49055505Sshin		fprintf(stderr, "ndp: %s: %s\n", host,
491121156Sume		    gai_strerror(gai_error));
49255505Sshin		return 1;
49355505Sshin	}
49455505Sshin	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
49562590Sitojun#ifdef __KAME__
49662590Sitojun	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
49762590Sitojun		*(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
498121156Sume		    htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
49962590Sitojun	}
50062590Sitojun#endif
50155505Sshin	if (rtmsg(RTM_GET) < 0) {
502121156Sume		errx(1, "RTM_GET(%s) failed", host);
503121156Sume		/* NOTREACHED */
50455505Sshin	}
50555505Sshin	sin = (struct sockaddr_in6 *)(rtm + 1);
50655505Sshin	sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
50755505Sshin	if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
50855505Sshin		if (sdl->sdl_family == AF_LINK &&
50955505Sshin		    (rtm->rtm_flags & RTF_LLINFO) &&
51062590Sitojun		    !(rtm->rtm_flags & RTF_GATEWAY)) {
51178064Sume			goto delete;
51255505Sshin		}
51362590Sitojun		/*
51462590Sitojun		 * IPv4 arp command retries with sin_other = SIN_PROXY here.
51562590Sitojun		 */
51662590Sitojun		fprintf(stderr, "delete: cannot delete non-NDP entry\n");
51762590Sitojun		return 1;
51855505Sshin	}
51962590Sitojun
52055505Sshindelete:
52155505Sshin	if (sdl->sdl_family != AF_LINK) {
52255505Sshin		printf("cannot locate %s\n", host);
52355505Sshin		return (1);
52455505Sshin	}
52555505Sshin	if (rtmsg(RTM_DELETE) == 0) {
52662590Sitojun		struct sockaddr_in6 s6 = *sin; /* XXX: for safety */
52762590Sitojun
52862590Sitojun#ifdef __KAME__
52962590Sitojun		if (IN6_IS_ADDR_LINKLOCAL(&s6.sin6_addr)) {
53062590Sitojun			s6.sin6_scope_id = ntohs(*(u_int16_t *)&s6.sin6_addr.s6_addr[2]);
53162590Sitojun			*(u_int16_t *)&s6.sin6_addr.s6_addr[2] = 0;
53262590Sitojun		}
53362590Sitojun#endif
53462590Sitojun		getnameinfo((struct sockaddr *)&s6,
535121156Sume		    s6.sin6_len, host_buf,
536121156Sume		    sizeof(host_buf), NULL, 0,
537121156Sume		    (nflag ? NI_NUMERICHOST : 0));
53855505Sshin		printf("%s (%s) deleted\n", host, host_buf);
53955505Sshin	}
54055505Sshin
54155505Sshin	return 0;
54255505Sshin}
54355505Sshin
54478064Sume#define W_ADDR	31
54578064Sume#define W_LL	17
54678064Sume#define W_IF	6
54778064Sume
54855505Sshin/*
54955505Sshin * Dump the entire neighbor cache
55055505Sshin */
55155505Sshinvoid
55255505Sshindump(addr)
55355505Sshin	struct in6_addr *addr;
55455505Sshin{
55555505Sshin	int mib[6];
55655505Sshin	size_t needed;
55762590Sitojun	char *lim, *buf, *next;
55855505Sshin	struct rt_msghdr *rtm;
55955505Sshin	struct sockaddr_in6 *sin;
56055505Sshin	struct sockaddr_dl *sdl;
56155505Sshin	extern int h_errno;
56255505Sshin	struct in6_nbrinfo *nbi;
56355505Sshin	struct timeval time;
56455505Sshin	int addrwidth;
56578064Sume	int llwidth;
56678064Sume	int ifwidth;
56762590Sitojun	char flgbuf[8];
56878064Sume	char *ifname;
56955505Sshin
57055505Sshin	/* Print header */
57166865Ssumikawa	if (!tflag && !cflag)
57278064Sume		printf("%-*.*s %-*.*s %*.*s %-9.9s %2s %4s %4s\n",
57378064Sume		    W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address",
57478064Sume		    W_IF, W_IF, "Netif", "Expire", "St", "Flgs", "Prbs");
57555505Sshin
57655505Sshinagain:;
57755505Sshin	mib[0] = CTL_NET;
57855505Sshin	mib[1] = PF_ROUTE;
57955505Sshin	mib[2] = 0;
58055505Sshin	mib[3] = AF_INET6;
58155505Sshin	mib[4] = NET_RT_FLAGS;
58255505Sshin	mib[5] = RTF_LLINFO;
58355505Sshin	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
58455505Sshin		err(1, "sysctl(PF_ROUTE estimate)");
58555505Sshin	if (needed > 0) {
58655505Sshin		if ((buf = malloc(needed)) == NULL)
587121156Sume			err(1, "malloc");
58855505Sshin		if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
58955505Sshin			err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
59055505Sshin		lim = buf + needed;
59155505Sshin	} else
59255505Sshin		buf = lim = NULL;
59355505Sshin
59455505Sshin	for (next = buf; next && next < lim; next += rtm->rtm_msglen) {
59555505Sshin		int isrouter = 0, prbs = 0;
59655505Sshin
59755505Sshin		rtm = (struct rt_msghdr *)next;
59855505Sshin		sin = (struct sockaddr_in6 *)(rtm + 1);
59955505Sshin		sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len));
60078064Sume
60178064Sume		/*
60278064Sume		 * Some OSes can produce a route that has the LINK flag but
60378064Sume		 * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD
60478064Sume		 * and BSD/OS, where xx is not the interface identifier on
60578064Sume		 * lo0).  Such routes entry would annoy getnbrinfo() below,
60678064Sume		 * so we skip them.
60778064Sume		 * XXX: such routes should have the GATEWAY flag, not the
608121156Sume		 * LINK flag.  However, there is rotten routing software
60978064Sume		 * that advertises all routes that have the GATEWAY flag.
61078064Sume		 * Thus, KAME kernel intentionally does not set the LINK flag.
61178064Sume		 * What is to be fixed is not ndp, but such routing software
61278064Sume		 * (and the kernel workaround)...
61378064Sume		 */
61478064Sume		if (sdl->sdl_family != AF_LINK)
61578064Sume			continue;
61678064Sume
61755505Sshin		if (addr) {
61855505Sshin			if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr))
61955505Sshin				continue;
62055505Sshin			found_entry = 1;
62155505Sshin		} else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
62255505Sshin			continue;
62355505Sshin		if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) ||
62455505Sshin		    IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) {
62555505Sshin			/* XXX: should scope id be filled in the kernel? */
62655505Sshin			if (sin->sin6_scope_id == 0)
62755505Sshin				sin->sin6_scope_id = sdl->sdl_index;
62866865Ssumikawa#ifdef __KAME__
62966865Ssumikawa			/* KAME specific hack; removed the embedded id */
63055505Sshin			*(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0;
63166865Ssumikawa#endif
63255505Sshin		}
63355505Sshin		getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
634121156Sume		    sizeof(host_buf), NULL, 0, (nflag ? NI_NUMERICHOST : 0));
63566865Ssumikawa		if (cflag == 1) {
63681366Ssumikawa#ifdef RTF_WASCLONED
63781366Ssumikawa			if (rtm->rtm_flags & RTF_WASCLONED)
63881366Ssumikawa				delete(host_buf);
63981366Ssumikawa#else
64066865Ssumikawa			delete(host_buf);
64181366Ssumikawa#endif
64266865Ssumikawa			continue;
64366865Ssumikawa		}
64455505Sshin		gettimeofday(&time, 0);
64555505Sshin		if (tflag)
64655505Sshin			ts_print(&time);
64755505Sshin
64878064Sume		addrwidth = strlen(host_buf);
64978064Sume		if (addrwidth < W_ADDR)
65078064Sume			addrwidth = W_ADDR;
65178064Sume		llwidth = strlen(ether_str(sdl));
65278064Sume		if (W_ADDR + W_LL - addrwidth > llwidth)
65378064Sume			llwidth = W_ADDR + W_LL - addrwidth;
65478064Sume		ifname = if_indextoname(sdl->sdl_index, ifix_buf);
65578064Sume		if (!ifname)
65678064Sume			ifname = "?";
65778064Sume		ifwidth = strlen(ifname);
65878064Sume		if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth)
65978064Sume			ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth;
66055505Sshin
66178064Sume		printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf,
66278064Sume		    llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname);
66355505Sshin
66455505Sshin		/* Print neighbor discovery specific informations */
66562590Sitojun		nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1);
66655505Sshin		if (nbi) {
66755505Sshin			if (nbi->expire > time.tv_sec) {
66855505Sshin				printf(" %-9.9s",
669121156Sume				    sec2str(nbi->expire - time.tv_sec));
67078064Sume			} else if (nbi->expire == 0)
67155505Sshin				printf(" %-9.9s", "permanent");
67255505Sshin			else
67355505Sshin				printf(" %-9.9s", "expired");
67455505Sshin
675121156Sume			switch (nbi->state) {
676121156Sume			case ND6_LLINFO_NOSTATE:
67755505Sshin				 printf(" N");
67855505Sshin				 break;
67978064Sume#ifdef ND6_LLINFO_WAITDELETE
680121156Sume			case ND6_LLINFO_WAITDELETE:
68155505Sshin				 printf(" W");
68255505Sshin				 break;
68378064Sume#endif
684121156Sume			case ND6_LLINFO_INCOMPLETE:
68555505Sshin				 printf(" I");
68655505Sshin				 break;
687121156Sume			case ND6_LLINFO_REACHABLE:
68855505Sshin				 printf(" R");
68955505Sshin				 break;
690121156Sume			case ND6_LLINFO_STALE:
69155505Sshin				 printf(" S");
69255505Sshin				 break;
693121156Sume			case ND6_LLINFO_DELAY:
69455505Sshin				 printf(" D");
69555505Sshin				 break;
696121156Sume			case ND6_LLINFO_PROBE:
69755505Sshin				 printf(" P");
69855505Sshin				 break;
699121156Sume			default:
70055505Sshin				 printf(" ?");
70155505Sshin				 break;
70255505Sshin			}
70355505Sshin
70455505Sshin			isrouter = nbi->isrouter;
70555505Sshin			prbs = nbi->asked;
70678064Sume		} else {
70755505Sshin			warnx("failed to get neighbor information");
70855505Sshin			printf("  ");
70955505Sshin		}
71055505Sshin		putchar(' ');
71155505Sshin
71262590Sitojun		/*
71362590Sitojun		 * other flags. R: router, P: proxy, W: ??
71462590Sitojun		 */
71562590Sitojun		if ((rtm->rtm_addrs & RTA_NETMASK) == 0) {
71662590Sitojun			snprintf(flgbuf, sizeof(flgbuf), "%s%s",
717121156Sume			    isrouter ? "R" : "",
718121156Sume			    (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
71962590Sitojun		} else {
72062590Sitojun			sin = (struct sockaddr_in6 *)
721121156Sume			    (sdl->sdl_len + (char *)sdl);
72262590Sitojun			snprintf(flgbuf, sizeof(flgbuf), "%s%s%s%s",
723121156Sume			    isrouter ? "R" : "",
724121156Sume			    !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr) ? "P" : "",
725121156Sume			    (sin->sin6_len != sizeof(struct sockaddr_in6)) ? "W" : "",
726121156Sume			    (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
72755505Sshin		}
72862590Sitojun		printf(" %-4.4s", flgbuf);
72955505Sshin
73055505Sshin		if (prbs)
73162590Sitojun			printf(" %4d", prbs);
73255505Sshin
73355505Sshin		printf("\n");
73455505Sshin	}
73578064Sume	if (buf != NULL)
73678064Sume		free(buf);
73755505Sshin
73855505Sshin	if (repeat) {
73955505Sshin		printf("\n");
74055505Sshin		sleep(repeat);
74155505Sshin		goto again;
74255505Sshin	}
74355505Sshin}
74455505Sshin
74555505Sshinstatic struct in6_nbrinfo *
74662590Sitojungetnbrinfo(addr, ifindex, warning)
74755505Sshin	struct in6_addr *addr;
74855505Sshin	int ifindex;
74962590Sitojun	int warning;
75055505Sshin{
75155505Sshin	static struct in6_nbrinfo nbi;
75255505Sshin	int s;
75355505Sshin
75455505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
75555505Sshin		err(1, "socket");
75655505Sshin
75755505Sshin	bzero(&nbi, sizeof(nbi));
75855505Sshin	if_indextoname(ifindex, nbi.ifname);
75955505Sshin	nbi.addr = *addr;
76055505Sshin	if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) {
76162590Sitojun		if (warning)
76262590Sitojun			warn("ioctl(SIOCGNBRINFO_IN6)");
76355505Sshin		close(s);
76455505Sshin		return(NULL);
76555505Sshin	}
76655505Sshin
76755505Sshin	close(s);
76855505Sshin	return(&nbi);
76955505Sshin}
77055505Sshin
77155505Sshinstatic char *
77255505Sshinether_str(sdl)
77355505Sshin	struct sockaddr_dl *sdl;
77455505Sshin{
775121156Sume	static char hbuf[NI_MAXHOST];
77655505Sshin	u_char *cp;
77755505Sshin
77855505Sshin	if (sdl->sdl_alen) {
77955505Sshin		cp = (u_char *)LLADDR(sdl);
780121156Sume		snprintf(hbuf, sizeof(hbuf), "%x:%x:%x:%x:%x:%x",
781121156Sume		    cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
782121156Sume	} else
783121156Sume		snprintf(hbuf, sizeof(hbuf), "(incomplete)");
78455505Sshin
785121156Sume	return(hbuf);
78655505Sshin}
78755505Sshin
78855505Sshinint
78955505Sshinndp_ether_aton(a, n)
79055505Sshin	char *a;
79155505Sshin	u_char *n;
79255505Sshin{
79355505Sshin	int i, o[6];
79455505Sshin
79555505Sshin	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
796121156Sume	    &o[3], &o[4], &o[5]);
79755505Sshin	if (i != 6) {
79855505Sshin		fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a);
79955505Sshin		return (1);
80055505Sshin	}
801121156Sume	for (i = 0; i < 6; i++)
80255505Sshin		n[i] = o[i];
80355505Sshin	return (0);
80455505Sshin}
80555505Sshin
80655505Sshinvoid
80755505Sshinusage()
80855505Sshin{
80955505Sshin	printf("usage: ndp hostname\n");
81078064Sume	printf("       ndp -a[nt]\n");
81178064Sume	printf("       ndp [-nt] -A wait\n");
81255505Sshin	printf("       ndp -c[nt]\n");
81355505Sshin	printf("       ndp -d[nt] hostname\n");
81455505Sshin	printf("       ndp -f[nt] filename\n");
81562590Sitojun	printf("       ndp -i interface [flags...]\n");
81662590Sitojun#ifdef SIOCSDEFIFACE_IN6
81762590Sitojun	printf("       ndp -I [interface|delete]\n");
81862590Sitojun#endif
81955505Sshin	printf("       ndp -p\n");
82055505Sshin	printf("       ndp -r\n");
82162590Sitojun	printf("       ndp -s hostname ether_addr [temp] [proxy]\n");
82255505Sshin	printf("       ndp -H\n");
82355505Sshin	printf("       ndp -P\n");
82455505Sshin	printf("       ndp -R\n");
82555505Sshin	exit(1);
82655505Sshin}
82755505Sshin
82855505Sshinint
82955505Sshinrtmsg(cmd)
83055505Sshin	int cmd;
83155505Sshin{
83255505Sshin	static int seq;
83355505Sshin	int rlen;
83455505Sshin	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
83555505Sshin	register char *cp = m_rtmsg.m_space;
83655505Sshin	register int l;
83755505Sshin
83855505Sshin	errno = 0;
83955505Sshin	if (cmd == RTM_DELETE)
84055505Sshin		goto doit;
84155505Sshin	bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
84255505Sshin	rtm->rtm_flags = flags;
84355505Sshin	rtm->rtm_version = RTM_VERSION;
84455505Sshin
84555505Sshin	switch (cmd) {
84655505Sshin	default:
84755505Sshin		fprintf(stderr, "ndp: internal wrong cmd\n");
84855505Sshin		exit(1);
84955505Sshin	case RTM_ADD:
85055505Sshin		rtm->rtm_addrs |= RTA_GATEWAY;
85155505Sshin		rtm->rtm_rmx.rmx_expire = expire_time;
85255505Sshin		rtm->rtm_inits = RTV_EXPIRE;
85355505Sshin		rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
85462590Sitojun		if (rtm->rtm_flags & RTF_ANNOUNCE) {
85562590Sitojun			rtm->rtm_flags &= ~RTF_HOST;
85662590Sitojun			rtm->rtm_flags |= RTA_NETMASK;
85762590Sitojun		}
85855505Sshin		/* FALLTHROUGH */
85955505Sshin	case RTM_GET:
86055505Sshin		rtm->rtm_addrs |= RTA_DST;
86155505Sshin	}
86262590Sitojun#define NEXTADDR(w, s) \
86355505Sshin	if (rtm->rtm_addrs & (w)) { \
86455505Sshin		bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);}
86555505Sshin
86655505Sshin	NEXTADDR(RTA_DST, sin_m);
86755505Sshin	NEXTADDR(RTA_GATEWAY, sdl_m);
86862590Sitojun	memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr));
86955505Sshin	NEXTADDR(RTA_NETMASK, so_mask);
87055505Sshin
87155505Sshin	rtm->rtm_msglen = cp - (char *)&m_rtmsg;
87255505Sshindoit:
87355505Sshin	l = rtm->rtm_msglen;
87455505Sshin	rtm->rtm_seq = ++seq;
87555505Sshin	rtm->rtm_type = cmd;
87655505Sshin	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
87755505Sshin		if (errno != ESRCH || cmd != RTM_DELETE) {
878121156Sume			err(1, "writing to routing socket");
879121156Sume			/* NOTREACHED */
88055505Sshin		}
88155505Sshin	}
88255505Sshin	do {
88355505Sshin		l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
88455505Sshin	} while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
88555505Sshin	if (l < 0)
88655505Sshin		(void) fprintf(stderr, "ndp: read from routing socket: %s\n",
88755505Sshin		    strerror(errno));
88855505Sshin	return (0);
88955505Sshin}
89055505Sshin
89155505Sshinvoid
89262590Sitojunifinfo(argc, argv)
89362590Sitojun	int argc;
89462590Sitojun	char **argv;
89555505Sshin{
89655505Sshin	struct in6_ndireq nd;
89762590Sitojun	int i, s;
89862590Sitojun	char *ifname = argv[0];
89962590Sitojun	u_int32_t newflags;
90078064Sume#ifdef IPV6CTL_USETEMPADDR
90178064Sume	u_int8_t nullbuf[8];
90278064Sume#endif
90355505Sshin
90455505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
905121156Sume		err(1, "socket");
906121156Sume		/* NOTREACHED */
90755505Sshin	}
90855505Sshin	bzero(&nd, sizeof(nd));
909121156Sume	strlcpy(nd.ifname, ifname, sizeof(nd.ifname));
91055505Sshin	if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
911121156Sume		err(1, "ioctl(SIOCGIFINFO_IN6)");
912121156Sume		/* NOTREACHED */
91355505Sshin 	}
91462590Sitojun#define ND nd.ndi
91562590Sitojun	newflags = ND.flags;
91662590Sitojun	for (i = 1; i < argc; i++) {
91762590Sitojun		int clear = 0;
91862590Sitojun		char *cp = argv[i];
91962590Sitojun
92062590Sitojun		if (*cp == '-') {
92162590Sitojun			clear = 1;
92262590Sitojun			cp++;
92362590Sitojun		}
92462590Sitojun
92562590Sitojun#define SETFLAG(s, f) \
92662590Sitojun	do {\
92762590Sitojun		if (strcmp(cp, (s)) == 0) {\
92862590Sitojun			if (clear)\
92962590Sitojun				newflags &= ~(f);\
93062590Sitojun			else\
93162590Sitojun				newflags |= (f);\
93262590Sitojun		}\
93362590Sitojun	} while (0)
93462590Sitojun		SETFLAG("nud", ND6_IFF_PERFORMNUD);
935118498Sume#ifdef ND6_IFF_ACCEPT_RTADV
936118498Sume		SETFLAG("accept_rtadv", ND6_IFF_ACCEPT_RTADV);
937118498Sume#endif
93862590Sitojun
93962590Sitojun		ND.flags = newflags;
94062590Sitojun		if (ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd) < 0) {
941121156Sume			err(1, "ioctl(SIOCSIFINFO_FLAGS)");
942121156Sume			/* NOTREACHED */
94362590Sitojun		}
94462590Sitojun#undef SETFLAG
94562590Sitojun	}
94662590Sitojun
947121162Sume	if (!ND.initialized) {
948121162Sume		errx(1, "%s: not initialized yet", ifname);
949121162Sume		/* NOTREACHED */
950121162Sume	}
951121162Sume
95255505Sshin	printf("linkmtu=%d", ND.linkmtu);
95355505Sshin	printf(", curhlim=%d", ND.chlim);
95455505Sshin	printf(", basereachable=%ds%dms",
955121156Sume	    ND.basereachable / 1000, ND.basereachable % 1000);
95655505Sshin	printf(", reachable=%ds", ND.reachable);
95762590Sitojun	printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000);
95878064Sume#ifdef IPV6CTL_USETEMPADDR
95978064Sume	memset(nullbuf, 0, sizeof(nullbuf));
96078064Sume	if (memcmp(nullbuf, ND.randomid, sizeof(nullbuf)) != 0) {
96178064Sume		int j;
96278064Sume		u_int8_t *rbuf;
96378064Sume
96478064Sume		for (i = 0; i < 3; i++) {
965121156Sume			switch (i) {
96678064Sume			case 0:
96778064Sume				printf("\nRandom seed(0): ");
96878064Sume				rbuf = ND.randomseed0;
96978064Sume				break;
97078064Sume			case 1:
97178064Sume				printf("\nRandom seed(1): ");
97278064Sume				rbuf = ND.randomseed1;
97378064Sume				break;
97478064Sume			case 2:
97578064Sume				printf("\nRandom ID:      ");
97678064Sume				rbuf = ND.randomid;
97778064Sume				break;
97878064Sume			}
97978064Sume			for (j = 0; j < 8; j++)
98078064Sume				printf("%02x", rbuf[j]);
98178064Sume		}
98278064Sume	}
98378064Sume#endif
98462590Sitojun	if (ND.flags) {
98562590Sitojun		printf("\nFlags: ");
986118498Sume		if ((ND.flags & ND6_IFF_PERFORMNUD))
987118498Sume			printf("nud ");
988118498Sume#ifdef ND6_IFF_ACCEPT_RTADV
989118498Sume		if ((ND.flags & ND6_IFF_ACCEPT_RTADV))
990118498Sume			printf("accept_rtadv ");
991118498Sume#endif
992118498Sume}
99362590Sitojun	putc('\n', stdout);
99455505Sshin#undef ND
995121156Sume
99655505Sshin	close(s);
99755505Sshin}
99855505Sshin
99978064Sume#ifndef ND_RA_FLAG_RTPREF_MASK	/* XXX: just for compilation on *BSD release */
100078064Sume#define ND_RA_FLAG_RTPREF_MASK	0x18 /* 00011000 */
100178064Sume#endif
100278064Sume
100355505Sshinvoid
100455505Sshinrtrlist()
100555505Sshin{
100678064Sume#ifdef ICMPV6CTL_ND6_DRLIST
100778064Sume	int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST };
100878064Sume	char *buf;
100978064Sume	struct in6_defrouter *p, *ep;
101078064Sume	size_t l;
101178064Sume	struct timeval time;
101278064Sume
101378064Sume	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
101478064Sume		err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
101578064Sume		/*NOTREACHED*/
101678064Sume	}
101778064Sume	buf = malloc(l);
101878064Sume	if (!buf) {
1019121156Sume		err(1, "malloc");
102078064Sume		/*NOTREACHED*/
102178064Sume	}
102278064Sume	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
102378064Sume		err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
102478064Sume		/*NOTREACHED*/
102578064Sume	}
102678064Sume
102778064Sume	ep = (struct in6_defrouter *)(buf + l);
102878064Sume	for (p = (struct in6_defrouter *)buf; p < ep; p++) {
102978064Sume		int rtpref;
103078064Sume
103178064Sume		if (getnameinfo((struct sockaddr *)&p->rtaddr,
103278064Sume		    p->rtaddr.sin6_len, host_buf, sizeof(host_buf), NULL, 0,
1033121156Sume		    (nflag ? NI_NUMERICHOST : 0)) != 0)
103478064Sume			strlcpy(host_buf, "?", sizeof(host_buf));
1035121156Sume
103678064Sume		printf("%s if=%s", host_buf,
1037121156Sume		    if_indextoname(p->if_index, ifix_buf));
103878064Sume		printf(", flags=%s%s",
1039121156Sume		    p->flags & ND_RA_FLAG_MANAGED ? "M" : "",
1040121156Sume		    p->flags & ND_RA_FLAG_OTHER   ? "O" : "");
104178064Sume		rtpref = ((p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff;
104278064Sume		printf(", pref=%s", rtpref_str[rtpref]);
1043121156Sume
104478064Sume		gettimeofday(&time, 0);
104578064Sume		if (p->expire == 0)
104678064Sume			printf(", expire=Never\n");
104778064Sume		else
104878064Sume			printf(", expire=%s\n",
1049121156Sume			    sec2str(p->expire - time.tv_sec));
105078064Sume	}
105178064Sume	free(buf);
105278064Sume#else
105355505Sshin	struct in6_drlist dr;
105455505Sshin	int s, i;
105555505Sshin	struct timeval time;
105655505Sshin
105755505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1058121156Sume		err(1, "socket");
1059121156Sume		/* NOTREACHED */
106055505Sshin	}
106155505Sshin	bzero(&dr, sizeof(dr));
1062121156Sume	strlcpy(dr.ifname, "lo0", sizeof(dr.ifname)); /* dummy */
106355505Sshin	if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) {
1064121156Sume		err(1, "ioctl(SIOCGDRLST_IN6)");
1065121156Sume		/* NOTREACHED */
1066121156Sume	}
106762590Sitojun#define DR dr.defrouter[i]
106878064Sume	for (i = 0 ; DR.if_index && i < DRLSTSIZ ; i++) {
106955505Sshin		struct sockaddr_in6 sin6;
107055505Sshin
107155505Sshin		bzero(&sin6, sizeof(sin6));
107255505Sshin		sin6.sin6_family = AF_INET6;
107355505Sshin		sin6.sin6_len = sizeof(sin6);
107455505Sshin		sin6.sin6_addr = DR.rtaddr;
107555505Sshin		getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf,
1076121156Sume		    sizeof(host_buf), NULL, 0,
1077121156Sume		    (nflag ? NI_NUMERICHOST : 0));
1078121156Sume
107955505Sshin		printf("%s if=%s", host_buf,
1080121156Sume		    if_indextoname(DR.if_index, ifix_buf));
108155505Sshin		printf(", flags=%s%s",
1082121156Sume		    DR.flags & ND_RA_FLAG_MANAGED ? "M" : "",
1083121156Sume		    DR.flags & ND_RA_FLAG_OTHER   ? "O" : "");
108455505Sshin		gettimeofday(&time, 0);
108555505Sshin		if (DR.expire == 0)
108655505Sshin			printf(", expire=Never\n");
108755505Sshin		else
108855505Sshin			printf(", expire=%s\n",
1089121156Sume			    sec2str(DR.expire - time.tv_sec));
109055505Sshin	}
109155505Sshin#undef DR
109255505Sshin	close(s);
109378064Sume#endif
109455505Sshin}
109555505Sshin
109655505Sshinvoid
109755505Sshinplist()
109855505Sshin{
109978064Sume#ifdef ICMPV6CTL_ND6_PRLIST
110078064Sume	int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST };
110178064Sume	char *buf;
110278064Sume	struct in6_prefix *p, *ep, *n;
110378064Sume	struct sockaddr_in6 *advrtr;
110478064Sume	size_t l;
110578064Sume	struct timeval time;
110678064Sume	const int niflags = NI_NUMERICHOST;
110778064Sume	int ninflags = nflag ? NI_NUMERICHOST : 0;
110878064Sume	char namebuf[NI_MAXHOST];
110978064Sume
111078064Sume	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
111178064Sume		err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
111278064Sume		/*NOTREACHED*/
111378064Sume	}
111478064Sume	buf = malloc(l);
111578064Sume	if (!buf) {
1116121156Sume		err(1, "malloc");
111778064Sume		/*NOTREACHED*/
111878064Sume	}
111978064Sume	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
112078064Sume		err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
112178064Sume		/*NOTREACHED*/
112278064Sume	}
112378064Sume
112478064Sume	ep = (struct in6_prefix *)(buf + l);
112578064Sume	for (p = (struct in6_prefix *)buf; p < ep; p = n) {
112678064Sume		advrtr = (struct sockaddr_in6 *)(p + 1);
112778064Sume		n = (struct in6_prefix *)&advrtr[p->advrtrs];
112878064Sume
112978064Sume		if (getnameinfo((struct sockaddr *)&p->prefix,
113078064Sume		    p->prefix.sin6_len, namebuf, sizeof(namebuf),
113178064Sume		    NULL, 0, niflags) != 0)
113278064Sume			strlcpy(namebuf, "?", sizeof(namebuf));
113378064Sume		printf("%s/%d if=%s\n", namebuf, p->prefixlen,
1134121156Sume		    if_indextoname(p->if_index, ifix_buf));
113578064Sume
113678064Sume		gettimeofday(&time, 0);
113778064Sume		/*
113878064Sume		 * meaning of fields, especially flags, is very different
113978064Sume		 * by origin.  notify the difference to the users.
114078064Sume		 */
114178064Sume		printf("flags=%s%s%s%s%s",
1142121156Sume		    p->raflags.onlink ? "L" : "",
1143121156Sume		    p->raflags.autonomous ? "A" : "",
1144121156Sume		    (p->flags & NDPRF_ONLINK) != 0 ? "O" : "",
1145121156Sume		    (p->flags & NDPRF_DETACHED) != 0 ? "D" : "",
114678064Sume#ifdef NDPRF_HOME
1147121156Sume		    (p->flags & NDPRF_HOME) != 0 ? "H" : ""
114878064Sume#else
1149121156Sume		    ""
115078064Sume#endif
1151121156Sume		    );
115278064Sume		if (p->vltime == ND6_INFINITE_LIFETIME)
115378064Sume			printf(" vltime=infinity");
115478064Sume		else
115578064Sume			printf(" vltime=%ld", (long)p->vltime);
115678064Sume		if (p->pltime == ND6_INFINITE_LIFETIME)
115778064Sume			printf(", pltime=infinity");
115878064Sume		else
115978064Sume			printf(", pltime=%ld", (long)p->pltime);
116078064Sume		if (p->expire == 0)
116178064Sume			printf(", expire=Never");
116278064Sume		else if (p->expire >= time.tv_sec)
116378064Sume			printf(", expire=%s",
1164121156Sume			    sec2str(p->expire - time.tv_sec));
116578064Sume		else
116678064Sume			printf(", expired");
116778064Sume		printf(", ref=%d", p->refcnt);
116878064Sume		printf("\n");
116978064Sume		/*
117078064Sume		 * "advertising router" list is meaningful only if the prefix
117178064Sume		 * information is from RA.
117278064Sume		 */
117378064Sume		if (p->advrtrs) {
117478064Sume			int j;
117578064Sume			struct sockaddr_in6 *sin6;
117678064Sume
117778064Sume			sin6 = (struct sockaddr_in6 *)(p + 1);
117878064Sume			printf("  advertised by\n");
117978064Sume			for (j = 0; j < p->advrtrs; j++) {
118078064Sume				struct in6_nbrinfo *nbi;
118178064Sume
118278064Sume				if (getnameinfo((struct sockaddr *)sin6,
118378064Sume				    sin6->sin6_len, namebuf, sizeof(namebuf),
118478064Sume				    NULL, 0, ninflags) != 0)
118578064Sume					strlcpy(namebuf, "?", sizeof(namebuf));
118678064Sume				printf("    %s", namebuf);
118778064Sume
1188121156Sume				nbi = getnbrinfo(&sin6->sin6_addr,
1189121156Sume				    p->if_index, 0);
119078064Sume				if (nbi) {
1191121156Sume					switch (nbi->state) {
119278064Sume					case ND6_LLINFO_REACHABLE:
119378064Sume					case ND6_LLINFO_STALE:
119478064Sume					case ND6_LLINFO_DELAY:
119578064Sume					case ND6_LLINFO_PROBE:
119678064Sume						printf(" (reachable)\n");
119778064Sume						break;
119878064Sume					default:
119978064Sume						printf(" (unreachable)\n");
120078064Sume					}
120178064Sume				} else
120278064Sume					printf(" (no neighbor state)\n");
120378064Sume				sin6++;
120478064Sume			}
120578064Sume		} else
120678064Sume			printf("  No advertising router\n");
120778064Sume	}
120878064Sume	free(buf);
120978064Sume#else
121055505Sshin	struct in6_prlist pr;
121155505Sshin	int s, i;
121255505Sshin	struct timeval time;
121355505Sshin
121455505Sshin	gettimeofday(&time, 0);
121555505Sshin
121655505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1217121156Sume		err(1, "socket");
1218121156Sume		/* NOTREACHED */
121955505Sshin	}
122055505Sshin	bzero(&pr, sizeof(pr));
1221121156Sume	strlcpy(pr.ifname, "lo0", sizeof(pr.ifname)); /* dummy */
122255505Sshin	if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) {
1223121156Sume		err(1, "ioctl(SIOCGPRLST_IN6)");
1224121156Sume		/* NOTREACHED */
1225121156Sume	}
122662590Sitojun#define PR pr.prefix[i]
122755505Sshin	for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) {
122878064Sume		struct sockaddr_in6 p6;
122978064Sume		char namebuf[NI_MAXHOST];
123078064Sume		int niflags;
123178064Sume
123278064Sume#ifdef NDPRF_ONLINK
123378064Sume		p6 = PR.prefix;
123478064Sume#else
123578064Sume		memset(&p6, 0, sizeof(p6));
123678064Sume		p6.sin6_family = AF_INET6;
123778064Sume		p6.sin6_len = sizeof(p6);
123878064Sume		p6.sin6_addr = PR.prefix;
123978064Sume#endif
124078064Sume
124178064Sume		/*
124278064Sume		 * copy link index to sin6_scope_id field.
124378064Sume		 * XXX: KAME specific.
124478064Sume		 */
124578064Sume		if (IN6_IS_ADDR_LINKLOCAL(&p6.sin6_addr)) {
124678064Sume			u_int16_t linkid;
124778064Sume
124878064Sume			memcpy(&linkid, &p6.sin6_addr.s6_addr[2],
1249121156Sume			    sizeof(linkid));
125078064Sume			linkid = ntohs(linkid);
125178064Sume			p6.sin6_scope_id = linkid;
125278064Sume			p6.sin6_addr.s6_addr[2] = 0;
125378064Sume			p6.sin6_addr.s6_addr[3] = 0;
125478064Sume		}
125578064Sume
125678064Sume		niflags = NI_NUMERICHOST;
125778064Sume		if (getnameinfo((struct sockaddr *)&p6,
1258121156Sume		    sizeof(p6), namebuf, sizeof(namebuf),
1259121156Sume		    NULL, 0, niflags)) {
126078064Sume			warnx("getnameinfo failed");
126178064Sume			continue;
126278064Sume		}
126378064Sume		printf("%s/%d if=%s\n", namebuf, PR.prefixlen,
1264121156Sume		    if_indextoname(PR.if_index, ifix_buf));
126578064Sume
126655505Sshin		gettimeofday(&time, 0);
126762590Sitojun		/*
126862590Sitojun		 * meaning of fields, especially flags, is very different
126962590Sitojun		 * by origin.  notify the difference to the users.
127062590Sitojun		 */
127178064Sume#if 0
127278064Sume		printf("  %s",
1273121156Sume		    PR.origin == PR_ORIG_RA ? "" : "advertise: ");
127478064Sume#endif
127578064Sume#ifdef NDPRF_ONLINK
127678064Sume		printf("flags=%s%s%s%s%s",
1277121156Sume		    PR.raflags.onlink ? "L" : "",
1278121156Sume		    PR.raflags.autonomous ? "A" : "",
1279121156Sume		    (PR.flags & NDPRF_ONLINK) != 0 ? "O" : "",
1280121156Sume		    (PR.flags & NDPRF_DETACHED) != 0 ? "D" : "",
128178064Sume#ifdef NDPRF_HOME
1282121156Sume		    (PR.flags & NDPRF_HOME) != 0 ? "H" : ""
128378064Sume#else
1284121156Sume		    ""
128578064Sume#endif
1286121156Sume		    );
128778064Sume#else
128862590Sitojun		printf("flags=%s%s",
1289121156Sume		    PR.raflags.onlink ? "L" : "",
1290121156Sume		    PR.raflags.autonomous ? "A" : "");
129178064Sume#endif
129255505Sshin		if (PR.vltime == ND6_INFINITE_LIFETIME)
129355505Sshin			printf(" vltime=infinity");
129455505Sshin		else
129555505Sshin			printf(" vltime=%ld", (long)PR.vltime);
129655505Sshin		if (PR.pltime == ND6_INFINITE_LIFETIME)
129755505Sshin			printf(", pltime=infinity");
129855505Sshin		else
129955505Sshin			printf(", pltime=%ld", (long)PR.pltime);
130055505Sshin		if (PR.expire == 0)
130162590Sitojun			printf(", expire=Never");
130255505Sshin		else if (PR.expire >= time.tv_sec)
130362590Sitojun			printf(", expire=%s",
1304121156Sume			    sec2str(PR.expire - time.tv_sec));
130555505Sshin		else
130662590Sitojun			printf(", expired");
130778064Sume#ifdef NDPRF_ONLINK
130878064Sume		printf(", ref=%d", PR.refcnt);
130978064Sume#endif
131078064Sume#if 0
131162590Sitojun		switch (PR.origin) {
131262590Sitojun		case PR_ORIG_RA:
131362590Sitojun			printf(", origin=RA");
131462590Sitojun			break;
131562590Sitojun		case PR_ORIG_RR:
131662590Sitojun			printf(", origin=RR");
131762590Sitojun			break;
131862590Sitojun		case PR_ORIG_STATIC:
131962590Sitojun			printf(", origin=static");
132062590Sitojun			break;
132162590Sitojun		case PR_ORIG_KERNEL:
132262590Sitojun			printf(", origin=kernel");
132362590Sitojun			break;
132462590Sitojun		default:
132562590Sitojun			printf(", origin=?");
132662590Sitojun			break;
132762590Sitojun		}
132878064Sume#endif
132962590Sitojun		printf("\n");
133062590Sitojun		/*
133162590Sitojun		 * "advertising router" list is meaningful only if the prefix
133262590Sitojun		 * information is from RA.
133362590Sitojun		 */
133478064Sume		if (0 &&	/* prefix origin is almost obsolted */
133578064Sume		    PR.origin != PR_ORIG_RA)
133662590Sitojun			;
133762590Sitojun		else if (PR.advrtrs) {
133855505Sshin			int j;
133955505Sshin			printf("  advertised by\n");
134055505Sshin			for (j = 0; j < PR.advrtrs; j++) {
134155505Sshin				struct sockaddr_in6 sin6;
134262590Sitojun				struct in6_nbrinfo *nbi;
134355505Sshin
134455505Sshin				bzero(&sin6, sizeof(sin6));
134555505Sshin				sin6.sin6_family = AF_INET6;
134655505Sshin				sin6.sin6_len = sizeof(sin6);
134755505Sshin				sin6.sin6_addr = PR.advrtr[j];
134862590Sitojun				sin6.sin6_scope_id = PR.if_index; /* XXX */
134955505Sshin				getnameinfo((struct sockaddr *)&sin6,
1350121156Sume				    sin6.sin6_len, host_buf,
1351121156Sume				    sizeof(host_buf), NULL, 0,
1352121156Sume				    (nflag ? NI_NUMERICHOST : 0));
135362590Sitojun				printf("    %s", host_buf);
135455505Sshin
1355121156Sume				nbi = getnbrinfo(&sin6.sin6_addr,
1356121156Sume				    PR.if_index, 0);
135762590Sitojun				if (nbi) {
1358121156Sume					switch (nbi->state) {
1359121156Sume					case ND6_LLINFO_REACHABLE:
1360121156Sume					case ND6_LLINFO_STALE:
1361121156Sume					case ND6_LLINFO_DELAY:
1362121156Sume					case ND6_LLINFO_PROBE:
136362590Sitojun						 printf(" (reachable)\n");
136462590Sitojun						 break;
1365121156Sume					default:
136662590Sitojun						 printf(" (unreachable)\n");
136762590Sitojun					}
136878064Sume				} else
136962590Sitojun					printf(" (no neighbor state)\n");
137055505Sshin			}
137155505Sshin			if (PR.advrtrs > DRLSTSIZ)
137255505Sshin				printf("    and %d routers\n",
1373121156Sume				    PR.advrtrs - DRLSTSIZ);
137462590Sitojun		} else
137555505Sshin			printf("  No advertising router\n");
137655505Sshin	}
137755505Sshin#undef PR
137855505Sshin	close(s);
137978064Sume#endif
138055505Sshin}
138155505Sshin
138255505Sshinvoid
138355505Sshinpfx_flush()
138455505Sshin{
138555505Sshin	char dummyif[IFNAMSIZ+8];
138655505Sshin	int s;
138755505Sshin
138855505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
138955505Sshin		err(1, "socket");
1390121156Sume	strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
139155505Sshin	if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0)
1392121156Sume		err(1, "ioctl(SIOCSPFXFLUSH_IN6)");
139355505Sshin}
139455505Sshin
139555505Sshinvoid
139655505Sshinrtr_flush()
139755505Sshin{
139855505Sshin	char dummyif[IFNAMSIZ+8];
139955505Sshin	int s;
140055505Sshin
140155505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
140255505Sshin		err(1, "socket");
1403121156Sume	strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
140455505Sshin	if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0)
1405121156Sume		err(1, "ioctl(SIOCSRTRFLUSH_IN6)");
140662590Sitojun
140762590Sitojun	close(s);
140855505Sshin}
140955505Sshin
141055505Sshinvoid
141155505Sshinharmonize_rtr()
141255505Sshin{
141355505Sshin	char dummyif[IFNAMSIZ+8];
141455505Sshin	int s;
141555505Sshin
141662590Sitojun	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
141762590Sitojun		err(1, "socket");
1418121156Sume	strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
141962590Sitojun	if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0)
1420121156Sume		err(1, "ioctl(SIOCSNDFLUSH_IN6)");
142162590Sitojun
142262590Sitojun	close(s);
142355505Sshin}
142455505Sshin
142562590Sitojun#ifdef SIOCSDEFIFACE_IN6	/* XXX: check SIOCGDEFIFACE_IN6 as well? */
142662590Sitojunstatic void
142762590Sitojunsetdefif(ifname)
142862590Sitojun	char *ifname;
142962590Sitojun{
143062590Sitojun	struct in6_ndifreq ndifreq;
143162590Sitojun	unsigned int ifindex;
143262590Sitojun
143362590Sitojun	if (strcasecmp(ifname, "delete") == 0)
143462590Sitojun		ifindex = 0;
143562590Sitojun	else {
143662590Sitojun		if ((ifindex = if_nametoindex(ifname)) == 0)
143762590Sitojun			err(1, "failed to resolve i/f index for %s", ifname);
143862590Sitojun	}
143962590Sitojun
144062590Sitojun	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
144162590Sitojun		err(1, "socket");
144262590Sitojun
1443121156Sume	strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */
144462590Sitojun	ndifreq.ifindex = ifindex;
144562590Sitojun
144662590Sitojun	if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1447121156Sume		err(1, "ioctl(SIOCSDEFIFACE_IN6)");
144862590Sitojun
144962590Sitojun	close(s);
145062590Sitojun}
145162590Sitojun
145262590Sitojunstatic void
145362590Sitojungetdefif()
145462590Sitojun{
145562590Sitojun	struct in6_ndifreq ndifreq;
145662590Sitojun	char ifname[IFNAMSIZ+8];
145762590Sitojun
145862590Sitojun	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
145962590Sitojun		err(1, "socket");
146062590Sitojun
146162590Sitojun	memset(&ndifreq, 0, sizeof(ndifreq));
1462121156Sume	strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */
146362590Sitojun
146462590Sitojun	if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1465121156Sume		err(1, "ioctl(SIOCGDEFIFACE_IN6)");
146662590Sitojun
146762590Sitojun	if (ndifreq.ifindex == 0)
146862590Sitojun		printf("No default interface.\n");
146962590Sitojun	else {
147062590Sitojun		if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL)
147162590Sitojun			err(1, "failed to resolve ifname for index %lu",
147262590Sitojun			    ndifreq.ifindex);
147362590Sitojun		printf("ND default interface = %s\n", ifname);
147462590Sitojun	}
147562590Sitojun
147662590Sitojun	close(s);
147762590Sitojun}
147862590Sitojun#endif
147962590Sitojun
148055505Sshinstatic char *
148155505Sshinsec2str(total)
148255505Sshin	time_t total;
148355505Sshin{
148455505Sshin	static char result[256];
148555505Sshin	int days, hours, mins, secs;
148655505Sshin	int first = 1;
148755505Sshin	char *p = result;
1488121156Sume	char *ep = &result[sizeof(result)];
1489121156Sume	int n;
149055505Sshin
149155505Sshin	days = total / 3600 / 24;
149255505Sshin	hours = (total / 3600) % 24;
149355505Sshin	mins = (total / 60) % 60;
149455505Sshin	secs = total % 60;
149555505Sshin
149655505Sshin	if (days) {
149755505Sshin		first = 0;
1498121156Sume		n = snprintf(p, ep - p, "%dd", days);
1499121156Sume		if (n < 0 || n >= ep - p)
1500121156Sume			return "?";
1501121156Sume		p += n;
150255505Sshin	}
150355505Sshin	if (!first || hours) {
150455505Sshin		first = 0;
1505121156Sume		n = snprintf(p, ep - p, "%dh", hours);
1506121156Sume		if (n < 0 || n >= ep - p)
1507121156Sume			return "?";
1508121156Sume		p += n;
150955505Sshin	}
151055505Sshin	if (!first || mins) {
151155505Sshin		first = 0;
1512121156Sume		n = snprintf(p, ep - p, "%dm", mins);
1513121156Sume		if (n < 0 || n >= ep - p)
1514121156Sume			return "?";
1515121156Sume		p += n;
151655505Sshin	}
1517121156Sume	snprintf(p, ep - p, "%ds", secs);
151855505Sshin
151955505Sshin	return(result);
152055505Sshin}
152155505Sshin
152255505Sshin/*
152355505Sshin * Print the timestamp
152455505Sshin * from tcpdump/util.c
152555505Sshin */
152655505Sshinstatic void
152755505Sshints_print(tvp)
152855505Sshin	const struct timeval *tvp;
152955505Sshin{
153055505Sshin	int s;
153155505Sshin
153255505Sshin	/* Default */
153355505Sshin	s = (tvp->tv_sec + thiszone) % 86400;
153455505Sshin	(void)printf("%02d:%02d:%02d.%06u ",
153555505Sshin	    s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec);
153655505Sshin}
1537