ndp.c revision 253970
162590Sitojun/*	$FreeBSD: head/usr.sbin/ndp/ndp.c 253970 2013-08-05 20:13:02Z hrs $	*/
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>
8278064Sume#include <sys/queue.h>
8355505Sshin
8455505Sshin#include <net/if.h>
8555505Sshin#include <net/if_var.h>
8655505Sshin#include <net/if_dl.h>
8755505Sshin#include <net/if_types.h>
8855505Sshin#include <net/route.h>
8955505Sshin
9055505Sshin#include <netinet/in.h>
9155505Sshin#include <netinet/if_ether.h>
9255505Sshin
9355505Sshin#include <netinet/icmp6.h>
9455505Sshin#include <netinet6/in6_var.h>
9555505Sshin#include <netinet6/nd6.h>
9655505Sshin
9755505Sshin#include <arpa/inet.h>
9855505Sshin
9955505Sshin#include <netdb.h>
10055505Sshin#include <errno.h>
10155505Sshin#include <nlist.h>
10255505Sshin#include <stdio.h>
10355505Sshin#include <string.h>
10455505Sshin#include <paths.h>
10555505Sshin#include <err.h>
10655505Sshin#include <stdlib.h>
107253970Shrs#include <time.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;
128253970Shrsstatic struct timespec ts, ts0;
12955505Sshin
13062590Sitojunchar ntop_buf[INET6_ADDRSTRLEN];	/* inet_ntop() */
13162590Sitojunchar host_buf[NI_MAXHOST];		/* getnameinfo() */
13262590Sitojunchar ifix_buf[IFNAMSIZ];		/* if_indextoname() */
13355505Sshin
134173412Skevloint main(int, char **);
135173412Skevloint file(char *);
136173412Skevlovoid getsocket(void);
137173412Skevloint set(int, char **);
138173412Skevlovoid get(char *);
139173412Skevloint delete(char *);
140173412Skevlovoid dump(struct in6_addr *, int);
141173412Skevlostatic struct in6_nbrinfo *getnbrinfo(struct in6_addr *, int, int);
142173412Skevlostatic char *ether_str(struct sockaddr_dl *);
143173412Skevloint ndp_ether_aton(char *, u_char *);
144173412Skevlovoid usage(void);
145173412Skevloint rtmsg(int);
146173412Skevlovoid ifinfo(char *, int, char **);
147173412Skevlovoid rtrlist(void);
148173412Skevlovoid plist(void);
149173412Skevlovoid pfx_flush(void);
150173412Skevlovoid rtr_flush(void);
151173412Skevlovoid harmonize_rtr(void);
15262590Sitojun#ifdef SIOCSDEFIFACE_IN6	/* XXX: check SIOCGDEFIFACE_IN6 as well? */
153173412Skevlostatic void getdefif(void);
154173412Skevlostatic void setdefif(char *);
15562590Sitojun#endif
156173412Skevlostatic char *sec2str(time_t);
157253970Shrsstatic void ts_print(const struct timespec *);
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
168253970Shrs#define	TS_SUB(tsp, usp, vsp)						\
169253970Shrs	do {								\
170253970Shrs		(vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec;		\
171253970Shrs		(vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec;	\
172253970Shrs		if ((vsp)->tv_nsec < 0) {				\
173253970Shrs			(vsp)->tv_sec--;				\
174253970Shrs			(vsp)->tv_nsec += 1000000000L;			\
175253970Shrs		}							\
176253970Shrs	} while (0)
177253970Shrs
178122615Sumeint mode = 0;
179122615Sumechar *arg = NULL;
180122615Sume
18155505Sshinint
18255505Sshinmain(argc, argv)
18355505Sshin	int argc;
18455505Sshin	char **argv;
18555505Sshin{
186253970Shrs	struct timespec now;
18755505Sshin	int ch;
18855505Sshin
18955505Sshin	pid = getpid();
19055505Sshin	thiszone = gmt2local(0);
191253970Shrs	clock_gettime(CLOCK_REALTIME_FAST, &now);
192253970Shrs	clock_gettime(CLOCK_MONOTONIC_FAST, &ts);
193253970Shrs	TS_SUB(&now, &ts, &ts0);
194122615Sume	while ((ch = getopt(argc, argv, "acd:f:Ii:nprstA:HPR")) != -1)
195121156Sume		switch (ch) {
19655505Sshin		case 'a':
19755505Sshin		case 'c':
198122615Sume		case 'p':
199122615Sume		case 'r':
200122615Sume		case 'H':
201122615Sume		case 'P':
202122615Sume		case 'R':
203122615Sume		case 's':
204122615Sume		case 'I':
205122615Sume			if (mode) {
206122615Sume				usage();
207122615Sume				/*NOTREACHED*/
208122615Sume			}
209122615Sume			mode = ch;
210122615Sume			arg = NULL;
21155505Sshin			break;
21255505Sshin		case 'd':
213122615Sume		case 'f':
21455505Sshin		case 'i' :
215122615Sume			if (mode) {
21655505Sshin				usage();
217122615Sume				/*NOTREACHED*/
218122615Sume			}
219122615Sume			mode = ch;
220122615Sume			arg = optarg;
221122615Sume			break;
22255505Sshin		case 'n':
22355505Sshin			nflag = 1;
22455505Sshin			break;
22555505Sshin		case 't':
22655505Sshin			tflag = 1;
22755505Sshin			break;
22855505Sshin		case 'A':
229122615Sume			if (mode) {
230122615Sume				usage();
231122615Sume				/*NOTREACHED*/
232122615Sume			}
233122615Sume			mode = 'a';
23455505Sshin			repeat = atoi(optarg);
235122615Sume			if (repeat < 0) {
23655505Sshin				usage();
237122615Sume				/*NOTREACHED*/
238122615Sume			}
23955505Sshin			break;
24055505Sshin		default:
24155505Sshin			usage();
24255505Sshin		}
24355505Sshin
24455505Sshin	argc -= optind;
24555505Sshin	argv += optind;
24655505Sshin
247122615Sume	switch (mode) {
248122615Sume	case 'a':
249122615Sume	case 'c':
250122615Sume		if (argc != 0) {
25155505Sshin			usage();
252122615Sume			/*NOTREACHED*/
253122615Sume		}
254122615Sume		dump(0, mode == 'c');
255122615Sume		break;
256122615Sume	case 'd':
257122615Sume		if (argc != 0) {
258122615Sume			usage();
259122615Sume			/*NOTREACHED*/
260122615Sume		}
261122615Sume		delete(arg);
262122615Sume		break;
263122615Sume	case 'I':
264122615Sume#ifdef SIOCSDEFIFACE_IN6	/* XXX: check SIOCGDEFIFACE_IN6 as well? */
265122615Sume		if (argc > 1) {
266122615Sume			usage();
267122615Sume			/*NOTREACHED*/
268122615Sume		} else if (argc == 1) {
269122615Sume			if (strcmp(*argv, "delete") == 0 ||
270122615Sume			    if_nametoindex(*argv))
271122615Sume				setdefif(*argv);
272122615Sume			else
273122615Sume				errx(1, "invalid interface %s", *argv);
274122615Sume		}
275122615Sume		getdefif(); /* always call it to print the result */
276122615Sume		break;
277122615Sume#else
278122615Sume		errx(1, "not supported yet");
279122615Sume		/*NOTREACHED*/
280122615Sume#endif
281122615Sume	case 'p':
282122615Sume		if (argc != 0) {
283122615Sume			usage();
284122615Sume			/*NOTREACHED*/
285122615Sume		}
28655505Sshin		plist();
287122615Sume		break;
288122615Sume	case 'i':
289122615Sume		ifinfo(arg, argc, argv);
290122615Sume		break;
291122615Sume	case 'r':
292122615Sume		if (argc != 0) {
293122615Sume			usage();
294122615Sume			/*NOTREACHED*/
295122615Sume		}
29655505Sshin		rtrlist();
297122615Sume		break;
298122615Sume	case 's':
29955505Sshin		if (argc < 2 || argc > 4)
30055505Sshin			usage();
30155505Sshin		exit(set(argc, argv) ? 1 : 0);
302122615Sume	case 'H':
303122615Sume		if (argc != 0) {
304122615Sume			usage();
305122615Sume			/*NOTREACHED*/
306122615Sume		}
30755505Sshin		harmonize_rtr();
308122615Sume		break;
309122615Sume	case 'P':
310122615Sume		if (argc != 0) {
311122615Sume			usage();
312122615Sume			/*NOTREACHED*/
313122615Sume		}
31455505Sshin		pfx_flush();
315122615Sume		break;
316122615Sume	case 'R':
317122615Sume		if (argc != 0) {
318122615Sume			usage();
319122615Sume			/*NOTREACHED*/
320122615Sume		}
32155505Sshin		rtr_flush();
322122615Sume		break;
323122615Sume	case 0:
324122615Sume		if (argc != 1) {
325122615Sume			usage();
326122615Sume			/*NOTREACHED*/
327122615Sume		}
328122615Sume		get(argv[0]);
329122615Sume		break;
33055505Sshin	}
33155505Sshin	exit(0);
33255505Sshin}
33355505Sshin
33455505Sshin/*
33555505Sshin * Process a file to set standard ndp entries
33655505Sshin */
33755505Sshinint
33855505Sshinfile(name)
33955505Sshin	char *name;
34055505Sshin{
34155505Sshin	FILE *fp;
34255505Sshin	int i, retval;
34355505Sshin	char line[100], arg[5][50], *args[5];
34455505Sshin
34555505Sshin	if ((fp = fopen(name, "r")) == NULL) {
34655505Sshin		fprintf(stderr, "ndp: cannot open %s\n", name);
34755505Sshin		exit(1);
34855505Sshin	}
34955505Sshin	args[0] = &arg[0][0];
35055505Sshin	args[1] = &arg[1][0];
35155505Sshin	args[2] = &arg[2][0];
35255505Sshin	args[3] = &arg[3][0];
35355505Sshin	args[4] = &arg[4][0];
35455505Sshin	retval = 0;
355167260Skevlo	while (fgets(line, sizeof(line), fp) != NULL) {
356122615Sume		i = sscanf(line, "%49s %49s %49s %49s %49s",
357122615Sume		    arg[0], arg[1], arg[2], arg[3], arg[4]);
35855505Sshin		if (i < 2) {
35955505Sshin			fprintf(stderr, "ndp: bad line: %s\n", line);
36055505Sshin			retval = 1;
36155505Sshin			continue;
36255505Sshin		}
36355505Sshin		if (set(i, args))
36455505Sshin			retval = 1;
36555505Sshin	}
36655505Sshin	fclose(fp);
36755505Sshin	return (retval);
36855505Sshin}
36955505Sshin
37055505Sshinvoid
37155505Sshingetsocket()
37255505Sshin{
37355505Sshin	if (s < 0) {
37455505Sshin		s = socket(PF_ROUTE, SOCK_RAW, 0);
37555505Sshin		if (s < 0) {
376121156Sume			err(1, "socket");
377121156Sume			/* NOTREACHED */
37855505Sshin		}
37955505Sshin	}
38055505Sshin}
38155505Sshin
38262590Sitojunstruct	sockaddr_in6 so_mask = {sizeof(so_mask), AF_INET6 };
38355505Sshinstruct	sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET6 }, sin_m;
38455505Sshinstruct	sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m;
385253970Shrsstatic time_t expire_time;
386253970Shrsstatic int flags, found_entry;
38755505Sshinstruct	{
38855505Sshin	struct	rt_msghdr m_rtm;
38955505Sshin	char	m_space[512];
39055505Sshin}	m_rtmsg;
39155505Sshin
39255505Sshin/*
39355505Sshin * Set an individual neighbor cache entry
39455505Sshin */
39555505Sshinint
39655505Sshinset(argc, argv)
39755505Sshin	int argc;
39855505Sshin	char **argv;
39955505Sshin{
40055505Sshin	register struct sockaddr_in6 *sin = &sin_m;
40155505Sshin	register struct sockaddr_dl *sdl;
40255505Sshin	register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
40355505Sshin	struct addrinfo hints, *res;
40455505Sshin	int gai_error;
40555505Sshin	u_char *ea;
40655505Sshin	char *host = argv[0], *eaddr = argv[1];
40755505Sshin
40855505Sshin	getsocket();
40955505Sshin	argc -= 2;
41055505Sshin	argv += 2;
41155505Sshin	sdl_m = blank_sdl;
41255505Sshin	sin_m = blank_sin;
41355505Sshin
41455505Sshin	bzero(&hints, sizeof(hints));
41555505Sshin	hints.ai_family = AF_INET6;
41655505Sshin	gai_error = getaddrinfo(host, NULL, &hints, &res);
41755505Sshin	if (gai_error) {
41855505Sshin		fprintf(stderr, "ndp: %s: %s\n", host,
41955505Sshin			gai_strerror(gai_error));
42055505Sshin		return 1;
42155505Sshin	}
42255505Sshin	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
423243903Shrs	sin->sin6_scope_id =
424243903Shrs	    ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
42555505Sshin	ea = (u_char *)LLADDR(&sdl_m);
42655505Sshin	if (ndp_ether_aton(eaddr, ea) == 0)
42755505Sshin		sdl_m.sdl_alen = 6;
42855505Sshin	flags = expire_time = 0;
42955505Sshin	while (argc-- > 0) {
43055505Sshin		if (strncmp(argv[0], "temp", 4) == 0) {
431253970Shrs			struct timespec now;
432121156Sume
433253970Shrs			clock_gettime(CLOCK_MONOTONIC_FAST, &now);
434253970Shrs			expire_time = now.tv_sec + 20 * 60;
43562590Sitojun		} else if (strncmp(argv[0], "proxy", 5) == 0)
43662590Sitojun			flags |= RTF_ANNOUNCE;
43755505Sshin		argv++;
43855505Sshin	}
43955505Sshin	if (rtmsg(RTM_GET) < 0) {
440121156Sume		errx(1, "RTM_GET(%s) failed", host);
441121156Sume		/* NOTREACHED */
44255505Sshin	}
44355505Sshin	sin = (struct sockaddr_in6 *)(rtm + 1);
44455505Sshin	sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
44555505Sshin	if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
44655505Sshin		if (sdl->sdl_family == AF_LINK &&
447122615Sume		    !(rtm->rtm_flags & RTF_GATEWAY)) {
448122615Sume			switch (sdl->sdl_type) {
449122615Sume			case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
450122615Sume			case IFT_ISO88024: case IFT_ISO88025:
451210936Sjhb			case IFT_L2VLAN: case IFT_BRIDGE:
452122615Sume				goto overwrite;
453122615Sume			}
45455505Sshin		}
45562590Sitojun		fprintf(stderr, "set: cannot configure a new entry\n");
45662590Sitojun		return 1;
45755505Sshin	}
45862590Sitojun
45955505Sshinoverwrite:
46055505Sshin	if (sdl->sdl_family != AF_LINK) {
46155505Sshin		printf("cannot intuit interface index and type for %s\n", host);
46255505Sshin		return (1);
46355505Sshin	}
46455505Sshin	sdl_m.sdl_type = sdl->sdl_type;
46555505Sshin	sdl_m.sdl_index = sdl->sdl_index;
46655505Sshin	return (rtmsg(RTM_ADD));
46755505Sshin}
46855505Sshin
46955505Sshin/*
47055505Sshin * Display an individual neighbor cache entry
47155505Sshin */
47255505Sshinvoid
47355505Sshinget(host)
47455505Sshin	char *host;
47555505Sshin{
47655505Sshin	struct sockaddr_in6 *sin = &sin_m;
47755505Sshin	struct addrinfo hints, *res;
47855505Sshin	int gai_error;
47955505Sshin
48055505Sshin	sin_m = blank_sin;
48155505Sshin	bzero(&hints, sizeof(hints));
48255505Sshin	hints.ai_family = AF_INET6;
48355505Sshin	gai_error = getaddrinfo(host, NULL, &hints, &res);
48455505Sshin	if (gai_error) {
48555505Sshin		fprintf(stderr, "ndp: %s: %s\n", host,
486121156Sume		    gai_strerror(gai_error));
48755505Sshin		return;
48855505Sshin	}
48955505Sshin	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
490122615Sume	dump(&sin->sin6_addr, 0);
49155505Sshin	if (found_entry == 0) {
49255505Sshin		getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
493121156Sume		    sizeof(host_buf), NULL ,0,
494121156Sume		    (nflag ? NI_NUMERICHOST : 0));
49555505Sshin		printf("%s (%s) -- no entry\n", host, host_buf);
49655505Sshin		exit(1);
49755505Sshin	}
49855505Sshin}
49955505Sshin
50055505Sshin/*
50155505Sshin * Delete a neighbor cache entry
50255505Sshin */
50355505Sshinint
50455505Sshindelete(host)
50555505Sshin	char *host;
50655505Sshin{
50755505Sshin	struct sockaddr_in6 *sin = &sin_m;
50855505Sshin	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
509186119Sqingli	register char *cp = m_rtmsg.m_space;
51055505Sshin	struct sockaddr_dl *sdl;
51155505Sshin	struct addrinfo hints, *res;
51255505Sshin	int gai_error;
51355505Sshin
51455505Sshin	getsocket();
51555505Sshin	sin_m = blank_sin;
51655505Sshin
51755505Sshin	bzero(&hints, sizeof(hints));
51855505Sshin	hints.ai_family = AF_INET6;
51955505Sshin	gai_error = getaddrinfo(host, NULL, &hints, &res);
52055505Sshin	if (gai_error) {
52155505Sshin		fprintf(stderr, "ndp: %s: %s\n", host,
522121156Sume		    gai_strerror(gai_error));
52355505Sshin		return 1;
52455505Sshin	}
52555505Sshin	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
526243903Shrs	sin->sin6_scope_id =
527243903Shrs	    ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
52855505Sshin	if (rtmsg(RTM_GET) < 0) {
529121156Sume		errx(1, "RTM_GET(%s) failed", host);
530121156Sume		/* NOTREACHED */
53155505Sshin	}
53255505Sshin	sin = (struct sockaddr_in6 *)(rtm + 1);
53355505Sshin	sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
53455505Sshin	if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
53555505Sshin		if (sdl->sdl_family == AF_LINK &&
53662590Sitojun		    !(rtm->rtm_flags & RTF_GATEWAY)) {
53778064Sume			goto delete;
53855505Sshin		}
53962590Sitojun		fprintf(stderr, "delete: cannot delete non-NDP entry\n");
54062590Sitojun		return 1;
54155505Sshin	}
54262590Sitojun
54355505Sshindelete:
54455505Sshin	if (sdl->sdl_family != AF_LINK) {
54555505Sshin		printf("cannot locate %s\n", host);
54655505Sshin		return (1);
54755505Sshin	}
548186119Sqingli        /*
549186119Sqingli         * need to reinit the field because it has rt_key
550186119Sqingli         * but we want the actual address
551186119Sqingli         */
552186119Sqingli	NEXTADDR(RTA_DST, sin_m);
553186500Sqingli	rtm->rtm_flags |= RTF_LLDATA;
55455505Sshin	if (rtmsg(RTM_DELETE) == 0) {
555243903Shrs		getnameinfo((struct sockaddr *)sin,
556243903Shrs		    sin->sin6_len, host_buf,
557121156Sume		    sizeof(host_buf), NULL, 0,
558121156Sume		    (nflag ? NI_NUMERICHOST : 0));
55955505Sshin		printf("%s (%s) deleted\n", host, host_buf);
56055505Sshin	}
56155505Sshin
56255505Sshin	return 0;
56355505Sshin}
56455505Sshin
565122615Sume#define W_ADDR	36
56678064Sume#define W_LL	17
56778064Sume#define W_IF	6
56878064Sume
56955505Sshin/*
57055505Sshin * Dump the entire neighbor cache
57155505Sshin */
57255505Sshinvoid
573122615Sumedump(addr, cflag)
57455505Sshin	struct in6_addr *addr;
575122615Sume	int cflag;
57655505Sshin{
57755505Sshin	int mib[6];
57855505Sshin	size_t needed;
57962590Sitojun	char *lim, *buf, *next;
58055505Sshin	struct rt_msghdr *rtm;
58155505Sshin	struct sockaddr_in6 *sin;
58255505Sshin	struct sockaddr_dl *sdl;
58355505Sshin	extern int h_errno;
58455505Sshin	struct in6_nbrinfo *nbi;
585253970Shrs	struct timespec now;
58655505Sshin	int addrwidth;
58778064Sume	int llwidth;
58878064Sume	int ifwidth;
58962590Sitojun	char flgbuf[8];
59078064Sume	char *ifname;
59155505Sshin
59255505Sshin	/* Print header */
59366865Ssumikawa	if (!tflag && !cflag)
594122615Sume		printf("%-*.*s %-*.*s %*.*s %-9.9s %1s %5s\n",
59578064Sume		    W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address",
596122615Sume		    W_IF, W_IF, "Netif", "Expire", "S", "Flags");
59755505Sshin
59855505Sshinagain:;
59955505Sshin	mib[0] = CTL_NET;
60055505Sshin	mib[1] = PF_ROUTE;
60155505Sshin	mib[2] = 0;
60255505Sshin	mib[3] = AF_INET6;
60355505Sshin	mib[4] = NET_RT_FLAGS;
604186119Sqingli#ifdef RTF_LLINFO
60555505Sshin	mib[5] = RTF_LLINFO;
606186119Sqingli#else
607186119Sqingli	mib[5] = 0;
608186119Sqingli#endif
60955505Sshin	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
61055505Sshin		err(1, "sysctl(PF_ROUTE estimate)");
61155505Sshin	if (needed > 0) {
61255505Sshin		if ((buf = malloc(needed)) == NULL)
613121156Sume			err(1, "malloc");
61455505Sshin		if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
61555505Sshin			err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
61655505Sshin		lim = buf + needed;
61755505Sshin	} else
61855505Sshin		buf = lim = NULL;
61955505Sshin
62055505Sshin	for (next = buf; next && next < lim; next += rtm->rtm_msglen) {
62155505Sshin		int isrouter = 0, prbs = 0;
62255505Sshin
62355505Sshin		rtm = (struct rt_msghdr *)next;
62455505Sshin		sin = (struct sockaddr_in6 *)(rtm + 1);
62555505Sshin		sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len));
62678064Sume
62778064Sume		/*
62878064Sume		 * Some OSes can produce a route that has the LINK flag but
62978064Sume		 * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD
63078064Sume		 * and BSD/OS, where xx is not the interface identifier on
63178064Sume		 * lo0).  Such routes entry would annoy getnbrinfo() below,
63278064Sume		 * so we skip them.
63378064Sume		 * XXX: such routes should have the GATEWAY flag, not the
634121156Sume		 * LINK flag.  However, there is rotten routing software
63578064Sume		 * that advertises all routes that have the GATEWAY flag.
63678064Sume		 * Thus, KAME kernel intentionally does not set the LINK flag.
63778064Sume		 * What is to be fixed is not ndp, but such routing software
63878064Sume		 * (and the kernel workaround)...
63978064Sume		 */
64078064Sume		if (sdl->sdl_family != AF_LINK)
64178064Sume			continue;
64278064Sume
643122615Sume		if (!(rtm->rtm_flags & RTF_HOST))
644122615Sume			continue;
645122615Sume
64655505Sshin		if (addr) {
64755505Sshin			if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr))
64855505Sshin				continue;
64955505Sshin			found_entry = 1;
65055505Sshin		} else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
65155505Sshin			continue;
65255505Sshin		if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) ||
65355505Sshin		    IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) {
65455505Sshin			/* XXX: should scope id be filled in the kernel? */
65555505Sshin			if (sin->sin6_scope_id == 0)
65655505Sshin				sin->sin6_scope_id = sdl->sdl_index;
65755505Sshin		}
65855505Sshin		getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
659121156Sume		    sizeof(host_buf), NULL, 0, (nflag ? NI_NUMERICHOST : 0));
660122615Sume		if (cflag) {
66181366Ssumikawa#ifdef RTF_WASCLONED
66281366Ssumikawa			if (rtm->rtm_flags & RTF_WASCLONED)
66381366Ssumikawa				delete(host_buf);
664122615Sume#elif defined(RTF_CLONED)
665122615Sume			if (rtm->rtm_flags & RTF_CLONED)
666122615Sume				delete(host_buf);
66781366Ssumikawa#else
66866865Ssumikawa			delete(host_buf);
66981366Ssumikawa#endif
67066865Ssumikawa			continue;
67166865Ssumikawa		}
672253970Shrs		clock_gettime(CLOCK_MONOTONIC_FAST, &now);
67355505Sshin		if (tflag)
674253970Shrs			ts_print(&now);
67555505Sshin
67678064Sume		addrwidth = strlen(host_buf);
67778064Sume		if (addrwidth < W_ADDR)
67878064Sume			addrwidth = W_ADDR;
67978064Sume		llwidth = strlen(ether_str(sdl));
68078064Sume		if (W_ADDR + W_LL - addrwidth > llwidth)
68178064Sume			llwidth = W_ADDR + W_LL - addrwidth;
68278064Sume		ifname = if_indextoname(sdl->sdl_index, ifix_buf);
68378064Sume		if (!ifname)
68478064Sume			ifname = "?";
68578064Sume		ifwidth = strlen(ifname);
68678064Sume		if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth)
68778064Sume			ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth;
68855505Sshin
68978064Sume		printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf,
69078064Sume		    llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname);
69155505Sshin
69255505Sshin		/* Print neighbor discovery specific informations */
69362590Sitojun		nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1);
69455505Sshin		if (nbi) {
695253970Shrs			if (nbi->expire > now.tv_sec) {
69655505Sshin				printf(" %-9.9s",
697253970Shrs				    sec2str(nbi->expire - now.tv_sec));
69878064Sume			} else if (nbi->expire == 0)
69955505Sshin				printf(" %-9.9s", "permanent");
70055505Sshin			else
70155505Sshin				printf(" %-9.9s", "expired");
70255505Sshin
703121156Sume			switch (nbi->state) {
704121156Sume			case ND6_LLINFO_NOSTATE:
70555505Sshin				 printf(" N");
70655505Sshin				 break;
70778064Sume#ifdef ND6_LLINFO_WAITDELETE
708121156Sume			case ND6_LLINFO_WAITDELETE:
70955505Sshin				 printf(" W");
71055505Sshin				 break;
71178064Sume#endif
712121156Sume			case ND6_LLINFO_INCOMPLETE:
71355505Sshin				 printf(" I");
71455505Sshin				 break;
715121156Sume			case ND6_LLINFO_REACHABLE:
71655505Sshin				 printf(" R");
71755505Sshin				 break;
718121156Sume			case ND6_LLINFO_STALE:
71955505Sshin				 printf(" S");
72055505Sshin				 break;
721121156Sume			case ND6_LLINFO_DELAY:
72255505Sshin				 printf(" D");
72355505Sshin				 break;
724121156Sume			case ND6_LLINFO_PROBE:
72555505Sshin				 printf(" P");
72655505Sshin				 break;
727121156Sume			default:
72855505Sshin				 printf(" ?");
72955505Sshin				 break;
73055505Sshin			}
73155505Sshin
73255505Sshin			isrouter = nbi->isrouter;
73355505Sshin			prbs = nbi->asked;
73478064Sume		} else {
73555505Sshin			warnx("failed to get neighbor information");
73655505Sshin			printf("  ");
73755505Sshin		}
73855505Sshin
73962590Sitojun		/*
74062590Sitojun		 * other flags. R: router, P: proxy, W: ??
74162590Sitojun		 */
74262590Sitojun		if ((rtm->rtm_addrs & RTA_NETMASK) == 0) {
74362590Sitojun			snprintf(flgbuf, sizeof(flgbuf), "%s%s",
744121156Sume			    isrouter ? "R" : "",
745121156Sume			    (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
74662590Sitojun		} else {
74762590Sitojun			sin = (struct sockaddr_in6 *)
748121156Sume			    (sdl->sdl_len + (char *)sdl);
749122615Sume#if 0	/* W and P are mystery even for us */
75062590Sitojun			snprintf(flgbuf, sizeof(flgbuf), "%s%s%s%s",
751121156Sume			    isrouter ? "R" : "",
752121156Sume			    !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr) ? "P" : "",
753121156Sume			    (sin->sin6_len != sizeof(struct sockaddr_in6)) ? "W" : "",
754121156Sume			    (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
755122615Sume#else
756122615Sume			snprintf(flgbuf, sizeof(flgbuf), "%s%s",
757122615Sume			    isrouter ? "R" : "",
758122615Sume			    (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
759122615Sume#endif
76055505Sshin		}
761122615Sume		printf(" %s", flgbuf);
76255505Sshin
76355505Sshin		if (prbs)
764122615Sume			printf(" %d", prbs);
76555505Sshin
76655505Sshin		printf("\n");
76755505Sshin	}
76878064Sume	if (buf != NULL)
76978064Sume		free(buf);
77055505Sshin
77155505Sshin	if (repeat) {
77255505Sshin		printf("\n");
773125675Ssumikawa		fflush(stdout);
77455505Sshin		sleep(repeat);
77555505Sshin		goto again;
77655505Sshin	}
77755505Sshin}
77855505Sshin
77955505Sshinstatic struct in6_nbrinfo *
78062590Sitojungetnbrinfo(addr, ifindex, warning)
78155505Sshin	struct in6_addr *addr;
78255505Sshin	int ifindex;
78362590Sitojun	int warning;
78455505Sshin{
78555505Sshin	static struct in6_nbrinfo nbi;
78655505Sshin	int s;
78755505Sshin
78855505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
78955505Sshin		err(1, "socket");
79055505Sshin
79155505Sshin	bzero(&nbi, sizeof(nbi));
79255505Sshin	if_indextoname(ifindex, nbi.ifname);
79355505Sshin	nbi.addr = *addr;
79455505Sshin	if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) {
79562590Sitojun		if (warning)
79662590Sitojun			warn("ioctl(SIOCGNBRINFO_IN6)");
79755505Sshin		close(s);
79855505Sshin		return(NULL);
79955505Sshin	}
80055505Sshin
80155505Sshin	close(s);
80255505Sshin	return(&nbi);
80355505Sshin}
80455505Sshin
80555505Sshinstatic char *
806217140Sdelphijether_str(struct sockaddr_dl *sdl)
80755505Sshin{
808121156Sume	static char hbuf[NI_MAXHOST];
809219819Sjeff	char *cp;
81055505Sshin
811219819Sjeff	if (sdl->sdl_alen == ETHER_ADDR_LEN) {
812217140Sdelphij		strlcpy(hbuf, ether_ntoa((struct ether_addr *)LLADDR(sdl)),
813217140Sdelphij		    sizeof(hbuf));
814219819Sjeff	} else if (sdl->sdl_alen) {
815219819Sjeff		int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;
816219819Sjeff		snprintf(hbuf, sizeof(hbuf), "%s", link_ntoa(sdl) + n);
817219819Sjeff	} else
818121156Sume		snprintf(hbuf, sizeof(hbuf), "(incomplete)");
81955505Sshin
820121156Sume	return(hbuf);
82155505Sshin}
82255505Sshin
82355505Sshinint
82455505Sshinndp_ether_aton(a, n)
82555505Sshin	char *a;
82655505Sshin	u_char *n;
82755505Sshin{
82855505Sshin	int i, o[6];
82955505Sshin
83055505Sshin	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
831121156Sume	    &o[3], &o[4], &o[5]);
83255505Sshin	if (i != 6) {
83355505Sshin		fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a);
83455505Sshin		return (1);
83555505Sshin	}
836121156Sume	for (i = 0; i < 6; i++)
83755505Sshin		n[i] = o[i];
83855505Sshin	return (0);
83955505Sshin}
84055505Sshin
84155505Sshinvoid
84255505Sshinusage()
84355505Sshin{
844122615Sume	printf("usage: ndp [-nt] hostname\n");
845122615Sume	printf("       ndp [-nt] -a | -c | -p | -r | -H | -P | -R\n");
84678064Sume	printf("       ndp [-nt] -A wait\n");
847122615Sume	printf("       ndp [-nt] -d hostname\n");
848122615Sume	printf("       ndp [-nt] -f filename\n");
849122615Sume	printf("       ndp [-nt] -i interface [flags...]\n");
85062590Sitojun#ifdef SIOCSDEFIFACE_IN6
851122615Sume	printf("       ndp [-nt] -I [interface|delete]\n");
85262590Sitojun#endif
853122615Sume	printf("       ndp [-nt] -s nodename etheraddr [temp] [proxy]\n");
85455505Sshin	exit(1);
85555505Sshin}
85655505Sshin
85755505Sshinint
85855505Sshinrtmsg(cmd)
85955505Sshin	int cmd;
86055505Sshin{
86155505Sshin	static int seq;
86255505Sshin	int rlen;
86355505Sshin	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
86455505Sshin	register char *cp = m_rtmsg.m_space;
86555505Sshin	register int l;
86655505Sshin
86755505Sshin	errno = 0;
86855505Sshin	if (cmd == RTM_DELETE)
86955505Sshin		goto doit;
87055505Sshin	bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
87155505Sshin	rtm->rtm_flags = flags;
87255505Sshin	rtm->rtm_version = RTM_VERSION;
87355505Sshin
87455505Sshin	switch (cmd) {
87555505Sshin	default:
87655505Sshin		fprintf(stderr, "ndp: internal wrong cmd\n");
87755505Sshin		exit(1);
87855505Sshin	case RTM_ADD:
87955505Sshin		rtm->rtm_addrs |= RTA_GATEWAY;
880122615Sume		if (expire_time) {
881122615Sume			rtm->rtm_rmx.rmx_expire = expire_time;
882122615Sume			rtm->rtm_inits = RTV_EXPIRE;
883122615Sume		}
884186500Sqingli		rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA);
885151473Ssuz#if 0 /* we don't support ipv6addr/128 type proxying */
88662590Sitojun		if (rtm->rtm_flags & RTF_ANNOUNCE) {
88762590Sitojun			rtm->rtm_flags &= ~RTF_HOST;
888124241Ssuz			rtm->rtm_addrs |= RTA_NETMASK;
88962590Sitojun		}
890151473Ssuz#endif
89155505Sshin		/* FALLTHROUGH */
89255505Sshin	case RTM_GET:
89355505Sshin		rtm->rtm_addrs |= RTA_DST;
89455505Sshin	}
89555505Sshin
89655505Sshin	NEXTADDR(RTA_DST, sin_m);
89755505Sshin	NEXTADDR(RTA_GATEWAY, sdl_m);
898151473Ssuz#if 0 /* we don't support ipv6addr/128 type proxying */
89962590Sitojun	memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr));
90055505Sshin	NEXTADDR(RTA_NETMASK, so_mask);
901151473Ssuz#endif
90255505Sshin
90355505Sshin	rtm->rtm_msglen = cp - (char *)&m_rtmsg;
90455505Sshindoit:
90555505Sshin	l = rtm->rtm_msglen;
90655505Sshin	rtm->rtm_seq = ++seq;
90755505Sshin	rtm->rtm_type = cmd;
90855505Sshin	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
90955505Sshin		if (errno != ESRCH || cmd != RTM_DELETE) {
910121156Sume			err(1, "writing to routing socket");
911121156Sume			/* NOTREACHED */
91255505Sshin		}
91355505Sshin	}
91455505Sshin	do {
91555505Sshin		l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
91655505Sshin	} while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
91755505Sshin	if (l < 0)
91855505Sshin		(void) fprintf(stderr, "ndp: read from routing socket: %s\n",
91955505Sshin		    strerror(errno));
92055505Sshin	return (0);
92155505Sshin}
92255505Sshin
92355505Sshinvoid
924122615Sumeifinfo(ifname, argc, argv)
925122615Sume	char *ifname;
92662590Sitojun	int argc;
92762590Sitojun	char **argv;
92855505Sshin{
92955505Sshin	struct in6_ndireq nd;
93062590Sitojun	int i, s;
93162590Sitojun	u_int32_t newflags;
93278064Sume#ifdef IPV6CTL_USETEMPADDR
93378064Sume	u_int8_t nullbuf[8];
93478064Sume#endif
93555505Sshin
93655505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
937121156Sume		err(1, "socket");
938121156Sume		/* NOTREACHED */
93955505Sshin	}
94055505Sshin	bzero(&nd, sizeof(nd));
941121156Sume	strlcpy(nd.ifname, ifname, sizeof(nd.ifname));
94255505Sshin	if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
943121156Sume		err(1, "ioctl(SIOCGIFINFO_IN6)");
944121156Sume		/* NOTREACHED */
945122615Sume	}
94662590Sitojun#define ND nd.ndi
94762590Sitojun	newflags = ND.flags;
948122615Sume	for (i = 0; i < argc; i++) {
94962590Sitojun		int clear = 0;
95062590Sitojun		char *cp = argv[i];
95162590Sitojun
95262590Sitojun		if (*cp == '-') {
95362590Sitojun			clear = 1;
95462590Sitojun			cp++;
95562590Sitojun		}
95662590Sitojun
95762590Sitojun#define SETFLAG(s, f) \
95862590Sitojun	do {\
95962590Sitojun		if (strcmp(cp, (s)) == 0) {\
96062590Sitojun			if (clear)\
96162590Sitojun				newflags &= ~(f);\
96262590Sitojun			else\
96362590Sitojun				newflags |= (f);\
96462590Sitojun		}\
96562590Sitojun	} while (0)
966151468Ssuz/*
967151468Ssuz * XXX: this macro is not 100% correct, in that it matches "nud" against
968151468Ssuz *      "nudbogus".  But we just let it go since this is minor.
969151468Ssuz */
970151468Ssuz#define SETVALUE(f, v) \
971151468Ssuz	do { \
972151468Ssuz		char *valptr; \
973151468Ssuz		unsigned long newval; \
974151468Ssuz		v = 0; /* unspecified */ \
975151468Ssuz		if (strncmp(cp, f, strlen(f)) == 0) { \
976151468Ssuz			valptr = strchr(cp, '='); \
977151468Ssuz			if (valptr == NULL) \
978151468Ssuz				err(1, "syntax error in %s field", (f)); \
979151468Ssuz			errno = 0; \
980151468Ssuz			newval = strtoul(++valptr, NULL, 0); \
981151468Ssuz			if (errno) \
982151468Ssuz				err(1, "syntax error in %s's value", (f)); \
983151468Ssuz			v = newval; \
984151468Ssuz		} \
985151468Ssuz	} while (0)
986151468Ssuz
987151474Ssuz		SETFLAG("disabled", ND6_IFF_IFDISABLED);
98862590Sitojun		SETFLAG("nud", ND6_IFF_PERFORMNUD);
989118498Sume#ifdef ND6_IFF_ACCEPT_RTADV
990118498Sume		SETFLAG("accept_rtadv", ND6_IFF_ACCEPT_RTADV);
991118498Sume#endif
992197138Shrs#ifdef ND6_IFF_AUTO_LINKLOCAL
993197138Shrs		SETFLAG("auto_linklocal", ND6_IFF_AUTO_LINKLOCAL);
994197138Shrs#endif
995245230Sume#ifdef ND6_IFF_NO_PREFER_IFACE
996245230Sume		SETFLAG("no_prefer_iface", ND6_IFF_NO_PREFER_IFACE);
997245230Sume#endif
998151468Ssuz		SETVALUE("basereachable", ND.basereachable);
999151468Ssuz		SETVALUE("retrans", ND.retrans);
1000151468Ssuz		SETVALUE("curhlim", ND.chlim);
100162590Sitojun
100262590Sitojun		ND.flags = newflags;
1003151468Ssuz		if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd) < 0) {
1004151468Ssuz			err(1, "ioctl(SIOCSIFINFO_IN6)");
1005121156Sume			/* NOTREACHED */
100662590Sitojun		}
100762590Sitojun#undef SETFLAG
1008151468Ssuz#undef SETVALUE
100962590Sitojun	}
101062590Sitojun
1011121162Sume	if (!ND.initialized) {
1012121162Sume		errx(1, "%s: not initialized yet", ifname);
1013121162Sume		/* NOTREACHED */
1014121162Sume	}
1015121162Sume
1016151468Ssuz	if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
1017151468Ssuz		err(1, "ioctl(SIOCGIFINFO_IN6)");
1018151468Ssuz		/* NOTREACHED */
1019151468Ssuz	}
102055505Sshin	printf("linkmtu=%d", ND.linkmtu);
1021121471Sume	printf(", maxmtu=%d", ND.maxmtu);
102255505Sshin	printf(", curhlim=%d", ND.chlim);
102355505Sshin	printf(", basereachable=%ds%dms",
1024121156Sume	    ND.basereachable / 1000, ND.basereachable % 1000);
102555505Sshin	printf(", reachable=%ds", ND.reachable);
102662590Sitojun	printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000);
102778064Sume#ifdef IPV6CTL_USETEMPADDR
102878064Sume	memset(nullbuf, 0, sizeof(nullbuf));
102978064Sume	if (memcmp(nullbuf, ND.randomid, sizeof(nullbuf)) != 0) {
103078064Sume		int j;
103178064Sume		u_int8_t *rbuf;
103278064Sume
103378064Sume		for (i = 0; i < 3; i++) {
1034121156Sume			switch (i) {
103578064Sume			case 0:
103678064Sume				printf("\nRandom seed(0): ");
103778064Sume				rbuf = ND.randomseed0;
103878064Sume				break;
103978064Sume			case 1:
104078064Sume				printf("\nRandom seed(1): ");
104178064Sume				rbuf = ND.randomseed1;
104278064Sume				break;
104378064Sume			case 2:
104478064Sume				printf("\nRandom ID:      ");
104578064Sume				rbuf = ND.randomid;
104678064Sume				break;
1047151472Ssuz			default:
1048151472Ssuz				errx(1, "impossible case for tempaddr display");
104978064Sume			}
105078064Sume			for (j = 0; j < 8; j++)
105178064Sume				printf("%02x", rbuf[j]);
105278064Sume		}
105378064Sume	}
105478064Sume#endif
105562590Sitojun	if (ND.flags) {
105662590Sitojun		printf("\nFlags: ");
1057151474Ssuz#ifdef ND6_IFF_IFDISABLED
1058151474Ssuz		if ((ND.flags & ND6_IFF_IFDISABLED))
1059151474Ssuz			printf("disabled ");
1060151474Ssuz#endif
1061118498Sume		if ((ND.flags & ND6_IFF_PERFORMNUD))
1062118498Sume			printf("nud ");
1063118498Sume#ifdef ND6_IFF_ACCEPT_RTADV
1064118498Sume		if ((ND.flags & ND6_IFF_ACCEPT_RTADV))
1065118498Sume			printf("accept_rtadv ");
1066118498Sume#endif
1067197138Shrs#ifdef ND6_IFF_AUTO_LINKLOCAL
1068197138Shrs		if ((ND.flags & ND6_IFF_AUTO_LINKLOCAL))
1069197138Shrs			printf("auto_linklocal ");
1070197138Shrs#endif
1071245230Sume#ifdef ND6_IFF_NO_PREFER_IFACE
1072245230Sume		if ((ND.flags & ND6_IFF_NO_PREFER_IFACE))
1073245230Sume			printf("no_prefer_iface ");
1074245230Sume#endif
1075122615Sume	}
107662590Sitojun	putc('\n', stdout);
107755505Sshin#undef ND
1078121156Sume
107955505Sshin	close(s);
108055505Sshin}
108155505Sshin
108278064Sume#ifndef ND_RA_FLAG_RTPREF_MASK	/* XXX: just for compilation on *BSD release */
108378064Sume#define ND_RA_FLAG_RTPREF_MASK	0x18 /* 00011000 */
108478064Sume#endif
108578064Sume
108655505Sshinvoid
108755505Sshinrtrlist()
108855505Sshin{
108978064Sume#ifdef ICMPV6CTL_ND6_DRLIST
109078064Sume	int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST };
109178064Sume	char *buf;
109278064Sume	struct in6_defrouter *p, *ep;
109378064Sume	size_t l;
1094253970Shrs	struct timespec now;
109578064Sume
109678064Sume	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
109778064Sume		err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
109878064Sume		/*NOTREACHED*/
109978064Sume	}
1100151472Ssuz	if (l == 0)
1101151472Ssuz		return;
110278064Sume	buf = malloc(l);
110378064Sume	if (!buf) {
1104121156Sume		err(1, "malloc");
110578064Sume		/*NOTREACHED*/
110678064Sume	}
110778064Sume	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
110878064Sume		err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
110978064Sume		/*NOTREACHED*/
111078064Sume	}
111178064Sume
111278064Sume	ep = (struct in6_defrouter *)(buf + l);
111378064Sume	for (p = (struct in6_defrouter *)buf; p < ep; p++) {
111478064Sume		int rtpref;
111578064Sume
111678064Sume		if (getnameinfo((struct sockaddr *)&p->rtaddr,
111778064Sume		    p->rtaddr.sin6_len, host_buf, sizeof(host_buf), NULL, 0,
1118121156Sume		    (nflag ? NI_NUMERICHOST : 0)) != 0)
111978064Sume			strlcpy(host_buf, "?", sizeof(host_buf));
1120121156Sume
112178064Sume		printf("%s if=%s", host_buf,
1122121156Sume		    if_indextoname(p->if_index, ifix_buf));
112378064Sume		printf(", flags=%s%s",
1124121156Sume		    p->flags & ND_RA_FLAG_MANAGED ? "M" : "",
1125121156Sume		    p->flags & ND_RA_FLAG_OTHER   ? "O" : "");
112678064Sume		rtpref = ((p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff;
112778064Sume		printf(", pref=%s", rtpref_str[rtpref]);
1128121156Sume
1129253970Shrs		clock_gettime(CLOCK_MONOTONIC_FAST, &now);
113078064Sume		if (p->expire == 0)
113178064Sume			printf(", expire=Never\n");
113278064Sume		else
113378064Sume			printf(", expire=%s\n",
1134253970Shrs			    sec2str(p->expire - now.tv_sec));
113578064Sume	}
113678064Sume	free(buf);
113778064Sume#else
113855505Sshin	struct in6_drlist dr;
113955505Sshin	int s, i;
1140253970Shrs	struct timespec now;
114155505Sshin
114255505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1143121156Sume		err(1, "socket");
1144121156Sume		/* NOTREACHED */
114555505Sshin	}
114655505Sshin	bzero(&dr, sizeof(dr));
1147121156Sume	strlcpy(dr.ifname, "lo0", sizeof(dr.ifname)); /* dummy */
114855505Sshin	if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) {
1149121156Sume		err(1, "ioctl(SIOCGDRLST_IN6)");
1150121156Sume		/* NOTREACHED */
1151121156Sume	}
115262590Sitojun#define DR dr.defrouter[i]
115378064Sume	for (i = 0 ; DR.if_index && i < DRLSTSIZ ; i++) {
115455505Sshin		struct sockaddr_in6 sin6;
115555505Sshin
115655505Sshin		bzero(&sin6, sizeof(sin6));
115755505Sshin		sin6.sin6_family = AF_INET6;
115855505Sshin		sin6.sin6_len = sizeof(sin6);
115955505Sshin		sin6.sin6_addr = DR.rtaddr;
116055505Sshin		getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf,
1161121156Sume		    sizeof(host_buf), NULL, 0,
1162121156Sume		    (nflag ? NI_NUMERICHOST : 0));
1163121156Sume
116455505Sshin		printf("%s if=%s", host_buf,
1165121156Sume		    if_indextoname(DR.if_index, ifix_buf));
116655505Sshin		printf(", flags=%s%s",
1167121156Sume		    DR.flags & ND_RA_FLAG_MANAGED ? "M" : "",
1168121156Sume		    DR.flags & ND_RA_FLAG_OTHER   ? "O" : "");
1169253970Shrs		clock_gettime(CLOCK_MONOTONIC_FAST, &now);
117055505Sshin		if (DR.expire == 0)
117155505Sshin			printf(", expire=Never\n");
117255505Sshin		else
117355505Sshin			printf(", expire=%s\n",
1174253970Shrs			    sec2str(DR.expire - now.tv_sec));
117555505Sshin	}
117655505Sshin#undef DR
117755505Sshin	close(s);
117878064Sume#endif
117955505Sshin}
118055505Sshin
118155505Sshinvoid
118255505Sshinplist()
118355505Sshin{
118478064Sume#ifdef ICMPV6CTL_ND6_PRLIST
118578064Sume	int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST };
118678064Sume	char *buf;
118778064Sume	struct in6_prefix *p, *ep, *n;
118878064Sume	struct sockaddr_in6 *advrtr;
118978064Sume	size_t l;
1190253970Shrs	struct timespec now;
119178064Sume	const int niflags = NI_NUMERICHOST;
119278064Sume	int ninflags = nflag ? NI_NUMERICHOST : 0;
119378064Sume	char namebuf[NI_MAXHOST];
119478064Sume
119578064Sume	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
119678064Sume		err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
119778064Sume		/*NOTREACHED*/
119878064Sume	}
119978064Sume	buf = malloc(l);
120078064Sume	if (!buf) {
1201121156Sume		err(1, "malloc");
120278064Sume		/*NOTREACHED*/
120378064Sume	}
120478064Sume	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
120578064Sume		err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
120678064Sume		/*NOTREACHED*/
120778064Sume	}
120878064Sume
120978064Sume	ep = (struct in6_prefix *)(buf + l);
121078064Sume	for (p = (struct in6_prefix *)buf; p < ep; p = n) {
121178064Sume		advrtr = (struct sockaddr_in6 *)(p + 1);
121278064Sume		n = (struct in6_prefix *)&advrtr[p->advrtrs];
121378064Sume
121478064Sume		if (getnameinfo((struct sockaddr *)&p->prefix,
121578064Sume		    p->prefix.sin6_len, namebuf, sizeof(namebuf),
121678064Sume		    NULL, 0, niflags) != 0)
121778064Sume			strlcpy(namebuf, "?", sizeof(namebuf));
121878064Sume		printf("%s/%d if=%s\n", namebuf, p->prefixlen,
1219121156Sume		    if_indextoname(p->if_index, ifix_buf));
122078064Sume
1221253970Shrs		clock_gettime(CLOCK_MONOTONIC_FAST, &now);
122278064Sume		/*
122378064Sume		 * meaning of fields, especially flags, is very different
122478064Sume		 * by origin.  notify the difference to the users.
122578064Sume		 */
122678064Sume		printf("flags=%s%s%s%s%s",
1227121156Sume		    p->raflags.onlink ? "L" : "",
1228121156Sume		    p->raflags.autonomous ? "A" : "",
1229121156Sume		    (p->flags & NDPRF_ONLINK) != 0 ? "O" : "",
1230121156Sume		    (p->flags & NDPRF_DETACHED) != 0 ? "D" : "",
123178064Sume#ifdef NDPRF_HOME
1232121156Sume		    (p->flags & NDPRF_HOME) != 0 ? "H" : ""
123378064Sume#else
1234121156Sume		    ""
123578064Sume#endif
1236121156Sume		    );
123778064Sume		if (p->vltime == ND6_INFINITE_LIFETIME)
123878064Sume			printf(" vltime=infinity");
123978064Sume		else
1240122615Sume			printf(" vltime=%lu", (unsigned long)p->vltime);
124178064Sume		if (p->pltime == ND6_INFINITE_LIFETIME)
124278064Sume			printf(", pltime=infinity");
124378064Sume		else
1244122615Sume			printf(", pltime=%lu", (unsigned long)p->pltime);
124578064Sume		if (p->expire == 0)
124678064Sume			printf(", expire=Never");
1247253970Shrs		else if (p->expire >= now.tv_sec)
124878064Sume			printf(", expire=%s",
1249253970Shrs			    sec2str(p->expire - now.tv_sec));
125078064Sume		else
125178064Sume			printf(", expired");
125278064Sume		printf(", ref=%d", p->refcnt);
125378064Sume		printf("\n");
125478064Sume		/*
125578064Sume		 * "advertising router" list is meaningful only if the prefix
125678064Sume		 * information is from RA.
125778064Sume		 */
125878064Sume		if (p->advrtrs) {
125978064Sume			int j;
126078064Sume			struct sockaddr_in6 *sin6;
126178064Sume
1262122615Sume			sin6 = advrtr;
126378064Sume			printf("  advertised by\n");
126478064Sume			for (j = 0; j < p->advrtrs; j++) {
126578064Sume				struct in6_nbrinfo *nbi;
126678064Sume
126778064Sume				if (getnameinfo((struct sockaddr *)sin6,
126878064Sume				    sin6->sin6_len, namebuf, sizeof(namebuf),
126978064Sume				    NULL, 0, ninflags) != 0)
127078064Sume					strlcpy(namebuf, "?", sizeof(namebuf));
127178064Sume				printf("    %s", namebuf);
127278064Sume
1273121156Sume				nbi = getnbrinfo(&sin6->sin6_addr,
1274121156Sume				    p->if_index, 0);
127578064Sume				if (nbi) {
1276121156Sume					switch (nbi->state) {
127778064Sume					case ND6_LLINFO_REACHABLE:
127878064Sume					case ND6_LLINFO_STALE:
127978064Sume					case ND6_LLINFO_DELAY:
128078064Sume					case ND6_LLINFO_PROBE:
128178064Sume						printf(" (reachable)\n");
128278064Sume						break;
128378064Sume					default:
128478064Sume						printf(" (unreachable)\n");
128578064Sume					}
128678064Sume				} else
128778064Sume					printf(" (no neighbor state)\n");
128878064Sume				sin6++;
128978064Sume			}
129078064Sume		} else
129178064Sume			printf("  No advertising router\n");
129278064Sume	}
129378064Sume	free(buf);
129478064Sume#else
129555505Sshin	struct in6_prlist pr;
129655505Sshin	int s, i;
1297253970Shrs	struct timespec now;
129855505Sshin
1299253970Shrs	clock_gettime(CLOCK_MONOTONIC_FAST, &now);
130055505Sshin
130155505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1302121156Sume		err(1, "socket");
1303121156Sume		/* NOTREACHED */
130455505Sshin	}
130555505Sshin	bzero(&pr, sizeof(pr));
1306121156Sume	strlcpy(pr.ifname, "lo0", sizeof(pr.ifname)); /* dummy */
130755505Sshin	if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) {
1308121156Sume		err(1, "ioctl(SIOCGPRLST_IN6)");
1309121156Sume		/* NOTREACHED */
1310121156Sume	}
131162590Sitojun#define PR pr.prefix[i]
131255505Sshin	for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) {
131378064Sume		struct sockaddr_in6 p6;
131478064Sume		char namebuf[NI_MAXHOST];
131578064Sume		int niflags;
131678064Sume
131778064Sume#ifdef NDPRF_ONLINK
131878064Sume		p6 = PR.prefix;
131978064Sume#else
132078064Sume		memset(&p6, 0, sizeof(p6));
132178064Sume		p6.sin6_family = AF_INET6;
132278064Sume		p6.sin6_len = sizeof(p6);
132378064Sume		p6.sin6_addr = PR.prefix;
132478064Sume#endif
132578064Sume		niflags = NI_NUMERICHOST;
132678064Sume		if (getnameinfo((struct sockaddr *)&p6,
1327121156Sume		    sizeof(p6), namebuf, sizeof(namebuf),
1328121156Sume		    NULL, 0, niflags)) {
132978064Sume			warnx("getnameinfo failed");
133078064Sume			continue;
133178064Sume		}
133278064Sume		printf("%s/%d if=%s\n", namebuf, PR.prefixlen,
1333121156Sume		    if_indextoname(PR.if_index, ifix_buf));
133478064Sume
1335253970Shrs		clock_gettime(CLOCK_MONOTONIC_FAST, &now);
133662590Sitojun		/*
133762590Sitojun		 * meaning of fields, especially flags, is very different
133862590Sitojun		 * by origin.  notify the difference to the users.
133962590Sitojun		 */
134078064Sume#if 0
134178064Sume		printf("  %s",
1342121156Sume		    PR.origin == PR_ORIG_RA ? "" : "advertise: ");
134378064Sume#endif
134478064Sume#ifdef NDPRF_ONLINK
134578064Sume		printf("flags=%s%s%s%s%s",
1346121156Sume		    PR.raflags.onlink ? "L" : "",
1347121156Sume		    PR.raflags.autonomous ? "A" : "",
1348121156Sume		    (PR.flags & NDPRF_ONLINK) != 0 ? "O" : "",
1349121156Sume		    (PR.flags & NDPRF_DETACHED) != 0 ? "D" : "",
135078064Sume#ifdef NDPRF_HOME
1351121156Sume		    (PR.flags & NDPRF_HOME) != 0 ? "H" : ""
135278064Sume#else
1353121156Sume		    ""
135478064Sume#endif
1355121156Sume		    );
135678064Sume#else
135762590Sitojun		printf("flags=%s%s",
1358121156Sume		    PR.raflags.onlink ? "L" : "",
1359121156Sume		    PR.raflags.autonomous ? "A" : "");
136078064Sume#endif
136155505Sshin		if (PR.vltime == ND6_INFINITE_LIFETIME)
136255505Sshin			printf(" vltime=infinity");
136355505Sshin		else
1364122615Sume			printf(" vltime=%lu", PR.vltime);
136555505Sshin		if (PR.pltime == ND6_INFINITE_LIFETIME)
136655505Sshin			printf(", pltime=infinity");
136755505Sshin		else
1368122615Sume			printf(", pltime=%lu", PR.pltime);
136955505Sshin		if (PR.expire == 0)
137062590Sitojun			printf(", expire=Never");
1371253970Shrs		else if (PR.expire >= now.tv_sec)
137262590Sitojun			printf(", expire=%s",
1373253970Shrs			    sec2str(PR.expire - now.tv_sec));
137455505Sshin		else
137562590Sitojun			printf(", expired");
137678064Sume#ifdef NDPRF_ONLINK
137778064Sume		printf(", ref=%d", PR.refcnt);
137878064Sume#endif
137978064Sume#if 0
138062590Sitojun		switch (PR.origin) {
138162590Sitojun		case PR_ORIG_RA:
138262590Sitojun			printf(", origin=RA");
138362590Sitojun			break;
138462590Sitojun		case PR_ORIG_RR:
138562590Sitojun			printf(", origin=RR");
138662590Sitojun			break;
138762590Sitojun		case PR_ORIG_STATIC:
138862590Sitojun			printf(", origin=static");
138962590Sitojun			break;
139062590Sitojun		case PR_ORIG_KERNEL:
139162590Sitojun			printf(", origin=kernel");
139262590Sitojun			break;
139362590Sitojun		default:
139462590Sitojun			printf(", origin=?");
139562590Sitojun			break;
139662590Sitojun		}
139778064Sume#endif
139862590Sitojun		printf("\n");
139962590Sitojun		/*
140062590Sitojun		 * "advertising router" list is meaningful only if the prefix
140162590Sitojun		 * information is from RA.
140262590Sitojun		 */
140378064Sume		if (0 &&	/* prefix origin is almost obsolted */
140478064Sume		    PR.origin != PR_ORIG_RA)
140562590Sitojun			;
140662590Sitojun		else if (PR.advrtrs) {
140755505Sshin			int j;
140855505Sshin			printf("  advertised by\n");
140955505Sshin			for (j = 0; j < PR.advrtrs; j++) {
141055505Sshin				struct sockaddr_in6 sin6;
141162590Sitojun				struct in6_nbrinfo *nbi;
141255505Sshin
141355505Sshin				bzero(&sin6, sizeof(sin6));
141455505Sshin				sin6.sin6_family = AF_INET6;
141555505Sshin				sin6.sin6_len = sizeof(sin6);
141655505Sshin				sin6.sin6_addr = PR.advrtr[j];
141762590Sitojun				sin6.sin6_scope_id = PR.if_index; /* XXX */
141855505Sshin				getnameinfo((struct sockaddr *)&sin6,
1419121156Sume				    sin6.sin6_len, host_buf,
1420121156Sume				    sizeof(host_buf), NULL, 0,
1421121156Sume				    (nflag ? NI_NUMERICHOST : 0));
142262590Sitojun				printf("    %s", host_buf);
142355505Sshin
1424121156Sume				nbi = getnbrinfo(&sin6.sin6_addr,
1425121156Sume				    PR.if_index, 0);
142662590Sitojun				if (nbi) {
1427121156Sume					switch (nbi->state) {
1428121156Sume					case ND6_LLINFO_REACHABLE:
1429121156Sume					case ND6_LLINFO_STALE:
1430121156Sume					case ND6_LLINFO_DELAY:
1431121156Sume					case ND6_LLINFO_PROBE:
143262590Sitojun						 printf(" (reachable)\n");
143362590Sitojun						 break;
1434121156Sume					default:
143562590Sitojun						 printf(" (unreachable)\n");
143662590Sitojun					}
143778064Sume				} else
143862590Sitojun					printf(" (no neighbor state)\n");
143955505Sshin			}
144055505Sshin			if (PR.advrtrs > DRLSTSIZ)
144155505Sshin				printf("    and %d routers\n",
1442121156Sume				    PR.advrtrs - DRLSTSIZ);
144362590Sitojun		} else
144455505Sshin			printf("  No advertising router\n");
144555505Sshin	}
144655505Sshin#undef PR
144755505Sshin	close(s);
144878064Sume#endif
144955505Sshin}
145055505Sshin
145155505Sshinvoid
145255505Sshinpfx_flush()
145355505Sshin{
145455505Sshin	char dummyif[IFNAMSIZ+8];
145555505Sshin	int s;
145655505Sshin
145755505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
145855505Sshin		err(1, "socket");
1459121156Sume	strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
146055505Sshin	if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0)
1461121156Sume		err(1, "ioctl(SIOCSPFXFLUSH_IN6)");
146255505Sshin}
146355505Sshin
146455505Sshinvoid
146555505Sshinrtr_flush()
146655505Sshin{
146755505Sshin	char dummyif[IFNAMSIZ+8];
146855505Sshin	int s;
146955505Sshin
147055505Sshin	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
147155505Sshin		err(1, "socket");
1472121156Sume	strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
147355505Sshin	if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0)
1474121156Sume		err(1, "ioctl(SIOCSRTRFLUSH_IN6)");
147562590Sitojun
147662590Sitojun	close(s);
147755505Sshin}
147855505Sshin
147955505Sshinvoid
148055505Sshinharmonize_rtr()
148155505Sshin{
148255505Sshin	char dummyif[IFNAMSIZ+8];
148355505Sshin	int s;
148455505Sshin
148562590Sitojun	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
148662590Sitojun		err(1, "socket");
1487121156Sume	strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
148862590Sitojun	if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0)
1489121156Sume		err(1, "ioctl(SIOCSNDFLUSH_IN6)");
149062590Sitojun
149162590Sitojun	close(s);
149255505Sshin}
149355505Sshin
149462590Sitojun#ifdef SIOCSDEFIFACE_IN6	/* XXX: check SIOCGDEFIFACE_IN6 as well? */
149562590Sitojunstatic void
149662590Sitojunsetdefif(ifname)
149762590Sitojun	char *ifname;
149862590Sitojun{
149962590Sitojun	struct in6_ndifreq ndifreq;
150062590Sitojun	unsigned int ifindex;
150162590Sitojun
150262590Sitojun	if (strcasecmp(ifname, "delete") == 0)
150362590Sitojun		ifindex = 0;
150462590Sitojun	else {
150562590Sitojun		if ((ifindex = if_nametoindex(ifname)) == 0)
150662590Sitojun			err(1, "failed to resolve i/f index for %s", ifname);
150762590Sitojun	}
150862590Sitojun
150962590Sitojun	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
151062590Sitojun		err(1, "socket");
151162590Sitojun
1512121156Sume	strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */
151362590Sitojun	ndifreq.ifindex = ifindex;
151462590Sitojun
151562590Sitojun	if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1516121156Sume		err(1, "ioctl(SIOCSDEFIFACE_IN6)");
151762590Sitojun
151862590Sitojun	close(s);
151962590Sitojun}
152062590Sitojun
152162590Sitojunstatic void
152262590Sitojungetdefif()
152362590Sitojun{
152462590Sitojun	struct in6_ndifreq ndifreq;
152562590Sitojun	char ifname[IFNAMSIZ+8];
152662590Sitojun
152762590Sitojun	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
152862590Sitojun		err(1, "socket");
152962590Sitojun
153062590Sitojun	memset(&ndifreq, 0, sizeof(ndifreq));
1531121156Sume	strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */
153262590Sitojun
153362590Sitojun	if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1534121156Sume		err(1, "ioctl(SIOCGDEFIFACE_IN6)");
153562590Sitojun
153662590Sitojun	if (ndifreq.ifindex == 0)
153762590Sitojun		printf("No default interface.\n");
153862590Sitojun	else {
153962590Sitojun		if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL)
154062590Sitojun			err(1, "failed to resolve ifname for index %lu",
154162590Sitojun			    ndifreq.ifindex);
154262590Sitojun		printf("ND default interface = %s\n", ifname);
154362590Sitojun	}
154462590Sitojun
154562590Sitojun	close(s);
154662590Sitojun}
154762590Sitojun#endif
154862590Sitojun
154955505Sshinstatic char *
155055505Sshinsec2str(total)
155155505Sshin	time_t total;
155255505Sshin{
155355505Sshin	static char result[256];
155455505Sshin	int days, hours, mins, secs;
155555505Sshin	int first = 1;
155655505Sshin	char *p = result;
1557121156Sume	char *ep = &result[sizeof(result)];
1558121156Sume	int n;
155955505Sshin
156055505Sshin	days = total / 3600 / 24;
156155505Sshin	hours = (total / 3600) % 24;
156255505Sshin	mins = (total / 60) % 60;
156355505Sshin	secs = total % 60;
156455505Sshin
156555505Sshin	if (days) {
156655505Sshin		first = 0;
1567121156Sume		n = snprintf(p, ep - p, "%dd", days);
1568121156Sume		if (n < 0 || n >= ep - p)
1569121156Sume			return "?";
1570121156Sume		p += n;
157155505Sshin	}
157255505Sshin	if (!first || hours) {
157355505Sshin		first = 0;
1574121156Sume		n = snprintf(p, ep - p, "%dh", hours);
1575121156Sume		if (n < 0 || n >= ep - p)
1576121156Sume			return "?";
1577121156Sume		p += n;
157855505Sshin	}
157955505Sshin	if (!first || mins) {
158055505Sshin		first = 0;
1581121156Sume		n = snprintf(p, ep - p, "%dm", mins);
1582121156Sume		if (n < 0 || n >= ep - p)
1583121156Sume			return "?";
1584121156Sume		p += n;
158555505Sshin	}
1586121156Sume	snprintf(p, ep - p, "%ds", secs);
158755505Sshin
158855505Sshin	return(result);
158955505Sshin}
159055505Sshin
159155505Sshin/*
159255505Sshin * Print the timestamp
159355505Sshin * from tcpdump/util.c
159455505Sshin */
159555505Sshinstatic void
1596253970Shrsts_print(tsp)
1597253970Shrs	const struct timespec *tsp;
159855505Sshin{
159955505Sshin	int s;
160055505Sshin
160155505Sshin	/* Default */
1602253970Shrs	s = (tsp->tv_sec + thiszone + ts0.tv_sec) % 86400;
160355505Sshin	(void)printf("%02d:%02d:%02d.%06u ",
1604253970Shrs	    s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tsp->tv_nsec / 1000);
160555505Sshin}
1606186119Sqingli
1607186119Sqingli#undef NEXTADDR
1608