ndp.c revision 259169
162590Sitojun/*	$FreeBSD: head/usr.sbin/ndp/ndp.c 259169 2013-12-10 13:14:54Z ae $	*/
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 * 4. Neither the name of the University nor the names of its contributors
4855505Sshin *    may be used to endorse or promote products derived from this software
4955505Sshin *    without specific prior written permission.
5055505Sshin *
5155505Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5255505Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5355505Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5455505Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5555505Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5655505Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5755505Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5855505Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5955505Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6055505Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6155505Sshin * SUCH DAMAGE.
6255505Sshin */
6355505Sshin
6455505Sshin/*
6555505Sshin * Based on:
6655505Sshin * "@(#) Copyright (c) 1984, 1993\n\
6755505Sshin *	The Regents of the University of California.  All rights reserved.\n";
6855505Sshin *
6955505Sshin * "@(#)arp.c	8.2 (Berkeley) 1/2/94";
7055505Sshin */
7155505Sshin
7255505Sshin/*
7355505Sshin * ndp - display, set, delete and flush neighbor cache
7455505Sshin */
7555505Sshin
7655505Sshin
7755505Sshin#include <sys/param.h>
7855505Sshin#include <sys/file.h>
7955505Sshin#include <sys/ioctl.h>
8055505Sshin#include <sys/socket.h>
8155505Sshin#include <sys/sysctl.h>
82253999Shrs#include <sys/time.h>
8378064Sume#include <sys/queue.h>
8455505Sshin
8555505Sshin#include <net/if.h>
8655505Sshin#include <net/if_var.h>
8755505Sshin#include <net/if_dl.h>
8855505Sshin#include <net/if_types.h>
8955505Sshin#include <net/route.h>
9055505Sshin
9155505Sshin#include <netinet/in.h>
9255505Sshin#include <netinet/if_ether.h>
9355505Sshin
9455505Sshin#include <netinet/icmp6.h>
9555505Sshin#include <netinet6/in6_var.h>
9655505Sshin#include <netinet6/nd6.h>
9755505Sshin
9855505Sshin#include <arpa/inet.h>
9955505Sshin
10055505Sshin#include <netdb.h>
10155505Sshin#include <errno.h>
10255505Sshin#include <nlist.h>
10355505Sshin#include <stdio.h>
10455505Sshin#include <string.h>
10555505Sshin#include <paths.h>
10655505Sshin#include <err.h>
10755505Sshin#include <stdlib.h>
10855505Sshin#include <fcntl.h>
10955505Sshin#include <unistd.h>
11055505Sshin#include "gmt2local.h"
11155505Sshin
11255505Sshin/* packing rule for routing socket */
11362590Sitojun#define ROUNDUP(a) \
11455505Sshin	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
11562590Sitojun#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
11655505Sshin
117186119Sqingli#define NEXTADDR(w, s) \
118186119Sqingli	if (rtm->rtm_addrs & (w)) { \
119196866Sbz		bcopy((char *)&s, cp, sizeof(s)); cp += SA_SIZE(&s);}
120186119Sqingli
121186119Sqingli
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
133173412Skevloint main(int, char **);
134173412Skevloint file(char *);
135173412Skevlovoid getsocket(void);
136173412Skevloint set(int, char **);
137173412Skevlovoid get(char *);
138173412Skevloint delete(char *);
139173412Skevlovoid dump(struct in6_addr *, int);
140173412Skevlostatic struct in6_nbrinfo *getnbrinfo(struct in6_addr *, int, int);
141173412Skevlostatic char *ether_str(struct sockaddr_dl *);
142173412Skevloint ndp_ether_aton(char *, u_char *);
143173412Skevlovoid usage(void);
144173412Skevloint rtmsg(int);
145173412Skevlovoid ifinfo(char *, int, char **);
146173412Skevlovoid rtrlist(void);
147173412Skevlovoid plist(void);
148173412Skevlovoid pfx_flush(void);
149173412Skevlovoid rtr_flush(void);
150173412Skevlovoid harmonize_rtr(void);
15162590Sitojun#ifdef SIOCSDEFIFACE_IN6	/* XXX: check SIOCGDEFIFACE_IN6 as well? */
152173412Skevlostatic void getdefif(void);
153173412Skevlostatic void setdefif(char *);
15462590Sitojun#endif
155173412Skevlostatic char *sec2str(time_t);
156253999Shrsstatic void ts_print(const struct timeval *);
15755505Sshin
158122615Sume#ifdef ICMPV6CTL_ND6_DRLIST
15978064Sumestatic char *rtpref_str[] = {
16078064Sume	"medium",		/* 00 */
16178064Sume	"high",			/* 01 */
16278064Sume	"rsv",			/* 10 */
16378064Sume	"low"			/* 11 */
16478064Sume};
165122615Sume#endif
16678064Sume
167122615Sumeint mode = 0;
168122615Sumechar *arg = NULL;
169122615Sume
17055505Sshinint
171259169Saemain(int argc, char **argv)
17255505Sshin{
17355505Sshin	int ch;
17455505Sshin
17555505Sshin	pid = getpid();
17655505Sshin	thiszone = gmt2local(0);
177122615Sume	while ((ch = getopt(argc, argv, "acd:f:Ii:nprstA:HPR")) != -1)
178121156Sume		switch (ch) {
17955505Sshin		case 'a':
18055505Sshin		case 'c':
181122615Sume		case 'p':
182122615Sume		case 'r':
183122615Sume		case 'H':
184122615Sume		case 'P':
185122615Sume		case 'R':
186122615Sume		case 's':
187122615Sume		case 'I':
188122615Sume			if (mode) {
189122615Sume				usage();
190122615Sume				/*NOTREACHED*/
191122615Sume			}
192122615Sume			mode = ch;
193122615Sume			arg = NULL;
19455505Sshin			break;
19555505Sshin		case 'd':
196122615Sume		case 'f':
19755505Sshin		case 'i' :
198122615Sume			if (mode) {
19955505Sshin				usage();
200122615Sume				/*NOTREACHED*/
201122615Sume			}
202122615Sume			mode = ch;
203122615Sume			arg = optarg;
204122615Sume			break;
20555505Sshin		case 'n':
20655505Sshin			nflag = 1;
20755505Sshin			break;
20855505Sshin		case 't':
20955505Sshin			tflag = 1;
21055505Sshin			break;
21155505Sshin		case 'A':
212122615Sume			if (mode) {
213122615Sume				usage();
214122615Sume				/*NOTREACHED*/
215122615Sume			}
216122615Sume			mode = 'a';
21755505Sshin			repeat = atoi(optarg);
218122615Sume			if (repeat < 0) {
21955505Sshin				usage();
220122615Sume				/*NOTREACHED*/
221122615Sume			}
22255505Sshin			break;
22355505Sshin		default:
22455505Sshin			usage();
22555505Sshin		}
22655505Sshin
22755505Sshin	argc -= optind;
22855505Sshin	argv += optind;
22955505Sshin
230122615Sume	switch (mode) {
231122615Sume	case 'a':
232122615Sume	case 'c':
233122615Sume		if (argc != 0) {
23455505Sshin			usage();
235122615Sume			/*NOTREACHED*/
236122615Sume		}
237122615Sume		dump(0, mode == 'c');
238122615Sume		break;
239122615Sume	case 'd':
240122615Sume		if (argc != 0) {
241122615Sume			usage();
242122615Sume			/*NOTREACHED*/
243122615Sume		}
244122615Sume		delete(arg);
245122615Sume		break;
246122615Sume	case 'I':
247122615Sume#ifdef SIOCSDEFIFACE_IN6	/* XXX: check SIOCGDEFIFACE_IN6 as well? */
248122615Sume		if (argc > 1) {
249122615Sume			usage();
250122615Sume			/*NOTREACHED*/
251122615Sume		} else if (argc == 1) {
252122615Sume			if (strcmp(*argv, "delete") == 0 ||
253122615Sume			    if_nametoindex(*argv))
254122615Sume				setdefif(*argv);
255122615Sume			else
256122615Sume				errx(1, "invalid interface %s", *argv);
257122615Sume		}
258122615Sume		getdefif(); /* always call it to print the result */
259122615Sume		break;
260122615Sume#else
261122615Sume		errx(1, "not supported yet");
262122615Sume		/*NOTREACHED*/
263122615Sume#endif
264122615Sume	case 'p':
265122615Sume		if (argc != 0) {
266122615Sume			usage();
267122615Sume			/*NOTREACHED*/
268122615Sume		}
26955505Sshin		plist();
270122615Sume		break;
271122615Sume	case 'i':
272122615Sume		ifinfo(arg, argc, argv);
273122615Sume		break;
274122615Sume	case 'r':
275122615Sume		if (argc != 0) {
276122615Sume			usage();
277122615Sume			/*NOTREACHED*/
278122615Sume		}
27955505Sshin		rtrlist();
280122615Sume		break;
281122615Sume	case 's':
28255505Sshin		if (argc < 2 || argc > 4)
28355505Sshin			usage();
28455505Sshin		exit(set(argc, argv) ? 1 : 0);
285122615Sume	case 'H':
286122615Sume		if (argc != 0) {
287122615Sume			usage();
288122615Sume			/*NOTREACHED*/
289122615Sume		}
29055505Sshin		harmonize_rtr();
291122615Sume		break;
292122615Sume	case 'P':
293122615Sume		if (argc != 0) {
294122615Sume			usage();
295122615Sume			/*NOTREACHED*/
296122615Sume		}
29755505Sshin		pfx_flush();
298122615Sume		break;
299122615Sume	case 'R':
300122615Sume		if (argc != 0) {
301122615Sume			usage();
302122615Sume			/*NOTREACHED*/
303122615Sume		}
30455505Sshin		rtr_flush();
305122615Sume		break;
306122615Sume	case 0:
307122615Sume		if (argc != 1) {
308122615Sume			usage();
309122615Sume			/*NOTREACHED*/
310122615Sume		}
311122615Sume		get(argv[0]);
312122615Sume		break;
31355505Sshin	}
31455505Sshin	exit(0);
31555505Sshin}
31655505Sshin
31755505Sshin/*
31855505Sshin * Process a file to set standard ndp entries
31955505Sshin */
32055505Sshinint
321259169Saefile(char *name)
32255505Sshin{
32355505Sshin	FILE *fp;
32455505Sshin	int i, retval;
32555505Sshin	char line[100], arg[5][50], *args[5];
32655505Sshin
32755505Sshin	if ((fp = fopen(name, "r")) == NULL) {
32855505Sshin		fprintf(stderr, "ndp: cannot open %s\n", name);
32955505Sshin		exit(1);
33055505Sshin	}
33155505Sshin	args[0] = &arg[0][0];
33255505Sshin	args[1] = &arg[1][0];
33355505Sshin	args[2] = &arg[2][0];
33455505Sshin	args[3] = &arg[3][0];
33555505Sshin	args[4] = &arg[4][0];
33655505Sshin	retval = 0;
337167260Skevlo	while (fgets(line, sizeof(line), fp) != NULL) {
338122615Sume		i = sscanf(line, "%49s %49s %49s %49s %49s",
339122615Sume		    arg[0], arg[1], arg[2], arg[3], arg[4]);
34055505Sshin		if (i < 2) {
34155505Sshin			fprintf(stderr, "ndp: bad line: %s\n", line);
34255505Sshin			retval = 1;
34355505Sshin			continue;
34455505Sshin		}
34555505Sshin		if (set(i, args))
34655505Sshin			retval = 1;
34755505Sshin	}
34855505Sshin	fclose(fp);
34955505Sshin	return (retval);
35055505Sshin}
35155505Sshin
35255505Sshinvoid
35355505Sshingetsocket()
35455505Sshin{
35555505Sshin	if (s < 0) {
35655505Sshin		s = socket(PF_ROUTE, SOCK_RAW, 0);
35755505Sshin		if (s < 0) {
358121156Sume			err(1, "socket");
359121156Sume			/* NOTREACHED */
36055505Sshin		}
36155505Sshin	}
36255505Sshin}
36355505Sshin
36462590Sitojunstruct	sockaddr_in6 so_mask = {sizeof(so_mask), AF_INET6 };
36555505Sshinstruct	sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET6 }, sin_m;
36655505Sshinstruct	sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m;
367253999Shrstime_t	expire_time;
368253999Shrsint	flags, found_entry;
36955505Sshinstruct	{
37055505Sshin	struct	rt_msghdr m_rtm;
37155505Sshin	char	m_space[512];
37255505Sshin}	m_rtmsg;
37355505Sshin
37455505Sshin/*
37555505Sshin * Set an individual neighbor cache entry
37655505Sshin */
37755505Sshinint
378259169Saeset(int argc, char **argv)
37955505Sshin{
38055505Sshin	register struct sockaddr_in6 *sin = &sin_m;
38155505Sshin	register struct sockaddr_dl *sdl;
38255505Sshin	register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
38355505Sshin	struct addrinfo hints, *res;
38455505Sshin	int gai_error;
38555505Sshin	u_char *ea;
38655505Sshin	char *host = argv[0], *eaddr = argv[1];
38755505Sshin
38855505Sshin	getsocket();
38955505Sshin	argc -= 2;
39055505Sshin	argv += 2;
39155505Sshin	sdl_m = blank_sdl;
39255505Sshin	sin_m = blank_sin;
39355505Sshin
39455505Sshin	bzero(&hints, sizeof(hints));
39555505Sshin	hints.ai_family = AF_INET6;
39655505Sshin	gai_error = getaddrinfo(host, NULL, &hints, &res);
39755505Sshin	if (gai_error) {
39855505Sshin		fprintf(stderr, "ndp: %s: %s\n", host,
39955505Sshin			gai_strerror(gai_error));
40055505Sshin		return 1;
40155505Sshin	}
40255505Sshin	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
403243903Shrs	sin->sin6_scope_id =
404243903Shrs	    ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
40555505Sshin	ea = (u_char *)LLADDR(&sdl_m);
40655505Sshin	if (ndp_ether_aton(eaddr, ea) == 0)
40755505Sshin		sdl_m.sdl_alen = 6;
40855505Sshin	flags = expire_time = 0;
40955505Sshin	while (argc-- > 0) {
41055505Sshin		if (strncmp(argv[0], "temp", 4) == 0) {
411253999Shrs			struct timeval now;
412121156Sume
413253999Shrs			gettimeofday(&now, 0);
414253970Shrs			expire_time = now.tv_sec + 20 * 60;
41562590Sitojun		} else if (strncmp(argv[0], "proxy", 5) == 0)
41662590Sitojun			flags |= RTF_ANNOUNCE;
41755505Sshin		argv++;
41855505Sshin	}
41955505Sshin	if (rtmsg(RTM_GET) < 0) {
420121156Sume		errx(1, "RTM_GET(%s) failed", host);
421121156Sume		/* NOTREACHED */
42255505Sshin	}
42355505Sshin	sin = (struct sockaddr_in6 *)(rtm + 1);
42455505Sshin	sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
42555505Sshin	if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
42655505Sshin		if (sdl->sdl_family == AF_LINK &&
427122615Sume		    !(rtm->rtm_flags & RTF_GATEWAY)) {
428122615Sume			switch (sdl->sdl_type) {
429122615Sume			case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
430122615Sume			case IFT_ISO88024: case IFT_ISO88025:
431210936Sjhb			case IFT_L2VLAN: case IFT_BRIDGE:
432122615Sume				goto overwrite;
433122615Sume			}
43455505Sshin		}
43562590Sitojun		fprintf(stderr, "set: cannot configure a new entry\n");
43662590Sitojun		return 1;
43755505Sshin	}
43862590Sitojun
43955505Sshinoverwrite:
44055505Sshin	if (sdl->sdl_family != AF_LINK) {
44155505Sshin		printf("cannot intuit interface index and type for %s\n", host);
44255505Sshin		return (1);
44355505Sshin	}
44455505Sshin	sdl_m.sdl_type = sdl->sdl_type;
44555505Sshin	sdl_m.sdl_index = sdl->sdl_index;
44655505Sshin	return (rtmsg(RTM_ADD));
44755505Sshin}
44855505Sshin
44955505Sshin/*
45055505Sshin * Display an individual neighbor cache entry
45155505Sshin */
45255505Sshinvoid
453259169Saeget(char *host)
45455505Sshin{
45555505Sshin	struct sockaddr_in6 *sin = &sin_m;
45655505Sshin	struct addrinfo hints, *res;
45755505Sshin	int gai_error;
45855505Sshin
45955505Sshin	sin_m = blank_sin;
46055505Sshin	bzero(&hints, sizeof(hints));
46155505Sshin	hints.ai_family = AF_INET6;
46255505Sshin	gai_error = getaddrinfo(host, NULL, &hints, &res);
46355505Sshin	if (gai_error) {
46455505Sshin		fprintf(stderr, "ndp: %s: %s\n", host,
465121156Sume		    gai_strerror(gai_error));
46655505Sshin		return;
46755505Sshin	}
46855505Sshin	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
469122615Sume	dump(&sin->sin6_addr, 0);
47055505Sshin	if (found_entry == 0) {
47155505Sshin		getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
472121156Sume		    sizeof(host_buf), NULL ,0,
473121156Sume		    (nflag ? NI_NUMERICHOST : 0));
47455505Sshin		printf("%s (%s) -- no entry\n", host, host_buf);
47555505Sshin		exit(1);
47655505Sshin	}
47755505Sshin}
47855505Sshin
47955505Sshin/*
48055505Sshin * Delete a neighbor cache entry
48155505Sshin */
48255505Sshinint
483259169Saedelete(char *host)
48455505Sshin{
48555505Sshin	struct sockaddr_in6 *sin = &sin_m;
48655505Sshin	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
487186119Sqingli	register char *cp = m_rtmsg.m_space;
48855505Sshin	struct sockaddr_dl *sdl;
48955505Sshin	struct addrinfo hints, *res;
49055505Sshin	int gai_error;
49155505Sshin
49255505Sshin	getsocket();
49355505Sshin	sin_m = blank_sin;
49455505Sshin
49555505Sshin	bzero(&hints, sizeof(hints));
49655505Sshin	hints.ai_family = AF_INET6;
49755505Sshin	gai_error = getaddrinfo(host, NULL, &hints, &res);
49855505Sshin	if (gai_error) {
49955505Sshin		fprintf(stderr, "ndp: %s: %s\n", host,
500121156Sume		    gai_strerror(gai_error));
50155505Sshin		return 1;
50255505Sshin	}
50355505Sshin	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
504243903Shrs	sin->sin6_scope_id =
505243903Shrs	    ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
50655505Sshin	if (rtmsg(RTM_GET) < 0) {
507121156Sume		errx(1, "RTM_GET(%s) failed", host);
508121156Sume		/* NOTREACHED */
50955505Sshin	}
51055505Sshin	sin = (struct sockaddr_in6 *)(rtm + 1);
51155505Sshin	sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
51255505Sshin	if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
51355505Sshin		if (sdl->sdl_family == AF_LINK &&
51462590Sitojun		    !(rtm->rtm_flags & RTF_GATEWAY)) {
51578064Sume			goto delete;
51655505Sshin		}
51762590Sitojun		fprintf(stderr, "delete: cannot delete non-NDP entry\n");
51862590Sitojun		return 1;
51955505Sshin	}
52062590Sitojun
52155505Sshindelete:
52255505Sshin	if (sdl->sdl_family != AF_LINK) {
52355505Sshin		printf("cannot locate %s\n", host);
52455505Sshin		return (1);
52555505Sshin	}
526186119Sqingli        /*
527186119Sqingli         * need to reinit the field because it has rt_key
528186119Sqingli         * but we want the actual address
529186119Sqingli         */
530186119Sqingli	NEXTADDR(RTA_DST, sin_m);
531186500Sqingli	rtm->rtm_flags |= RTF_LLDATA;
53255505Sshin	if (rtmsg(RTM_DELETE) == 0) {
533243903Shrs		getnameinfo((struct sockaddr *)sin,
534243903Shrs		    sin->sin6_len, host_buf,
535121156Sume		    sizeof(host_buf), NULL, 0,
536121156Sume		    (nflag ? NI_NUMERICHOST : 0));
53755505Sshin		printf("%s (%s) deleted\n", host, host_buf);
53855505Sshin	}
53955505Sshin
54055505Sshin	return 0;
54155505Sshin}
54255505Sshin
543122615Sume#define W_ADDR	36
54478064Sume#define W_LL	17
54578064Sume#define W_IF	6
54678064Sume
54755505Sshin/*
54855505Sshin * Dump the entire neighbor cache
54955505Sshin */
55055505Sshinvoid
551259169Saedump(struct in6_addr *addr, int cflag)
55255505Sshin{
55355505Sshin	int mib[6];
55455505Sshin	size_t needed;
55562590Sitojun	char *lim, *buf, *next;
55655505Sshin	struct rt_msghdr *rtm;
55755505Sshin	struct sockaddr_in6 *sin;
55855505Sshin	struct sockaddr_dl *sdl;
55955505Sshin	extern int h_errno;
56055505Sshin	struct in6_nbrinfo *nbi;
561253999Shrs	struct timeval now;
56255505Sshin	int addrwidth;
56378064Sume	int llwidth;
56478064Sume	int ifwidth;
56562590Sitojun	char flgbuf[8];
56678064Sume	char *ifname;
56755505Sshin
56855505Sshin	/* Print header */
56966865Ssumikawa	if (!tflag && !cflag)
570122615Sume		printf("%-*.*s %-*.*s %*.*s %-9.9s %1s %5s\n",
57178064Sume		    W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address",
572122615Sume		    W_IF, W_IF, "Netif", "Expire", "S", "Flags");
57355505Sshin
57455505Sshinagain:;
57555505Sshin	mib[0] = CTL_NET;
57655505Sshin	mib[1] = PF_ROUTE;
57755505Sshin	mib[2] = 0;
57855505Sshin	mib[3] = AF_INET6;
57955505Sshin	mib[4] = NET_RT_FLAGS;
580186119Sqingli#ifdef RTF_LLINFO
58155505Sshin	mib[5] = RTF_LLINFO;
582186119Sqingli#else
583186119Sqingli	mib[5] = 0;
584186119Sqingli#endif
58555505Sshin	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
58655505Sshin		err(1, "sysctl(PF_ROUTE estimate)");
58755505Sshin	if (needed > 0) {
58855505Sshin		if ((buf = malloc(needed)) == NULL)
589121156Sume			err(1, "malloc");
59055505Sshin		if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
59155505Sshin			err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
59255505Sshin		lim = buf + needed;
59355505Sshin	} else
59455505Sshin		buf = lim = NULL;
59555505Sshin
59655505Sshin	for (next = buf; next && next < lim; next += rtm->rtm_msglen) {
59755505Sshin		int isrouter = 0, prbs = 0;
59855505Sshin
59955505Sshin		rtm = (struct rt_msghdr *)next;
60055505Sshin		sin = (struct sockaddr_in6 *)(rtm + 1);
60155505Sshin		sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len));
60278064Sume
60378064Sume		/*
60478064Sume		 * Some OSes can produce a route that has the LINK flag but
60578064Sume		 * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD
60678064Sume		 * and BSD/OS, where xx is not the interface identifier on
60778064Sume		 * lo0).  Such routes entry would annoy getnbrinfo() below,
60878064Sume		 * so we skip them.
60978064Sume		 * XXX: such routes should have the GATEWAY flag, not the
610121156Sume		 * LINK flag.  However, there is rotten routing software
61178064Sume		 * that advertises all routes that have the GATEWAY flag.
61278064Sume		 * Thus, KAME kernel intentionally does not set the LINK flag.
61378064Sume		 * What is to be fixed is not ndp, but such routing software
61478064Sume		 * (and the kernel workaround)...
61578064Sume		 */
61678064Sume		if (sdl->sdl_family != AF_LINK)
61778064Sume			continue;
61878064Sume
619122615Sume		if (!(rtm->rtm_flags & RTF_HOST))
620122615Sume			continue;
621122615Sume
62255505Sshin		if (addr) {
62355505Sshin			if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr))
62455505Sshin				continue;
62555505Sshin			found_entry = 1;
62655505Sshin		} else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
62755505Sshin			continue;
62855505Sshin		if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) ||
62955505Sshin		    IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) {
63055505Sshin			/* XXX: should scope id be filled in the kernel? */
63155505Sshin			if (sin->sin6_scope_id == 0)
63255505Sshin				sin->sin6_scope_id = sdl->sdl_index;
63355505Sshin		}
63455505Sshin		getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
635121156Sume		    sizeof(host_buf), NULL, 0, (nflag ? NI_NUMERICHOST : 0));
636122615Sume		if (cflag) {
63781366Ssumikawa#ifdef RTF_WASCLONED
63881366Ssumikawa			if (rtm->rtm_flags & RTF_WASCLONED)
63981366Ssumikawa				delete(host_buf);
640122615Sume#elif defined(RTF_CLONED)
641122615Sume			if (rtm->rtm_flags & RTF_CLONED)
642122615Sume				delete(host_buf);
64381366Ssumikawa#else
64466865Ssumikawa			delete(host_buf);
64581366Ssumikawa#endif
64666865Ssumikawa			continue;
64766865Ssumikawa		}
648253999Shrs		gettimeofday(&now, 0);
64955505Sshin		if (tflag)
650253970Shrs			ts_print(&now);
65155505Sshin
65278064Sume		addrwidth = strlen(host_buf);
65378064Sume		if (addrwidth < W_ADDR)
65478064Sume			addrwidth = W_ADDR;
65578064Sume		llwidth = strlen(ether_str(sdl));
65678064Sume		if (W_ADDR + W_LL - addrwidth > llwidth)
65778064Sume			llwidth = W_ADDR + W_LL - addrwidth;
65878064Sume		ifname = if_indextoname(sdl->sdl_index, ifix_buf);
65978064Sume		if (!ifname)
66078064Sume			ifname = "?";
66178064Sume		ifwidth = strlen(ifname);
66278064Sume		if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth)
66378064Sume			ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth;
66455505Sshin
66578064Sume		printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf,
66678064Sume		    llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname);
66755505Sshin
66855505Sshin		/* Print neighbor discovery specific informations */
66962590Sitojun		nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1);
67055505Sshin		if (nbi) {
671253970Shrs			if (nbi->expire > now.tv_sec) {
67255505Sshin				printf(" %-9.9s",
673253970Shrs				    sec2str(nbi->expire - now.tv_sec));
67478064Sume			} else if (nbi->expire == 0)
67555505Sshin				printf(" %-9.9s", "permanent");
67655505Sshin			else
67755505Sshin				printf(" %-9.9s", "expired");
67855505Sshin
679121156Sume			switch (nbi->state) {
680121156Sume			case ND6_LLINFO_NOSTATE:
68155505Sshin				 printf(" N");
68255505Sshin				 break;
68378064Sume#ifdef ND6_LLINFO_WAITDELETE
684121156Sume			case ND6_LLINFO_WAITDELETE:
68555505Sshin				 printf(" W");
68655505Sshin				 break;
68778064Sume#endif
688121156Sume			case ND6_LLINFO_INCOMPLETE:
68955505Sshin				 printf(" I");
69055505Sshin				 break;
691121156Sume			case ND6_LLINFO_REACHABLE:
69255505Sshin				 printf(" R");
69355505Sshin				 break;
694121156Sume			case ND6_LLINFO_STALE:
69555505Sshin				 printf(" S");
69655505Sshin				 break;
697121156Sume			case ND6_LLINFO_DELAY:
69855505Sshin				 printf(" D");
69955505Sshin				 break;
700121156Sume			case ND6_LLINFO_PROBE:
70155505Sshin				 printf(" P");
70255505Sshin				 break;
703121156Sume			default:
70455505Sshin				 printf(" ?");
70555505Sshin				 break;
70655505Sshin			}
70755505Sshin
70855505Sshin			isrouter = nbi->isrouter;
70955505Sshin			prbs = nbi->asked;
71078064Sume		} else {
71155505Sshin			warnx("failed to get neighbor information");
71255505Sshin			printf("  ");
71355505Sshin		}
71455505Sshin
71562590Sitojun		/*
71662590Sitojun		 * other flags. R: router, P: proxy, W: ??
71762590Sitojun		 */
71862590Sitojun		if ((rtm->rtm_addrs & RTA_NETMASK) == 0) {
71962590Sitojun			snprintf(flgbuf, sizeof(flgbuf), "%s%s",
720121156Sume			    isrouter ? "R" : "",
721121156Sume			    (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
72262590Sitojun		} else {
72362590Sitojun			sin = (struct sockaddr_in6 *)
724121156Sume			    (sdl->sdl_len + (char *)sdl);
725122615Sume#if 0	/* W and P are mystery even for us */
72662590Sitojun			snprintf(flgbuf, sizeof(flgbuf), "%s%s%s%s",
727121156Sume			    isrouter ? "R" : "",
728121156Sume			    !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr) ? "P" : "",
729121156Sume			    (sin->sin6_len != sizeof(struct sockaddr_in6)) ? "W" : "",
730121156Sume			    (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
731122615Sume#else
732122615Sume			snprintf(flgbuf, sizeof(flgbuf), "%s%s",
733122615Sume			    isrouter ? "R" : "",
734122615Sume			    (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
735122615Sume#endif
73655505Sshin		}
737122615Sume		printf(" %s", flgbuf);
73855505Sshin
73955505Sshin		if (prbs)
740122615Sume			printf(" %d", prbs);
74155505Sshin
74255505Sshin		printf("\n");
74355505Sshin	}
74478064Sume	if (buf != NULL)
74578064Sume		free(buf);
74655505Sshin
74755505Sshin	if (repeat) {
74855505Sshin		printf("\n");
749125675Ssumikawa		fflush(stdout);
75055505Sshin		sleep(repeat);
75155505Sshin		goto again;
75255505Sshin	}
75355505Sshin}
75455505Sshin
75555505Sshinstatic struct in6_nbrinfo *
756259169Saegetnbrinfo(struct in6_addr *addr, int ifindex, int warning)
75755505Sshin{
75855505Sshin	static struct in6_nbrinfo nbi;
75955505Sshin	int s;
76055505Sshin
76155505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
76255505Sshin		err(1, "socket");
76355505Sshin
76455505Sshin	bzero(&nbi, sizeof(nbi));
76555505Sshin	if_indextoname(ifindex, nbi.ifname);
76655505Sshin	nbi.addr = *addr;
76755505Sshin	if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) {
76862590Sitojun		if (warning)
76962590Sitojun			warn("ioctl(SIOCGNBRINFO_IN6)");
77055505Sshin		close(s);
77155505Sshin		return(NULL);
77255505Sshin	}
77355505Sshin
77455505Sshin	close(s);
77555505Sshin	return(&nbi);
77655505Sshin}
77755505Sshin
77855505Sshinstatic char *
779217140Sdelphijether_str(struct sockaddr_dl *sdl)
78055505Sshin{
781121156Sume	static char hbuf[NI_MAXHOST];
782219819Sjeff	char *cp;
78355505Sshin
784219819Sjeff	if (sdl->sdl_alen == ETHER_ADDR_LEN) {
785217140Sdelphij		strlcpy(hbuf, ether_ntoa((struct ether_addr *)LLADDR(sdl)),
786217140Sdelphij		    sizeof(hbuf));
787219819Sjeff	} else if (sdl->sdl_alen) {
788219819Sjeff		int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;
789219819Sjeff		snprintf(hbuf, sizeof(hbuf), "%s", link_ntoa(sdl) + n);
790219819Sjeff	} else
791121156Sume		snprintf(hbuf, sizeof(hbuf), "(incomplete)");
79255505Sshin
793121156Sume	return(hbuf);
79455505Sshin}
79555505Sshin
79655505Sshinint
797259169Saendp_ether_aton(char *a, u_char *n)
79855505Sshin{
79955505Sshin	int i, o[6];
80055505Sshin
80155505Sshin	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
802121156Sume	    &o[3], &o[4], &o[5]);
80355505Sshin	if (i != 6) {
80455505Sshin		fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a);
80555505Sshin		return (1);
80655505Sshin	}
807121156Sume	for (i = 0; i < 6; i++)
80855505Sshin		n[i] = o[i];
80955505Sshin	return (0);
81055505Sshin}
81155505Sshin
81255505Sshinvoid
81355505Sshinusage()
81455505Sshin{
815122615Sume	printf("usage: ndp [-nt] hostname\n");
816122615Sume	printf("       ndp [-nt] -a | -c | -p | -r | -H | -P | -R\n");
81778064Sume	printf("       ndp [-nt] -A wait\n");
818122615Sume	printf("       ndp [-nt] -d hostname\n");
819122615Sume	printf("       ndp [-nt] -f filename\n");
820122615Sume	printf("       ndp [-nt] -i interface [flags...]\n");
82162590Sitojun#ifdef SIOCSDEFIFACE_IN6
822122615Sume	printf("       ndp [-nt] -I [interface|delete]\n");
82362590Sitojun#endif
824122615Sume	printf("       ndp [-nt] -s nodename etheraddr [temp] [proxy]\n");
82555505Sshin	exit(1);
82655505Sshin}
82755505Sshin
82855505Sshinint
829259169Saertmsg(int cmd)
83055505Sshin{
83155505Sshin	static int seq;
83255505Sshin	int rlen;
83355505Sshin	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
83455505Sshin	register char *cp = m_rtmsg.m_space;
83555505Sshin	register int l;
83655505Sshin
83755505Sshin	errno = 0;
83855505Sshin	if (cmd == RTM_DELETE)
83955505Sshin		goto doit;
84055505Sshin	bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
84155505Sshin	rtm->rtm_flags = flags;
84255505Sshin	rtm->rtm_version = RTM_VERSION;
84355505Sshin
84455505Sshin	switch (cmd) {
84555505Sshin	default:
84655505Sshin		fprintf(stderr, "ndp: internal wrong cmd\n");
84755505Sshin		exit(1);
84855505Sshin	case RTM_ADD:
84955505Sshin		rtm->rtm_addrs |= RTA_GATEWAY;
850122615Sume		if (expire_time) {
851122615Sume			rtm->rtm_rmx.rmx_expire = expire_time;
852122615Sume			rtm->rtm_inits = RTV_EXPIRE;
853122615Sume		}
854186500Sqingli		rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA);
855151473Ssuz#if 0 /* we don't support ipv6addr/128 type proxying */
85662590Sitojun		if (rtm->rtm_flags & RTF_ANNOUNCE) {
85762590Sitojun			rtm->rtm_flags &= ~RTF_HOST;
858124241Ssuz			rtm->rtm_addrs |= RTA_NETMASK;
85962590Sitojun		}
860151473Ssuz#endif
86155505Sshin		/* FALLTHROUGH */
86255505Sshin	case RTM_GET:
86355505Sshin		rtm->rtm_addrs |= RTA_DST;
86455505Sshin	}
86555505Sshin
86655505Sshin	NEXTADDR(RTA_DST, sin_m);
86755505Sshin	NEXTADDR(RTA_GATEWAY, sdl_m);
868151473Ssuz#if 0 /* we don't support ipv6addr/128 type proxying */
86962590Sitojun	memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr));
87055505Sshin	NEXTADDR(RTA_NETMASK, so_mask);
871151473Ssuz#endif
87255505Sshin
87355505Sshin	rtm->rtm_msglen = cp - (char *)&m_rtmsg;
87455505Sshindoit:
87555505Sshin	l = rtm->rtm_msglen;
87655505Sshin	rtm->rtm_seq = ++seq;
87755505Sshin	rtm->rtm_type = cmd;
87855505Sshin	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
87955505Sshin		if (errno != ESRCH || cmd != RTM_DELETE) {
880121156Sume			err(1, "writing to routing socket");
881121156Sume			/* NOTREACHED */
88255505Sshin		}
88355505Sshin	}
88455505Sshin	do {
88555505Sshin		l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
88655505Sshin	} while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
88755505Sshin	if (l < 0)
88855505Sshin		(void) fprintf(stderr, "ndp: read from routing socket: %s\n",
88955505Sshin		    strerror(errno));
89055505Sshin	return (0);
89155505Sshin}
89255505Sshin
89355505Sshinvoid
894259169Saeifinfo(char *ifname, int argc, char **argv)
89555505Sshin{
89655505Sshin	struct in6_ndireq nd;
89762590Sitojun	int i, s;
89862590Sitojun	u_int32_t newflags;
89978064Sume#ifdef IPV6CTL_USETEMPADDR
90078064Sume	u_int8_t nullbuf[8];
90178064Sume#endif
90255505Sshin
90355505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
904121156Sume		err(1, "socket");
905121156Sume		/* NOTREACHED */
90655505Sshin	}
90755505Sshin	bzero(&nd, sizeof(nd));
908121156Sume	strlcpy(nd.ifname, ifname, sizeof(nd.ifname));
90955505Sshin	if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
910121156Sume		err(1, "ioctl(SIOCGIFINFO_IN6)");
911121156Sume		/* NOTREACHED */
912122615Sume	}
91362590Sitojun#define ND nd.ndi
91462590Sitojun	newflags = ND.flags;
915122615Sume	for (i = 0; i < argc; i++) {
91662590Sitojun		int clear = 0;
91762590Sitojun		char *cp = argv[i];
91862590Sitojun
91962590Sitojun		if (*cp == '-') {
92062590Sitojun			clear = 1;
92162590Sitojun			cp++;
92262590Sitojun		}
92362590Sitojun
92462590Sitojun#define SETFLAG(s, f) \
92562590Sitojun	do {\
92662590Sitojun		if (strcmp(cp, (s)) == 0) {\
92762590Sitojun			if (clear)\
92862590Sitojun				newflags &= ~(f);\
92962590Sitojun			else\
93062590Sitojun				newflags |= (f);\
93162590Sitojun		}\
93262590Sitojun	} while (0)
933151468Ssuz/*
934151468Ssuz * XXX: this macro is not 100% correct, in that it matches "nud" against
935151468Ssuz *      "nudbogus".  But we just let it go since this is minor.
936151468Ssuz */
937151468Ssuz#define SETVALUE(f, v) \
938151468Ssuz	do { \
939151468Ssuz		char *valptr; \
940151468Ssuz		unsigned long newval; \
941151468Ssuz		v = 0; /* unspecified */ \
942151468Ssuz		if (strncmp(cp, f, strlen(f)) == 0) { \
943151468Ssuz			valptr = strchr(cp, '='); \
944151468Ssuz			if (valptr == NULL) \
945151468Ssuz				err(1, "syntax error in %s field", (f)); \
946151468Ssuz			errno = 0; \
947151468Ssuz			newval = strtoul(++valptr, NULL, 0); \
948151468Ssuz			if (errno) \
949151468Ssuz				err(1, "syntax error in %s's value", (f)); \
950151468Ssuz			v = newval; \
951151468Ssuz		} \
952151468Ssuz	} while (0)
953151468Ssuz
954151474Ssuz		SETFLAG("disabled", ND6_IFF_IFDISABLED);
95562590Sitojun		SETFLAG("nud", ND6_IFF_PERFORMNUD);
956118498Sume#ifdef ND6_IFF_ACCEPT_RTADV
957118498Sume		SETFLAG("accept_rtadv", ND6_IFF_ACCEPT_RTADV);
958118498Sume#endif
959197138Shrs#ifdef ND6_IFF_AUTO_LINKLOCAL
960197138Shrs		SETFLAG("auto_linklocal", ND6_IFF_AUTO_LINKLOCAL);
961197138Shrs#endif
962245230Sume#ifdef ND6_IFF_NO_PREFER_IFACE
963245230Sume		SETFLAG("no_prefer_iface", ND6_IFF_NO_PREFER_IFACE);
964245230Sume#endif
965151468Ssuz		SETVALUE("basereachable", ND.basereachable);
966151468Ssuz		SETVALUE("retrans", ND.retrans);
967151468Ssuz		SETVALUE("curhlim", ND.chlim);
96862590Sitojun
96962590Sitojun		ND.flags = newflags;
970151468Ssuz		if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd) < 0) {
971151468Ssuz			err(1, "ioctl(SIOCSIFINFO_IN6)");
972121156Sume			/* NOTREACHED */
97362590Sitojun		}
97462590Sitojun#undef SETFLAG
975151468Ssuz#undef SETVALUE
97662590Sitojun	}
97762590Sitojun
978121162Sume	if (!ND.initialized) {
979121162Sume		errx(1, "%s: not initialized yet", ifname);
980121162Sume		/* NOTREACHED */
981121162Sume	}
982121162Sume
983151468Ssuz	if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
984151468Ssuz		err(1, "ioctl(SIOCGIFINFO_IN6)");
985151468Ssuz		/* NOTREACHED */
986151468Ssuz	}
98755505Sshin	printf("linkmtu=%d", ND.linkmtu);
988121471Sume	printf(", maxmtu=%d", ND.maxmtu);
98955505Sshin	printf(", curhlim=%d", ND.chlim);
99055505Sshin	printf(", basereachable=%ds%dms",
991121156Sume	    ND.basereachable / 1000, ND.basereachable % 1000);
99255505Sshin	printf(", reachable=%ds", ND.reachable);
99362590Sitojun	printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000);
99478064Sume#ifdef IPV6CTL_USETEMPADDR
99578064Sume	memset(nullbuf, 0, sizeof(nullbuf));
99678064Sume	if (memcmp(nullbuf, ND.randomid, sizeof(nullbuf)) != 0) {
99778064Sume		int j;
99878064Sume		u_int8_t *rbuf;
99978064Sume
100078064Sume		for (i = 0; i < 3; i++) {
1001121156Sume			switch (i) {
100278064Sume			case 0:
100378064Sume				printf("\nRandom seed(0): ");
100478064Sume				rbuf = ND.randomseed0;
100578064Sume				break;
100678064Sume			case 1:
100778064Sume				printf("\nRandom seed(1): ");
100878064Sume				rbuf = ND.randomseed1;
100978064Sume				break;
101078064Sume			case 2:
101178064Sume				printf("\nRandom ID:      ");
101278064Sume				rbuf = ND.randomid;
101378064Sume				break;
1014151472Ssuz			default:
1015151472Ssuz				errx(1, "impossible case for tempaddr display");
101678064Sume			}
101778064Sume			for (j = 0; j < 8; j++)
101878064Sume				printf("%02x", rbuf[j]);
101978064Sume		}
102078064Sume	}
102178064Sume#endif
102262590Sitojun	if (ND.flags) {
102362590Sitojun		printf("\nFlags: ");
1024151474Ssuz#ifdef ND6_IFF_IFDISABLED
1025151474Ssuz		if ((ND.flags & ND6_IFF_IFDISABLED))
1026151474Ssuz			printf("disabled ");
1027151474Ssuz#endif
1028118498Sume		if ((ND.flags & ND6_IFF_PERFORMNUD))
1029118498Sume			printf("nud ");
1030118498Sume#ifdef ND6_IFF_ACCEPT_RTADV
1031118498Sume		if ((ND.flags & ND6_IFF_ACCEPT_RTADV))
1032118498Sume			printf("accept_rtadv ");
1033118498Sume#endif
1034197138Shrs#ifdef ND6_IFF_AUTO_LINKLOCAL
1035197138Shrs		if ((ND.flags & ND6_IFF_AUTO_LINKLOCAL))
1036197138Shrs			printf("auto_linklocal ");
1037197138Shrs#endif
1038245230Sume#ifdef ND6_IFF_NO_PREFER_IFACE
1039245230Sume		if ((ND.flags & ND6_IFF_NO_PREFER_IFACE))
1040245230Sume			printf("no_prefer_iface ");
1041245230Sume#endif
1042122615Sume	}
104362590Sitojun	putc('\n', stdout);
104455505Sshin#undef ND
1045121156Sume
104655505Sshin	close(s);
104755505Sshin}
104855505Sshin
104978064Sume#ifndef ND_RA_FLAG_RTPREF_MASK	/* XXX: just for compilation on *BSD release */
105078064Sume#define ND_RA_FLAG_RTPREF_MASK	0x18 /* 00011000 */
105178064Sume#endif
105278064Sume
105355505Sshinvoid
105455505Sshinrtrlist()
105555505Sshin{
105678064Sume#ifdef ICMPV6CTL_ND6_DRLIST
105778064Sume	int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST };
105878064Sume	char *buf;
105978064Sume	struct in6_defrouter *p, *ep;
106078064Sume	size_t l;
1061253999Shrs	struct timeval now;
106278064Sume
106378064Sume	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
106478064Sume		err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
106578064Sume		/*NOTREACHED*/
106678064Sume	}
1067151472Ssuz	if (l == 0)
1068151472Ssuz		return;
106978064Sume	buf = malloc(l);
107078064Sume	if (!buf) {
1071121156Sume		err(1, "malloc");
107278064Sume		/*NOTREACHED*/
107378064Sume	}
107478064Sume	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
107578064Sume		err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
107678064Sume		/*NOTREACHED*/
107778064Sume	}
107878064Sume
107978064Sume	ep = (struct in6_defrouter *)(buf + l);
108078064Sume	for (p = (struct in6_defrouter *)buf; p < ep; p++) {
108178064Sume		int rtpref;
108278064Sume
108378064Sume		if (getnameinfo((struct sockaddr *)&p->rtaddr,
108478064Sume		    p->rtaddr.sin6_len, host_buf, sizeof(host_buf), NULL, 0,
1085121156Sume		    (nflag ? NI_NUMERICHOST : 0)) != 0)
108678064Sume			strlcpy(host_buf, "?", sizeof(host_buf));
1087121156Sume
108878064Sume		printf("%s if=%s", host_buf,
1089121156Sume		    if_indextoname(p->if_index, ifix_buf));
109078064Sume		printf(", flags=%s%s",
1091121156Sume		    p->flags & ND_RA_FLAG_MANAGED ? "M" : "",
1092121156Sume		    p->flags & ND_RA_FLAG_OTHER   ? "O" : "");
109378064Sume		rtpref = ((p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff;
109478064Sume		printf(", pref=%s", rtpref_str[rtpref]);
1095121156Sume
1096253999Shrs		gettimeofday(&now, 0);
109778064Sume		if (p->expire == 0)
109878064Sume			printf(", expire=Never\n");
109978064Sume		else
110078064Sume			printf(", expire=%s\n",
1101253970Shrs			    sec2str(p->expire - now.tv_sec));
110278064Sume	}
110378064Sume	free(buf);
110478064Sume#else
110555505Sshin	struct in6_drlist dr;
110655505Sshin	int s, i;
1107253999Shrs	struct timeval now;
110855505Sshin
110955505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1110121156Sume		err(1, "socket");
1111121156Sume		/* NOTREACHED */
111255505Sshin	}
111355505Sshin	bzero(&dr, sizeof(dr));
1114121156Sume	strlcpy(dr.ifname, "lo0", sizeof(dr.ifname)); /* dummy */
111555505Sshin	if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) {
1116121156Sume		err(1, "ioctl(SIOCGDRLST_IN6)");
1117121156Sume		/* NOTREACHED */
1118121156Sume	}
111962590Sitojun#define DR dr.defrouter[i]
112078064Sume	for (i = 0 ; DR.if_index && i < DRLSTSIZ ; i++) {
112155505Sshin		struct sockaddr_in6 sin6;
112255505Sshin
112355505Sshin		bzero(&sin6, sizeof(sin6));
112455505Sshin		sin6.sin6_family = AF_INET6;
112555505Sshin		sin6.sin6_len = sizeof(sin6);
112655505Sshin		sin6.sin6_addr = DR.rtaddr;
112755505Sshin		getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf,
1128121156Sume		    sizeof(host_buf), NULL, 0,
1129121156Sume		    (nflag ? NI_NUMERICHOST : 0));
1130121156Sume
113155505Sshin		printf("%s if=%s", host_buf,
1132121156Sume		    if_indextoname(DR.if_index, ifix_buf));
113355505Sshin		printf(", flags=%s%s",
1134121156Sume		    DR.flags & ND_RA_FLAG_MANAGED ? "M" : "",
1135121156Sume		    DR.flags & ND_RA_FLAG_OTHER   ? "O" : "");
1136253999Shrs		gettimeofday(&now, 0);
113755505Sshin		if (DR.expire == 0)
113855505Sshin			printf(", expire=Never\n");
113955505Sshin		else
114055505Sshin			printf(", expire=%s\n",
1141253970Shrs			    sec2str(DR.expire - now.tv_sec));
114255505Sshin	}
114355505Sshin#undef DR
114455505Sshin	close(s);
114578064Sume#endif
114655505Sshin}
114755505Sshin
114855505Sshinvoid
114955505Sshinplist()
115055505Sshin{
115178064Sume#ifdef ICMPV6CTL_ND6_PRLIST
115278064Sume	int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST };
115378064Sume	char *buf;
115478064Sume	struct in6_prefix *p, *ep, *n;
115578064Sume	struct sockaddr_in6 *advrtr;
115678064Sume	size_t l;
1157253999Shrs	struct timeval now;
115878064Sume	const int niflags = NI_NUMERICHOST;
115978064Sume	int ninflags = nflag ? NI_NUMERICHOST : 0;
116078064Sume	char namebuf[NI_MAXHOST];
116178064Sume
116278064Sume	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
116378064Sume		err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
116478064Sume		/*NOTREACHED*/
116578064Sume	}
116678064Sume	buf = malloc(l);
116778064Sume	if (!buf) {
1168121156Sume		err(1, "malloc");
116978064Sume		/*NOTREACHED*/
117078064Sume	}
117178064Sume	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
117278064Sume		err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
117378064Sume		/*NOTREACHED*/
117478064Sume	}
117578064Sume
117678064Sume	ep = (struct in6_prefix *)(buf + l);
117778064Sume	for (p = (struct in6_prefix *)buf; p < ep; p = n) {
117878064Sume		advrtr = (struct sockaddr_in6 *)(p + 1);
117978064Sume		n = (struct in6_prefix *)&advrtr[p->advrtrs];
118078064Sume
118178064Sume		if (getnameinfo((struct sockaddr *)&p->prefix,
118278064Sume		    p->prefix.sin6_len, namebuf, sizeof(namebuf),
118378064Sume		    NULL, 0, niflags) != 0)
118478064Sume			strlcpy(namebuf, "?", sizeof(namebuf));
118578064Sume		printf("%s/%d if=%s\n", namebuf, p->prefixlen,
1186121156Sume		    if_indextoname(p->if_index, ifix_buf));
118778064Sume
1188253999Shrs		gettimeofday(&now, 0);
118978064Sume		/*
119078064Sume		 * meaning of fields, especially flags, is very different
119178064Sume		 * by origin.  notify the difference to the users.
119278064Sume		 */
119378064Sume		printf("flags=%s%s%s%s%s",
1194121156Sume		    p->raflags.onlink ? "L" : "",
1195121156Sume		    p->raflags.autonomous ? "A" : "",
1196121156Sume		    (p->flags & NDPRF_ONLINK) != 0 ? "O" : "",
1197121156Sume		    (p->flags & NDPRF_DETACHED) != 0 ? "D" : "",
119878064Sume#ifdef NDPRF_HOME
1199121156Sume		    (p->flags & NDPRF_HOME) != 0 ? "H" : ""
120078064Sume#else
1201121156Sume		    ""
120278064Sume#endif
1203121156Sume		    );
120478064Sume		if (p->vltime == ND6_INFINITE_LIFETIME)
120578064Sume			printf(" vltime=infinity");
120678064Sume		else
1207122615Sume			printf(" vltime=%lu", (unsigned long)p->vltime);
120878064Sume		if (p->pltime == ND6_INFINITE_LIFETIME)
120978064Sume			printf(", pltime=infinity");
121078064Sume		else
1211122615Sume			printf(", pltime=%lu", (unsigned long)p->pltime);
121278064Sume		if (p->expire == 0)
121378064Sume			printf(", expire=Never");
1214253970Shrs		else if (p->expire >= now.tv_sec)
121578064Sume			printf(", expire=%s",
1216253970Shrs			    sec2str(p->expire - now.tv_sec));
121778064Sume		else
121878064Sume			printf(", expired");
121978064Sume		printf(", ref=%d", p->refcnt);
122078064Sume		printf("\n");
122178064Sume		/*
122278064Sume		 * "advertising router" list is meaningful only if the prefix
122378064Sume		 * information is from RA.
122478064Sume		 */
122578064Sume		if (p->advrtrs) {
122678064Sume			int j;
122778064Sume			struct sockaddr_in6 *sin6;
122878064Sume
1229122615Sume			sin6 = advrtr;
123078064Sume			printf("  advertised by\n");
123178064Sume			for (j = 0; j < p->advrtrs; j++) {
123278064Sume				struct in6_nbrinfo *nbi;
123378064Sume
123478064Sume				if (getnameinfo((struct sockaddr *)sin6,
123578064Sume				    sin6->sin6_len, namebuf, sizeof(namebuf),
123678064Sume				    NULL, 0, ninflags) != 0)
123778064Sume					strlcpy(namebuf, "?", sizeof(namebuf));
123878064Sume				printf("    %s", namebuf);
123978064Sume
1240121156Sume				nbi = getnbrinfo(&sin6->sin6_addr,
1241121156Sume				    p->if_index, 0);
124278064Sume				if (nbi) {
1243121156Sume					switch (nbi->state) {
124478064Sume					case ND6_LLINFO_REACHABLE:
124578064Sume					case ND6_LLINFO_STALE:
124678064Sume					case ND6_LLINFO_DELAY:
124778064Sume					case ND6_LLINFO_PROBE:
124878064Sume						printf(" (reachable)\n");
124978064Sume						break;
125078064Sume					default:
125178064Sume						printf(" (unreachable)\n");
125278064Sume					}
125378064Sume				} else
125478064Sume					printf(" (no neighbor state)\n");
125578064Sume				sin6++;
125678064Sume			}
125778064Sume		} else
125878064Sume			printf("  No advertising router\n");
125978064Sume	}
126078064Sume	free(buf);
126178064Sume#else
126255505Sshin	struct in6_prlist pr;
126355505Sshin	int s, i;
1264253999Shrs	struct timeval now;
126555505Sshin
1266253999Shrs	gettimeofday(&now, 0);
126755505Sshin
126855505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1269121156Sume		err(1, "socket");
1270121156Sume		/* NOTREACHED */
127155505Sshin	}
127255505Sshin	bzero(&pr, sizeof(pr));
1273121156Sume	strlcpy(pr.ifname, "lo0", sizeof(pr.ifname)); /* dummy */
127455505Sshin	if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) {
1275121156Sume		err(1, "ioctl(SIOCGPRLST_IN6)");
1276121156Sume		/* NOTREACHED */
1277121156Sume	}
127862590Sitojun#define PR pr.prefix[i]
127955505Sshin	for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) {
128078064Sume		struct sockaddr_in6 p6;
128178064Sume		char namebuf[NI_MAXHOST];
128278064Sume		int niflags;
128378064Sume
128478064Sume#ifdef NDPRF_ONLINK
128578064Sume		p6 = PR.prefix;
128678064Sume#else
128778064Sume		memset(&p6, 0, sizeof(p6));
128878064Sume		p6.sin6_family = AF_INET6;
128978064Sume		p6.sin6_len = sizeof(p6);
129078064Sume		p6.sin6_addr = PR.prefix;
129178064Sume#endif
129278064Sume		niflags = NI_NUMERICHOST;
129378064Sume		if (getnameinfo((struct sockaddr *)&p6,
1294121156Sume		    sizeof(p6), namebuf, sizeof(namebuf),
1295121156Sume		    NULL, 0, niflags)) {
129678064Sume			warnx("getnameinfo failed");
129778064Sume			continue;
129878064Sume		}
129978064Sume		printf("%s/%d if=%s\n", namebuf, PR.prefixlen,
1300121156Sume		    if_indextoname(PR.if_index, ifix_buf));
130178064Sume
1302253999Shrs		gettimeofday(&now, 0);
130362590Sitojun		/*
130462590Sitojun		 * meaning of fields, especially flags, is very different
130562590Sitojun		 * by origin.  notify the difference to the users.
130662590Sitojun		 */
130778064Sume#if 0
130878064Sume		printf("  %s",
1309121156Sume		    PR.origin == PR_ORIG_RA ? "" : "advertise: ");
131078064Sume#endif
131178064Sume#ifdef NDPRF_ONLINK
131278064Sume		printf("flags=%s%s%s%s%s",
1313121156Sume		    PR.raflags.onlink ? "L" : "",
1314121156Sume		    PR.raflags.autonomous ? "A" : "",
1315121156Sume		    (PR.flags & NDPRF_ONLINK) != 0 ? "O" : "",
1316121156Sume		    (PR.flags & NDPRF_DETACHED) != 0 ? "D" : "",
131778064Sume#ifdef NDPRF_HOME
1318121156Sume		    (PR.flags & NDPRF_HOME) != 0 ? "H" : ""
131978064Sume#else
1320121156Sume		    ""
132178064Sume#endif
1322121156Sume		    );
132378064Sume#else
132462590Sitojun		printf("flags=%s%s",
1325121156Sume		    PR.raflags.onlink ? "L" : "",
1326121156Sume		    PR.raflags.autonomous ? "A" : "");
132778064Sume#endif
132855505Sshin		if (PR.vltime == ND6_INFINITE_LIFETIME)
132955505Sshin			printf(" vltime=infinity");
133055505Sshin		else
1331122615Sume			printf(" vltime=%lu", PR.vltime);
133255505Sshin		if (PR.pltime == ND6_INFINITE_LIFETIME)
133355505Sshin			printf(", pltime=infinity");
133455505Sshin		else
1335122615Sume			printf(", pltime=%lu", PR.pltime);
133655505Sshin		if (PR.expire == 0)
133762590Sitojun			printf(", expire=Never");
1338253970Shrs		else if (PR.expire >= now.tv_sec)
133962590Sitojun			printf(", expire=%s",
1340253970Shrs			    sec2str(PR.expire - now.tv_sec));
134155505Sshin		else
134262590Sitojun			printf(", expired");
134378064Sume#ifdef NDPRF_ONLINK
134478064Sume		printf(", ref=%d", PR.refcnt);
134578064Sume#endif
134678064Sume#if 0
134762590Sitojun		switch (PR.origin) {
134862590Sitojun		case PR_ORIG_RA:
134962590Sitojun			printf(", origin=RA");
135062590Sitojun			break;
135162590Sitojun		case PR_ORIG_RR:
135262590Sitojun			printf(", origin=RR");
135362590Sitojun			break;
135462590Sitojun		case PR_ORIG_STATIC:
135562590Sitojun			printf(", origin=static");
135662590Sitojun			break;
135762590Sitojun		case PR_ORIG_KERNEL:
135862590Sitojun			printf(", origin=kernel");
135962590Sitojun			break;
136062590Sitojun		default:
136162590Sitojun			printf(", origin=?");
136262590Sitojun			break;
136362590Sitojun		}
136478064Sume#endif
136562590Sitojun		printf("\n");
136662590Sitojun		/*
136762590Sitojun		 * "advertising router" list is meaningful only if the prefix
136862590Sitojun		 * information is from RA.
136962590Sitojun		 */
137078064Sume		if (0 &&	/* prefix origin is almost obsolted */
137178064Sume		    PR.origin != PR_ORIG_RA)
137262590Sitojun			;
137362590Sitojun		else if (PR.advrtrs) {
137455505Sshin			int j;
137555505Sshin			printf("  advertised by\n");
137655505Sshin			for (j = 0; j < PR.advrtrs; j++) {
137755505Sshin				struct sockaddr_in6 sin6;
137862590Sitojun				struct in6_nbrinfo *nbi;
137955505Sshin
138055505Sshin				bzero(&sin6, sizeof(sin6));
138155505Sshin				sin6.sin6_family = AF_INET6;
138255505Sshin				sin6.sin6_len = sizeof(sin6);
138355505Sshin				sin6.sin6_addr = PR.advrtr[j];
138462590Sitojun				sin6.sin6_scope_id = PR.if_index; /* XXX */
138555505Sshin				getnameinfo((struct sockaddr *)&sin6,
1386121156Sume				    sin6.sin6_len, host_buf,
1387121156Sume				    sizeof(host_buf), NULL, 0,
1388121156Sume				    (nflag ? NI_NUMERICHOST : 0));
138962590Sitojun				printf("    %s", host_buf);
139055505Sshin
1391121156Sume				nbi = getnbrinfo(&sin6.sin6_addr,
1392121156Sume				    PR.if_index, 0);
139362590Sitojun				if (nbi) {
1394121156Sume					switch (nbi->state) {
1395121156Sume					case ND6_LLINFO_REACHABLE:
1396121156Sume					case ND6_LLINFO_STALE:
1397121156Sume					case ND6_LLINFO_DELAY:
1398121156Sume					case ND6_LLINFO_PROBE:
139962590Sitojun						 printf(" (reachable)\n");
140062590Sitojun						 break;
1401121156Sume					default:
140262590Sitojun						 printf(" (unreachable)\n");
140362590Sitojun					}
140478064Sume				} else
140562590Sitojun					printf(" (no neighbor state)\n");
140655505Sshin			}
140755505Sshin			if (PR.advrtrs > DRLSTSIZ)
140855505Sshin				printf("    and %d routers\n",
1409121156Sume				    PR.advrtrs - DRLSTSIZ);
141062590Sitojun		} else
141155505Sshin			printf("  No advertising router\n");
141255505Sshin	}
141355505Sshin#undef PR
141455505Sshin	close(s);
141578064Sume#endif
141655505Sshin}
141755505Sshin
141855505Sshinvoid
141955505Sshinpfx_flush()
142055505Sshin{
142155505Sshin	char dummyif[IFNAMSIZ+8];
142255505Sshin	int s;
142355505Sshin
142455505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
142555505Sshin		err(1, "socket");
1426121156Sume	strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
142755505Sshin	if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0)
1428121156Sume		err(1, "ioctl(SIOCSPFXFLUSH_IN6)");
142955505Sshin}
143055505Sshin
143155505Sshinvoid
143255505Sshinrtr_flush()
143355505Sshin{
143455505Sshin	char dummyif[IFNAMSIZ+8];
143555505Sshin	int s;
143655505Sshin
143755505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
143855505Sshin		err(1, "socket");
1439121156Sume	strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
144055505Sshin	if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0)
1441121156Sume		err(1, "ioctl(SIOCSRTRFLUSH_IN6)");
144262590Sitojun
144362590Sitojun	close(s);
144455505Sshin}
144555505Sshin
144655505Sshinvoid
144755505Sshinharmonize_rtr()
144855505Sshin{
144955505Sshin	char dummyif[IFNAMSIZ+8];
145055505Sshin	int s;
145155505Sshin
145262590Sitojun	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
145362590Sitojun		err(1, "socket");
1454121156Sume	strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
145562590Sitojun	if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0)
1456121156Sume		err(1, "ioctl(SIOCSNDFLUSH_IN6)");
145762590Sitojun
145862590Sitojun	close(s);
145955505Sshin}
146055505Sshin
146162590Sitojun#ifdef SIOCSDEFIFACE_IN6	/* XXX: check SIOCGDEFIFACE_IN6 as well? */
146262590Sitojunstatic void
1463259169Saesetdefif(char *ifname)
146462590Sitojun{
146562590Sitojun	struct in6_ndifreq ndifreq;
146662590Sitojun	unsigned int ifindex;
146762590Sitojun
146862590Sitojun	if (strcasecmp(ifname, "delete") == 0)
146962590Sitojun		ifindex = 0;
147062590Sitojun	else {
147162590Sitojun		if ((ifindex = if_nametoindex(ifname)) == 0)
147262590Sitojun			err(1, "failed to resolve i/f index for %s", ifname);
147362590Sitojun	}
147462590Sitojun
147562590Sitojun	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
147662590Sitojun		err(1, "socket");
147762590Sitojun
1478121156Sume	strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */
147962590Sitojun	ndifreq.ifindex = ifindex;
148062590Sitojun
148162590Sitojun	if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1482121156Sume		err(1, "ioctl(SIOCSDEFIFACE_IN6)");
148362590Sitojun
148462590Sitojun	close(s);
148562590Sitojun}
148662590Sitojun
148762590Sitojunstatic void
148862590Sitojungetdefif()
148962590Sitojun{
149062590Sitojun	struct in6_ndifreq ndifreq;
149162590Sitojun	char ifname[IFNAMSIZ+8];
149262590Sitojun
149362590Sitojun	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
149462590Sitojun		err(1, "socket");
149562590Sitojun
149662590Sitojun	memset(&ndifreq, 0, sizeof(ndifreq));
1497121156Sume	strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */
149862590Sitojun
149962590Sitojun	if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1500121156Sume		err(1, "ioctl(SIOCGDEFIFACE_IN6)");
150162590Sitojun
150262590Sitojun	if (ndifreq.ifindex == 0)
150362590Sitojun		printf("No default interface.\n");
150462590Sitojun	else {
150562590Sitojun		if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL)
150662590Sitojun			err(1, "failed to resolve ifname for index %lu",
150762590Sitojun			    ndifreq.ifindex);
150862590Sitojun		printf("ND default interface = %s\n", ifname);
150962590Sitojun	}
151062590Sitojun
151162590Sitojun	close(s);
151262590Sitojun}
151362590Sitojun#endif
151462590Sitojun
151555505Sshinstatic char *
1516259169Saesec2str(time_t total)
151755505Sshin{
151855505Sshin	static char result[256];
151955505Sshin	int days, hours, mins, secs;
152055505Sshin	int first = 1;
152155505Sshin	char *p = result;
1522121156Sume	char *ep = &result[sizeof(result)];
1523121156Sume	int n;
152455505Sshin
152555505Sshin	days = total / 3600 / 24;
152655505Sshin	hours = (total / 3600) % 24;
152755505Sshin	mins = (total / 60) % 60;
152855505Sshin	secs = total % 60;
152955505Sshin
153055505Sshin	if (days) {
153155505Sshin		first = 0;
1532121156Sume		n = snprintf(p, ep - p, "%dd", days);
1533121156Sume		if (n < 0 || n >= ep - p)
1534121156Sume			return "?";
1535121156Sume		p += n;
153655505Sshin	}
153755505Sshin	if (!first || hours) {
153855505Sshin		first = 0;
1539121156Sume		n = snprintf(p, ep - p, "%dh", hours);
1540121156Sume		if (n < 0 || n >= ep - p)
1541121156Sume			return "?";
1542121156Sume		p += n;
154355505Sshin	}
154455505Sshin	if (!first || mins) {
154555505Sshin		first = 0;
1546121156Sume		n = snprintf(p, ep - p, "%dm", mins);
1547121156Sume		if (n < 0 || n >= ep - p)
1548121156Sume			return "?";
1549121156Sume		p += n;
155055505Sshin	}
1551121156Sume	snprintf(p, ep - p, "%ds", secs);
155255505Sshin
155355505Sshin	return(result);
155455505Sshin}
155555505Sshin
155655505Sshin/*
155755505Sshin * Print the timestamp
155855505Sshin * from tcpdump/util.c
155955505Sshin */
156055505Sshinstatic void
1561259169Saets_print(const struct timeval *tvp)
156255505Sshin{
156355505Sshin	int s;
156455505Sshin
156555505Sshin	/* Default */
1566253999Shrs	s = (tvp->tv_sec + thiszone) % 86400;
156755505Sshin	(void)printf("%02d:%02d:%02d.%06u ",
1568253999Shrs	    s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec);
156955505Sshin}
1570186119Sqingli
1571186119Sqingli#undef NEXTADDR
1572