ndp.c revision 210936
162590Sitojun/*	$FreeBSD: head/usr.sbin/ndp/ndp.c 210936 2010-08-06 15:09:21Z jhb $	*/
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>
8255505Sshin#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);
156173412Skevlostatic char *ether_str(struct sockaddr_dl *);
157173412Skevlostatic void ts_print(const struct timeval *);
15855505Sshin
159122615Sume#ifdef ICMPV6CTL_ND6_DRLIST
16078064Sumestatic char *rtpref_str[] = {
16178064Sume	"medium",		/* 00 */
16278064Sume	"high",			/* 01 */
16378064Sume	"rsv",			/* 10 */
16478064Sume	"low"			/* 11 */
16578064Sume};
166122615Sume#endif
16778064Sume
168122615Sumeint mode = 0;
169122615Sumechar *arg = NULL;
170122615Sume
17155505Sshinint
17255505Sshinmain(argc, argv)
17355505Sshin	int argc;
17455505Sshin	char **argv;
17555505Sshin{
17655505Sshin	int ch;
17755505Sshin
17855505Sshin	pid = getpid();
17955505Sshin	thiszone = gmt2local(0);
180122615Sume	while ((ch = getopt(argc, argv, "acd:f:Ii:nprstA:HPR")) != -1)
181121156Sume		switch (ch) {
18255505Sshin		case 'a':
18355505Sshin		case 'c':
184122615Sume		case 'p':
185122615Sume		case 'r':
186122615Sume		case 'H':
187122615Sume		case 'P':
188122615Sume		case 'R':
189122615Sume		case 's':
190122615Sume		case 'I':
191122615Sume			if (mode) {
192122615Sume				usage();
193122615Sume				/*NOTREACHED*/
194122615Sume			}
195122615Sume			mode = ch;
196122615Sume			arg = NULL;
19755505Sshin			break;
19855505Sshin		case 'd':
199122615Sume		case 'f':
20055505Sshin		case 'i' :
201122615Sume			if (mode) {
20255505Sshin				usage();
203122615Sume				/*NOTREACHED*/
204122615Sume			}
205122615Sume			mode = ch;
206122615Sume			arg = optarg;
207122615Sume			break;
20855505Sshin		case 'n':
20955505Sshin			nflag = 1;
21055505Sshin			break;
21155505Sshin		case 't':
21255505Sshin			tflag = 1;
21355505Sshin			break;
21455505Sshin		case 'A':
215122615Sume			if (mode) {
216122615Sume				usage();
217122615Sume				/*NOTREACHED*/
218122615Sume			}
219122615Sume			mode = 'a';
22055505Sshin			repeat = atoi(optarg);
221122615Sume			if (repeat < 0) {
22255505Sshin				usage();
223122615Sume				/*NOTREACHED*/
224122615Sume			}
22555505Sshin			break;
22655505Sshin		default:
22755505Sshin			usage();
22855505Sshin		}
22955505Sshin
23055505Sshin	argc -= optind;
23155505Sshin	argv += optind;
23255505Sshin
233122615Sume	switch (mode) {
234122615Sume	case 'a':
235122615Sume	case 'c':
236122615Sume		if (argc != 0) {
23755505Sshin			usage();
238122615Sume			/*NOTREACHED*/
239122615Sume		}
240122615Sume		dump(0, mode == 'c');
241122615Sume		break;
242122615Sume	case 'd':
243122615Sume		if (argc != 0) {
244122615Sume			usage();
245122615Sume			/*NOTREACHED*/
246122615Sume		}
247122615Sume		delete(arg);
248122615Sume		break;
249122615Sume	case 'I':
250122615Sume#ifdef SIOCSDEFIFACE_IN6	/* XXX: check SIOCGDEFIFACE_IN6 as well? */
251122615Sume		if (argc > 1) {
252122615Sume			usage();
253122615Sume			/*NOTREACHED*/
254122615Sume		} else if (argc == 1) {
255122615Sume			if (strcmp(*argv, "delete") == 0 ||
256122615Sume			    if_nametoindex(*argv))
257122615Sume				setdefif(*argv);
258122615Sume			else
259122615Sume				errx(1, "invalid interface %s", *argv);
260122615Sume		}
261122615Sume		getdefif(); /* always call it to print the result */
262122615Sume		break;
263122615Sume#else
264122615Sume		errx(1, "not supported yet");
265122615Sume		/*NOTREACHED*/
266122615Sume#endif
267122615Sume	case 'p':
268122615Sume		if (argc != 0) {
269122615Sume			usage();
270122615Sume			/*NOTREACHED*/
271122615Sume		}
27255505Sshin		plist();
273122615Sume		break;
274122615Sume	case 'i':
275122615Sume		ifinfo(arg, argc, argv);
276122615Sume		break;
277122615Sume	case 'r':
278122615Sume		if (argc != 0) {
279122615Sume			usage();
280122615Sume			/*NOTREACHED*/
281122615Sume		}
28255505Sshin		rtrlist();
283122615Sume		break;
284122615Sume	case 's':
28555505Sshin		if (argc < 2 || argc > 4)
28655505Sshin			usage();
28755505Sshin		exit(set(argc, argv) ? 1 : 0);
288122615Sume	case 'H':
289122615Sume		if (argc != 0) {
290122615Sume			usage();
291122615Sume			/*NOTREACHED*/
292122615Sume		}
29355505Sshin		harmonize_rtr();
294122615Sume		break;
295122615Sume	case 'P':
296122615Sume		if (argc != 0) {
297122615Sume			usage();
298122615Sume			/*NOTREACHED*/
299122615Sume		}
30055505Sshin		pfx_flush();
301122615Sume		break;
302122615Sume	case 'R':
303122615Sume		if (argc != 0) {
304122615Sume			usage();
305122615Sume			/*NOTREACHED*/
306122615Sume		}
30755505Sshin		rtr_flush();
308122615Sume		break;
309122615Sume	case 0:
310122615Sume		if (argc != 1) {
311122615Sume			usage();
312122615Sume			/*NOTREACHED*/
313122615Sume		}
314122615Sume		get(argv[0]);
315122615Sume		break;
31655505Sshin	}
31755505Sshin	exit(0);
31855505Sshin}
31955505Sshin
32055505Sshin/*
32155505Sshin * Process a file to set standard ndp entries
32255505Sshin */
32355505Sshinint
32455505Sshinfile(name)
32555505Sshin	char *name;
32655505Sshin{
32755505Sshin	FILE *fp;
32855505Sshin	int i, retval;
32955505Sshin	char line[100], arg[5][50], *args[5];
33055505Sshin
33155505Sshin	if ((fp = fopen(name, "r")) == NULL) {
33255505Sshin		fprintf(stderr, "ndp: cannot open %s\n", name);
33355505Sshin		exit(1);
33455505Sshin	}
33555505Sshin	args[0] = &arg[0][0];
33655505Sshin	args[1] = &arg[1][0];
33755505Sshin	args[2] = &arg[2][0];
33855505Sshin	args[3] = &arg[3][0];
33955505Sshin	args[4] = &arg[4][0];
34055505Sshin	retval = 0;
341167260Skevlo	while (fgets(line, sizeof(line), fp) != NULL) {
342122615Sume		i = sscanf(line, "%49s %49s %49s %49s %49s",
343122615Sume		    arg[0], arg[1], arg[2], arg[3], arg[4]);
34455505Sshin		if (i < 2) {
34555505Sshin			fprintf(stderr, "ndp: bad line: %s\n", line);
34655505Sshin			retval = 1;
34755505Sshin			continue;
34855505Sshin		}
34955505Sshin		if (set(i, args))
35055505Sshin			retval = 1;
35155505Sshin	}
35255505Sshin	fclose(fp);
35355505Sshin	return (retval);
35455505Sshin}
35555505Sshin
35655505Sshinvoid
35755505Sshingetsocket()
35855505Sshin{
35955505Sshin	if (s < 0) {
36055505Sshin		s = socket(PF_ROUTE, SOCK_RAW, 0);
36155505Sshin		if (s < 0) {
362121156Sume			err(1, "socket");
363121156Sume			/* NOTREACHED */
36455505Sshin		}
36555505Sshin	}
36655505Sshin}
36755505Sshin
36862590Sitojunstruct	sockaddr_in6 so_mask = {sizeof(so_mask), AF_INET6 };
36955505Sshinstruct	sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET6 }, sin_m;
37055505Sshinstruct	sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m;
37155505Sshinint	expire_time, flags, found_entry;
37255505Sshinstruct	{
37355505Sshin	struct	rt_msghdr m_rtm;
37455505Sshin	char	m_space[512];
37555505Sshin}	m_rtmsg;
37655505Sshin
37755505Sshin/*
37855505Sshin * Set an individual neighbor cache entry
37955505Sshin */
38055505Sshinint
38155505Sshinset(argc, argv)
38255505Sshin	int argc;
38355505Sshin	char **argv;
38455505Sshin{
38555505Sshin	register struct sockaddr_in6 *sin = &sin_m;
38655505Sshin	register struct sockaddr_dl *sdl;
38755505Sshin	register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
38855505Sshin	struct addrinfo hints, *res;
38955505Sshin	int gai_error;
39055505Sshin	u_char *ea;
39155505Sshin	char *host = argv[0], *eaddr = argv[1];
39255505Sshin
39355505Sshin	getsocket();
39455505Sshin	argc -= 2;
39555505Sshin	argv += 2;
39655505Sshin	sdl_m = blank_sdl;
39755505Sshin	sin_m = blank_sin;
39855505Sshin
39955505Sshin	bzero(&hints, sizeof(hints));
40055505Sshin	hints.ai_family = AF_INET6;
40155505Sshin	gai_error = getaddrinfo(host, NULL, &hints, &res);
40255505Sshin	if (gai_error) {
40355505Sshin		fprintf(stderr, "ndp: %s: %s\n", host,
40455505Sshin			gai_strerror(gai_error));
40555505Sshin		return 1;
40655505Sshin	}
40755505Sshin	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
40862590Sitojun#ifdef __KAME__
40962590Sitojun	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
41062590Sitojun		*(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
411121156Sume		    htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
41262590Sitojun	}
41362590Sitojun#endif
41455505Sshin	ea = (u_char *)LLADDR(&sdl_m);
41555505Sshin	if (ndp_ether_aton(eaddr, ea) == 0)
41655505Sshin		sdl_m.sdl_alen = 6;
41755505Sshin	flags = expire_time = 0;
41855505Sshin	while (argc-- > 0) {
41955505Sshin		if (strncmp(argv[0], "temp", 4) == 0) {
42055505Sshin			struct timeval time;
421121156Sume
42255505Sshin			gettimeofday(&time, 0);
42355505Sshin			expire_time = time.tv_sec + 20 * 60;
42462590Sitojun		} else if (strncmp(argv[0], "proxy", 5) == 0)
42562590Sitojun			flags |= RTF_ANNOUNCE;
42655505Sshin		argv++;
42755505Sshin	}
42855505Sshin	if (rtmsg(RTM_GET) < 0) {
429121156Sume		errx(1, "RTM_GET(%s) failed", host);
430121156Sume		/* NOTREACHED */
43155505Sshin	}
43255505Sshin	sin = (struct sockaddr_in6 *)(rtm + 1);
43355505Sshin	sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
43455505Sshin	if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
43555505Sshin		if (sdl->sdl_family == AF_LINK &&
436122615Sume		    !(rtm->rtm_flags & RTF_GATEWAY)) {
437122615Sume			switch (sdl->sdl_type) {
438122615Sume			case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
439122615Sume			case IFT_ISO88024: case IFT_ISO88025:
440210936Sjhb			case IFT_L2VLAN: case IFT_BRIDGE:
441122615Sume				goto overwrite;
442122615Sume			}
44355505Sshin		}
44462590Sitojun		/*
44562590Sitojun		 * IPv4 arp command retries with sin_other = SIN_PROXY here.
44662590Sitojun		 */
44762590Sitojun		fprintf(stderr, "set: cannot configure a new entry\n");
44862590Sitojun		return 1;
44955505Sshin	}
45062590Sitojun
45155505Sshinoverwrite:
45255505Sshin	if (sdl->sdl_family != AF_LINK) {
45355505Sshin		printf("cannot intuit interface index and type for %s\n", host);
45455505Sshin		return (1);
45555505Sshin	}
45655505Sshin	sdl_m.sdl_type = sdl->sdl_type;
45755505Sshin	sdl_m.sdl_index = sdl->sdl_index;
45855505Sshin	return (rtmsg(RTM_ADD));
45955505Sshin}
46055505Sshin
46155505Sshin/*
46255505Sshin * Display an individual neighbor cache entry
46355505Sshin */
46455505Sshinvoid
46555505Sshinget(host)
46655505Sshin	char *host;
46755505Sshin{
46855505Sshin	struct sockaddr_in6 *sin = &sin_m;
46955505Sshin	struct addrinfo hints, *res;
47055505Sshin	int gai_error;
47155505Sshin
47255505Sshin	sin_m = blank_sin;
47355505Sshin	bzero(&hints, sizeof(hints));
47455505Sshin	hints.ai_family = AF_INET6;
47555505Sshin	gai_error = getaddrinfo(host, NULL, &hints, &res);
47655505Sshin	if (gai_error) {
47755505Sshin		fprintf(stderr, "ndp: %s: %s\n", host,
478121156Sume		    gai_strerror(gai_error));
47955505Sshin		return;
48055505Sshin	}
48155505Sshin	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
48262590Sitojun#ifdef __KAME__
48362590Sitojun	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
48462590Sitojun		*(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
485121156Sume		    htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
48662590Sitojun	}
48762590Sitojun#endif
488122615Sume	dump(&sin->sin6_addr, 0);
48955505Sshin	if (found_entry == 0) {
49055505Sshin		getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
491121156Sume		    sizeof(host_buf), NULL ,0,
492121156Sume		    (nflag ? NI_NUMERICHOST : 0));
49355505Sshin		printf("%s (%s) -- no entry\n", host, host_buf);
49455505Sshin		exit(1);
49555505Sshin	}
49655505Sshin}
49755505Sshin
49855505Sshin/*
49955505Sshin * Delete a neighbor cache entry
50055505Sshin */
50155505Sshinint
50255505Sshindelete(host)
50355505Sshin	char *host;
50455505Sshin{
50555505Sshin	struct sockaddr_in6 *sin = &sin_m;
50655505Sshin	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
507186119Sqingli	register char *cp = m_rtmsg.m_space;
50855505Sshin	struct sockaddr_dl *sdl;
50955505Sshin	struct addrinfo hints, *res;
51055505Sshin	int gai_error;
51155505Sshin
51255505Sshin	getsocket();
51355505Sshin	sin_m = blank_sin;
51455505Sshin
51555505Sshin	bzero(&hints, sizeof(hints));
51655505Sshin	hints.ai_family = AF_INET6;
51755505Sshin	gai_error = getaddrinfo(host, NULL, &hints, &res);
51855505Sshin	if (gai_error) {
51955505Sshin		fprintf(stderr, "ndp: %s: %s\n", host,
520121156Sume		    gai_strerror(gai_error));
52155505Sshin		return 1;
52255505Sshin	}
52355505Sshin	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
52462590Sitojun#ifdef __KAME__
52562590Sitojun	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
52662590Sitojun		*(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
527121156Sume		    htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
52862590Sitojun	}
52962590Sitojun#endif
53055505Sshin	if (rtmsg(RTM_GET) < 0) {
531121156Sume		errx(1, "RTM_GET(%s) failed", host);
532121156Sume		/* NOTREACHED */
53355505Sshin	}
53455505Sshin	sin = (struct sockaddr_in6 *)(rtm + 1);
53555505Sshin	sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
53655505Sshin	if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
53755505Sshin		if (sdl->sdl_family == AF_LINK &&
53862590Sitojun		    !(rtm->rtm_flags & RTF_GATEWAY)) {
53978064Sume			goto delete;
54055505Sshin		}
54162590Sitojun		/*
54262590Sitojun		 * IPv4 arp command retries with sin_other = SIN_PROXY here.
54362590Sitojun		 */
54462590Sitojun		fprintf(stderr, "delete: cannot delete non-NDP entry\n");
54562590Sitojun		return 1;
54655505Sshin	}
54762590Sitojun
54855505Sshindelete:
54955505Sshin	if (sdl->sdl_family != AF_LINK) {
55055505Sshin		printf("cannot locate %s\n", host);
55155505Sshin		return (1);
55255505Sshin	}
553186119Sqingli        /*
554186119Sqingli         * need to reinit the field because it has rt_key
555186119Sqingli         * but we want the actual address
556186119Sqingli         */
557186119Sqingli	NEXTADDR(RTA_DST, sin_m);
558186500Sqingli	rtm->rtm_flags |= RTF_LLDATA;
55955505Sshin	if (rtmsg(RTM_DELETE) == 0) {
56062590Sitojun		struct sockaddr_in6 s6 = *sin; /* XXX: for safety */
56162590Sitojun
56262590Sitojun#ifdef __KAME__
56362590Sitojun		if (IN6_IS_ADDR_LINKLOCAL(&s6.sin6_addr)) {
56462590Sitojun			s6.sin6_scope_id = ntohs(*(u_int16_t *)&s6.sin6_addr.s6_addr[2]);
56562590Sitojun			*(u_int16_t *)&s6.sin6_addr.s6_addr[2] = 0;
56662590Sitojun		}
56762590Sitojun#endif
56862590Sitojun		getnameinfo((struct sockaddr *)&s6,
569121156Sume		    s6.sin6_len, host_buf,
570121156Sume		    sizeof(host_buf), NULL, 0,
571121156Sume		    (nflag ? NI_NUMERICHOST : 0));
57255505Sshin		printf("%s (%s) deleted\n", host, host_buf);
57355505Sshin	}
57455505Sshin
57555505Sshin	return 0;
57655505Sshin}
57755505Sshin
578122615Sume#define W_ADDR	36
57978064Sume#define W_LL	17
58078064Sume#define W_IF	6
58178064Sume
58255505Sshin/*
58355505Sshin * Dump the entire neighbor cache
58455505Sshin */
58555505Sshinvoid
586122615Sumedump(addr, cflag)
58755505Sshin	struct in6_addr *addr;
588122615Sume	int cflag;
58955505Sshin{
59055505Sshin	int mib[6];
59155505Sshin	size_t needed;
59262590Sitojun	char *lim, *buf, *next;
59355505Sshin	struct rt_msghdr *rtm;
59455505Sshin	struct sockaddr_in6 *sin;
59555505Sshin	struct sockaddr_dl *sdl;
59655505Sshin	extern int h_errno;
59755505Sshin	struct in6_nbrinfo *nbi;
59855505Sshin	struct timeval time;
59955505Sshin	int addrwidth;
60078064Sume	int llwidth;
60178064Sume	int ifwidth;
60262590Sitojun	char flgbuf[8];
60378064Sume	char *ifname;
60455505Sshin
60555505Sshin	/* Print header */
60666865Ssumikawa	if (!tflag && !cflag)
607122615Sume		printf("%-*.*s %-*.*s %*.*s %-9.9s %1s %5s\n",
60878064Sume		    W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address",
609122615Sume		    W_IF, W_IF, "Netif", "Expire", "S", "Flags");
61055505Sshin
61155505Sshinagain:;
61255505Sshin	mib[0] = CTL_NET;
61355505Sshin	mib[1] = PF_ROUTE;
61455505Sshin	mib[2] = 0;
61555505Sshin	mib[3] = AF_INET6;
61655505Sshin	mib[4] = NET_RT_FLAGS;
617186119Sqingli#ifdef RTF_LLINFO
61855505Sshin	mib[5] = RTF_LLINFO;
619186119Sqingli#else
620186119Sqingli	mib[5] = 0;
621186119Sqingli#endif
62255505Sshin	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
62355505Sshin		err(1, "sysctl(PF_ROUTE estimate)");
62455505Sshin	if (needed > 0) {
62555505Sshin		if ((buf = malloc(needed)) == NULL)
626121156Sume			err(1, "malloc");
62755505Sshin		if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
62855505Sshin			err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
62955505Sshin		lim = buf + needed;
63055505Sshin	} else
63155505Sshin		buf = lim = NULL;
63255505Sshin
63355505Sshin	for (next = buf; next && next < lim; next += rtm->rtm_msglen) {
63455505Sshin		int isrouter = 0, prbs = 0;
63555505Sshin
63655505Sshin		rtm = (struct rt_msghdr *)next;
63755505Sshin		sin = (struct sockaddr_in6 *)(rtm + 1);
63855505Sshin		sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len));
63978064Sume
64078064Sume		/*
64178064Sume		 * Some OSes can produce a route that has the LINK flag but
64278064Sume		 * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD
64378064Sume		 * and BSD/OS, where xx is not the interface identifier on
64478064Sume		 * lo0).  Such routes entry would annoy getnbrinfo() below,
64578064Sume		 * so we skip them.
64678064Sume		 * XXX: such routes should have the GATEWAY flag, not the
647121156Sume		 * LINK flag.  However, there is rotten routing software
64878064Sume		 * that advertises all routes that have the GATEWAY flag.
64978064Sume		 * Thus, KAME kernel intentionally does not set the LINK flag.
65078064Sume		 * What is to be fixed is not ndp, but such routing software
65178064Sume		 * (and the kernel workaround)...
65278064Sume		 */
65378064Sume		if (sdl->sdl_family != AF_LINK)
65478064Sume			continue;
65578064Sume
656122615Sume		if (!(rtm->rtm_flags & RTF_HOST))
657122615Sume			continue;
658122615Sume
65955505Sshin		if (addr) {
66055505Sshin			if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr))
66155505Sshin				continue;
66255505Sshin			found_entry = 1;
66355505Sshin		} else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
66455505Sshin			continue;
66555505Sshin		if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) ||
66655505Sshin		    IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) {
66755505Sshin			/* XXX: should scope id be filled in the kernel? */
66855505Sshin			if (sin->sin6_scope_id == 0)
66955505Sshin				sin->sin6_scope_id = sdl->sdl_index;
67066865Ssumikawa#ifdef __KAME__
67166865Ssumikawa			/* KAME specific hack; removed the embedded id */
67255505Sshin			*(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0;
67366865Ssumikawa#endif
67455505Sshin		}
67555505Sshin		getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
676121156Sume		    sizeof(host_buf), NULL, 0, (nflag ? NI_NUMERICHOST : 0));
677122615Sume		if (cflag) {
67881366Ssumikawa#ifdef RTF_WASCLONED
67981366Ssumikawa			if (rtm->rtm_flags & RTF_WASCLONED)
68081366Ssumikawa				delete(host_buf);
681122615Sume#elif defined(RTF_CLONED)
682122615Sume			if (rtm->rtm_flags & RTF_CLONED)
683122615Sume				delete(host_buf);
68481366Ssumikawa#else
68566865Ssumikawa			delete(host_buf);
68681366Ssumikawa#endif
68766865Ssumikawa			continue;
68866865Ssumikawa		}
68955505Sshin		gettimeofday(&time, 0);
69055505Sshin		if (tflag)
69155505Sshin			ts_print(&time);
69255505Sshin
69378064Sume		addrwidth = strlen(host_buf);
69478064Sume		if (addrwidth < W_ADDR)
69578064Sume			addrwidth = W_ADDR;
69678064Sume		llwidth = strlen(ether_str(sdl));
69778064Sume		if (W_ADDR + W_LL - addrwidth > llwidth)
69878064Sume			llwidth = W_ADDR + W_LL - addrwidth;
69978064Sume		ifname = if_indextoname(sdl->sdl_index, ifix_buf);
70078064Sume		if (!ifname)
70178064Sume			ifname = "?";
70278064Sume		ifwidth = strlen(ifname);
70378064Sume		if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth)
70478064Sume			ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth;
70555505Sshin
70678064Sume		printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf,
70778064Sume		    llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname);
70855505Sshin
70955505Sshin		/* Print neighbor discovery specific informations */
71062590Sitojun		nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1);
71155505Sshin		if (nbi) {
71255505Sshin			if (nbi->expire > time.tv_sec) {
71355505Sshin				printf(" %-9.9s",
714121156Sume				    sec2str(nbi->expire - time.tv_sec));
71578064Sume			} else if (nbi->expire == 0)
71655505Sshin				printf(" %-9.9s", "permanent");
71755505Sshin			else
71855505Sshin				printf(" %-9.9s", "expired");
71955505Sshin
720121156Sume			switch (nbi->state) {
721121156Sume			case ND6_LLINFO_NOSTATE:
72255505Sshin				 printf(" N");
72355505Sshin				 break;
72478064Sume#ifdef ND6_LLINFO_WAITDELETE
725121156Sume			case ND6_LLINFO_WAITDELETE:
72655505Sshin				 printf(" W");
72755505Sshin				 break;
72878064Sume#endif
729121156Sume			case ND6_LLINFO_INCOMPLETE:
73055505Sshin				 printf(" I");
73155505Sshin				 break;
732121156Sume			case ND6_LLINFO_REACHABLE:
73355505Sshin				 printf(" R");
73455505Sshin				 break;
735121156Sume			case ND6_LLINFO_STALE:
73655505Sshin				 printf(" S");
73755505Sshin				 break;
738121156Sume			case ND6_LLINFO_DELAY:
73955505Sshin				 printf(" D");
74055505Sshin				 break;
741121156Sume			case ND6_LLINFO_PROBE:
74255505Sshin				 printf(" P");
74355505Sshin				 break;
744121156Sume			default:
74555505Sshin				 printf(" ?");
74655505Sshin				 break;
74755505Sshin			}
74855505Sshin
74955505Sshin			isrouter = nbi->isrouter;
75055505Sshin			prbs = nbi->asked;
75178064Sume		} else {
75255505Sshin			warnx("failed to get neighbor information");
75355505Sshin			printf("  ");
75455505Sshin		}
75555505Sshin
75662590Sitojun		/*
75762590Sitojun		 * other flags. R: router, P: proxy, W: ??
75862590Sitojun		 */
75962590Sitojun		if ((rtm->rtm_addrs & RTA_NETMASK) == 0) {
76062590Sitojun			snprintf(flgbuf, sizeof(flgbuf), "%s%s",
761121156Sume			    isrouter ? "R" : "",
762121156Sume			    (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
76362590Sitojun		} else {
76462590Sitojun			sin = (struct sockaddr_in6 *)
765121156Sume			    (sdl->sdl_len + (char *)sdl);
766122615Sume#if 0	/* W and P are mystery even for us */
76762590Sitojun			snprintf(flgbuf, sizeof(flgbuf), "%s%s%s%s",
768121156Sume			    isrouter ? "R" : "",
769121156Sume			    !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr) ? "P" : "",
770121156Sume			    (sin->sin6_len != sizeof(struct sockaddr_in6)) ? "W" : "",
771121156Sume			    (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
772122615Sume#else
773122615Sume			snprintf(flgbuf, sizeof(flgbuf), "%s%s",
774122615Sume			    isrouter ? "R" : "",
775122615Sume			    (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
776122615Sume#endif
77755505Sshin		}
778122615Sume		printf(" %s", flgbuf);
77955505Sshin
78055505Sshin		if (prbs)
781122615Sume			printf(" %d", prbs);
78255505Sshin
78355505Sshin		printf("\n");
78455505Sshin	}
78578064Sume	if (buf != NULL)
78678064Sume		free(buf);
78755505Sshin
78855505Sshin	if (repeat) {
78955505Sshin		printf("\n");
790125675Ssumikawa		fflush(stdout);
79155505Sshin		sleep(repeat);
79255505Sshin		goto again;
79355505Sshin	}
79455505Sshin}
79555505Sshin
79655505Sshinstatic struct in6_nbrinfo *
79762590Sitojungetnbrinfo(addr, ifindex, warning)
79855505Sshin	struct in6_addr *addr;
79955505Sshin	int ifindex;
80062590Sitojun	int warning;
80155505Sshin{
80255505Sshin	static struct in6_nbrinfo nbi;
80355505Sshin	int s;
80455505Sshin
80555505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
80655505Sshin		err(1, "socket");
80755505Sshin
80855505Sshin	bzero(&nbi, sizeof(nbi));
80955505Sshin	if_indextoname(ifindex, nbi.ifname);
81055505Sshin	nbi.addr = *addr;
81155505Sshin	if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) {
81262590Sitojun		if (warning)
81362590Sitojun			warn("ioctl(SIOCGNBRINFO_IN6)");
81455505Sshin		close(s);
81555505Sshin		return(NULL);
81655505Sshin	}
81755505Sshin
81855505Sshin	close(s);
81955505Sshin	return(&nbi);
82055505Sshin}
82155505Sshin
82255505Sshinstatic char *
82355505Sshinether_str(sdl)
82455505Sshin	struct sockaddr_dl *sdl;
82555505Sshin{
826121156Sume	static char hbuf[NI_MAXHOST];
82755505Sshin	u_char *cp;
82855505Sshin
82955505Sshin	if (sdl->sdl_alen) {
83055505Sshin		cp = (u_char *)LLADDR(sdl);
831121156Sume		snprintf(hbuf, sizeof(hbuf), "%x:%x:%x:%x:%x:%x",
832121156Sume		    cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
833121156Sume	} else
834121156Sume		snprintf(hbuf, sizeof(hbuf), "(incomplete)");
83555505Sshin
836121156Sume	return(hbuf);
83755505Sshin}
83855505Sshin
83955505Sshinint
84055505Sshinndp_ether_aton(a, n)
84155505Sshin	char *a;
84255505Sshin	u_char *n;
84355505Sshin{
84455505Sshin	int i, o[6];
84555505Sshin
84655505Sshin	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
847121156Sume	    &o[3], &o[4], &o[5]);
84855505Sshin	if (i != 6) {
84955505Sshin		fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a);
85055505Sshin		return (1);
85155505Sshin	}
852121156Sume	for (i = 0; i < 6; i++)
85355505Sshin		n[i] = o[i];
85455505Sshin	return (0);
85555505Sshin}
85655505Sshin
85755505Sshinvoid
85855505Sshinusage()
85955505Sshin{
860122615Sume	printf("usage: ndp [-nt] hostname\n");
861122615Sume	printf("       ndp [-nt] -a | -c | -p | -r | -H | -P | -R\n");
86278064Sume	printf("       ndp [-nt] -A wait\n");
863122615Sume	printf("       ndp [-nt] -d hostname\n");
864122615Sume	printf("       ndp [-nt] -f filename\n");
865122615Sume	printf("       ndp [-nt] -i interface [flags...]\n");
86662590Sitojun#ifdef SIOCSDEFIFACE_IN6
867122615Sume	printf("       ndp [-nt] -I [interface|delete]\n");
86862590Sitojun#endif
869122615Sume	printf("       ndp [-nt] -s nodename etheraddr [temp] [proxy]\n");
87055505Sshin	exit(1);
87155505Sshin}
87255505Sshin
87355505Sshinint
87455505Sshinrtmsg(cmd)
87555505Sshin	int cmd;
87655505Sshin{
87755505Sshin	static int seq;
87855505Sshin	int rlen;
87955505Sshin	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
88055505Sshin	register char *cp = m_rtmsg.m_space;
88155505Sshin	register int l;
88255505Sshin
88355505Sshin	errno = 0;
88455505Sshin	if (cmd == RTM_DELETE)
88555505Sshin		goto doit;
88655505Sshin	bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
88755505Sshin	rtm->rtm_flags = flags;
88855505Sshin	rtm->rtm_version = RTM_VERSION;
88955505Sshin
89055505Sshin	switch (cmd) {
89155505Sshin	default:
89255505Sshin		fprintf(stderr, "ndp: internal wrong cmd\n");
89355505Sshin		exit(1);
89455505Sshin	case RTM_ADD:
89555505Sshin		rtm->rtm_addrs |= RTA_GATEWAY;
896122615Sume		if (expire_time) {
897122615Sume			rtm->rtm_rmx.rmx_expire = expire_time;
898122615Sume			rtm->rtm_inits = RTV_EXPIRE;
899122615Sume		}
900186500Sqingli		rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA);
901151473Ssuz#if 0 /* we don't support ipv6addr/128 type proxying */
90262590Sitojun		if (rtm->rtm_flags & RTF_ANNOUNCE) {
90362590Sitojun			rtm->rtm_flags &= ~RTF_HOST;
904124241Ssuz			rtm->rtm_addrs |= RTA_NETMASK;
90562590Sitojun		}
906151473Ssuz#endif
90755505Sshin		/* FALLTHROUGH */
90855505Sshin	case RTM_GET:
90955505Sshin		rtm->rtm_addrs |= RTA_DST;
91055505Sshin	}
91155505Sshin
91255505Sshin	NEXTADDR(RTA_DST, sin_m);
91355505Sshin	NEXTADDR(RTA_GATEWAY, sdl_m);
914151473Ssuz#if 0 /* we don't support ipv6addr/128 type proxying */
91562590Sitojun	memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr));
91655505Sshin	NEXTADDR(RTA_NETMASK, so_mask);
917151473Ssuz#endif
91855505Sshin
91955505Sshin	rtm->rtm_msglen = cp - (char *)&m_rtmsg;
92055505Sshindoit:
92155505Sshin	l = rtm->rtm_msglen;
92255505Sshin	rtm->rtm_seq = ++seq;
92355505Sshin	rtm->rtm_type = cmd;
92455505Sshin	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
92555505Sshin		if (errno != ESRCH || cmd != RTM_DELETE) {
926121156Sume			err(1, "writing to routing socket");
927121156Sume			/* NOTREACHED */
92855505Sshin		}
92955505Sshin	}
93055505Sshin	do {
93155505Sshin		l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
93255505Sshin	} while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
93355505Sshin	if (l < 0)
93455505Sshin		(void) fprintf(stderr, "ndp: read from routing socket: %s\n",
93555505Sshin		    strerror(errno));
93655505Sshin	return (0);
93755505Sshin}
93855505Sshin
93955505Sshinvoid
940122615Sumeifinfo(ifname, argc, argv)
941122615Sume	char *ifname;
94262590Sitojun	int argc;
94362590Sitojun	char **argv;
94455505Sshin{
94555505Sshin	struct in6_ndireq nd;
94662590Sitojun	int i, s;
94762590Sitojun	u_int32_t newflags;
94878064Sume#ifdef IPV6CTL_USETEMPADDR
94978064Sume	u_int8_t nullbuf[8];
95078064Sume#endif
95155505Sshin
95255505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
953121156Sume		err(1, "socket");
954121156Sume		/* NOTREACHED */
95555505Sshin	}
95655505Sshin	bzero(&nd, sizeof(nd));
957121156Sume	strlcpy(nd.ifname, ifname, sizeof(nd.ifname));
95855505Sshin	if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
959121156Sume		err(1, "ioctl(SIOCGIFINFO_IN6)");
960121156Sume		/* NOTREACHED */
961122615Sume	}
96262590Sitojun#define ND nd.ndi
96362590Sitojun	newflags = ND.flags;
964122615Sume	for (i = 0; i < argc; i++) {
96562590Sitojun		int clear = 0;
96662590Sitojun		char *cp = argv[i];
96762590Sitojun
96862590Sitojun		if (*cp == '-') {
96962590Sitojun			clear = 1;
97062590Sitojun			cp++;
97162590Sitojun		}
97262590Sitojun
97362590Sitojun#define SETFLAG(s, f) \
97462590Sitojun	do {\
97562590Sitojun		if (strcmp(cp, (s)) == 0) {\
97662590Sitojun			if (clear)\
97762590Sitojun				newflags &= ~(f);\
97862590Sitojun			else\
97962590Sitojun				newflags |= (f);\
98062590Sitojun		}\
98162590Sitojun	} while (0)
982151468Ssuz/*
983151468Ssuz * XXX: this macro is not 100% correct, in that it matches "nud" against
984151468Ssuz *      "nudbogus".  But we just let it go since this is minor.
985151468Ssuz */
986151468Ssuz#define SETVALUE(f, v) \
987151468Ssuz	do { \
988151468Ssuz		char *valptr; \
989151468Ssuz		unsigned long newval; \
990151468Ssuz		v = 0; /* unspecified */ \
991151468Ssuz		if (strncmp(cp, f, strlen(f)) == 0) { \
992151468Ssuz			valptr = strchr(cp, '='); \
993151468Ssuz			if (valptr == NULL) \
994151468Ssuz				err(1, "syntax error in %s field", (f)); \
995151468Ssuz			errno = 0; \
996151468Ssuz			newval = strtoul(++valptr, NULL, 0); \
997151468Ssuz			if (errno) \
998151468Ssuz				err(1, "syntax error in %s's value", (f)); \
999151468Ssuz			v = newval; \
1000151468Ssuz		} \
1001151468Ssuz	} while (0)
1002151468Ssuz
1003151474Ssuz		SETFLAG("disabled", ND6_IFF_IFDISABLED);
100462590Sitojun		SETFLAG("nud", ND6_IFF_PERFORMNUD);
1005118498Sume#ifdef ND6_IFF_ACCEPT_RTADV
1006118498Sume		SETFLAG("accept_rtadv", ND6_IFF_ACCEPT_RTADV);
1007118498Sume#endif
1008197138Shrs#ifdef ND6_IFF_AUTO_LINKLOCAL
1009197138Shrs		SETFLAG("auto_linklocal", ND6_IFF_AUTO_LINKLOCAL);
1010197138Shrs#endif
1011122615Sume#ifdef ND6_IFF_PREFER_SOURCE
1012122615Sume		SETFLAG("prefer_source", ND6_IFF_PREFER_SOURCE);
1013122615Sume#endif
1014151468Ssuz		SETVALUE("basereachable", ND.basereachable);
1015151468Ssuz		SETVALUE("retrans", ND.retrans);
1016151468Ssuz		SETVALUE("curhlim", ND.chlim);
101762590Sitojun
101862590Sitojun		ND.flags = newflags;
1019151468Ssuz		if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd) < 0) {
1020151468Ssuz			err(1, "ioctl(SIOCSIFINFO_IN6)");
1021121156Sume			/* NOTREACHED */
102262590Sitojun		}
102362590Sitojun#undef SETFLAG
1024151468Ssuz#undef SETVALUE
102562590Sitojun	}
102662590Sitojun
1027121162Sume	if (!ND.initialized) {
1028121162Sume		errx(1, "%s: not initialized yet", ifname);
1029121162Sume		/* NOTREACHED */
1030121162Sume	}
1031121162Sume
1032151468Ssuz	if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
1033151468Ssuz		err(1, "ioctl(SIOCGIFINFO_IN6)");
1034151468Ssuz		/* NOTREACHED */
1035151468Ssuz	}
103655505Sshin	printf("linkmtu=%d", ND.linkmtu);
1037121471Sume	printf(", maxmtu=%d", ND.maxmtu);
103855505Sshin	printf(", curhlim=%d", ND.chlim);
103955505Sshin	printf(", basereachable=%ds%dms",
1040121156Sume	    ND.basereachable / 1000, ND.basereachable % 1000);
104155505Sshin	printf(", reachable=%ds", ND.reachable);
104262590Sitojun	printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000);
104378064Sume#ifdef IPV6CTL_USETEMPADDR
104478064Sume	memset(nullbuf, 0, sizeof(nullbuf));
104578064Sume	if (memcmp(nullbuf, ND.randomid, sizeof(nullbuf)) != 0) {
104678064Sume		int j;
104778064Sume		u_int8_t *rbuf;
104878064Sume
104978064Sume		for (i = 0; i < 3; i++) {
1050121156Sume			switch (i) {
105178064Sume			case 0:
105278064Sume				printf("\nRandom seed(0): ");
105378064Sume				rbuf = ND.randomseed0;
105478064Sume				break;
105578064Sume			case 1:
105678064Sume				printf("\nRandom seed(1): ");
105778064Sume				rbuf = ND.randomseed1;
105878064Sume				break;
105978064Sume			case 2:
106078064Sume				printf("\nRandom ID:      ");
106178064Sume				rbuf = ND.randomid;
106278064Sume				break;
1063151472Ssuz			default:
1064151472Ssuz				errx(1, "impossible case for tempaddr display");
106578064Sume			}
106678064Sume			for (j = 0; j < 8; j++)
106778064Sume				printf("%02x", rbuf[j]);
106878064Sume		}
106978064Sume	}
107078064Sume#endif
107162590Sitojun	if (ND.flags) {
107262590Sitojun		printf("\nFlags: ");
1073151474Ssuz#ifdef ND6_IFF_IFDISABLED
1074151474Ssuz		if ((ND.flags & ND6_IFF_IFDISABLED))
1075151474Ssuz			printf("disabled ");
1076151474Ssuz#endif
1077118498Sume		if ((ND.flags & ND6_IFF_PERFORMNUD))
1078118498Sume			printf("nud ");
1079118498Sume#ifdef ND6_IFF_ACCEPT_RTADV
1080118498Sume		if ((ND.flags & ND6_IFF_ACCEPT_RTADV))
1081118498Sume			printf("accept_rtadv ");
1082118498Sume#endif
1083197138Shrs#ifdef ND6_IFF_AUTO_LINKLOCAL
1084197138Shrs		if ((ND.flags & ND6_IFF_AUTO_LINKLOCAL))
1085197138Shrs			printf("auto_linklocal ");
1086197138Shrs#endif
1087122615Sume#ifdef ND6_IFF_PREFER_SOURCE
1088122615Sume		if ((ND.flags & ND6_IFF_PREFER_SOURCE))
1089122615Sume			printf("prefer_source ");
1090122615Sume#endif
1091122615Sume	}
109262590Sitojun	putc('\n', stdout);
109355505Sshin#undef ND
1094121156Sume
109555505Sshin	close(s);
109655505Sshin}
109755505Sshin
109878064Sume#ifndef ND_RA_FLAG_RTPREF_MASK	/* XXX: just for compilation on *BSD release */
109978064Sume#define ND_RA_FLAG_RTPREF_MASK	0x18 /* 00011000 */
110078064Sume#endif
110178064Sume
110255505Sshinvoid
110355505Sshinrtrlist()
110455505Sshin{
110578064Sume#ifdef ICMPV6CTL_ND6_DRLIST
110678064Sume	int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST };
110778064Sume	char *buf;
110878064Sume	struct in6_defrouter *p, *ep;
110978064Sume	size_t l;
111078064Sume	struct timeval time;
111178064Sume
111278064Sume	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
111378064Sume		err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
111478064Sume		/*NOTREACHED*/
111578064Sume	}
1116151472Ssuz	if (l == 0)
1117151472Ssuz		return;
111878064Sume	buf = malloc(l);
111978064Sume	if (!buf) {
1120121156Sume		err(1, "malloc");
112178064Sume		/*NOTREACHED*/
112278064Sume	}
112378064Sume	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
112478064Sume		err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
112578064Sume		/*NOTREACHED*/
112678064Sume	}
112778064Sume
112878064Sume	ep = (struct in6_defrouter *)(buf + l);
112978064Sume	for (p = (struct in6_defrouter *)buf; p < ep; p++) {
113078064Sume		int rtpref;
113178064Sume
113278064Sume		if (getnameinfo((struct sockaddr *)&p->rtaddr,
113378064Sume		    p->rtaddr.sin6_len, host_buf, sizeof(host_buf), NULL, 0,
1134121156Sume		    (nflag ? NI_NUMERICHOST : 0)) != 0)
113578064Sume			strlcpy(host_buf, "?", sizeof(host_buf));
1136121156Sume
113778064Sume		printf("%s if=%s", host_buf,
1138121156Sume		    if_indextoname(p->if_index, ifix_buf));
113978064Sume		printf(", flags=%s%s",
1140121156Sume		    p->flags & ND_RA_FLAG_MANAGED ? "M" : "",
1141121156Sume		    p->flags & ND_RA_FLAG_OTHER   ? "O" : "");
114278064Sume		rtpref = ((p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff;
114378064Sume		printf(", pref=%s", rtpref_str[rtpref]);
1144121156Sume
114578064Sume		gettimeofday(&time, 0);
114678064Sume		if (p->expire == 0)
114778064Sume			printf(", expire=Never\n");
114878064Sume		else
114978064Sume			printf(", expire=%s\n",
1150121156Sume			    sec2str(p->expire - time.tv_sec));
115178064Sume	}
115278064Sume	free(buf);
115378064Sume#else
115455505Sshin	struct in6_drlist dr;
115555505Sshin	int s, i;
115655505Sshin	struct timeval time;
115755505Sshin
115855505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1159121156Sume		err(1, "socket");
1160121156Sume		/* NOTREACHED */
116155505Sshin	}
116255505Sshin	bzero(&dr, sizeof(dr));
1163121156Sume	strlcpy(dr.ifname, "lo0", sizeof(dr.ifname)); /* dummy */
116455505Sshin	if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) {
1165121156Sume		err(1, "ioctl(SIOCGDRLST_IN6)");
1166121156Sume		/* NOTREACHED */
1167121156Sume	}
116862590Sitojun#define DR dr.defrouter[i]
116978064Sume	for (i = 0 ; DR.if_index && i < DRLSTSIZ ; i++) {
117055505Sshin		struct sockaddr_in6 sin6;
117155505Sshin
117255505Sshin		bzero(&sin6, sizeof(sin6));
117355505Sshin		sin6.sin6_family = AF_INET6;
117455505Sshin		sin6.sin6_len = sizeof(sin6);
117555505Sshin		sin6.sin6_addr = DR.rtaddr;
117655505Sshin		getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf,
1177121156Sume		    sizeof(host_buf), NULL, 0,
1178121156Sume		    (nflag ? NI_NUMERICHOST : 0));
1179121156Sume
118055505Sshin		printf("%s if=%s", host_buf,
1181121156Sume		    if_indextoname(DR.if_index, ifix_buf));
118255505Sshin		printf(", flags=%s%s",
1183121156Sume		    DR.flags & ND_RA_FLAG_MANAGED ? "M" : "",
1184121156Sume		    DR.flags & ND_RA_FLAG_OTHER   ? "O" : "");
118555505Sshin		gettimeofday(&time, 0);
118655505Sshin		if (DR.expire == 0)
118755505Sshin			printf(", expire=Never\n");
118855505Sshin		else
118955505Sshin			printf(", expire=%s\n",
1190121156Sume			    sec2str(DR.expire - time.tv_sec));
119155505Sshin	}
119255505Sshin#undef DR
119355505Sshin	close(s);
119478064Sume#endif
119555505Sshin}
119655505Sshin
119755505Sshinvoid
119855505Sshinplist()
119955505Sshin{
120078064Sume#ifdef ICMPV6CTL_ND6_PRLIST
120178064Sume	int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST };
120278064Sume	char *buf;
120378064Sume	struct in6_prefix *p, *ep, *n;
120478064Sume	struct sockaddr_in6 *advrtr;
120578064Sume	size_t l;
120678064Sume	struct timeval time;
120778064Sume	const int niflags = NI_NUMERICHOST;
120878064Sume	int ninflags = nflag ? NI_NUMERICHOST : 0;
120978064Sume	char namebuf[NI_MAXHOST];
121078064Sume
121178064Sume	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
121278064Sume		err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
121378064Sume		/*NOTREACHED*/
121478064Sume	}
121578064Sume	buf = malloc(l);
121678064Sume	if (!buf) {
1217121156Sume		err(1, "malloc");
121878064Sume		/*NOTREACHED*/
121978064Sume	}
122078064Sume	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
122178064Sume		err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
122278064Sume		/*NOTREACHED*/
122378064Sume	}
122478064Sume
122578064Sume	ep = (struct in6_prefix *)(buf + l);
122678064Sume	for (p = (struct in6_prefix *)buf; p < ep; p = n) {
122778064Sume		advrtr = (struct sockaddr_in6 *)(p + 1);
122878064Sume		n = (struct in6_prefix *)&advrtr[p->advrtrs];
122978064Sume
123078064Sume		if (getnameinfo((struct sockaddr *)&p->prefix,
123178064Sume		    p->prefix.sin6_len, namebuf, sizeof(namebuf),
123278064Sume		    NULL, 0, niflags) != 0)
123378064Sume			strlcpy(namebuf, "?", sizeof(namebuf));
123478064Sume		printf("%s/%d if=%s\n", namebuf, p->prefixlen,
1235121156Sume		    if_indextoname(p->if_index, ifix_buf));
123678064Sume
123778064Sume		gettimeofday(&time, 0);
123878064Sume		/*
123978064Sume		 * meaning of fields, especially flags, is very different
124078064Sume		 * by origin.  notify the difference to the users.
124178064Sume		 */
124278064Sume		printf("flags=%s%s%s%s%s",
1243121156Sume		    p->raflags.onlink ? "L" : "",
1244121156Sume		    p->raflags.autonomous ? "A" : "",
1245121156Sume		    (p->flags & NDPRF_ONLINK) != 0 ? "O" : "",
1246121156Sume		    (p->flags & NDPRF_DETACHED) != 0 ? "D" : "",
124778064Sume#ifdef NDPRF_HOME
1248121156Sume		    (p->flags & NDPRF_HOME) != 0 ? "H" : ""
124978064Sume#else
1250121156Sume		    ""
125178064Sume#endif
1252121156Sume		    );
125378064Sume		if (p->vltime == ND6_INFINITE_LIFETIME)
125478064Sume			printf(" vltime=infinity");
125578064Sume		else
1256122615Sume			printf(" vltime=%lu", (unsigned long)p->vltime);
125778064Sume		if (p->pltime == ND6_INFINITE_LIFETIME)
125878064Sume			printf(", pltime=infinity");
125978064Sume		else
1260122615Sume			printf(", pltime=%lu", (unsigned long)p->pltime);
126178064Sume		if (p->expire == 0)
126278064Sume			printf(", expire=Never");
126378064Sume		else if (p->expire >= time.tv_sec)
126478064Sume			printf(", expire=%s",
1265121156Sume			    sec2str(p->expire - time.tv_sec));
126678064Sume		else
126778064Sume			printf(", expired");
126878064Sume		printf(", ref=%d", p->refcnt);
126978064Sume		printf("\n");
127078064Sume		/*
127178064Sume		 * "advertising router" list is meaningful only if the prefix
127278064Sume		 * information is from RA.
127378064Sume		 */
127478064Sume		if (p->advrtrs) {
127578064Sume			int j;
127678064Sume			struct sockaddr_in6 *sin6;
127778064Sume
1278122615Sume			sin6 = advrtr;
127978064Sume			printf("  advertised by\n");
128078064Sume			for (j = 0; j < p->advrtrs; j++) {
128178064Sume				struct in6_nbrinfo *nbi;
128278064Sume
128378064Sume				if (getnameinfo((struct sockaddr *)sin6,
128478064Sume				    sin6->sin6_len, namebuf, sizeof(namebuf),
128578064Sume				    NULL, 0, ninflags) != 0)
128678064Sume					strlcpy(namebuf, "?", sizeof(namebuf));
128778064Sume				printf("    %s", namebuf);
128878064Sume
1289121156Sume				nbi = getnbrinfo(&sin6->sin6_addr,
1290121156Sume				    p->if_index, 0);
129178064Sume				if (nbi) {
1292121156Sume					switch (nbi->state) {
129378064Sume					case ND6_LLINFO_REACHABLE:
129478064Sume					case ND6_LLINFO_STALE:
129578064Sume					case ND6_LLINFO_DELAY:
129678064Sume					case ND6_LLINFO_PROBE:
129778064Sume						printf(" (reachable)\n");
129878064Sume						break;
129978064Sume					default:
130078064Sume						printf(" (unreachable)\n");
130178064Sume					}
130278064Sume				} else
130378064Sume					printf(" (no neighbor state)\n");
130478064Sume				sin6++;
130578064Sume			}
130678064Sume		} else
130778064Sume			printf("  No advertising router\n");
130878064Sume	}
130978064Sume	free(buf);
131078064Sume#else
131155505Sshin	struct in6_prlist pr;
131255505Sshin	int s, i;
131355505Sshin	struct timeval time;
131455505Sshin
131555505Sshin	gettimeofday(&time, 0);
131655505Sshin
131755505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1318121156Sume		err(1, "socket");
1319121156Sume		/* NOTREACHED */
132055505Sshin	}
132155505Sshin	bzero(&pr, sizeof(pr));
1322121156Sume	strlcpy(pr.ifname, "lo0", sizeof(pr.ifname)); /* dummy */
132355505Sshin	if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) {
1324121156Sume		err(1, "ioctl(SIOCGPRLST_IN6)");
1325121156Sume		/* NOTREACHED */
1326121156Sume	}
132762590Sitojun#define PR pr.prefix[i]
132855505Sshin	for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) {
132978064Sume		struct sockaddr_in6 p6;
133078064Sume		char namebuf[NI_MAXHOST];
133178064Sume		int niflags;
133278064Sume
133378064Sume#ifdef NDPRF_ONLINK
133478064Sume		p6 = PR.prefix;
133578064Sume#else
133678064Sume		memset(&p6, 0, sizeof(p6));
133778064Sume		p6.sin6_family = AF_INET6;
133878064Sume		p6.sin6_len = sizeof(p6);
133978064Sume		p6.sin6_addr = PR.prefix;
134078064Sume#endif
134178064Sume
134278064Sume		/*
134378064Sume		 * copy link index to sin6_scope_id field.
134478064Sume		 * XXX: KAME specific.
134578064Sume		 */
134678064Sume		if (IN6_IS_ADDR_LINKLOCAL(&p6.sin6_addr)) {
134778064Sume			u_int16_t linkid;
134878064Sume
134978064Sume			memcpy(&linkid, &p6.sin6_addr.s6_addr[2],
1350121156Sume			    sizeof(linkid));
135178064Sume			linkid = ntohs(linkid);
135278064Sume			p6.sin6_scope_id = linkid;
135378064Sume			p6.sin6_addr.s6_addr[2] = 0;
135478064Sume			p6.sin6_addr.s6_addr[3] = 0;
135578064Sume		}
135678064Sume
135778064Sume		niflags = NI_NUMERICHOST;
135878064Sume		if (getnameinfo((struct sockaddr *)&p6,
1359121156Sume		    sizeof(p6), namebuf, sizeof(namebuf),
1360121156Sume		    NULL, 0, niflags)) {
136178064Sume			warnx("getnameinfo failed");
136278064Sume			continue;
136378064Sume		}
136478064Sume		printf("%s/%d if=%s\n", namebuf, PR.prefixlen,
1365121156Sume		    if_indextoname(PR.if_index, ifix_buf));
136678064Sume
136755505Sshin		gettimeofday(&time, 0);
136862590Sitojun		/*
136962590Sitojun		 * meaning of fields, especially flags, is very different
137062590Sitojun		 * by origin.  notify the difference to the users.
137162590Sitojun		 */
137278064Sume#if 0
137378064Sume		printf("  %s",
1374121156Sume		    PR.origin == PR_ORIG_RA ? "" : "advertise: ");
137578064Sume#endif
137678064Sume#ifdef NDPRF_ONLINK
137778064Sume		printf("flags=%s%s%s%s%s",
1378121156Sume		    PR.raflags.onlink ? "L" : "",
1379121156Sume		    PR.raflags.autonomous ? "A" : "",
1380121156Sume		    (PR.flags & NDPRF_ONLINK) != 0 ? "O" : "",
1381121156Sume		    (PR.flags & NDPRF_DETACHED) != 0 ? "D" : "",
138278064Sume#ifdef NDPRF_HOME
1383121156Sume		    (PR.flags & NDPRF_HOME) != 0 ? "H" : ""
138478064Sume#else
1385121156Sume		    ""
138678064Sume#endif
1387121156Sume		    );
138878064Sume#else
138962590Sitojun		printf("flags=%s%s",
1390121156Sume		    PR.raflags.onlink ? "L" : "",
1391121156Sume		    PR.raflags.autonomous ? "A" : "");
139278064Sume#endif
139355505Sshin		if (PR.vltime == ND6_INFINITE_LIFETIME)
139455505Sshin			printf(" vltime=infinity");
139555505Sshin		else
1396122615Sume			printf(" vltime=%lu", PR.vltime);
139755505Sshin		if (PR.pltime == ND6_INFINITE_LIFETIME)
139855505Sshin			printf(", pltime=infinity");
139955505Sshin		else
1400122615Sume			printf(", pltime=%lu", PR.pltime);
140155505Sshin		if (PR.expire == 0)
140262590Sitojun			printf(", expire=Never");
140355505Sshin		else if (PR.expire >= time.tv_sec)
140462590Sitojun			printf(", expire=%s",
1405121156Sume			    sec2str(PR.expire - time.tv_sec));
140655505Sshin		else
140762590Sitojun			printf(", expired");
140878064Sume#ifdef NDPRF_ONLINK
140978064Sume		printf(", ref=%d", PR.refcnt);
141078064Sume#endif
141178064Sume#if 0
141262590Sitojun		switch (PR.origin) {
141362590Sitojun		case PR_ORIG_RA:
141462590Sitojun			printf(", origin=RA");
141562590Sitojun			break;
141662590Sitojun		case PR_ORIG_RR:
141762590Sitojun			printf(", origin=RR");
141862590Sitojun			break;
141962590Sitojun		case PR_ORIG_STATIC:
142062590Sitojun			printf(", origin=static");
142162590Sitojun			break;
142262590Sitojun		case PR_ORIG_KERNEL:
142362590Sitojun			printf(", origin=kernel");
142462590Sitojun			break;
142562590Sitojun		default:
142662590Sitojun			printf(", origin=?");
142762590Sitojun			break;
142862590Sitojun		}
142978064Sume#endif
143062590Sitojun		printf("\n");
143162590Sitojun		/*
143262590Sitojun		 * "advertising router" list is meaningful only if the prefix
143362590Sitojun		 * information is from RA.
143462590Sitojun		 */
143578064Sume		if (0 &&	/* prefix origin is almost obsolted */
143678064Sume		    PR.origin != PR_ORIG_RA)
143762590Sitojun			;
143862590Sitojun		else if (PR.advrtrs) {
143955505Sshin			int j;
144055505Sshin			printf("  advertised by\n");
144155505Sshin			for (j = 0; j < PR.advrtrs; j++) {
144255505Sshin				struct sockaddr_in6 sin6;
144362590Sitojun				struct in6_nbrinfo *nbi;
144455505Sshin
144555505Sshin				bzero(&sin6, sizeof(sin6));
144655505Sshin				sin6.sin6_family = AF_INET6;
144755505Sshin				sin6.sin6_len = sizeof(sin6);
144855505Sshin				sin6.sin6_addr = PR.advrtr[j];
144962590Sitojun				sin6.sin6_scope_id = PR.if_index; /* XXX */
145055505Sshin				getnameinfo((struct sockaddr *)&sin6,
1451121156Sume				    sin6.sin6_len, host_buf,
1452121156Sume				    sizeof(host_buf), NULL, 0,
1453121156Sume				    (nflag ? NI_NUMERICHOST : 0));
145462590Sitojun				printf("    %s", host_buf);
145555505Sshin
1456121156Sume				nbi = getnbrinfo(&sin6.sin6_addr,
1457121156Sume				    PR.if_index, 0);
145862590Sitojun				if (nbi) {
1459121156Sume					switch (nbi->state) {
1460121156Sume					case ND6_LLINFO_REACHABLE:
1461121156Sume					case ND6_LLINFO_STALE:
1462121156Sume					case ND6_LLINFO_DELAY:
1463121156Sume					case ND6_LLINFO_PROBE:
146462590Sitojun						 printf(" (reachable)\n");
146562590Sitojun						 break;
1466121156Sume					default:
146762590Sitojun						 printf(" (unreachable)\n");
146862590Sitojun					}
146978064Sume				} else
147062590Sitojun					printf(" (no neighbor state)\n");
147155505Sshin			}
147255505Sshin			if (PR.advrtrs > DRLSTSIZ)
147355505Sshin				printf("    and %d routers\n",
1474121156Sume				    PR.advrtrs - DRLSTSIZ);
147562590Sitojun		} else
147655505Sshin			printf("  No advertising router\n");
147755505Sshin	}
147855505Sshin#undef PR
147955505Sshin	close(s);
148078064Sume#endif
148155505Sshin}
148255505Sshin
148355505Sshinvoid
148455505Sshinpfx_flush()
148555505Sshin{
148655505Sshin	char dummyif[IFNAMSIZ+8];
148755505Sshin	int s;
148855505Sshin
148955505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
149055505Sshin		err(1, "socket");
1491121156Sume	strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
149255505Sshin	if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0)
1493121156Sume		err(1, "ioctl(SIOCSPFXFLUSH_IN6)");
149455505Sshin}
149555505Sshin
149655505Sshinvoid
149755505Sshinrtr_flush()
149855505Sshin{
149955505Sshin	char dummyif[IFNAMSIZ+8];
150055505Sshin	int s;
150155505Sshin
150255505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
150355505Sshin		err(1, "socket");
1504121156Sume	strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
150555505Sshin	if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0)
1506121156Sume		err(1, "ioctl(SIOCSRTRFLUSH_IN6)");
150762590Sitojun
150862590Sitojun	close(s);
150955505Sshin}
151055505Sshin
151155505Sshinvoid
151255505Sshinharmonize_rtr()
151355505Sshin{
151455505Sshin	char dummyif[IFNAMSIZ+8];
151555505Sshin	int s;
151655505Sshin
151762590Sitojun	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
151862590Sitojun		err(1, "socket");
1519121156Sume	strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
152062590Sitojun	if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0)
1521121156Sume		err(1, "ioctl(SIOCSNDFLUSH_IN6)");
152262590Sitojun
152362590Sitojun	close(s);
152455505Sshin}
152555505Sshin
152662590Sitojun#ifdef SIOCSDEFIFACE_IN6	/* XXX: check SIOCGDEFIFACE_IN6 as well? */
152762590Sitojunstatic void
152862590Sitojunsetdefif(ifname)
152962590Sitojun	char *ifname;
153062590Sitojun{
153162590Sitojun	struct in6_ndifreq ndifreq;
153262590Sitojun	unsigned int ifindex;
153362590Sitojun
153462590Sitojun	if (strcasecmp(ifname, "delete") == 0)
153562590Sitojun		ifindex = 0;
153662590Sitojun	else {
153762590Sitojun		if ((ifindex = if_nametoindex(ifname)) == 0)
153862590Sitojun			err(1, "failed to resolve i/f index for %s", ifname);
153962590Sitojun	}
154062590Sitojun
154162590Sitojun	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
154262590Sitojun		err(1, "socket");
154362590Sitojun
1544121156Sume	strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */
154562590Sitojun	ndifreq.ifindex = ifindex;
154662590Sitojun
154762590Sitojun	if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1548121156Sume		err(1, "ioctl(SIOCSDEFIFACE_IN6)");
154962590Sitojun
155062590Sitojun	close(s);
155162590Sitojun}
155262590Sitojun
155362590Sitojunstatic void
155462590Sitojungetdefif()
155562590Sitojun{
155662590Sitojun	struct in6_ndifreq ndifreq;
155762590Sitojun	char ifname[IFNAMSIZ+8];
155862590Sitojun
155962590Sitojun	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
156062590Sitojun		err(1, "socket");
156162590Sitojun
156262590Sitojun	memset(&ndifreq, 0, sizeof(ndifreq));
1563121156Sume	strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */
156462590Sitojun
156562590Sitojun	if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1566121156Sume		err(1, "ioctl(SIOCGDEFIFACE_IN6)");
156762590Sitojun
156862590Sitojun	if (ndifreq.ifindex == 0)
156962590Sitojun		printf("No default interface.\n");
157062590Sitojun	else {
157162590Sitojun		if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL)
157262590Sitojun			err(1, "failed to resolve ifname for index %lu",
157362590Sitojun			    ndifreq.ifindex);
157462590Sitojun		printf("ND default interface = %s\n", ifname);
157562590Sitojun	}
157662590Sitojun
157762590Sitojun	close(s);
157862590Sitojun}
157962590Sitojun#endif
158062590Sitojun
158155505Sshinstatic char *
158255505Sshinsec2str(total)
158355505Sshin	time_t total;
158455505Sshin{
158555505Sshin	static char result[256];
158655505Sshin	int days, hours, mins, secs;
158755505Sshin	int first = 1;
158855505Sshin	char *p = result;
1589121156Sume	char *ep = &result[sizeof(result)];
1590121156Sume	int n;
159155505Sshin
159255505Sshin	days = total / 3600 / 24;
159355505Sshin	hours = (total / 3600) % 24;
159455505Sshin	mins = (total / 60) % 60;
159555505Sshin	secs = total % 60;
159655505Sshin
159755505Sshin	if (days) {
159855505Sshin		first = 0;
1599121156Sume		n = snprintf(p, ep - p, "%dd", days);
1600121156Sume		if (n < 0 || n >= ep - p)
1601121156Sume			return "?";
1602121156Sume		p += n;
160355505Sshin	}
160455505Sshin	if (!first || hours) {
160555505Sshin		first = 0;
1606121156Sume		n = snprintf(p, ep - p, "%dh", hours);
1607121156Sume		if (n < 0 || n >= ep - p)
1608121156Sume			return "?";
1609121156Sume		p += n;
161055505Sshin	}
161155505Sshin	if (!first || mins) {
161255505Sshin		first = 0;
1613121156Sume		n = snprintf(p, ep - p, "%dm", mins);
1614121156Sume		if (n < 0 || n >= ep - p)
1615121156Sume			return "?";
1616121156Sume		p += n;
161755505Sshin	}
1618121156Sume	snprintf(p, ep - p, "%ds", secs);
161955505Sshin
162055505Sshin	return(result);
162155505Sshin}
162255505Sshin
162355505Sshin/*
162455505Sshin * Print the timestamp
162555505Sshin * from tcpdump/util.c
162655505Sshin */
162755505Sshinstatic void
162855505Sshints_print(tvp)
162955505Sshin	const struct timeval *tvp;
163055505Sshin{
163155505Sshin	int s;
163255505Sshin
163355505Sshin	/* Default */
163455505Sshin	s = (tvp->tv_sec + thiszone) % 86400;
163555505Sshin	(void)printf("%02d:%02d:%02d.%06u ",
163655505Sshin	    s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec);
163755505Sshin}
1638186119Sqingli
1639186119Sqingli#undef NEXTADDR
1640