xref: /freebsd/usr.sbin/ndp/ndp.c (revision e1c7783e220b6120ddc116ff2e09f228d8475bfd)
1ccf935ddSJun-ichiro itojun Hagino /*	$FreeBSD$	*/
23174c1d4SHajimu UMEMOTO /*	$KAME: ndp.c,v 1.104 2003/06/27 07:48:39 itojun Exp $	*/
3ccf935ddSJun-ichiro itojun Hagino 
48a16b7a1SPedro F. Giffuni /*-
58a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
68a16b7a1SPedro F. Giffuni  *
79a4365d0SYoshinobu Inoue  * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
89a4365d0SYoshinobu Inoue  * All rights reserved.
99a4365d0SYoshinobu Inoue  *
109a4365d0SYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
119a4365d0SYoshinobu Inoue  * modification, are permitted provided that the following conditions
129a4365d0SYoshinobu Inoue  * are met:
139a4365d0SYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
149a4365d0SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
159a4365d0SYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
169a4365d0SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
179a4365d0SYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
189a4365d0SYoshinobu Inoue  * 3. Neither the name of the project nor the names of its contributors
199a4365d0SYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
209a4365d0SYoshinobu Inoue  *    without specific prior written permission.
219a4365d0SYoshinobu Inoue  *
229a4365d0SYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
239a4365d0SYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
249a4365d0SYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
259a4365d0SYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
269a4365d0SYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
279a4365d0SYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
289a4365d0SYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
299a4365d0SYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
309a4365d0SYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
319a4365d0SYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
329a4365d0SYoshinobu Inoue  * SUCH DAMAGE.
339a4365d0SYoshinobu Inoue  */
349a4365d0SYoshinobu Inoue /*
359a4365d0SYoshinobu Inoue  * Copyright (c) 1984, 1993
369a4365d0SYoshinobu Inoue  *	The Regents of the University of California.  All rights reserved.
379a4365d0SYoshinobu Inoue  *
389a4365d0SYoshinobu Inoue  * This code is derived from software contributed to Berkeley by
399a4365d0SYoshinobu Inoue  * Sun Microsystems, Inc.
409a4365d0SYoshinobu Inoue  *
419a4365d0SYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
429a4365d0SYoshinobu Inoue  * modification, are permitted provided that the following conditions
439a4365d0SYoshinobu Inoue  * are met:
449a4365d0SYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
459a4365d0SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
469a4365d0SYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
479a4365d0SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
489a4365d0SYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
49fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
509a4365d0SYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
519a4365d0SYoshinobu Inoue  *    without specific prior written permission.
529a4365d0SYoshinobu Inoue  *
539a4365d0SYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
549a4365d0SYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
559a4365d0SYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
569a4365d0SYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
579a4365d0SYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
589a4365d0SYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
599a4365d0SYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
609a4365d0SYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
619a4365d0SYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
629a4365d0SYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
639a4365d0SYoshinobu Inoue  * SUCH DAMAGE.
649a4365d0SYoshinobu Inoue  */
659a4365d0SYoshinobu Inoue 
669a4365d0SYoshinobu Inoue /*
679a4365d0SYoshinobu Inoue  * Based on:
689a4365d0SYoshinobu Inoue  * "@(#) Copyright (c) 1984, 1993\n\
699a4365d0SYoshinobu Inoue  *	The Regents of the University of California.  All rights reserved.\n";
709a4365d0SYoshinobu Inoue  *
719a4365d0SYoshinobu Inoue  * "@(#)arp.c	8.2 (Berkeley) 1/2/94";
729a4365d0SYoshinobu Inoue  */
739a4365d0SYoshinobu Inoue 
749a4365d0SYoshinobu Inoue /*
759a4365d0SYoshinobu Inoue  * ndp - display, set, delete and flush neighbor cache
769a4365d0SYoshinobu Inoue  */
779a4365d0SYoshinobu Inoue 
789a4365d0SYoshinobu Inoue 
799a4365d0SYoshinobu Inoue #include <sys/param.h>
809a4365d0SYoshinobu Inoue #include <sys/file.h>
819a4365d0SYoshinobu Inoue #include <sys/ioctl.h>
829a4365d0SYoshinobu Inoue #include <sys/socket.h>
839a4365d0SYoshinobu Inoue #include <sys/sysctl.h>
84ffa0165aSHiroki Sato #include <sys/time.h>
8533841545SHajimu UMEMOTO #include <sys/queue.h>
869a4365d0SYoshinobu Inoue 
879a4365d0SYoshinobu Inoue #include <net/if.h>
889a4365d0SYoshinobu Inoue #include <net/if_dl.h>
899a4365d0SYoshinobu Inoue #include <net/if_types.h>
909a4365d0SYoshinobu Inoue #include <net/route.h>
919a4365d0SYoshinobu Inoue 
929a4365d0SYoshinobu Inoue #include <netinet/in.h>
939a4365d0SYoshinobu Inoue #include <netinet/if_ether.h>
949a4365d0SYoshinobu Inoue 
959a4365d0SYoshinobu Inoue #include <netinet/icmp6.h>
969a4365d0SYoshinobu Inoue #include <netinet6/in6_var.h>
979a4365d0SYoshinobu Inoue #include <netinet6/nd6.h>
989a4365d0SYoshinobu Inoue 
999a4365d0SYoshinobu Inoue #include <arpa/inet.h>
1009a4365d0SYoshinobu Inoue 
101aa06c87eSAlexander V. Chernikov #include <ctype.h>
1029a4365d0SYoshinobu Inoue #include <netdb.h>
1039a4365d0SYoshinobu Inoue #include <errno.h>
1049a4365d0SYoshinobu Inoue #include <nlist.h>
1059a4365d0SYoshinobu Inoue #include <stdio.h>
1069a4365d0SYoshinobu Inoue #include <string.h>
1079a4365d0SYoshinobu Inoue #include <paths.h>
1089a4365d0SYoshinobu Inoue #include <err.h>
1099a4365d0SYoshinobu Inoue #include <stdlib.h>
1109a4365d0SYoshinobu Inoue #include <fcntl.h>
1119a4365d0SYoshinobu Inoue #include <unistd.h>
112*e1c7783eSAlexander V. Chernikov #include <libxo/xo.h>
1139a4365d0SYoshinobu Inoue #include "gmt2local.h"
1149a4365d0SYoshinobu Inoue 
1156e6b3f7cSQing Li #define	NEXTADDR(w, s)					\
1166e6b3f7cSQing Li 	if (rtm->rtm_addrs & (w)) {			\
117937f8ddfSRenato Botelho 		bcopy((char *)&s, cp, sizeof(s));	\
118937f8ddfSRenato Botelho 		cp += SA_SIZE(&s);			\
119937f8ddfSRenato Botelho 	}
1206e6b3f7cSQing Li 
12142f3352bSJuli Mallett static pid_t pid;
1229a4365d0SYoshinobu Inoue static int nflag;
1239a4365d0SYoshinobu Inoue static int tflag;
1249a4365d0SYoshinobu Inoue static int32_t thiszone;	/* time difference with gmt */
1259a4365d0SYoshinobu Inoue static int s = -1;
1269a4365d0SYoshinobu Inoue static int repeat = 0;
1279a4365d0SYoshinobu Inoue 
128f2203c27SHiroki Sato static char host_buf[NI_MAXHOST];	/* getnameinfo() */
129f2203c27SHiroki Sato static char ifix_buf[IFNAMSIZ];		/* if_indextoname() */
1309a4365d0SYoshinobu Inoue 
131aa06c87eSAlexander V. Chernikov static int file(char *);
132f2203c27SHiroki Sato static void getsocket(void);
133f2203c27SHiroki Sato static int set(int, char **);
134f2203c27SHiroki Sato static void get(char *);
135f2203c27SHiroki Sato static int delete(char *);
136f2203c27SHiroki Sato static void dump(struct sockaddr_in6 *, int);
137784bddbcSKevin Lo static struct in6_nbrinfo *getnbrinfo(struct in6_addr *, int, int);
138784bddbcSKevin Lo static char *ether_str(struct sockaddr_dl *);
139f2203c27SHiroki Sato static int ndp_ether_aton(char *, u_char *);
140f2203c27SHiroki Sato static void usage(void);
141f2203c27SHiroki Sato static int rtmsg(int);
142f2203c27SHiroki Sato static void ifinfo(char *, int, char **);
143f2203c27SHiroki Sato static void rtrlist(void);
144f2203c27SHiroki Sato static void plist(void);
145f2203c27SHiroki Sato static void pfx_flush(void);
146f2203c27SHiroki Sato static void rtr_flush(void);
147f2203c27SHiroki Sato static void harmonize_rtr(void);
148ccf935ddSJun-ichiro itojun Hagino #ifdef SIOCSDEFIFACE_IN6	/* XXX: check SIOCGDEFIFACE_IN6 as well? */
149784bddbcSKevin Lo static void getdefif(void);
150784bddbcSKevin Lo static void setdefif(char *);
151ccf935ddSJun-ichiro itojun Hagino #endif
152784bddbcSKevin Lo static char *sec2str(time_t);
153ffa0165aSHiroki Sato static void ts_print(const struct timeval *);
1549a4365d0SYoshinobu Inoue 
1557ae43b31SRenato Botelho static const char *rtpref_str[] = {
15633841545SHajimu UMEMOTO 	"medium",		/* 00 */
15733841545SHajimu UMEMOTO 	"high",			/* 01 */
15833841545SHajimu UMEMOTO 	"rsv",			/* 10 */
15933841545SHajimu UMEMOTO 	"low"			/* 11 */
16033841545SHajimu UMEMOTO };
1613174c1d4SHajimu UMEMOTO 
162*e1c7783eSAlexander V. Chernikov #define NDP_XO_VERSION	"1"
163*e1c7783eSAlexander V. Chernikov 
1649a4365d0SYoshinobu Inoue int
165bfc75db0SAndrey V. Elsukov main(int argc, char **argv)
1669a4365d0SYoshinobu Inoue {
167f2203c27SHiroki Sato 	int ch, mode = 0;
168f2203c27SHiroki Sato 	char *arg = NULL;
1699a4365d0SYoshinobu Inoue 
1709a4365d0SYoshinobu Inoue 	pid = getpid();
1719a4365d0SYoshinobu Inoue 	thiszone = gmt2local(0);
172*e1c7783eSAlexander V. Chernikov 
173*e1c7783eSAlexander V. Chernikov 	argc = xo_parse_args(argc, argv);
174*e1c7783eSAlexander V. Chernikov 	if (argc < 0)
175*e1c7783eSAlexander V. Chernikov 		exit(1);
176*e1c7783eSAlexander V. Chernikov 	xo_set_version(NDP_XO_VERSION);
177*e1c7783eSAlexander V. Chernikov 	xo_open_container("ndp");
178*e1c7783eSAlexander V. Chernikov 
1793174c1d4SHajimu UMEMOTO 	while ((ch = getopt(argc, argv, "acd:f:Ii:nprstA:HPR")) != -1)
180a96bd784SHajimu UMEMOTO 		switch (ch) {
1819a4365d0SYoshinobu Inoue 		case 'a':
1829a4365d0SYoshinobu Inoue 		case 'c':
1833174c1d4SHajimu UMEMOTO 		case 'p':
1843174c1d4SHajimu UMEMOTO 		case 'r':
1853174c1d4SHajimu UMEMOTO 		case 'H':
1863174c1d4SHajimu UMEMOTO 		case 'P':
1873174c1d4SHajimu UMEMOTO 		case 'R':
1883174c1d4SHajimu UMEMOTO 		case 's':
1893174c1d4SHajimu UMEMOTO 		case 'I':
1903174c1d4SHajimu UMEMOTO 			if (mode) {
1913174c1d4SHajimu UMEMOTO 				usage();
1923174c1d4SHajimu UMEMOTO 				/*NOTREACHED*/
1933174c1d4SHajimu UMEMOTO 			}
1943174c1d4SHajimu UMEMOTO 			mode = ch;
1953174c1d4SHajimu UMEMOTO 			arg = NULL;
1969a4365d0SYoshinobu Inoue 			break;
1973174c1d4SHajimu UMEMOTO 		case 'f':
198aa06c87eSAlexander V. Chernikov 			exit(file(optarg) ? 1 : 0);
19901d5742fSPeter Wemm 		case 'd':
2009a4365d0SYoshinobu Inoue 		case 'i':
2013174c1d4SHajimu UMEMOTO 			if (mode) {
2029a4365d0SYoshinobu Inoue 				usage();
2033174c1d4SHajimu UMEMOTO 				/*NOTREACHED*/
2043174c1d4SHajimu UMEMOTO 			}
2053174c1d4SHajimu UMEMOTO 			mode = ch;
2063174c1d4SHajimu UMEMOTO 			arg = optarg;
2073174c1d4SHajimu UMEMOTO 			break;
2089a4365d0SYoshinobu Inoue 		case 'n':
2099a4365d0SYoshinobu Inoue 			nflag = 1;
2109a4365d0SYoshinobu Inoue 			break;
2119a4365d0SYoshinobu Inoue 		case 't':
2129a4365d0SYoshinobu Inoue 			tflag = 1;
2139a4365d0SYoshinobu Inoue 			break;
2149a4365d0SYoshinobu Inoue 		case 'A':
2153174c1d4SHajimu UMEMOTO 			if (mode) {
2169a4365d0SYoshinobu Inoue 				usage();
2173174c1d4SHajimu UMEMOTO 				/*NOTREACHED*/
2183174c1d4SHajimu UMEMOTO 			}
2193174c1d4SHajimu UMEMOTO 			mode = 'a';
2203174c1d4SHajimu UMEMOTO 			repeat = atoi(optarg);
2213174c1d4SHajimu UMEMOTO 			if (repeat < 0) {
2223174c1d4SHajimu UMEMOTO 				usage();
2233174c1d4SHajimu UMEMOTO 				/*NOTREACHED*/
2243174c1d4SHajimu UMEMOTO 			}
2259a4365d0SYoshinobu Inoue 			break;
2269a4365d0SYoshinobu Inoue 		default:
2279a4365d0SYoshinobu Inoue 			usage();
2289a4365d0SYoshinobu Inoue 		}
2299a4365d0SYoshinobu Inoue 
2309a4365d0SYoshinobu Inoue 	argc -= optind;
2319a4365d0SYoshinobu Inoue 	argv += optind;
2329a4365d0SYoshinobu Inoue 
2333174c1d4SHajimu UMEMOTO 	switch (mode) {
2343174c1d4SHajimu UMEMOTO 	case 'a':
2353174c1d4SHajimu UMEMOTO 	case 'c':
2363174c1d4SHajimu UMEMOTO 		if (argc != 0) {
2379a4365d0SYoshinobu Inoue 			usage();
2383174c1d4SHajimu UMEMOTO 			/*NOTREACHED*/
2399a4365d0SYoshinobu Inoue 		}
2403174c1d4SHajimu UMEMOTO 		dump(0, mode == 'c');
2413174c1d4SHajimu UMEMOTO 		break;
2423174c1d4SHajimu UMEMOTO 	case 'd':
2433174c1d4SHajimu UMEMOTO 		if (argc != 0) {
2443174c1d4SHajimu UMEMOTO 			usage();
2453174c1d4SHajimu UMEMOTO 			/*NOTREACHED*/
2463174c1d4SHajimu UMEMOTO 		}
247*e1c7783eSAlexander V. Chernikov 		xo_open_list("neighbor-cache");
2483174c1d4SHajimu UMEMOTO 		delete(arg);
249*e1c7783eSAlexander V. Chernikov 		xo_close_list("neighbor-cache");
2503174c1d4SHajimu UMEMOTO 		break;
2513174c1d4SHajimu UMEMOTO 	case 'I':
2523174c1d4SHajimu UMEMOTO #ifdef SIOCSDEFIFACE_IN6	/* XXX: check SIOCGDEFIFACE_IN6 as well? */
2533174c1d4SHajimu UMEMOTO 		if (argc > 1) {
2543174c1d4SHajimu UMEMOTO 			usage();
2553174c1d4SHajimu UMEMOTO 			/*NOTREACHED*/
2563174c1d4SHajimu UMEMOTO 		} else if (argc == 1) {
2573174c1d4SHajimu UMEMOTO 			if (strcmp(*argv, "delete") == 0 ||
2583174c1d4SHajimu UMEMOTO 			    if_nametoindex(*argv))
2593174c1d4SHajimu UMEMOTO 				setdefif(*argv);
2603174c1d4SHajimu UMEMOTO 			else
261*e1c7783eSAlexander V. Chernikov 				xo_errx(1, "invalid interface %s", *argv);
2623174c1d4SHajimu UMEMOTO 		}
2633174c1d4SHajimu UMEMOTO 		getdefif(); /* always call it to print the result */
2643174c1d4SHajimu UMEMOTO 		break;
2653174c1d4SHajimu UMEMOTO #else
266*e1c7783eSAlexander V. Chernikov 		xo_errx(1, "not supported yet");
2673174c1d4SHajimu UMEMOTO 		/*NOTREACHED*/
2683174c1d4SHajimu UMEMOTO #endif
2693174c1d4SHajimu UMEMOTO 	case 'p':
2703174c1d4SHajimu UMEMOTO 		if (argc != 0) {
2713174c1d4SHajimu UMEMOTO 			usage();
2723174c1d4SHajimu UMEMOTO 			/*NOTREACHED*/
2733174c1d4SHajimu UMEMOTO 		}
2749a4365d0SYoshinobu Inoue 		plist();
2753174c1d4SHajimu UMEMOTO 		break;
2763174c1d4SHajimu UMEMOTO 	case 'i':
2773174c1d4SHajimu UMEMOTO 		ifinfo(arg, argc, argv);
2783174c1d4SHajimu UMEMOTO 		break;
2793174c1d4SHajimu UMEMOTO 	case 'r':
2803174c1d4SHajimu UMEMOTO 		if (argc != 0) {
2813174c1d4SHajimu UMEMOTO 			usage();
2823174c1d4SHajimu UMEMOTO 			/*NOTREACHED*/
2839a4365d0SYoshinobu Inoue 		}
2849a4365d0SYoshinobu Inoue 		rtrlist();
2853174c1d4SHajimu UMEMOTO 		break;
2863174c1d4SHajimu UMEMOTO 	case 's':
2879a4365d0SYoshinobu Inoue 		if (argc < 2 || argc > 4)
2889a4365d0SYoshinobu Inoue 			usage();
2899a4365d0SYoshinobu Inoue 		exit(set(argc, argv) ? 1 : 0);
2903174c1d4SHajimu UMEMOTO 	case 'H':
2913174c1d4SHajimu UMEMOTO 		if (argc != 0) {
2929a4365d0SYoshinobu Inoue 			usage();
2933174c1d4SHajimu UMEMOTO 			/*NOTREACHED*/
2943174c1d4SHajimu UMEMOTO 		}
2953174c1d4SHajimu UMEMOTO 		harmonize_rtr();
2963174c1d4SHajimu UMEMOTO 		break;
2973174c1d4SHajimu UMEMOTO 	case 'P':
2983174c1d4SHajimu UMEMOTO 		if (argc != 0) {
2993174c1d4SHajimu UMEMOTO 			usage();
3003174c1d4SHajimu UMEMOTO 			/*NOTREACHED*/
3013174c1d4SHajimu UMEMOTO 		}
3023174c1d4SHajimu UMEMOTO 		pfx_flush();
3033174c1d4SHajimu UMEMOTO 		break;
3043174c1d4SHajimu UMEMOTO 	case 'R':
3053174c1d4SHajimu UMEMOTO 		if (argc != 0) {
3063174c1d4SHajimu UMEMOTO 			usage();
3073174c1d4SHajimu UMEMOTO 			/*NOTREACHED*/
3083174c1d4SHajimu UMEMOTO 		}
3093174c1d4SHajimu UMEMOTO 		rtr_flush();
3103174c1d4SHajimu UMEMOTO 		break;
3113174c1d4SHajimu UMEMOTO 	case 0:
3123174c1d4SHajimu UMEMOTO 		if (argc != 1) {
3133174c1d4SHajimu UMEMOTO 			usage();
3143174c1d4SHajimu UMEMOTO 			/*NOTREACHED*/
3153174c1d4SHajimu UMEMOTO 		}
3169a4365d0SYoshinobu Inoue 		get(argv[0]);
3173174c1d4SHajimu UMEMOTO 		break;
3183174c1d4SHajimu UMEMOTO 	}
319*e1c7783eSAlexander V. Chernikov 	xo_close_container("ndp");
320*e1c7783eSAlexander V. Chernikov 	xo_finish();
3219a4365d0SYoshinobu Inoue 	exit(0);
3229a4365d0SYoshinobu Inoue }
3239a4365d0SYoshinobu Inoue 
3249a4365d0SYoshinobu Inoue /*
3259a4365d0SYoshinobu Inoue  * Process a file to set standard ndp entries
3269a4365d0SYoshinobu Inoue  */
327aa06c87eSAlexander V. Chernikov static int
328bfc75db0SAndrey V. Elsukov file(char *name)
3299a4365d0SYoshinobu Inoue {
3309a4365d0SYoshinobu Inoue 	FILE *fp;
3319a4365d0SYoshinobu Inoue 	int i, retval;
332aa06c87eSAlexander V. Chernikov 	char line[100], arg[5][50], *args[5], *p;
3339a4365d0SYoshinobu Inoue 
334aa06c87eSAlexander V. Chernikov 	if ((fp = fopen(name, "r")) == NULL)
335*e1c7783eSAlexander V. Chernikov 		xo_err(1, "cannot open %s", name);
3369a4365d0SYoshinobu Inoue 	args[0] = &arg[0][0];
3379a4365d0SYoshinobu Inoue 	args[1] = &arg[1][0];
3389a4365d0SYoshinobu Inoue 	args[2] = &arg[2][0];
3399a4365d0SYoshinobu Inoue 	args[3] = &arg[3][0];
3409a4365d0SYoshinobu Inoue 	args[4] = &arg[4][0];
3419a4365d0SYoshinobu Inoue 	retval = 0;
342d0691403SKevin Lo 	while (fgets(line, sizeof(line), fp) != NULL) {
343aa06c87eSAlexander V. Chernikov 		if ((p = strchr(line, '#')) != NULL)
344aa06c87eSAlexander V. Chernikov 			*p = '\0';
345aa06c87eSAlexander V. Chernikov 		for (p = line; isblank(*p); p++);
346aa06c87eSAlexander V. Chernikov 		if (*p == '\n' || *p == '\0')
347aa06c87eSAlexander V. Chernikov 			continue;
3483174c1d4SHajimu UMEMOTO 		i = sscanf(line, "%49s %49s %49s %49s %49s",
3493174c1d4SHajimu UMEMOTO 		    arg[0], arg[1], arg[2], arg[3], arg[4]);
3509a4365d0SYoshinobu Inoue 		if (i < 2) {
351*e1c7783eSAlexander V. Chernikov 			xo_warnx("bad line: %s", line);
3529a4365d0SYoshinobu Inoue 			retval = 1;
3539a4365d0SYoshinobu Inoue 			continue;
3549a4365d0SYoshinobu Inoue 		}
3559a4365d0SYoshinobu Inoue 		if (set(i, args))
3569a4365d0SYoshinobu Inoue 			retval = 1;
3579a4365d0SYoshinobu Inoue 	}
3589a4365d0SYoshinobu Inoue 	fclose(fp);
3599a4365d0SYoshinobu Inoue 	return (retval);
3609a4365d0SYoshinobu Inoue }
3619a4365d0SYoshinobu Inoue 
362f2203c27SHiroki Sato static void
3639a4365d0SYoshinobu Inoue getsocket()
3649a4365d0SYoshinobu Inoue {
3659a4365d0SYoshinobu Inoue 	if (s < 0) {
3669a4365d0SYoshinobu Inoue 		s = socket(PF_ROUTE, SOCK_RAW, 0);
3679a4365d0SYoshinobu Inoue 		if (s < 0) {
368*e1c7783eSAlexander V. Chernikov 			xo_err(1, "socket");
369a96bd784SHajimu UMEMOTO 			/* NOTREACHED */
3709a4365d0SYoshinobu Inoue 		}
3719a4365d0SYoshinobu Inoue 	}
3729a4365d0SYoshinobu Inoue }
3739a4365d0SYoshinobu Inoue 
374f2203c27SHiroki Sato static struct sockaddr_in6 so_mask = {
375f2203c27SHiroki Sato 	.sin6_len = sizeof(so_mask),
376f2203c27SHiroki Sato 	.sin6_family = AF_INET6
377f2203c27SHiroki Sato };
378f2203c27SHiroki Sato static struct sockaddr_in6 blank_sin = {
379f2203c27SHiroki Sato 	.sin6_len = sizeof(blank_sin),
380f2203c27SHiroki Sato 	.sin6_family = AF_INET6
381f2203c27SHiroki Sato };
382f2203c27SHiroki Sato static struct sockaddr_in6 sin_m;
383f2203c27SHiroki Sato static struct sockaddr_dl blank_sdl = {
384f2203c27SHiroki Sato 	.sdl_len = sizeof(blank_sdl),
385f2203c27SHiroki Sato 	.sdl_family = AF_LINK
386f2203c27SHiroki Sato };
387f2203c27SHiroki Sato static struct sockaddr_dl sdl_m;
388f2203c27SHiroki Sato static time_t expire_time;
389f2203c27SHiroki Sato static int flags, found_entry;
390f2203c27SHiroki Sato static struct {
3919a4365d0SYoshinobu Inoue 	struct	rt_msghdr m_rtm;
3929a4365d0SYoshinobu Inoue 	char	m_space[512];
3939a4365d0SYoshinobu Inoue } m_rtmsg;
3949a4365d0SYoshinobu Inoue 
3959a4365d0SYoshinobu Inoue /*
3969a4365d0SYoshinobu Inoue  * Set an individual neighbor cache entry
3979a4365d0SYoshinobu Inoue  */
398f2203c27SHiroki Sato static int
399bfc75db0SAndrey V. Elsukov set(int argc, char **argv)
4009a4365d0SYoshinobu Inoue {
4019a4365d0SYoshinobu Inoue 	register struct sockaddr_in6 *sin = &sin_m;
4029a4365d0SYoshinobu Inoue 	register struct sockaddr_dl *sdl;
4039a4365d0SYoshinobu Inoue 	register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
4049a4365d0SYoshinobu Inoue 	struct addrinfo hints, *res;
4059a4365d0SYoshinobu Inoue 	int gai_error;
4069a4365d0SYoshinobu Inoue 	u_char *ea;
4079a4365d0SYoshinobu Inoue 	char *host = argv[0], *eaddr = argv[1];
4089a4365d0SYoshinobu Inoue 
4099a4365d0SYoshinobu Inoue 	getsocket();
4109a4365d0SYoshinobu Inoue 	argc -= 2;
4119a4365d0SYoshinobu Inoue 	argv += 2;
4129a4365d0SYoshinobu Inoue 	sdl_m = blank_sdl;
4139a4365d0SYoshinobu Inoue 	sin_m = blank_sin;
4149a4365d0SYoshinobu Inoue 
4159a4365d0SYoshinobu Inoue 	bzero(&hints, sizeof(hints));
4169a4365d0SYoshinobu Inoue 	hints.ai_family = AF_INET6;
4179a4365d0SYoshinobu Inoue 	gai_error = getaddrinfo(host, NULL, &hints, &res);
4189a4365d0SYoshinobu Inoue 	if (gai_error) {
419*e1c7783eSAlexander V. Chernikov 		xo_warnx("%s: %s", host, gai_strerror(gai_error));
4209a4365d0SYoshinobu Inoue 		return 1;
4219a4365d0SYoshinobu Inoue 	}
4229a4365d0SYoshinobu Inoue 	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
4230bebb544SHiroki Sato 	sin->sin6_scope_id =
4240bebb544SHiroki Sato 	    ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
4259a4365d0SYoshinobu Inoue 	ea = (u_char *)LLADDR(&sdl_m);
4269a4365d0SYoshinobu Inoue 	if (ndp_ether_aton(eaddr, ea) == 0)
4279a4365d0SYoshinobu Inoue 		sdl_m.sdl_alen = 6;
4289a4365d0SYoshinobu Inoue 	flags = expire_time = 0;
4299a4365d0SYoshinobu Inoue 	while (argc-- > 0) {
4309a4365d0SYoshinobu Inoue 		if (strncmp(argv[0], "temp", 4) == 0) {
431ffa0165aSHiroki Sato 			struct timeval now;
432a96bd784SHajimu UMEMOTO 
433ffa0165aSHiroki Sato 			gettimeofday(&now, 0);
4347d26db17SHiroki Sato 			expire_time = now.tv_sec + 20 * 60;
435ccf935ddSJun-ichiro itojun Hagino 		} else if (strncmp(argv[0], "proxy", 5) == 0)
436ccf935ddSJun-ichiro itojun Hagino 			flags |= RTF_ANNOUNCE;
4379a4365d0SYoshinobu Inoue 		argv++;
4389a4365d0SYoshinobu Inoue 	}
4399a4365d0SYoshinobu Inoue 	if (rtmsg(RTM_GET) < 0) {
440*e1c7783eSAlexander V. Chernikov 		xo_errx(1, "RTM_GET(%s) failed", host);
441a96bd784SHajimu UMEMOTO 		/* NOTREACHED */
4429a4365d0SYoshinobu Inoue 	}
4439a4365d0SYoshinobu Inoue 	sin = (struct sockaddr_in6 *)(rtm + 1);
4442a81c6f1SAndrey V. Elsukov 	sdl = (struct sockaddr_dl *)(ALIGN(sin->sin6_len) + (char *)sin);
4459a4365d0SYoshinobu Inoue 	if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
4469a4365d0SYoshinobu Inoue 		if (sdl->sdl_family == AF_LINK &&
4473174c1d4SHajimu UMEMOTO 		    !(rtm->rtm_flags & RTF_GATEWAY)) {
4483174c1d4SHajimu UMEMOTO 			switch (sdl->sdl_type) {
4499a4365d0SYoshinobu Inoue 			case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
4509a4365d0SYoshinobu Inoue 			case IFT_ISO88024: case IFT_ISO88025:
451d99d8e2eSJohn Baldwin 			case IFT_L2VLAN: case IFT_BRIDGE:
4529a4365d0SYoshinobu Inoue 				goto overwrite;
4539a4365d0SYoshinobu Inoue 			}
4543174c1d4SHajimu UMEMOTO 		}
455*e1c7783eSAlexander V. Chernikov 		xo_warnx("cannot configure a new entry");
456ccf935ddSJun-ichiro itojun Hagino 		return 1;
4579a4365d0SYoshinobu Inoue 	}
458ccf935ddSJun-ichiro itojun Hagino 
4599a4365d0SYoshinobu Inoue overwrite:
4609a4365d0SYoshinobu Inoue 	if (sdl->sdl_family != AF_LINK) {
461*e1c7783eSAlexander V. Chernikov 		xo_warnx("cannot intuit interface index and type for %s", host);
4629a4365d0SYoshinobu Inoue 		return (1);
4639a4365d0SYoshinobu Inoue 	}
4649a4365d0SYoshinobu Inoue 	sdl_m.sdl_type = sdl->sdl_type;
4659a4365d0SYoshinobu Inoue 	sdl_m.sdl_index = sdl->sdl_index;
4669a4365d0SYoshinobu Inoue 	return (rtmsg(RTM_ADD));
4679a4365d0SYoshinobu Inoue }
4689a4365d0SYoshinobu Inoue 
4699a4365d0SYoshinobu Inoue /*
4709a4365d0SYoshinobu Inoue  * Display an individual neighbor cache entry
4719a4365d0SYoshinobu Inoue  */
472f2203c27SHiroki Sato static void
473bfc75db0SAndrey V. Elsukov get(char *host)
4749a4365d0SYoshinobu Inoue {
4759a4365d0SYoshinobu Inoue 	struct sockaddr_in6 *sin = &sin_m;
4769a4365d0SYoshinobu Inoue 	struct addrinfo hints, *res;
4779a4365d0SYoshinobu Inoue 	int gai_error;
4789a4365d0SYoshinobu Inoue 
4799a4365d0SYoshinobu Inoue 	sin_m = blank_sin;
4809a4365d0SYoshinobu Inoue 	bzero(&hints, sizeof(hints));
4819a4365d0SYoshinobu Inoue 	hints.ai_family = AF_INET6;
4829a4365d0SYoshinobu Inoue 	gai_error = getaddrinfo(host, NULL, &hints, &res);
4839a4365d0SYoshinobu Inoue 	if (gai_error) {
484*e1c7783eSAlexander V. Chernikov 		xo_warnx("%s: %s", host, gai_strerror(gai_error));
4859a4365d0SYoshinobu Inoue 		return;
4869a4365d0SYoshinobu Inoue 	}
4879a4365d0SYoshinobu Inoue 	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
488b1d9695cSAndrey V. Elsukov 	sin->sin6_scope_id =
489b1d9695cSAndrey V. Elsukov 	    ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
490b1d9695cSAndrey V. Elsukov 	dump(sin, 0);
4919a4365d0SYoshinobu Inoue 	if (found_entry == 0) {
4929a4365d0SYoshinobu Inoue 		getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
4939a4365d0SYoshinobu Inoue 		    sizeof(host_buf), NULL ,0,
494a96bd784SHajimu UMEMOTO 		    (nflag ? NI_NUMERICHOST : 0));
495*e1c7783eSAlexander V. Chernikov 		xo_errx(1, "%s (%s) -- no entry", host, host_buf);
4969a4365d0SYoshinobu Inoue 	}
4979a4365d0SYoshinobu Inoue }
4989a4365d0SYoshinobu Inoue 
4999a4365d0SYoshinobu Inoue /*
5009a4365d0SYoshinobu Inoue  * Delete a neighbor cache entry
5019a4365d0SYoshinobu Inoue  */
502f2203c27SHiroki Sato static int
503bfc75db0SAndrey V. Elsukov delete(char *host)
5049a4365d0SYoshinobu Inoue {
5059a4365d0SYoshinobu Inoue 	struct sockaddr_in6 *sin = &sin_m;
5069a4365d0SYoshinobu Inoue 	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
5076e6b3f7cSQing Li 	register char *cp = m_rtmsg.m_space;
5089a4365d0SYoshinobu Inoue 	struct sockaddr_dl *sdl;
5099a4365d0SYoshinobu Inoue 	struct addrinfo hints, *res;
5109a4365d0SYoshinobu Inoue 	int gai_error;
5119a4365d0SYoshinobu Inoue 
5129a4365d0SYoshinobu Inoue 	getsocket();
5139a4365d0SYoshinobu Inoue 	sin_m = blank_sin;
5149a4365d0SYoshinobu Inoue 
5159a4365d0SYoshinobu Inoue 	bzero(&hints, sizeof(hints));
5169a4365d0SYoshinobu Inoue 	hints.ai_family = AF_INET6;
5179a4365d0SYoshinobu Inoue 	gai_error = getaddrinfo(host, NULL, &hints, &res);
5189a4365d0SYoshinobu Inoue 	if (gai_error) {
519*e1c7783eSAlexander V. Chernikov 		xo_warnx("%s: %s", host, gai_strerror(gai_error));
5209a4365d0SYoshinobu Inoue 		return 1;
5219a4365d0SYoshinobu Inoue 	}
5229a4365d0SYoshinobu Inoue 	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
5230bebb544SHiroki Sato 	sin->sin6_scope_id =
5240bebb544SHiroki Sato 	    ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
5259a4365d0SYoshinobu Inoue 	if (rtmsg(RTM_GET) < 0) {
526*e1c7783eSAlexander V. Chernikov 		xo_errx(1, "RTM_GET(%s) failed", host);
527a96bd784SHajimu UMEMOTO 		/* NOTREACHED */
5289a4365d0SYoshinobu Inoue 	}
5299a4365d0SYoshinobu Inoue 	sin = (struct sockaddr_in6 *)(rtm + 1);
5302a81c6f1SAndrey V. Elsukov 	sdl = (struct sockaddr_dl *)(ALIGN(sin->sin6_len) + (char *)sin);
5319a4365d0SYoshinobu Inoue 	if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
5329a4365d0SYoshinobu Inoue 		if (sdl->sdl_family == AF_LINK &&
533ccf935ddSJun-ichiro itojun Hagino 		    !(rtm->rtm_flags & RTF_GATEWAY)) {
5349a4365d0SYoshinobu Inoue 			goto delete;
5359a4365d0SYoshinobu Inoue 		}
536*e1c7783eSAlexander V. Chernikov 		xo_warnx("delete: cannot delete non-NDP entry");
537ccf935ddSJun-ichiro itojun Hagino 		return 1;
538ccf935ddSJun-ichiro itojun Hagino 	}
539ccf935ddSJun-ichiro itojun Hagino 
5409a4365d0SYoshinobu Inoue delete:
5419a4365d0SYoshinobu Inoue 	if (sdl->sdl_family != AF_LINK) {
542*e1c7783eSAlexander V. Chernikov 		xo_warnx("cannot locate %s", host);
5439a4365d0SYoshinobu Inoue 		return (1);
5449a4365d0SYoshinobu Inoue 	}
5456e6b3f7cSQing Li 	/*
5466e6b3f7cSQing Li 	 * need to reinit the field because it has rt_key
5476e6b3f7cSQing Li 	 * but we want the actual address
5486e6b3f7cSQing Li 	 */
5496e6b3f7cSQing Li 	NEXTADDR(RTA_DST, sin_m);
5508eca593cSQing Li 	rtm->rtm_flags |= RTF_LLDATA;
5519a4365d0SYoshinobu Inoue 	if (rtmsg(RTM_DELETE) == 0) {
5520bebb544SHiroki Sato 		getnameinfo((struct sockaddr *)sin,
5530bebb544SHiroki Sato 		    sin->sin6_len, host_buf,
5549a4365d0SYoshinobu Inoue 		    sizeof(host_buf), NULL, 0,
555a96bd784SHajimu UMEMOTO 		    (nflag ? NI_NUMERICHOST : 0));
556*e1c7783eSAlexander V. Chernikov 		xo_open_instance("neighbor-cache");
557*e1c7783eSAlexander V. Chernikov 
558*e1c7783eSAlexander V. Chernikov 		char *ifname = if_indextoname(sdl->sdl_index, ifix_buf);
559*e1c7783eSAlexander V. Chernikov 		if (ifname == NULL) {
560*e1c7783eSAlexander V. Chernikov 			strlcpy(ifix_buf, "?", sizeof(ifix_buf));
561*e1c7783eSAlexander V. Chernikov 			ifname = ifix_buf;
562*e1c7783eSAlexander V. Chernikov 		}
563*e1c7783eSAlexander V. Chernikov 		char abuf[INET6_ADDRSTRLEN];
564*e1c7783eSAlexander V. Chernikov 		inet_ntop(AF_INET6, &sin->sin6_addr, abuf, sizeof(abuf));
565*e1c7783eSAlexander V. Chernikov 
566*e1c7783eSAlexander V. Chernikov 		xo_emit("{:hostname/%s}{d:/ (%s) deleted\n}", host, host_buf);
567*e1c7783eSAlexander V. Chernikov 		xo_emit("{e:address/%s}{e:interface/%s}", abuf, ifname);
568*e1c7783eSAlexander V. Chernikov 		xo_close_instance("neighbor-cache");
5699a4365d0SYoshinobu Inoue 	}
5709a4365d0SYoshinobu Inoue 
5719a4365d0SYoshinobu Inoue 	return 0;
5729a4365d0SYoshinobu Inoue }
5739a4365d0SYoshinobu Inoue 
5743174c1d4SHajimu UMEMOTO #define W_ADDR	36
57533841545SHajimu UMEMOTO #define W_LL	17
57633841545SHajimu UMEMOTO #define W_IF	6
57733841545SHajimu UMEMOTO 
5789a4365d0SYoshinobu Inoue /*
5799a4365d0SYoshinobu Inoue  * Dump the entire neighbor cache
5809a4365d0SYoshinobu Inoue  */
581f2203c27SHiroki Sato static void
582b1d9695cSAndrey V. Elsukov dump(struct sockaddr_in6 *addr, int cflag)
5839a4365d0SYoshinobu Inoue {
5849a4365d0SYoshinobu Inoue 	int mib[6];
5859a4365d0SYoshinobu Inoue 	size_t needed;
586ccf935ddSJun-ichiro itojun Hagino 	char *lim, *buf, *next;
5879a4365d0SYoshinobu Inoue 	struct rt_msghdr *rtm;
5889a4365d0SYoshinobu Inoue 	struct sockaddr_in6 *sin;
5899a4365d0SYoshinobu Inoue 	struct sockaddr_dl *sdl;
590ffa0165aSHiroki Sato 	struct timeval now;
5917ae43b31SRenato Botelho 	time_t expire;
5929a4365d0SYoshinobu Inoue 	int addrwidth;
59333841545SHajimu UMEMOTO 	int llwidth;
59433841545SHajimu UMEMOTO 	int ifwidth;
595ccf935ddSJun-ichiro itojun Hagino 	char flgbuf[8];
59633841545SHajimu UMEMOTO 	char *ifname;
5979a4365d0SYoshinobu Inoue 
5989a4365d0SYoshinobu Inoue 	/* Print header */
599*e1c7783eSAlexander V. Chernikov 	if (!tflag && !cflag) {
600*e1c7783eSAlexander V. Chernikov 		char xobuf[200];
601*e1c7783eSAlexander V. Chernikov 		snprintf(xobuf, sizeof(xobuf),
602*e1c7783eSAlexander V. Chernikov 		    "{T:/%%-%d.%ds} {T:/%%-%d.%ds} {T:/%%%d.%ds} {T:/%%-9.9s} {T:%%1s} {T:%%5s}\n",
603*e1c7783eSAlexander V. Chernikov 		    W_ADDR, W_ADDR, W_LL, W_LL, W_IF, W_IF);
604*e1c7783eSAlexander V. Chernikov 		xo_emit(xobuf, "Neighbor", "Linklayer Address", "Netif", "Expire", "S", "Flags");
605*e1c7783eSAlexander V. Chernikov 	}
606*e1c7783eSAlexander V. Chernikov 	xo_open_list("neighbor-cache");
6079a4365d0SYoshinobu Inoue again:;
6089a4365d0SYoshinobu Inoue 	mib[0] = CTL_NET;
6099a4365d0SYoshinobu Inoue 	mib[1] = PF_ROUTE;
6109a4365d0SYoshinobu Inoue 	mib[2] = 0;
6119a4365d0SYoshinobu Inoue 	mib[3] = AF_INET6;
6129a4365d0SYoshinobu Inoue 	mib[4] = NET_RT_FLAGS;
6136e6b3f7cSQing Li #ifdef RTF_LLINFO
6149a4365d0SYoshinobu Inoue 	mib[5] = RTF_LLINFO;
6156e6b3f7cSQing Li #else
6166e6b3f7cSQing Li 	mib[5] = 0;
6176e6b3f7cSQing Li #endif
6189a4365d0SYoshinobu Inoue 	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
619*e1c7783eSAlexander V. Chernikov 		xo_err(1, "sysctl(PF_ROUTE estimate)");
6209a4365d0SYoshinobu Inoue 	if (needed > 0) {
6219a4365d0SYoshinobu Inoue 		if ((buf = malloc(needed)) == NULL)
622*e1c7783eSAlexander V. Chernikov 			xo_err(1, "malloc");
6239a4365d0SYoshinobu Inoue 		if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
624*e1c7783eSAlexander V. Chernikov 			xo_err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
6259a4365d0SYoshinobu Inoue 		lim = buf + needed;
6269a4365d0SYoshinobu Inoue 	} else
6279a4365d0SYoshinobu Inoue 		buf = lim = NULL;
6289a4365d0SYoshinobu Inoue 
6299a4365d0SYoshinobu Inoue 	for (next = buf; next && next < lim; next += rtm->rtm_msglen) {
6309a4365d0SYoshinobu Inoue 		int isrouter = 0, prbs = 0;
6319a4365d0SYoshinobu Inoue 
6329a4365d0SYoshinobu Inoue 		rtm = (struct rt_msghdr *)next;
6339a4365d0SYoshinobu Inoue 		sin = (struct sockaddr_in6 *)(rtm + 1);
634937f8ddfSRenato Botelho 		sdl = (struct sockaddr_dl *)((char *)sin +
635937f8ddfSRenato Botelho 		    ALIGN(sin->sin6_len));
63633841545SHajimu UMEMOTO 
63733841545SHajimu UMEMOTO 		/*
63833841545SHajimu UMEMOTO 		 * Some OSes can produce a route that has the LINK flag but
63933841545SHajimu UMEMOTO 		 * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD
64033841545SHajimu UMEMOTO 		 * and BSD/OS, where xx is not the interface identifier on
64133841545SHajimu UMEMOTO 		 * lo0).  Such routes entry would annoy getnbrinfo() below,
64233841545SHajimu UMEMOTO 		 * so we skip them.
64333841545SHajimu UMEMOTO 		 * XXX: such routes should have the GATEWAY flag, not the
644a96bd784SHajimu UMEMOTO 		 * LINK flag.  However, there is rotten routing software
64533841545SHajimu UMEMOTO 		 * that advertises all routes that have the GATEWAY flag.
64633841545SHajimu UMEMOTO 		 * Thus, KAME kernel intentionally does not set the LINK flag.
64733841545SHajimu UMEMOTO 		 * What is to be fixed is not ndp, but such routing software
64833841545SHajimu UMEMOTO 		 * (and the kernel workaround)...
64933841545SHajimu UMEMOTO 		 */
65033841545SHajimu UMEMOTO 		if (sdl->sdl_family != AF_LINK)
65133841545SHajimu UMEMOTO 			continue;
65233841545SHajimu UMEMOTO 
6533174c1d4SHajimu UMEMOTO 		if (!(rtm->rtm_flags & RTF_HOST))
6543174c1d4SHajimu UMEMOTO 			continue;
6553174c1d4SHajimu UMEMOTO 
6569a4365d0SYoshinobu Inoue 		if (addr) {
657b1d9695cSAndrey V. Elsukov 			if (IN6_ARE_ADDR_EQUAL(&addr->sin6_addr,
658b1d9695cSAndrey V. Elsukov 			    &sin->sin6_addr) == 0 ||
659b1d9695cSAndrey V. Elsukov 			    addr->sin6_scope_id != sin->sin6_scope_id)
6609a4365d0SYoshinobu Inoue 				continue;
6619a4365d0SYoshinobu Inoue 			found_entry = 1;
6629a4365d0SYoshinobu Inoue 		} else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
6639a4365d0SYoshinobu Inoue 			continue;
6649a4365d0SYoshinobu Inoue 		if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) ||
6659a4365d0SYoshinobu Inoue 		    IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) {
6669a4365d0SYoshinobu Inoue 			/* XXX: should scope id be filled in the kernel? */
6679a4365d0SYoshinobu Inoue 			if (sin->sin6_scope_id == 0)
6689a4365d0SYoshinobu Inoue 				sin->sin6_scope_id = sdl->sdl_index;
6699a4365d0SYoshinobu Inoue 		}
6709a4365d0SYoshinobu Inoue 		getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
671a96bd784SHajimu UMEMOTO 		    sizeof(host_buf), NULL, 0, (nflag ? NI_NUMERICHOST : 0));
6723174c1d4SHajimu UMEMOTO 		if (cflag) {
673220f01cdSMunechika SUMIKAWA #ifdef RTF_WASCLONED
674220f01cdSMunechika SUMIKAWA 			if (rtm->rtm_flags & RTF_WASCLONED)
67502647224SMunechika SUMIKAWA 				delete(host_buf);
6763174c1d4SHajimu UMEMOTO #elif defined(RTF_CLONED)
6773174c1d4SHajimu UMEMOTO 			if (rtm->rtm_flags & RTF_CLONED)
6783174c1d4SHajimu UMEMOTO 				delete(host_buf);
679220f01cdSMunechika SUMIKAWA #else
6804a336ef4SAlexander V. Chernikov 			if (rtm->rtm_flags & RTF_PINNED)
6814a336ef4SAlexander V. Chernikov 				continue;
682220f01cdSMunechika SUMIKAWA 			delete(host_buf);
683220f01cdSMunechika SUMIKAWA #endif
68402647224SMunechika SUMIKAWA 			continue;
68502647224SMunechika SUMIKAWA 		}
686ffa0165aSHiroki Sato 		gettimeofday(&now, 0);
6879a4365d0SYoshinobu Inoue 		if (tflag)
6887d26db17SHiroki Sato 			ts_print(&now);
6899a4365d0SYoshinobu Inoue 
6909a4365d0SYoshinobu Inoue 		addrwidth = strlen(host_buf);
69133841545SHajimu UMEMOTO 		if (addrwidth < W_ADDR)
69233841545SHajimu UMEMOTO 			addrwidth = W_ADDR;
69333841545SHajimu UMEMOTO 		llwidth = strlen(ether_str(sdl));
69433841545SHajimu UMEMOTO 		if (W_ADDR + W_LL - addrwidth > llwidth)
69533841545SHajimu UMEMOTO 			llwidth = W_ADDR + W_LL - addrwidth;
69633841545SHajimu UMEMOTO 		ifname = if_indextoname(sdl->sdl_index, ifix_buf);
6977ae43b31SRenato Botelho 		if (ifname == NULL) {
6987ae43b31SRenato Botelho 			strlcpy(ifix_buf, "?", sizeof(ifix_buf));
6997ae43b31SRenato Botelho 			ifname = ifix_buf;
7007ae43b31SRenato Botelho 		}
70133841545SHajimu UMEMOTO 		ifwidth = strlen(ifname);
70233841545SHajimu UMEMOTO 		if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth)
70333841545SHajimu UMEMOTO 			ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth;
7049a4365d0SYoshinobu Inoue 
705*e1c7783eSAlexander V. Chernikov 		xo_open_instance("neighbor-cache");
706*e1c7783eSAlexander V. Chernikov 		/* Compose format string for libxo, as it doesn't support *.* */
707*e1c7783eSAlexander V. Chernikov 		char xobuf[200];
708*e1c7783eSAlexander V. Chernikov 		snprintf(xobuf, sizeof(xobuf),
709*e1c7783eSAlexander V. Chernikov 		    "{:address/%%-%d.%ds/%%s} {:mac-address/%%-%d.%ds/%%s} {:interface/%%%d.%ds/%%s}",
710*e1c7783eSAlexander V. Chernikov 		    addrwidth, addrwidth, llwidth, llwidth, ifwidth, ifwidth);
711*e1c7783eSAlexander V. Chernikov 		xo_emit(xobuf, host_buf, ether_str(sdl), ifname);
7129a4365d0SYoshinobu Inoue 
713463a577bSEitan Adler 		/* Print neighbor discovery specific information */
714427c2f4eSAlexander V. Chernikov 		expire = rtm->rtm_rmx.rmx_expire;
715*e1c7783eSAlexander V. Chernikov 		int expire_in = expire - now.tv_sec;
716427c2f4eSAlexander V. Chernikov 		if (expire > now.tv_sec)
717*e1c7783eSAlexander V. Chernikov 			xo_emit("{d:/ %-9.9s}{e:expires_sec/%d}", sec2str(expire_in), expire_in);
718427c2f4eSAlexander V. Chernikov 		else if (expire == 0)
719*e1c7783eSAlexander V. Chernikov 			xo_emit("{d:/ %-9.9s}{en:permanent/true}", "permanent");
7209a4365d0SYoshinobu Inoue 		else
721*e1c7783eSAlexander V. Chernikov 			xo_emit("{d:/ %-9.9s}{e:expires_sec/%d}", "expired", expire_in);
7229a4365d0SYoshinobu Inoue 
723*e1c7783eSAlexander V. Chernikov 		char *lle_state = "";
724427c2f4eSAlexander V. Chernikov 		switch (rtm->rtm_rmx.rmx_state) {
7259a4365d0SYoshinobu Inoue 		case ND6_LLINFO_NOSTATE:
726*e1c7783eSAlexander V. Chernikov 			lle_state = "N";
7279a4365d0SYoshinobu Inoue 			break;
72833841545SHajimu UMEMOTO #ifdef ND6_LLINFO_WAITDELETE
7299a4365d0SYoshinobu Inoue 		case ND6_LLINFO_WAITDELETE:
730*e1c7783eSAlexander V. Chernikov 			lle_state = "W";
7319a4365d0SYoshinobu Inoue 			break;
73233841545SHajimu UMEMOTO #endif
7339a4365d0SYoshinobu Inoue 		case ND6_LLINFO_INCOMPLETE:
734*e1c7783eSAlexander V. Chernikov 			lle_state = "I";
7359a4365d0SYoshinobu Inoue 			break;
7369a4365d0SYoshinobu Inoue 		case ND6_LLINFO_REACHABLE:
737*e1c7783eSAlexander V. Chernikov 			lle_state = "R";
7389a4365d0SYoshinobu Inoue 			break;
7399a4365d0SYoshinobu Inoue 		case ND6_LLINFO_STALE:
740*e1c7783eSAlexander V. Chernikov 			lle_state = "S";
7419a4365d0SYoshinobu Inoue 			break;
7429a4365d0SYoshinobu Inoue 		case ND6_LLINFO_DELAY:
743*e1c7783eSAlexander V. Chernikov 			lle_state = "D";
7449a4365d0SYoshinobu Inoue 			break;
7459a4365d0SYoshinobu Inoue 		case ND6_LLINFO_PROBE:
746*e1c7783eSAlexander V. Chernikov 			lle_state = "P";
7479a4365d0SYoshinobu Inoue 			break;
7489a4365d0SYoshinobu Inoue 		default:
749*e1c7783eSAlexander V. Chernikov 			lle_state = "?";
7509a4365d0SYoshinobu Inoue 			break;
7519a4365d0SYoshinobu Inoue 		}
752*e1c7783eSAlexander V. Chernikov 		xo_emit(" {:neighbor-state/%s}", lle_state);
7539a4365d0SYoshinobu Inoue 
754427c2f4eSAlexander V. Chernikov 		isrouter = rtm->rtm_flags & RTF_GATEWAY;
755427c2f4eSAlexander V. Chernikov 		prbs = rtm->rtm_rmx.rmx_pksent;
7569a4365d0SYoshinobu Inoue 
757ccf935ddSJun-ichiro itojun Hagino 		/*
758ccf935ddSJun-ichiro itojun Hagino 		 * other flags. R: router, P: proxy, W: ??
759ccf935ddSJun-ichiro itojun Hagino 		 */
760ccf935ddSJun-ichiro itojun Hagino 		if ((rtm->rtm_addrs & RTA_NETMASK) == 0) {
761ccf935ddSJun-ichiro itojun Hagino 			snprintf(flgbuf, sizeof(flgbuf), "%s%s",
762ccf935ddSJun-ichiro itojun Hagino 			    isrouter ? "R" : "",
763ccf935ddSJun-ichiro itojun Hagino 			    (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
764ccf935ddSJun-ichiro itojun Hagino 		} else {
76599e46388SXin LI #if 0			/* W and P are mystery even for us */
7669a4365d0SYoshinobu Inoue 			sin = (struct sockaddr_in6 *)
7679a4365d0SYoshinobu Inoue 			    (sdl->sdl_len + (char *)sdl);
768ccf935ddSJun-ichiro itojun Hagino 			snprintf(flgbuf, sizeof(flgbuf), "%s%s%s%s",
769ccf935ddSJun-ichiro itojun Hagino 			    isrouter ? "R" : "",
770a96bd784SHajimu UMEMOTO 			    !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr) ? "P" : "",
771a96bd784SHajimu UMEMOTO 			    (sin->sin6_len != sizeof(struct sockaddr_in6)) ? "W" : "",
772ccf935ddSJun-ichiro itojun Hagino 			    (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
7733174c1d4SHajimu UMEMOTO #else
7743174c1d4SHajimu UMEMOTO 			snprintf(flgbuf, sizeof(flgbuf), "%s%s",
7753174c1d4SHajimu UMEMOTO 			    isrouter ? "R" : "",
7763174c1d4SHajimu UMEMOTO 			    (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
7773174c1d4SHajimu UMEMOTO #endif
7789a4365d0SYoshinobu Inoue 		}
779*e1c7783eSAlexander V. Chernikov 		xo_emit(" {:nd-flags/%s}", flgbuf);
7809a4365d0SYoshinobu Inoue 
7819a4365d0SYoshinobu Inoue 		if (prbs)
782*e1c7783eSAlexander V. Chernikov 			xo_emit("{d:/ %d}", prbs);
7839a4365d0SYoshinobu Inoue 
784*e1c7783eSAlexander V. Chernikov 		xo_emit("\n");
785*e1c7783eSAlexander V. Chernikov 		xo_close_instance("neighbor-cache");
7869a4365d0SYoshinobu Inoue 	}
78733841545SHajimu UMEMOTO 	if (buf != NULL)
78833841545SHajimu UMEMOTO 		free(buf);
7899a4365d0SYoshinobu Inoue 
7909a4365d0SYoshinobu Inoue 	if (repeat) {
791*e1c7783eSAlexander V. Chernikov 		xo_emit("\n");
792*e1c7783eSAlexander V. Chernikov 		xo_flush();
7939a4365d0SYoshinobu Inoue 		sleep(repeat);
7949a4365d0SYoshinobu Inoue 		goto again;
7959a4365d0SYoshinobu Inoue 	}
796*e1c7783eSAlexander V. Chernikov 
797*e1c7783eSAlexander V. Chernikov 	xo_close_list("neighbor-cache");
7989a4365d0SYoshinobu Inoue }
7999a4365d0SYoshinobu Inoue 
8009a4365d0SYoshinobu Inoue static struct in6_nbrinfo *
801bfc75db0SAndrey V. Elsukov getnbrinfo(struct in6_addr *addr, int ifindex, int warning)
8029a4365d0SYoshinobu Inoue {
8039a4365d0SYoshinobu Inoue 	static struct in6_nbrinfo nbi;
8047ae43b31SRenato Botelho 	int sock;
8059a4365d0SYoshinobu Inoue 
8067ae43b31SRenato Botelho 	if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
807*e1c7783eSAlexander V. Chernikov 		xo_err(1, "socket");
8089a4365d0SYoshinobu Inoue 
8099a4365d0SYoshinobu Inoue 	bzero(&nbi, sizeof(nbi));
8109a4365d0SYoshinobu Inoue 	if_indextoname(ifindex, nbi.ifname);
8119a4365d0SYoshinobu Inoue 	nbi.addr = *addr;
8127ae43b31SRenato Botelho 	if (ioctl(sock, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) {
813ccf935ddSJun-ichiro itojun Hagino 		if (warning)
814*e1c7783eSAlexander V. Chernikov 			xo_warn("ioctl(SIOCGNBRINFO_IN6)");
8157ae43b31SRenato Botelho 		close(sock);
8169a4365d0SYoshinobu Inoue 		return(NULL);
8179a4365d0SYoshinobu Inoue 	}
8189a4365d0SYoshinobu Inoue 
8197ae43b31SRenato Botelho 	close(sock);
8209a4365d0SYoshinobu Inoue 	return(&nbi);
8219a4365d0SYoshinobu Inoue }
8229a4365d0SYoshinobu Inoue 
8239a4365d0SYoshinobu Inoue static char *
82497f8d655SXin LI ether_str(struct sockaddr_dl *sdl)
8259a4365d0SYoshinobu Inoue {
826a96bd784SHajimu UMEMOTO 	static char hbuf[NI_MAXHOST];
8279a4365d0SYoshinobu Inoue 
828e4cd31ddSJeff Roberson 	if (sdl->sdl_alen == ETHER_ADDR_LEN) {
82997f8d655SXin LI 		strlcpy(hbuf, ether_ntoa((struct ether_addr *)LLADDR(sdl)),
83097f8d655SXin LI 		    sizeof(hbuf));
831e4cd31ddSJeff Roberson 	} else if (sdl->sdl_alen) {
832e4cd31ddSJeff Roberson 		int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;
833e4cd31ddSJeff Roberson 		snprintf(hbuf, sizeof(hbuf), "%s", link_ntoa(sdl) + n);
834e4cd31ddSJeff Roberson 	} else
835a96bd784SHajimu UMEMOTO 		snprintf(hbuf, sizeof(hbuf), "(incomplete)");
8369a4365d0SYoshinobu Inoue 
837a96bd784SHajimu UMEMOTO 	return(hbuf);
8389a4365d0SYoshinobu Inoue }
8399a4365d0SYoshinobu Inoue 
840f2203c27SHiroki Sato static int
841bfc75db0SAndrey V. Elsukov ndp_ether_aton(char *a, u_char *n)
8429a4365d0SYoshinobu Inoue {
8439a4365d0SYoshinobu Inoue 	int i, o[6];
8449a4365d0SYoshinobu Inoue 
8459a4365d0SYoshinobu Inoue 	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
8469a4365d0SYoshinobu Inoue 	    &o[3], &o[4], &o[5]);
8479a4365d0SYoshinobu Inoue 	if (i != 6) {
848*e1c7783eSAlexander V. Chernikov 		xo_warnx("invalid Ethernet address '%s'", a);
8499a4365d0SYoshinobu Inoue 		return (1);
8509a4365d0SYoshinobu Inoue 	}
8519a4365d0SYoshinobu Inoue 	for (i = 0; i < 6; i++)
8529a4365d0SYoshinobu Inoue 		n[i] = o[i];
8539a4365d0SYoshinobu Inoue 	return (0);
8549a4365d0SYoshinobu Inoue }
8559a4365d0SYoshinobu Inoue 
856f2203c27SHiroki Sato static void
8579a4365d0SYoshinobu Inoue usage()
8589a4365d0SYoshinobu Inoue {
8593174c1d4SHajimu UMEMOTO 	printf("usage: ndp [-nt] hostname\n");
8603174c1d4SHajimu UMEMOTO 	printf("       ndp [-nt] -a | -c | -p | -r | -H | -P | -R\n");
86133841545SHajimu UMEMOTO 	printf("       ndp [-nt] -A wait\n");
8623174c1d4SHajimu UMEMOTO 	printf("       ndp [-nt] -d hostname\n");
8633174c1d4SHajimu UMEMOTO 	printf("       ndp [-nt] -f filename\n");
8643174c1d4SHajimu UMEMOTO 	printf("       ndp [-nt] -i interface [flags...]\n");
865ccf935ddSJun-ichiro itojun Hagino #ifdef SIOCSDEFIFACE_IN6
8663174c1d4SHajimu UMEMOTO 	printf("       ndp [-nt] -I [interface|delete]\n");
867ccf935ddSJun-ichiro itojun Hagino #endif
8683174c1d4SHajimu UMEMOTO 	printf("       ndp [-nt] -s nodename etheraddr [temp] [proxy]\n");
8699a4365d0SYoshinobu Inoue 	exit(1);
8709a4365d0SYoshinobu Inoue }
8719a4365d0SYoshinobu Inoue 
872f2203c27SHiroki Sato static int
873bfc75db0SAndrey V. Elsukov rtmsg(int cmd)
8749a4365d0SYoshinobu Inoue {
8759a4365d0SYoshinobu Inoue 	static int seq;
8769a4365d0SYoshinobu Inoue 	int rlen;
8779a4365d0SYoshinobu Inoue 	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
8789a4365d0SYoshinobu Inoue 	register char *cp = m_rtmsg.m_space;
8799a4365d0SYoshinobu Inoue 	register int l;
8809a4365d0SYoshinobu Inoue 
8819a4365d0SYoshinobu Inoue 	errno = 0;
8829a4365d0SYoshinobu Inoue 	if (cmd == RTM_DELETE)
8839a4365d0SYoshinobu Inoue 		goto doit;
8849a4365d0SYoshinobu Inoue 	bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
8859a4365d0SYoshinobu Inoue 	rtm->rtm_flags = flags;
8869a4365d0SYoshinobu Inoue 	rtm->rtm_version = RTM_VERSION;
8879a4365d0SYoshinobu Inoue 
8889a4365d0SYoshinobu Inoue 	switch (cmd) {
8899a4365d0SYoshinobu Inoue 	default:
890*e1c7783eSAlexander V. Chernikov 		xo_errx(1, "internal wrong cmd");
8919a4365d0SYoshinobu Inoue 	case RTM_ADD:
8929a4365d0SYoshinobu Inoue 		rtm->rtm_addrs |= RTA_GATEWAY;
8933174c1d4SHajimu UMEMOTO 		if (expire_time) {
8949a4365d0SYoshinobu Inoue 			rtm->rtm_rmx.rmx_expire = expire_time;
8959a4365d0SYoshinobu Inoue 			rtm->rtm_inits = RTV_EXPIRE;
8963174c1d4SHajimu UMEMOTO 		}
8978eca593cSQing Li 		rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA);
8989a4365d0SYoshinobu Inoue 		/* FALLTHROUGH */
8999a4365d0SYoshinobu Inoue 	case RTM_GET:
9009a4365d0SYoshinobu Inoue 		rtm->rtm_addrs |= RTA_DST;
9019a4365d0SYoshinobu Inoue 	}
9029a4365d0SYoshinobu Inoue 
9039a4365d0SYoshinobu Inoue 	NEXTADDR(RTA_DST, sin_m);
9049a4365d0SYoshinobu Inoue 	NEXTADDR(RTA_GATEWAY, sdl_m);
9059a4365d0SYoshinobu Inoue 
9069a4365d0SYoshinobu Inoue 	rtm->rtm_msglen = cp - (char *)&m_rtmsg;
9079a4365d0SYoshinobu Inoue doit:
9089a4365d0SYoshinobu Inoue 	l = rtm->rtm_msglen;
9099a4365d0SYoshinobu Inoue 	rtm->rtm_seq = ++seq;
9109a4365d0SYoshinobu Inoue 	rtm->rtm_type = cmd;
9119a4365d0SYoshinobu Inoue 	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
9129a4365d0SYoshinobu Inoue 		if (errno != ESRCH || cmd != RTM_DELETE) {
913*e1c7783eSAlexander V. Chernikov 			xo_err(1, "writing to routing socket");
914a96bd784SHajimu UMEMOTO 			/* NOTREACHED */
9159a4365d0SYoshinobu Inoue 		}
9169a4365d0SYoshinobu Inoue 	}
9179a4365d0SYoshinobu Inoue 	do {
9189a4365d0SYoshinobu Inoue 		l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
9192f8c6c0aSPatrick Kelsey 	} while (l > 0 && (rtm->rtm_type != cmd || rtm->rtm_seq != seq ||
9202f8c6c0aSPatrick Kelsey 	    rtm->rtm_pid != pid));
9219a4365d0SYoshinobu Inoue 	if (l < 0)
922*e1c7783eSAlexander V. Chernikov 		xo_warn("read from routing socket");
9239a4365d0SYoshinobu Inoue 	return (0);
9249a4365d0SYoshinobu Inoue }
9259a4365d0SYoshinobu Inoue 
926f2203c27SHiroki Sato static void
927bfc75db0SAndrey V. Elsukov ifinfo(char *ifname, int argc, char **argv)
9289a4365d0SYoshinobu Inoue {
9299a4365d0SYoshinobu Inoue 	struct in6_ndireq nd;
9307ae43b31SRenato Botelho 	int i, sock;
931ccf935ddSJun-ichiro itojun Hagino 	u_int32_t newflags;
93233841545SHajimu UMEMOTO #ifdef IPV6CTL_USETEMPADDR
93333841545SHajimu UMEMOTO 	u_int8_t nullbuf[8];
93433841545SHajimu UMEMOTO #endif
9359a4365d0SYoshinobu Inoue 
9367ae43b31SRenato Botelho 	if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
937*e1c7783eSAlexander V. Chernikov 		xo_err(1, "socket");
938a96bd784SHajimu UMEMOTO 		/* NOTREACHED */
9399a4365d0SYoshinobu Inoue 	}
9409a4365d0SYoshinobu Inoue 	bzero(&nd, sizeof(nd));
941a96bd784SHajimu UMEMOTO 	strlcpy(nd.ifname, ifname, sizeof(nd.ifname));
9427ae43b31SRenato Botelho 	if (ioctl(sock, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
943*e1c7783eSAlexander V. Chernikov 		xo_err(1, "ioctl(SIOCGIFINFO_IN6)");
944a96bd784SHajimu UMEMOTO 		/* NOTREACHED */
9459a4365d0SYoshinobu Inoue 	}
9469a4365d0SYoshinobu Inoue #define	ND nd.ndi
947ccf935ddSJun-ichiro itojun Hagino 	newflags = ND.flags;
9483174c1d4SHajimu UMEMOTO 	for (i = 0; i < argc; i++) {
949ccf935ddSJun-ichiro itojun Hagino 		int clear = 0;
950ccf935ddSJun-ichiro itojun Hagino 		char *cp = argv[i];
951ccf935ddSJun-ichiro itojun Hagino 
952ccf935ddSJun-ichiro itojun Hagino 		if (*cp == '-') {
953ccf935ddSJun-ichiro itojun Hagino 			clear = 1;
954ccf935ddSJun-ichiro itojun Hagino 			cp++;
955ccf935ddSJun-ichiro itojun Hagino 		}
956ccf935ddSJun-ichiro itojun Hagino 
957937f8ddfSRenato Botelho #define	SETFLAG(s, f) do {			\
958ccf935ddSJun-ichiro itojun Hagino 	if (strcmp(cp, (s)) == 0) {		\
959ccf935ddSJun-ichiro itojun Hagino 		if (clear)			\
960ccf935ddSJun-ichiro itojun Hagino 			newflags &= ~(f);	\
961ccf935ddSJun-ichiro itojun Hagino 		else				\
962ccf935ddSJun-ichiro itojun Hagino 			newflags |= (f);	\
963ccf935ddSJun-ichiro itojun Hagino 	}					\
964ccf935ddSJun-ichiro itojun Hagino } while (0)
965b9204379SSUZUKI Shinsuke /*
966b9204379SSUZUKI Shinsuke  * XXX: this macro is not 100% correct, in that it matches "nud" against
967b9204379SSUZUKI Shinsuke  *      "nudbogus".  But we just let it go since this is minor.
968b9204379SSUZUKI Shinsuke  */
969937f8ddfSRenato Botelho #define	SETVALUE(f, v) do {						\
970b9204379SSUZUKI Shinsuke 	char *valptr;							\
971b9204379SSUZUKI Shinsuke 	unsigned long newval;						\
972b9204379SSUZUKI Shinsuke 	v = 0; /* unspecified */					\
973b9204379SSUZUKI Shinsuke 	if (strncmp(cp, f, strlen(f)) == 0) {				\
974b9204379SSUZUKI Shinsuke 		valptr = strchr(cp, '=');				\
975b9204379SSUZUKI Shinsuke 		if (valptr == NULL)					\
976*e1c7783eSAlexander V. Chernikov 			xo_err(1, "syntax error in %s field", (f));	\
977b9204379SSUZUKI Shinsuke 		errno = 0;						\
978b9204379SSUZUKI Shinsuke 		newval = strtoul(++valptr, NULL, 0);			\
979b9204379SSUZUKI Shinsuke 		if (errno)						\
980*e1c7783eSAlexander V. Chernikov 			xo_err(1, "syntax error in %s's value", (f));	\
981b9204379SSUZUKI Shinsuke 		v = newval;						\
982b9204379SSUZUKI Shinsuke 	}								\
983b9204379SSUZUKI Shinsuke } while (0)
984b9204379SSUZUKI Shinsuke 
9855b27b045SSUZUKI Shinsuke 		SETFLAG("disabled", ND6_IFF_IFDISABLED);
986ccf935ddSJun-ichiro itojun Hagino 		SETFLAG("nud", ND6_IFF_PERFORMNUD);
98707cf047dSHajimu UMEMOTO #ifdef ND6_IFF_ACCEPT_RTADV
98807cf047dSHajimu UMEMOTO 		SETFLAG("accept_rtadv", ND6_IFF_ACCEPT_RTADV);
98907cf047dSHajimu UMEMOTO #endif
990a283298cSHiroki Sato #ifdef ND6_IFF_AUTO_LINKLOCAL
991a283298cSHiroki Sato 		SETFLAG("auto_linklocal", ND6_IFF_AUTO_LINKLOCAL);
992a283298cSHiroki Sato #endif
993164051ceSHajimu UMEMOTO #ifdef ND6_IFF_NO_PREFER_IFACE
994164051ceSHajimu UMEMOTO 		SETFLAG("no_prefer_iface", ND6_IFF_NO_PREFER_IFACE);
995164051ceSHajimu UMEMOTO #endif
996b9204379SSUZUKI Shinsuke 		SETVALUE("basereachable", ND.basereachable);
997b9204379SSUZUKI Shinsuke 		SETVALUE("retrans", ND.retrans);
998b9204379SSUZUKI Shinsuke 		SETVALUE("curhlim", ND.chlim);
999ccf935ddSJun-ichiro itojun Hagino 
1000ccf935ddSJun-ichiro itojun Hagino 		ND.flags = newflags;
10017ae43b31SRenato Botelho 		if (ioctl(sock, SIOCSIFINFO_IN6, (caddr_t)&nd) < 0) {
1002*e1c7783eSAlexander V. Chernikov 			xo_err(1, "ioctl(SIOCSIFINFO_IN6)");
1003a96bd784SHajimu UMEMOTO 			/* NOTREACHED */
1004ccf935ddSJun-ichiro itojun Hagino 		}
1005ccf935ddSJun-ichiro itojun Hagino #undef SETFLAG
1006b9204379SSUZUKI Shinsuke #undef SETVALUE
1007ccf935ddSJun-ichiro itojun Hagino 	}
1008ccf935ddSJun-ichiro itojun Hagino 
100931423309SHajimu UMEMOTO 	if (!ND.initialized) {
1010*e1c7783eSAlexander V. Chernikov 		xo_errx(1, "%s: not initialized yet", ifname);
101131423309SHajimu UMEMOTO 		/* NOTREACHED */
101231423309SHajimu UMEMOTO 	}
101331423309SHajimu UMEMOTO 
10147ae43b31SRenato Botelho 	if (ioctl(sock, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
1015*e1c7783eSAlexander V. Chernikov 		xo_err(1, "ioctl(SIOCGIFINFO_IN6)");
1016b9204379SSUZUKI Shinsuke 		/* NOTREACHED */
1017b9204379SSUZUKI Shinsuke 	}
1018*e1c7783eSAlexander V. Chernikov 	xo_open_container("ifinfo");
1019*e1c7783eSAlexander V. Chernikov 
1020*e1c7783eSAlexander V. Chernikov 	xo_emit("{e:interface/%s}", ifname);
1021*e1c7783eSAlexander V. Chernikov 	xo_emit("linkmtu={:linkmtu/%d}", ND.linkmtu);
1022*e1c7783eSAlexander V. Chernikov 	xo_emit(", maxmtu={:maxmtu/%d}", ND.maxmtu);
1023*e1c7783eSAlexander V. Chernikov 	xo_emit(", curhlim={:curhlim/%d}", ND.chlim);
1024*e1c7783eSAlexander V. Chernikov 	xo_emit("{d:/, basereachable=%ds%dms}{e:basereachable_ms/%u}",
1025*e1c7783eSAlexander V. Chernikov 	    ND.basereachable / 1000, ND.basereachable % 1000, ND.basereachable);
1026*e1c7783eSAlexander V. Chernikov 	xo_emit("{d:/, reachable=%ds}{e:reachable_ms/%u}", ND.reachable, ND.reachable * 1000);
1027*e1c7783eSAlexander V. Chernikov 	xo_emit("{d:/, retrans=%ds%dms}{e:retrans_ms/%u}", ND.retrans / 1000, ND.retrans % 1000,
1028*e1c7783eSAlexander V. Chernikov 	    ND.retrans);
102933841545SHajimu UMEMOTO #ifdef IPV6CTL_USETEMPADDR
103033841545SHajimu UMEMOTO 	memset(nullbuf, 0, sizeof(nullbuf));
103133841545SHajimu UMEMOTO 	if (memcmp(nullbuf, ND.randomid, sizeof(nullbuf)) != 0) {
103233841545SHajimu UMEMOTO 		int j;
103333841545SHajimu UMEMOTO 		u_int8_t *rbuf;
103433841545SHajimu UMEMOTO 
103533841545SHajimu UMEMOTO 		for (i = 0; i < 3; i++) {
1036*e1c7783eSAlexander V. Chernikov 			const char *txt, *field;
103733841545SHajimu UMEMOTO 			switch (i) {
103833841545SHajimu UMEMOTO 			case 0:
1039*e1c7783eSAlexander V. Chernikov 				txt = "\nRandom seed(0): ";
1040*e1c7783eSAlexander V. Chernikov 				field = "seed_0";
104133841545SHajimu UMEMOTO 				rbuf = ND.randomseed0;
104233841545SHajimu UMEMOTO 				break;
104333841545SHajimu UMEMOTO 			case 1:
1044*e1c7783eSAlexander V. Chernikov 				txt = "\nRandom seed(1): ";
1045*e1c7783eSAlexander V. Chernikov 				field = "seed_1";
104633841545SHajimu UMEMOTO 				rbuf = ND.randomseed1;
104733841545SHajimu UMEMOTO 				break;
104833841545SHajimu UMEMOTO 			case 2:
1049*e1c7783eSAlexander V. Chernikov 				txt = "\nRandom ID:      ";
1050*e1c7783eSAlexander V. Chernikov 				field = "random_id";
105133841545SHajimu UMEMOTO 				rbuf = ND.randomid;
105233841545SHajimu UMEMOTO 				break;
1053ec0176bbSSUZUKI Shinsuke 			default:
1054*e1c7783eSAlexander V. Chernikov 				xo_errx(1, "impossible case for tempaddr display");
105533841545SHajimu UMEMOTO 			}
1056*e1c7783eSAlexander V. Chernikov 			char abuf[20], xobuf[200];
105733841545SHajimu UMEMOTO 			for (j = 0; j < 8; j++)
1058*e1c7783eSAlexander V. Chernikov 				snprintf(&abuf[j * 2], sizeof(abuf), "%02X", rbuf[j]);
1059*e1c7783eSAlexander V. Chernikov 			snprintf(xobuf, sizeof(xobuf), "%s{:%s/%%s}", txt, field);
1060*e1c7783eSAlexander V. Chernikov 			xo_emit(xobuf, abuf);
106133841545SHajimu UMEMOTO 		}
106233841545SHajimu UMEMOTO 	}
1063937f8ddfSRenato Botelho #endif /* IPV6CTL_USETEMPADDR */
1064ccf935ddSJun-ichiro itojun Hagino 	if (ND.flags) {
1065*e1c7783eSAlexander V. Chernikov 		xo_emit("\nFlags: {e:flags/%u}", ND.flags);
1066*e1c7783eSAlexander V. Chernikov 		xo_open_list("flags_pretty");
10675b27b045SSUZUKI Shinsuke #ifdef ND6_IFF_IFDISABLED
10685b27b045SSUZUKI Shinsuke 		if ((ND.flags & ND6_IFF_IFDISABLED))
1069*e1c7783eSAlexander V. Chernikov 			xo_emit("{l:%s} ", "disabled");
10705b27b045SSUZUKI Shinsuke #endif
107107cf047dSHajimu UMEMOTO 		if ((ND.flags & ND6_IFF_PERFORMNUD))
1072*e1c7783eSAlexander V. Chernikov 			xo_emit("{l:%s} ", "nud");
107307cf047dSHajimu UMEMOTO #ifdef ND6_IFF_ACCEPT_RTADV
107407cf047dSHajimu UMEMOTO 		if ((ND.flags & ND6_IFF_ACCEPT_RTADV))
1075*e1c7783eSAlexander V. Chernikov 			xo_emit("{l:%s} ", "accept_rtadv");
107607cf047dSHajimu UMEMOTO #endif
1077a283298cSHiroki Sato #ifdef ND6_IFF_AUTO_LINKLOCAL
1078a283298cSHiroki Sato 		if ((ND.flags & ND6_IFF_AUTO_LINKLOCAL))
1079*e1c7783eSAlexander V. Chernikov 			xo_emit("{l:%s} ", "auto_linklocal");
1080a283298cSHiroki Sato #endif
1081164051ceSHajimu UMEMOTO #ifdef ND6_IFF_NO_PREFER_IFACE
1082164051ceSHajimu UMEMOTO 		if ((ND.flags & ND6_IFF_NO_PREFER_IFACE))
1083*e1c7783eSAlexander V. Chernikov 			xo_emit("{l:%s} ", "no_prefer_iface");
1084164051ceSHajimu UMEMOTO #endif
1085*e1c7783eSAlexander V. Chernikov 		xo_close_list("flags");
1086ccf935ddSJun-ichiro itojun Hagino 	}
1087*e1c7783eSAlexander V. Chernikov 	xo_emit("\n");
10889a4365d0SYoshinobu Inoue #undef ND
1089*e1c7783eSAlexander V. Chernikov 	xo_close_container("ifinfo");
1090ccf935ddSJun-ichiro itojun Hagino 
10917ae43b31SRenato Botelho 	close(sock);
10929a4365d0SYoshinobu Inoue }
10939a4365d0SYoshinobu Inoue 
109433841545SHajimu UMEMOTO #ifndef ND_RA_FLAG_RTPREF_MASK	/* XXX: just for compilation on *BSD release */
109533841545SHajimu UMEMOTO #define ND_RA_FLAG_RTPREF_MASK	0x18 /* 00011000 */
109633841545SHajimu UMEMOTO #endif
109733841545SHajimu UMEMOTO 
1098f2203c27SHiroki Sato static void
10999a4365d0SYoshinobu Inoue rtrlist()
11009a4365d0SYoshinobu Inoue {
110133841545SHajimu UMEMOTO 	int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST };
110233841545SHajimu UMEMOTO 	char *buf;
110333841545SHajimu UMEMOTO 	struct in6_defrouter *p, *ep;
110433841545SHajimu UMEMOTO 	size_t l;
1105ffa0165aSHiroki Sato 	struct timeval now;
110633841545SHajimu UMEMOTO 
110733841545SHajimu UMEMOTO 	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
1108*e1c7783eSAlexander V. Chernikov 		xo_err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
110933841545SHajimu UMEMOTO 		/*NOTREACHED*/
111033841545SHajimu UMEMOTO 	}
1111ec0176bbSSUZUKI Shinsuke 	if (l == 0)
1112ec0176bbSSUZUKI Shinsuke 		return;
111333841545SHajimu UMEMOTO 	buf = malloc(l);
111433841545SHajimu UMEMOTO 	if (!buf) {
1115*e1c7783eSAlexander V. Chernikov 		xo_err(1, "malloc");
111633841545SHajimu UMEMOTO 		/*NOTREACHED*/
111733841545SHajimu UMEMOTO 	}
111833841545SHajimu UMEMOTO 	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
1119*e1c7783eSAlexander V. Chernikov 		xo_err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
112033841545SHajimu UMEMOTO 		/*NOTREACHED*/
112133841545SHajimu UMEMOTO 	}
112233841545SHajimu UMEMOTO 
1123*e1c7783eSAlexander V. Chernikov 	xo_open_list("router-list");
1124*e1c7783eSAlexander V. Chernikov 
112533841545SHajimu UMEMOTO 	ep = (struct in6_defrouter *)(buf + l);
112633841545SHajimu UMEMOTO 	for (p = (struct in6_defrouter *)buf; p < ep; p++) {
112733841545SHajimu UMEMOTO 		int rtpref;
1128*e1c7783eSAlexander V. Chernikov 		char abuf[INET6_ADDRSTRLEN], *paddr;
112933841545SHajimu UMEMOTO 
113033841545SHajimu UMEMOTO 		if (getnameinfo((struct sockaddr *)&p->rtaddr,
113133841545SHajimu UMEMOTO 		    p->rtaddr.sin6_len, host_buf, sizeof(host_buf), NULL, 0,
1132a96bd784SHajimu UMEMOTO 		    (nflag ? NI_NUMERICHOST : 0)) != 0)
113333841545SHajimu UMEMOTO 			strlcpy(host_buf, "?", sizeof(host_buf));
1134*e1c7783eSAlexander V. Chernikov 		if (nflag)
1135*e1c7783eSAlexander V. Chernikov 			paddr = host_buf;
1136*e1c7783eSAlexander V. Chernikov 		else {
1137*e1c7783eSAlexander V. Chernikov 			inet_ntop(AF_INET6, &p->rtaddr.sin6_addr, abuf, sizeof(abuf));
1138*e1c7783eSAlexander V. Chernikov 			paddr = abuf;
1139*e1c7783eSAlexander V. Chernikov 		}
114033841545SHajimu UMEMOTO 
1141*e1c7783eSAlexander V. Chernikov 		xo_open_instance("router-list");
1142*e1c7783eSAlexander V. Chernikov 		xo_emit("{:hostname/%s}{e:address/%s} if={:interface/%s}",
1143*e1c7783eSAlexander V. Chernikov 		    host_buf, paddr,
114433841545SHajimu UMEMOTO 		    if_indextoname(p->if_index, ifix_buf));
1145*e1c7783eSAlexander V. Chernikov 		xo_open_list("flags_pretty");
1146*e1c7783eSAlexander V. Chernikov 		char rflags[6] = {}, *pflags = rflags;
1147*e1c7783eSAlexander V. Chernikov 		if (p->flags & ND_RA_FLAG_MANAGED) {
1148*e1c7783eSAlexander V. Chernikov 			*pflags++ = 'M';
1149*e1c7783eSAlexander V. Chernikov 			xo_emit("{el:%s}", "managed");
1150*e1c7783eSAlexander V. Chernikov 		}
1151*e1c7783eSAlexander V. Chernikov 		if (p->flags & ND_RA_FLAG_OTHER) {
1152*e1c7783eSAlexander V. Chernikov 			*pflags++ = 'O';
1153*e1c7783eSAlexander V. Chernikov 			xo_emit("{el:%s}", "other");
1154*e1c7783eSAlexander V. Chernikov 		}
1155201100c5SBjoern A. Zeeb #ifdef DRAFT_IETF_6MAN_IPV6ONLY_FLAG
1156*e1c7783eSAlexander V. Chernikov 		if (p->flags & ND_RA_FLAG_IPV6_ONLY) {
1157*e1c7783eSAlexander V. Chernikov 			*pflags++ = 'S';
1158*e1c7783eSAlexander V. Chernikov 			xo_emit("{el:%s}", "ipv6only");
1159*e1c7783eSAlexander V. Chernikov 		}
1160201100c5SBjoern A. Zeeb #endif
1161*e1c7783eSAlexander V. Chernikov 		xo_close_list("flags_pretty");
1162*e1c7783eSAlexander V. Chernikov 		xo_emit(", flags={:flags/%s}", rflags);
1163*e1c7783eSAlexander V. Chernikov 
116433841545SHajimu UMEMOTO 		rtpref = ((p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff;
1165*e1c7783eSAlexander V. Chernikov 		xo_emit(", pref={:preference/%s}", rtpref_str[rtpref]);
116633841545SHajimu UMEMOTO 
1167ffa0165aSHiroki Sato 		gettimeofday(&now, 0);
116833841545SHajimu UMEMOTO 		if (p->expire == 0)
1169*e1c7783eSAlexander V. Chernikov 			xo_emit(", expire=Never\n{en:permanent/true}");
117033841545SHajimu UMEMOTO 		else
1171*e1c7783eSAlexander V. Chernikov 			xo_emit("{d:/, expire=%s\n}{e:expires_sec/%ld}",
1172*e1c7783eSAlexander V. Chernikov 			    sec2str(p->expire - now.tv_sec),
1173*e1c7783eSAlexander V. Chernikov 			    (long)p->expire - now.tv_sec);
1174*e1c7783eSAlexander V. Chernikov 		xo_close_instance("router-list");
117533841545SHajimu UMEMOTO 	}
117633841545SHajimu UMEMOTO 	free(buf);
1177*e1c7783eSAlexander V. Chernikov 	xo_close_list("router-list");
11789a4365d0SYoshinobu Inoue }
11799a4365d0SYoshinobu Inoue 
1180f2203c27SHiroki Sato static void
11819a4365d0SYoshinobu Inoue plist()
11829a4365d0SYoshinobu Inoue {
118333841545SHajimu UMEMOTO 	int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST };
118433841545SHajimu UMEMOTO 	char *buf;
118533841545SHajimu UMEMOTO 	struct in6_prefix *p, *ep, *n;
118633841545SHajimu UMEMOTO 	struct sockaddr_in6 *advrtr;
118733841545SHajimu UMEMOTO 	size_t l;
1188ffa0165aSHiroki Sato 	struct timeval now;
118933841545SHajimu UMEMOTO 	const int niflags = NI_NUMERICHOST;
119033841545SHajimu UMEMOTO 	int ninflags = nflag ? NI_NUMERICHOST : 0;
119133841545SHajimu UMEMOTO 	char namebuf[NI_MAXHOST];
119233841545SHajimu UMEMOTO 
119333841545SHajimu UMEMOTO 	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
1194*e1c7783eSAlexander V. Chernikov 		xo_err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
119533841545SHajimu UMEMOTO 		/*NOTREACHED*/
119633841545SHajimu UMEMOTO 	}
119733841545SHajimu UMEMOTO 	buf = malloc(l);
119833841545SHajimu UMEMOTO 	if (!buf) {
1199*e1c7783eSAlexander V. Chernikov 		xo_err(1, "malloc");
120033841545SHajimu UMEMOTO 		/*NOTREACHED*/
120133841545SHajimu UMEMOTO 	}
120233841545SHajimu UMEMOTO 	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
1203*e1c7783eSAlexander V. Chernikov 		xo_err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
120433841545SHajimu UMEMOTO 		/*NOTREACHED*/
120533841545SHajimu UMEMOTO 	}
120633841545SHajimu UMEMOTO 
1207*e1c7783eSAlexander V. Chernikov 	xo_open_list("prefix-list");
1208*e1c7783eSAlexander V. Chernikov 
120933841545SHajimu UMEMOTO 	ep = (struct in6_prefix *)(buf + l);
121033841545SHajimu UMEMOTO 	for (p = (struct in6_prefix *)buf; p < ep; p = n) {
121133841545SHajimu UMEMOTO 		advrtr = (struct sockaddr_in6 *)(p + 1);
121233841545SHajimu UMEMOTO 		n = (struct in6_prefix *)&advrtr[p->advrtrs];
121333841545SHajimu UMEMOTO 
1214*e1c7783eSAlexander V. Chernikov 		xo_open_instance("prefix-list");
121533841545SHajimu UMEMOTO 		if (getnameinfo((struct sockaddr *)&p->prefix,
121633841545SHajimu UMEMOTO 		    p->prefix.sin6_len, namebuf, sizeof(namebuf),
121733841545SHajimu UMEMOTO 		    NULL, 0, niflags) != 0)
121833841545SHajimu UMEMOTO 			strlcpy(namebuf, "?", sizeof(namebuf));
1219*e1c7783eSAlexander V. Chernikov 		xo_emit("{:prefix/%s%s%d} if={:interface/%s}\n", namebuf, "/",
1220*e1c7783eSAlexander V. Chernikov 		    p->prefixlen, if_indextoname(p->if_index, ifix_buf));
122133841545SHajimu UMEMOTO 
1222ffa0165aSHiroki Sato 		gettimeofday(&now, 0);
122333841545SHajimu UMEMOTO 		/*
122433841545SHajimu UMEMOTO 		 * meaning of fields, especially flags, is very different
122533841545SHajimu UMEMOTO 		 * by origin.  notify the difference to the users.
122633841545SHajimu UMEMOTO 		 */
1227*e1c7783eSAlexander V. Chernikov 		char flags[10] = {}, *pflags = flags;
1228*e1c7783eSAlexander V. Chernikov 		xo_open_list("flags_pretty");
1229*e1c7783eSAlexander V. Chernikov 		if (p->raflags.onlink) {
1230*e1c7783eSAlexander V. Chernikov 			*pflags++ = 'L';
1231*e1c7783eSAlexander V. Chernikov 			xo_emit("{el:%s}", "ra_onlink");
1232*e1c7783eSAlexander V. Chernikov 		}
1233*e1c7783eSAlexander V. Chernikov 		if (p->raflags.autonomous) {
1234*e1c7783eSAlexander V. Chernikov 			*pflags++ = 'A';
1235*e1c7783eSAlexander V. Chernikov 			xo_emit("{el:%s}", "ra_autonomous");
1236*e1c7783eSAlexander V. Chernikov 		}
1237*e1c7783eSAlexander V. Chernikov 		if (p->flags & NDPRF_ONLINK) {
1238*e1c7783eSAlexander V. Chernikov 			*pflags++ = 'O';
1239*e1c7783eSAlexander V. Chernikov 			xo_emit("{el:%s}", "is_onlink");
1240*e1c7783eSAlexander V. Chernikov 		}
1241*e1c7783eSAlexander V. Chernikov 		if (p->flags & NDPRF_DETACHED) {
1242*e1c7783eSAlexander V. Chernikov 			*pflags++ = 'D';
1243*e1c7783eSAlexander V. Chernikov 			xo_emit("{el:%s}", "is_detached");
1244*e1c7783eSAlexander V. Chernikov 		}
124533841545SHajimu UMEMOTO #ifdef NDPRF_HOME
1246*e1c7783eSAlexander V. Chernikov 		if (p->flags & NDPRF_HOME) {
1247*e1c7783eSAlexander V. Chernikov 			*pflags++ = 'H';
1248*e1c7783eSAlexander V. Chernikov 			xo_emit("{el:%s}", "is_home");
1249*e1c7783eSAlexander V. Chernikov 		}
125033841545SHajimu UMEMOTO #endif
1251*e1c7783eSAlexander V. Chernikov 		xo_close_list("flags_pretty");
1252*e1c7783eSAlexander V. Chernikov 		xo_emit("flags={:flags/%s}", flags);
1253*e1c7783eSAlexander V. Chernikov 		int expire_in = p->expire - now.tv_sec;
1254*e1c7783eSAlexander V. Chernikov 
125533841545SHajimu UMEMOTO 		if (p->vltime == ND6_INFINITE_LIFETIME)
1256*e1c7783eSAlexander V. Chernikov 			xo_emit(" vltime=infinity{e:valid-lifetime/%lu}",
1257*e1c7783eSAlexander V. Chernikov 			    (unsigned long)p->vltime);
125833841545SHajimu UMEMOTO 		else
1259*e1c7783eSAlexander V. Chernikov 			xo_emit(" vltime={:valid-lifetime/%lu}",
1260*e1c7783eSAlexander V. Chernikov 			    (unsigned long)p->vltime);
126133841545SHajimu UMEMOTO 		if (p->pltime == ND6_INFINITE_LIFETIME)
1262*e1c7783eSAlexander V. Chernikov 			xo_emit(", pltime=infinity{e:preferred-lifetime/%lu}",
1263*e1c7783eSAlexander V. Chernikov 			    (unsigned long)p->pltime);
126433841545SHajimu UMEMOTO 		else
1265*e1c7783eSAlexander V. Chernikov 			xo_emit(", pltime={:preferred-lifetime/%lu}",
1266*e1c7783eSAlexander V. Chernikov 			    (unsigned long)p->pltime);
126733841545SHajimu UMEMOTO 		if (p->expire == 0)
1268*e1c7783eSAlexander V. Chernikov 			xo_emit(", expire=Never{en:permanent/true}");
12697d26db17SHiroki Sato 		else if (p->expire >= now.tv_sec)
1270*e1c7783eSAlexander V. Chernikov 			xo_emit(", expire=%s{e:expires_sec/%d}",
1271*e1c7783eSAlexander V. Chernikov 			    sec2str(expire_in), expire_in);
127233841545SHajimu UMEMOTO 		else
1273*e1c7783eSAlexander V. Chernikov 			xo_emit(", expired{e:expires_sec/%d}", expire_in);
1274*e1c7783eSAlexander V. Chernikov 		xo_emit(", ref={:refcount/%d}", p->refcnt);
1275*e1c7783eSAlexander V. Chernikov 		xo_emit("\n");
127633841545SHajimu UMEMOTO 		/*
127733841545SHajimu UMEMOTO 		 * "advertising router" list is meaningful only if the prefix
127833841545SHajimu UMEMOTO 		 * information is from RA.
127933841545SHajimu UMEMOTO 		 */
128033841545SHajimu UMEMOTO 		if (p->advrtrs) {
128133841545SHajimu UMEMOTO 			int j;
128233841545SHajimu UMEMOTO 			struct sockaddr_in6 *sin6;
128333841545SHajimu UMEMOTO 
12843174c1d4SHajimu UMEMOTO 			sin6 = advrtr;
1285*e1c7783eSAlexander V. Chernikov 			xo_emit("  advertised by\n");
1286*e1c7783eSAlexander V. Chernikov 			xo_open_list("advertising-routers");
128733841545SHajimu UMEMOTO 			for (j = 0; j < p->advrtrs; j++) {
128833841545SHajimu UMEMOTO 				struct in6_nbrinfo *nbi;
128933841545SHajimu UMEMOTO 
1290*e1c7783eSAlexander V. Chernikov 				xo_open_instance("advertising-routers");
129133841545SHajimu UMEMOTO 				if (getnameinfo((struct sockaddr *)sin6,
129233841545SHajimu UMEMOTO 				    sin6->sin6_len, namebuf, sizeof(namebuf),
129333841545SHajimu UMEMOTO 				    NULL, 0, ninflags) != 0)
129433841545SHajimu UMEMOTO 					strlcpy(namebuf, "?", sizeof(namebuf));
1295*e1c7783eSAlexander V. Chernikov 				char abuf[INET6_ADDRSTRLEN];
1296*e1c7783eSAlexander V. Chernikov 				inet_ntop(AF_INET6, &sin6->sin6_addr, abuf,
1297*e1c7783eSAlexander V. Chernikov 				    sizeof(abuf));
1298*e1c7783eSAlexander V. Chernikov 
1299*e1c7783eSAlexander V. Chernikov 				xo_emit("    {:hostname/%s}{e:address/%s}",
1300*e1c7783eSAlexander V. Chernikov 				    namebuf, abuf);
130133841545SHajimu UMEMOTO 
1302a96bd784SHajimu UMEMOTO 				nbi = getnbrinfo(&sin6->sin6_addr,
1303a96bd784SHajimu UMEMOTO 				    p->if_index, 0);
1304*e1c7783eSAlexander V. Chernikov 				const char *state = "";
130533841545SHajimu UMEMOTO 				if (nbi) {
130633841545SHajimu UMEMOTO 					switch (nbi->state) {
130733841545SHajimu UMEMOTO 					case ND6_LLINFO_REACHABLE:
130833841545SHajimu UMEMOTO 					case ND6_LLINFO_STALE:
130933841545SHajimu UMEMOTO 					case ND6_LLINFO_DELAY:
131033841545SHajimu UMEMOTO 					case ND6_LLINFO_PROBE:
1311*e1c7783eSAlexander V. Chernikov 						state = "reachable";
131233841545SHajimu UMEMOTO 						break;
131333841545SHajimu UMEMOTO 					default:
1314*e1c7783eSAlexander V. Chernikov 						state = "unreachable";
131533841545SHajimu UMEMOTO 					}
131633841545SHajimu UMEMOTO 				} else
1317*e1c7783eSAlexander V. Chernikov 					state = "no neighbor state";
1318*e1c7783eSAlexander V. Chernikov 				xo_emit(" ({:state/%s})\n", state);
131933841545SHajimu UMEMOTO 				sin6++;
1320*e1c7783eSAlexander V. Chernikov 				xo_close_instance("advertising-routers");
132133841545SHajimu UMEMOTO 			}
1322*e1c7783eSAlexander V. Chernikov 			xo_close_list("advertising-routers");
132333841545SHajimu UMEMOTO 		} else
1324*e1c7783eSAlexander V. Chernikov 			xo_emit("  No advertising router\n");
1325*e1c7783eSAlexander V. Chernikov 		xo_close_instance("prefix-list");
132633841545SHajimu UMEMOTO 	}
132733841545SHajimu UMEMOTO 	free(buf);
1328*e1c7783eSAlexander V. Chernikov 
1329*e1c7783eSAlexander V. Chernikov 	xo_close_list("prefix-list");
13309a4365d0SYoshinobu Inoue }
13319a4365d0SYoshinobu Inoue 
1332f2203c27SHiroki Sato static void
13339a4365d0SYoshinobu Inoue pfx_flush()
13349a4365d0SYoshinobu Inoue {
13359a4365d0SYoshinobu Inoue 	char dummyif[IFNAMSIZ+8];
13367ae43b31SRenato Botelho 	int sock;
13379a4365d0SYoshinobu Inoue 
13387ae43b31SRenato Botelho 	if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1339*e1c7783eSAlexander V. Chernikov 		xo_err(1, "socket");
1340a96bd784SHajimu UMEMOTO 	strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
13417ae43b31SRenato Botelho 	if (ioctl(sock, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0)
1342*e1c7783eSAlexander V. Chernikov 		xo_err(1, "ioctl(SIOCSPFXFLUSH_IN6)");
13437ae43b31SRenato Botelho 
13447ae43b31SRenato Botelho 	close(sock);
13459a4365d0SYoshinobu Inoue }
13469a4365d0SYoshinobu Inoue 
1347f2203c27SHiroki Sato static void
13489a4365d0SYoshinobu Inoue rtr_flush()
13499a4365d0SYoshinobu Inoue {
13509a4365d0SYoshinobu Inoue 	char dummyif[IFNAMSIZ+8];
13517ae43b31SRenato Botelho 	int sock;
13529a4365d0SYoshinobu Inoue 
13537ae43b31SRenato Botelho 	if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1354*e1c7783eSAlexander V. Chernikov 		xo_err(1, "socket");
1355a96bd784SHajimu UMEMOTO 	strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
13567ae43b31SRenato Botelho 	if (ioctl(sock, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0)
1357*e1c7783eSAlexander V. Chernikov 		xo_err(1, "ioctl(SIOCSRTRFLUSH_IN6)");
1358ccf935ddSJun-ichiro itojun Hagino 
13597ae43b31SRenato Botelho 	close(sock);
13609a4365d0SYoshinobu Inoue }
13619a4365d0SYoshinobu Inoue 
1362f2203c27SHiroki Sato static void
13639a4365d0SYoshinobu Inoue harmonize_rtr()
13649a4365d0SYoshinobu Inoue {
13659a4365d0SYoshinobu Inoue 	char dummyif[IFNAMSIZ+8];
13667ae43b31SRenato Botelho 	int sock;
13679a4365d0SYoshinobu Inoue 
13687ae43b31SRenato Botelho 	if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1369*e1c7783eSAlexander V. Chernikov 		xo_err(1, "socket");
1370a96bd784SHajimu UMEMOTO 	strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
13717ae43b31SRenato Botelho 	if (ioctl(sock, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0)
1372*e1c7783eSAlexander V. Chernikov 		xo_err(1, "ioctl(SIOCSNDFLUSH_IN6)");
1373ccf935ddSJun-ichiro itojun Hagino 
13747ae43b31SRenato Botelho 	close(sock);
13759a4365d0SYoshinobu Inoue }
1376ccf935ddSJun-ichiro itojun Hagino 
1377ccf935ddSJun-ichiro itojun Hagino #ifdef SIOCSDEFIFACE_IN6	/* XXX: check SIOCGDEFIFACE_IN6 as well? */
1378ccf935ddSJun-ichiro itojun Hagino static void
1379bfc75db0SAndrey V. Elsukov setdefif(char *ifname)
1380ccf935ddSJun-ichiro itojun Hagino {
1381ccf935ddSJun-ichiro itojun Hagino 	struct in6_ndifreq ndifreq;
1382ccf935ddSJun-ichiro itojun Hagino 	unsigned int ifindex;
13837ae43b31SRenato Botelho 	int sock;
1384ccf935ddSJun-ichiro itojun Hagino 
1385ccf935ddSJun-ichiro itojun Hagino 	if (strcasecmp(ifname, "delete") == 0)
1386ccf935ddSJun-ichiro itojun Hagino 		ifindex = 0;
1387ccf935ddSJun-ichiro itojun Hagino 	else {
1388ccf935ddSJun-ichiro itojun Hagino 		if ((ifindex = if_nametoindex(ifname)) == 0)
1389*e1c7783eSAlexander V. Chernikov 			xo_err(1, "failed to resolve i/f index for %s", ifname);
13909a4365d0SYoshinobu Inoue 	}
13919a4365d0SYoshinobu Inoue 
13927ae43b31SRenato Botelho 	if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1393*e1c7783eSAlexander V. Chernikov 		xo_err(1, "socket");
1394ccf935ddSJun-ichiro itojun Hagino 
1395a96bd784SHajimu UMEMOTO 	strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */
1396ccf935ddSJun-ichiro itojun Hagino 	ndifreq.ifindex = ifindex;
1397ccf935ddSJun-ichiro itojun Hagino 
13987ae43b31SRenato Botelho 	if (ioctl(sock, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1399*e1c7783eSAlexander V. Chernikov 		xo_err(1, "ioctl(SIOCSDEFIFACE_IN6)");
1400ccf935ddSJun-ichiro itojun Hagino 
14017ae43b31SRenato Botelho 	close(sock);
1402ccf935ddSJun-ichiro itojun Hagino }
1403ccf935ddSJun-ichiro itojun Hagino 
1404ccf935ddSJun-ichiro itojun Hagino static void
1405ccf935ddSJun-ichiro itojun Hagino getdefif()
1406ccf935ddSJun-ichiro itojun Hagino {
1407ccf935ddSJun-ichiro itojun Hagino 	struct in6_ndifreq ndifreq;
1408ccf935ddSJun-ichiro itojun Hagino 	char ifname[IFNAMSIZ+8];
14097ae43b31SRenato Botelho 	int sock;
1410ccf935ddSJun-ichiro itojun Hagino 
14117ae43b31SRenato Botelho 	if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1412*e1c7783eSAlexander V. Chernikov 		xo_err(1, "socket");
1413ccf935ddSJun-ichiro itojun Hagino 
1414ccf935ddSJun-ichiro itojun Hagino 	memset(&ndifreq, 0, sizeof(ndifreq));
1415a96bd784SHajimu UMEMOTO 	strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */
1416ccf935ddSJun-ichiro itojun Hagino 
14177ae43b31SRenato Botelho 	if (ioctl(sock, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1418*e1c7783eSAlexander V. Chernikov 		xo_err(1, "ioctl(SIOCGDEFIFACE_IN6)");
1419ccf935ddSJun-ichiro itojun Hagino 
1420ccf935ddSJun-ichiro itojun Hagino 	if (ndifreq.ifindex == 0)
1421*e1c7783eSAlexander V. Chernikov 		xo_emit("No default interface.\n");
1422ccf935ddSJun-ichiro itojun Hagino 	else {
1423ccf935ddSJun-ichiro itojun Hagino 		if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL)
1424*e1c7783eSAlexander V. Chernikov 			xo_err(1, "failed to resolve ifname for index %lu",
1425ccf935ddSJun-ichiro itojun Hagino 			    ndifreq.ifindex);
1426*e1c7783eSAlexander V. Chernikov 		xo_emit("ND default interface = {:default-interface/%s}\n", ifname);
1427ccf935ddSJun-ichiro itojun Hagino 	}
1428ccf935ddSJun-ichiro itojun Hagino 
14297ae43b31SRenato Botelho 	close(sock);
1430ccf935ddSJun-ichiro itojun Hagino }
1431937f8ddfSRenato Botelho #endif /* SIOCSDEFIFACE_IN6 */
1432ccf935ddSJun-ichiro itojun Hagino 
14339a4365d0SYoshinobu Inoue static char *
1434bfc75db0SAndrey V. Elsukov sec2str(time_t total)
14359a4365d0SYoshinobu Inoue {
14369a4365d0SYoshinobu Inoue 	static char result[256];
14379a4365d0SYoshinobu Inoue 	int days, hours, mins, secs;
14389a4365d0SYoshinobu Inoue 	int first = 1;
14399a4365d0SYoshinobu Inoue 	char *p = result;
1440a96bd784SHajimu UMEMOTO 	char *ep = &result[sizeof(result)];
1441a96bd784SHajimu UMEMOTO 	int n;
14429a4365d0SYoshinobu Inoue 
14439a4365d0SYoshinobu Inoue 	days = total / 3600 / 24;
14449a4365d0SYoshinobu Inoue 	hours = (total / 3600) % 24;
14459a4365d0SYoshinobu Inoue 	mins = (total / 60) % 60;
14469a4365d0SYoshinobu Inoue 	secs = total % 60;
14479a4365d0SYoshinobu Inoue 
14489a4365d0SYoshinobu Inoue 	if (days) {
14499a4365d0SYoshinobu Inoue 		first = 0;
1450a96bd784SHajimu UMEMOTO 		n = snprintf(p, ep - p, "%dd", days);
1451a96bd784SHajimu UMEMOTO 		if (n < 0 || n >= ep - p)
1452a96bd784SHajimu UMEMOTO 			return "?";
1453a96bd784SHajimu UMEMOTO 		p += n;
14549a4365d0SYoshinobu Inoue 	}
14559a4365d0SYoshinobu Inoue 	if (!first || hours) {
14569a4365d0SYoshinobu Inoue 		first = 0;
1457a96bd784SHajimu UMEMOTO 		n = snprintf(p, ep - p, "%dh", hours);
1458a96bd784SHajimu UMEMOTO 		if (n < 0 || n >= ep - p)
1459a96bd784SHajimu UMEMOTO 			return "?";
1460a96bd784SHajimu UMEMOTO 		p += n;
14619a4365d0SYoshinobu Inoue 	}
14629a4365d0SYoshinobu Inoue 	if (!first || mins) {
14639a4365d0SYoshinobu Inoue 		first = 0;
1464a96bd784SHajimu UMEMOTO 		n = snprintf(p, ep - p, "%dm", mins);
1465a96bd784SHajimu UMEMOTO 		if (n < 0 || n >= ep - p)
1466a96bd784SHajimu UMEMOTO 			return "?";
1467a96bd784SHajimu UMEMOTO 		p += n;
14689a4365d0SYoshinobu Inoue 	}
1469a96bd784SHajimu UMEMOTO 	snprintf(p, ep - p, "%ds", secs);
14709a4365d0SYoshinobu Inoue 
14719a4365d0SYoshinobu Inoue 	return(result);
14729a4365d0SYoshinobu Inoue }
14739a4365d0SYoshinobu Inoue 
14749a4365d0SYoshinobu Inoue /*
14759a4365d0SYoshinobu Inoue  * Print the timestamp
14769a4365d0SYoshinobu Inoue  * from tcpdump/util.c
14779a4365d0SYoshinobu Inoue  */
14789a4365d0SYoshinobu Inoue static void
1479bfc75db0SAndrey V. Elsukov ts_print(const struct timeval *tvp)
14809a4365d0SYoshinobu Inoue {
14817ae43b31SRenato Botelho 	int sec;
14829a4365d0SYoshinobu Inoue 
14839a4365d0SYoshinobu Inoue 	/* Default */
14847ae43b31SRenato Botelho 	sec = (tvp->tv_sec + thiszone) % 86400;
1485*e1c7783eSAlexander V. Chernikov 	xo_emit("{:tv_sec/%lld}{:tv_usec/%lld}%02d:%02d:%02d.%06u ",
1486*e1c7783eSAlexander V. Chernikov 	    tvp->tv_sec, tvp->tv_usec,
14877ae43b31SRenato Botelho 	    sec / 3600, (sec % 3600) / 60, sec % 60, (u_int32_t)tvp->tv_usec);
14889a4365d0SYoshinobu Inoue }
14896e6b3f7cSQing Li 
14906e6b3f7cSQing Li #undef NEXTADDR
1491