xref: /dragonfly/usr.sbin/ndp/ndp.c (revision dc71b7ab)
1 /*	$FreeBSD: src/usr.sbin/ndp/ndp.c,v 1.2.2.6 2003/08/12 16:27:57 ume Exp $	*/
2 /*	$DragonFly: src/usr.sbin/ndp/ndp.c,v 1.6 2004/12/30 02:35:24 hsu Exp $	*/
3 /*	$KAME: ndp.c,v 1.65 2001/05/08 04:36:34 itojun Exp $	*/
4 
5 /*
6  * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the project nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 /*
34  * Copyright (c) 1984, 1993
35  *	The Regents of the University of California.  All rights reserved.
36  *
37  * This code is derived from software contributed to Berkeley by
38  * Sun Microsystems, Inc.
39  *
40  * Redistribution and use in source and binary forms, with or without
41  * modification, are permitted provided that the following conditions
42  * are met:
43  * 1. Redistributions of source code must retain the above copyright
44  *    notice, this list of conditions and the following disclaimer.
45  * 2. Redistributions in binary form must reproduce the above copyright
46  *    notice, this list of conditions and the following disclaimer in the
47  *    documentation and/or other materials provided with the distribution.
48  * 3. Neither the name of the University nor the names of its contributors
49  *    may be used to endorse or promote products derived from this software
50  *    without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62  * SUCH DAMAGE.
63  */
64 
65 /*
66  * Based on:
67  * "@(#) Copyright (c) 1984, 1993\n\
68  *	The Regents of the University of California.  All rights reserved.\n";
69  *
70  * "@(#)arp.c	8.2 (Berkeley) 1/2/94";
71  */
72 
73 /*
74  * ndp - display, set, delete and flush neighbor cache
75  */
76 
77 
78 #include <sys/param.h>
79 #include <sys/file.h>
80 #include <sys/ioctl.h>
81 #include <sys/socket.h>
82 #include <sys/sysctl.h>
83 #include <sys/time.h>
84 #include <sys/queue.h>
85 
86 #include <net/if.h>
87 #include <net/if_var.h>
88 #include <net/if_dl.h>
89 #include <net/if_types.h>
90 #include <net/route.h>
91 
92 #include <netinet/in.h>
93 #include <netinet/if_ether.h>
94 
95 #include <netinet/icmp6.h>
96 #include <netinet6/in6_var.h>
97 #include <netinet6/nd6.h>
98 
99 #include <arpa/inet.h>
100 
101 #include <netdb.h>
102 #include <errno.h>
103 #include <nlist.h>
104 #include <stdio.h>
105 #include <string.h>
106 #include <paths.h>
107 #include <err.h>
108 #include <stdlib.h>
109 #include <fcntl.h>
110 #include <unistd.h>
111 #include "gmt2local.h"
112 
113 #ifndef NI_WITHSCOPEID
114 #define NI_WITHSCOPEID	0
115 #endif
116 
117 /* packing rule for routing socket */
118 #define ROUNDUP(a) \
119 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
120 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
121 
122 static int pid;
123 static int cflag;
124 static int nflag;
125 static int tflag;
126 static int32_t thiszone;	/* time difference with gmt */
127 static int s = -1;
128 static int repeat = 0;
129 
130 char ntop_buf[INET6_ADDRSTRLEN];	/* inet_ntop() */
131 char host_buf[NI_MAXHOST];		/* getnameinfo() */
132 char ifix_buf[IFNAMSIZ];		/* if_indextoname() */
133 
134 int main(int, char **);
135 int file(char *);
136 void getsocket(void);
137 int set(int, char **);
138 void get(char *);
139 int delete(char *);
140 void dump(struct in6_addr *);
141 static struct in6_nbrinfo *getnbrinfo(struct in6_addr *addr,
142 					   int ifindex, int);
143 static char *ether_str(struct sockaddr_dl *);
144 int ndp_ether_aton(char *, u_char *);
145 void usage(void);
146 int rtmsg(int);
147 void ifinfo(int, char **);
148 void rtrlist(void);
149 void plist(void);
150 void pfx_flush(void);
151 void rtrlist(void);
152 void rtr_flush(void);
153 void harmonize_rtr(void);
154 #ifdef SIOCSDEFIFACE_IN6	/* XXX: check SIOCGDEFIFACE_IN6 as well? */
155 static void getdefif(void);
156 static void setdefif(char *);
157 #endif
158 static char *sec2str(time_t t);
159 static char *ether_str(struct sockaddr_dl *sdl);
160 static void ts_print(const struct timeval *);
161 
162 static char *rtpref_str[] = {
163 	"medium",		/* 00 */
164 	"high",			/* 01 */
165 	"rsv",			/* 10 */
166 	"low"			/* 11 */
167 };
168 
169 int
170 main(int argc, char **argv)
171 {
172 	int ch;
173 	int aflag = 0, dflag = 0, sflag = 0, Hflag = 0,
174 		pflag = 0, rflag = 0, Pflag = 0, Rflag = 0;
175 
176 	pid = getpid();
177 	thiszone = gmt2local(0);
178 	while ((ch = getopt(argc, argv, "acndfIilprstA:HPR")) != -1)
179 		switch ((char)ch) {
180 		case 'a':
181 			aflag = 1;
182 			break;
183 		case 'c':
184 			cflag = 1;
185 			break;
186 		case 'd':
187 			dflag = 1;
188 			break;
189 		case 'I':
190 #ifdef SIOCSDEFIFACE_IN6	/* XXX: check SIOCGDEFIFACE_IN6 as well? */
191 			if (argc > 2)
192 				setdefif(argv[2]);
193 			getdefif(); /* always call it to print the result */
194 			exit(0);
195 #else
196 			errx(1, "not supported yet");
197 			/*NOTREACHED*/
198 #endif
199 		case 'i' :
200 			argc -= optind;
201 			argv += optind;
202 			if (argc < 1)
203 				usage();
204 			ifinfo(argc, argv);
205 			exit(0);
206 		case 'n':
207 			nflag = 1;
208 			continue;
209 		case 'p':
210 			pflag = 1;
211 			break;
212 		case 'f' :
213 			if (argc != 3)
214 				usage();
215 			file(argv[2]);
216 			exit(0);
217 		case 'l' :
218 			/* obsolete, ignored */
219 			break;
220 		case 'r' :
221 			rflag = 1;
222 			break;
223 		case 's':
224 			sflag = 1;
225 			break;
226 		case 't':
227 			tflag = 1;
228 			break;
229 		case 'A':
230 			aflag = 1;
231 			repeat = atoi(optarg);
232 			if (repeat < 0)
233 				usage();
234 			break;
235 		case 'H' :
236 			Hflag = 1;
237 			break;
238 		case 'P':
239 			Pflag = 1;
240 			break;
241 		case 'R':
242 			Rflag = 1;
243 			break;
244 		default:
245 			usage();
246 		}
247 
248 	argc -= optind;
249 	argv += optind;
250 
251 	if (aflag || cflag) {
252 		dump(0);
253 		exit(0);
254 	}
255 	if (dflag) {
256 		if (argc != 1)
257 			usage();
258 		delete(argv[0]);
259 		exit(0);
260 	}
261 	if (pflag) {
262 		plist();
263 		exit(0);
264 	}
265 	if (rflag) {
266 		rtrlist();
267 		exit(0);
268 	}
269 	if (sflag) {
270 		if (argc < 2 || argc > 4)
271 			usage();
272 		exit(set(argc, argv) ? 1 : 0);
273 	}
274 	if (Hflag) {
275 		harmonize_rtr();
276 		exit(0);
277 	}
278 	if (Pflag) {
279 		pfx_flush();
280 		exit(0);
281 	}
282 	if (Rflag) {
283 		rtr_flush();
284 		exit(0);
285 	}
286 
287 	if (argc != 1)
288 		usage();
289 	get(argv[0]);
290 	exit(0);
291 }
292 
293 /*
294  * Process a file to set standard ndp entries
295  */
296 int
297 file(char *name)
298 {
299 	FILE *fp;
300 	int i, retval;
301 	char line[100], arg[5][50], *args[5];
302 
303 	if ((fp = fopen(name, "r")) == NULL) {
304 		fprintf(stderr, "ndp: cannot open %s\n", name);
305 		exit(1);
306 	}
307 	args[0] = &arg[0][0];
308 	args[1] = &arg[1][0];
309 	args[2] = &arg[2][0];
310 	args[3] = &arg[3][0];
311 	args[4] = &arg[4][0];
312 	retval = 0;
313 	while(fgets(line, 100, fp) != NULL) {
314 		i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2],
315 		    arg[3], arg[4]);
316 		if (i < 2) {
317 			fprintf(stderr, "ndp: bad line: %s\n", line);
318 			retval = 1;
319 			continue;
320 		}
321 		if (set(i, args))
322 			retval = 1;
323 	}
324 	fclose(fp);
325 	return (retval);
326 }
327 
328 void
329 getsocket(void)
330 {
331 	if (s < 0) {
332 		s = socket(PF_ROUTE, SOCK_RAW, 0);
333 		if (s < 0) {
334 			perror("ndp: socket");
335 			exit(1);
336 		}
337 	}
338 }
339 
340 struct	sockaddr_in6 so_mask = {sizeof(so_mask), AF_INET6 };
341 struct	sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET6 }, sin_m;
342 struct	sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m;
343 int	expire_time, flags, found_entry;
344 struct	{
345 	struct	rt_msghdr m_rtm;
346 	char	m_space[512];
347 }	m_rtmsg;
348 
349 /*
350  * Set an individual neighbor cache entry
351  */
352 int
353 set(int argc, char **argv)
354 {
355 	struct sockaddr_in6 *sin = &sin_m;
356 	struct sockaddr_dl *sdl;
357 	struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
358 	struct addrinfo hints, *res;
359 	int gai_error;
360 	u_char *ea;
361 	char *host = argv[0], *eaddr = argv[1];
362 
363 	getsocket();
364 	argc -= 2;
365 	argv += 2;
366 	sdl_m = blank_sdl;
367 	sin_m = blank_sin;
368 
369 	bzero(&hints, sizeof(hints));
370 	hints.ai_family = AF_INET6;
371 	gai_error = getaddrinfo(host, NULL, &hints, &res);
372 	if (gai_error) {
373 		fprintf(stderr, "ndp: %s: %s\n", host,
374 			gai_strerror(gai_error));
375 		return 1;
376 	}
377 	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
378 #ifdef __KAME__
379 	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
380 		*(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
381 			htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
382 	}
383 #endif
384 	ea = (u_char *)LLADDR(&sdl_m);
385 	if (ndp_ether_aton(eaddr, ea) == 0)
386 		sdl_m.sdl_alen = 6;
387 	flags = expire_time = 0;
388 	while (argc-- > 0) {
389 		if (strncmp(argv[0], "temp", 4) == 0) {
390 			struct timeval time;
391 			gettimeofday(&time, 0);
392 			expire_time = time.tv_sec + 20 * 60;
393 		} else if (strncmp(argv[0], "proxy", 5) == 0)
394 			flags |= RTF_ANNOUNCE;
395 		argv++;
396 	}
397 	if (rtmsg(RTM_GET) < 0) {
398 		perror(host);
399 		return (1);
400 	}
401 	sin = (struct sockaddr_in6 *)(rtm + 1);
402 	sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
403 	if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
404 		if (sdl->sdl_family == AF_LINK &&
405 		    (rtm->rtm_flags & RTF_LLINFO) &&
406 		    !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
407 		case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
408 		case IFT_ISO88024: case IFT_ISO88025:
409 			goto overwrite;
410 		}
411 		/*
412 		 * IPv4 arp command retries with sin_other = SIN_PROXY here.
413 		 */
414 		fprintf(stderr, "set: cannot configure a new entry\n");
415 		return 1;
416 	}
417 
418 overwrite:
419 	if (sdl->sdl_family != AF_LINK) {
420 		printf("cannot intuit interface index and type for %s\n", host);
421 		return (1);
422 	}
423 	sdl_m.sdl_type = sdl->sdl_type;
424 	sdl_m.sdl_index = sdl->sdl_index;
425 	return (rtmsg(RTM_ADD));
426 }
427 
428 /*
429  * Display an individual neighbor cache entry
430  */
431 void
432 get(char *host)
433 {
434 	struct sockaddr_in6 *sin = &sin_m;
435 	struct addrinfo hints, *res;
436 	int gai_error;
437 
438 	sin_m = blank_sin;
439 	bzero(&hints, sizeof(hints));
440 	hints.ai_family = AF_INET6;
441 	gai_error = getaddrinfo(host, NULL, &hints, &res);
442 	if (gai_error) {
443 		fprintf(stderr, "ndp: %s: %s\n", host,
444 			gai_strerror(gai_error));
445 		return;
446 	}
447 	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
448 #ifdef __KAME__
449 	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
450 		*(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
451 			htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
452 	}
453 #endif
454 	dump(&sin->sin6_addr);
455 	if (found_entry == 0) {
456 		getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
457 			    sizeof(host_buf), NULL ,0,
458 			    NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
459 		printf("%s (%s) -- no entry\n", host, host_buf);
460 		exit(1);
461 	}
462 }
463 
464 /*
465  * Delete a neighbor cache entry
466  */
467 int
468 delete(char *host)
469 {
470 	struct sockaddr_in6 *sin = &sin_m;
471 	struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
472 	struct sockaddr_dl *sdl;
473 	struct addrinfo hints, *res;
474 	int gai_error;
475 
476 	getsocket();
477 	sin_m = blank_sin;
478 
479 	bzero(&hints, sizeof(hints));
480 	hints.ai_family = AF_INET6;
481 	gai_error = getaddrinfo(host, NULL, &hints, &res);
482 	if (gai_error) {
483 		fprintf(stderr, "ndp: %s: %s\n", host,
484 			gai_strerror(gai_error));
485 		return 1;
486 	}
487 	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
488 #ifdef __KAME__
489 	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
490 		*(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
491 			htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
492 	}
493 #endif
494 	if (rtmsg(RTM_GET) < 0) {
495 		perror(host);
496 		return (1);
497 	}
498 	sin = (struct sockaddr_in6 *)(rtm + 1);
499 	sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
500 	if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
501 		if (sdl->sdl_family == AF_LINK &&
502 		    (rtm->rtm_flags & RTF_LLINFO) &&
503 		    !(rtm->rtm_flags & RTF_GATEWAY)) {
504 			goto delete;
505 		}
506 		/*
507 		 * IPv4 arp command retries with sin_other = SIN_PROXY here.
508 		 */
509 		fprintf(stderr, "delete: cannot delete non-NDP entry\n");
510 		return 1;
511 	}
512 
513 delete:
514 	if (sdl->sdl_family != AF_LINK) {
515 		printf("cannot locate %s\n", host);
516 		return (1);
517 	}
518 	if (rtmsg(RTM_DELETE) == 0) {
519 		struct sockaddr_in6 s6 = *sin; /* XXX: for safety */
520 
521 #ifdef __KAME__
522 		if (IN6_IS_ADDR_LINKLOCAL(&s6.sin6_addr)) {
523 			s6.sin6_scope_id = ntohs(*(u_int16_t *)&s6.sin6_addr.s6_addr[2]);
524 			*(u_int16_t *)&s6.sin6_addr.s6_addr[2] = 0;
525 		}
526 #endif
527 		getnameinfo((struct sockaddr *)&s6,
528 			    s6.sin6_len, host_buf,
529 			    sizeof(host_buf), NULL, 0,
530 			    NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
531 		printf("%s (%s) deleted\n", host, host_buf);
532 	}
533 
534 	return 0;
535 }
536 
537 #define W_ADDR	31
538 #define W_LL	17
539 #define W_IF	6
540 
541 /*
542  * Dump the entire neighbor cache
543  */
544 void
545 dump(struct in6_addr *addr)
546 {
547 	int mib[6];
548 	size_t needed;
549 	char *lim, *buf, *next;
550 	struct rt_msghdr *rtm;
551 	struct sockaddr_in6 *sin;
552 	struct sockaddr_dl *sdl;
553 	extern int h_errno;
554 	struct in6_nbrinfo *nbi;
555 	struct timeval time;
556 	int addrwidth;
557 	int llwidth;
558 	int ifwidth;
559 	char flgbuf[8];
560 	char *ifname;
561 
562 	/* Print header */
563 	if (!tflag && !cflag)
564 		printf("%-*.*s %-*.*s %*.*s %-9.9s %2s %4s %4s\n",
565 		    W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address",
566 		    W_IF, W_IF, "Netif", "Expire", "St", "Flgs", "Prbs");
567 
568 again:;
569 	mib[0] = CTL_NET;
570 	mib[1] = PF_ROUTE;
571 	mib[2] = 0;
572 	mib[3] = AF_INET6;
573 	mib[4] = NET_RT_FLAGS;
574 	mib[5] = RTF_LLINFO;
575 	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
576 		err(1, "sysctl(PF_ROUTE estimate)");
577 	if (needed > 0) {
578 		if ((buf = malloc(needed)) == NULL)
579 			errx(1, "malloc");
580 		if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
581 			err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
582 		lim = buf + needed;
583 	} else
584 		buf = lim = NULL;
585 
586 	for (next = buf; next && next < lim; next += rtm->rtm_msglen) {
587 		int isrouter = 0, prbs = 0;
588 
589 		rtm = (struct rt_msghdr *)next;
590 		sin = (struct sockaddr_in6 *)(rtm + 1);
591 		sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len));
592 
593 		/*
594 		 * Some OSes can produce a route that has the LINK flag but
595 		 * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD
596 		 * and BSD/OS, where xx is not the interface identifier on
597 		 * lo0).  Such routes entry would annoy getnbrinfo() below,
598 		 * so we skip them.
599 		 * XXX: such routes should have the GATEWAY flag, not the
600 		 * LINK flag.  However, there are rotten routing software
601 		 * that advertises all routes that have the GATEWAY flag.
602 		 * Thus, KAME kernel intentionally does not set the LINK flag.
603 		 * What is to be fixed is not ndp, but such routing software
604 		 * (and the kernel workaround)...
605 		 */
606 		if (sdl->sdl_family != AF_LINK)
607 			continue;
608 
609 		if (addr) {
610 			if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr))
611 				continue;
612 			found_entry = 1;
613 		} else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
614 			continue;
615 		if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) ||
616 		    IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) {
617 			/* XXX: should scope id be filled in the kernel? */
618 			if (sin->sin6_scope_id == 0)
619 				sin->sin6_scope_id = sdl->sdl_index;
620 #ifdef __KAME__
621 			/* KAME specific hack; removed the embedded id */
622 			*(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0;
623 #endif
624 		}
625 		getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
626 			    sizeof(host_buf), NULL, 0,
627 			    NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
628 		if (cflag == 1) {
629 #ifdef RTF_WASCLONED
630 			if (rtm->rtm_flags & RTF_WASCLONED)
631 				delete(host_buf);
632 #else
633 			delete(host_buf);
634 #endif
635 			continue;
636 		}
637 		gettimeofday(&time, 0);
638 		if (tflag)
639 			ts_print(&time);
640 
641 		addrwidth = strlen(host_buf);
642 		if (addrwidth < W_ADDR)
643 			addrwidth = W_ADDR;
644 		llwidth = strlen(ether_str(sdl));
645 		if (W_ADDR + W_LL - addrwidth > llwidth)
646 			llwidth = W_ADDR + W_LL - addrwidth;
647 		ifname = if_indextoname(sdl->sdl_index, ifix_buf);
648 		if (!ifname)
649 			ifname = "?";
650 		ifwidth = strlen(ifname);
651 		if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth)
652 			ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth;
653 
654 		printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf,
655 		    llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname);
656 
657 		/* Print neighbor discovery specific informations */
658 		nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1);
659 		if (nbi) {
660 			if (nbi->expire > time.tv_sec) {
661 				printf(" %-9.9s",
662 				       sec2str(nbi->expire - time.tv_sec));
663 			} else if (nbi->expire == 0)
664 				printf(" %-9.9s", "permanent");
665 			else
666 				printf(" %-9.9s", "expired");
667 
668 			switch(nbi->state) {
669 			 case ND6_LLINFO_NOSTATE:
670 				 printf(" N");
671 				 break;
672 #ifdef ND6_LLINFO_WAITDELETE
673 			 case ND6_LLINFO_WAITDELETE:
674 				 printf(" W");
675 				 break;
676 #endif
677 			 case ND6_LLINFO_INCOMPLETE:
678 				 printf(" I");
679 				 break;
680 			 case ND6_LLINFO_REACHABLE:
681 				 printf(" R");
682 				 break;
683 			 case ND6_LLINFO_STALE:
684 				 printf(" S");
685 				 break;
686 			 case ND6_LLINFO_DELAY:
687 				 printf(" D");
688 				 break;
689 			 case ND6_LLINFO_PROBE:
690 				 printf(" P");
691 				 break;
692 			 default:
693 				 printf(" ?");
694 				 break;
695 			}
696 
697 			isrouter = nbi->isrouter;
698 			prbs = nbi->asked;
699 		} else {
700 			warnx("failed to get neighbor information");
701 			printf("  ");
702 		}
703 		putchar(' ');
704 
705 		/*
706 		 * other flags. R: router, P: proxy, W: ??
707 		 */
708 		if ((rtm->rtm_addrs & RTA_NETMASK) == 0) {
709 			snprintf(flgbuf, sizeof(flgbuf), "%s%s",
710 				isrouter ? "R" : "",
711 				(rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
712 		} else {
713 			sin = (struct sockaddr_in6 *)
714 				(sdl->sdl_len + (char *)sdl);
715 			snprintf(flgbuf, sizeof(flgbuf), "%s%s%s%s",
716 				isrouter ? "R" : "",
717 				!IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr)
718 					? "P" : "",
719 				(sin->sin6_len != sizeof(struct sockaddr_in6))
720 					? "W" : "",
721 				(rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
722 		}
723 		printf(" %-4.4s", flgbuf);
724 
725 		if (prbs)
726 			printf(" %4d", prbs);
727 
728 		printf("\n");
729 	}
730 	if (buf != NULL)
731 		free(buf);
732 
733 	if (repeat) {
734 		printf("\n");
735 		sleep(repeat);
736 		goto again;
737 	}
738 }
739 
740 static struct in6_nbrinfo *
741 getnbrinfo(struct in6_addr *addr, int ifindex, int warning)
742 {
743 	static struct in6_nbrinfo nbi;
744 	int s;
745 
746 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
747 		err(1, "socket");
748 
749 	bzero(&nbi, sizeof(nbi));
750 	if_indextoname(ifindex, nbi.ifname);
751 	nbi.addr = *addr;
752 	if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) {
753 		if (warning)
754 			warn("ioctl(SIOCGNBRINFO_IN6)");
755 		close(s);
756 		return(NULL);
757 	}
758 
759 	close(s);
760 	return(&nbi);
761 }
762 
763 static char *
764 ether_str(struct sockaddr_dl *sdl)
765 {
766 	static char ebuf[32];
767 	u_char *cp;
768 
769 	if (sdl->sdl_alen) {
770 		cp = (u_char *)LLADDR(sdl);
771 		sprintf(ebuf, "%x:%x:%x:%x:%x:%x",
772 			cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
773 	} else {
774 		sprintf(ebuf, "(incomplete)");
775 	}
776 
777 	return(ebuf);
778 }
779 
780 int
781 ndp_ether_aton(char *a, u_char *n)
782 {
783 	int i, o[6];
784 
785 	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
786 					   &o[3], &o[4], &o[5]);
787 	if (i != 6) {
788 		fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a);
789 		return (1);
790 	}
791 	for (i=0; i<6; i++)
792 		n[i] = o[i];
793 	return (0);
794 }
795 
796 void
797 usage(void)
798 {
799 	printf("usage: ndp hostname\n");
800 	printf("       ndp -a[nt]\n");
801 	printf("       ndp [-nt] -A wait\n");
802 	printf("       ndp -c[nt]\n");
803 	printf("       ndp -d[nt] hostname\n");
804 	printf("       ndp -f[nt] filename\n");
805 	printf("       ndp -i interface [flags...]\n");
806 #ifdef SIOCSDEFIFACE_IN6
807 	printf("       ndp -I [interface|delete]\n");
808 #endif
809 	printf("       ndp -p\n");
810 	printf("       ndp -r\n");
811 	printf("       ndp -s hostname ether_addr [temp] [proxy]\n");
812 	printf("       ndp -H\n");
813 	printf("       ndp -P\n");
814 	printf("       ndp -R\n");
815 	exit(1);
816 }
817 
818 int
819 rtmsg(int cmd)
820 {
821 	static int seq;
822 	int rlen;
823 	struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
824 	char *cp = m_rtmsg.m_space;
825 	int l;
826 
827 	errno = 0;
828 	if (cmd == RTM_DELETE)
829 		goto doit;
830 	bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
831 	rtm->rtm_flags = flags;
832 	rtm->rtm_version = RTM_VERSION;
833 
834 	switch (cmd) {
835 	default:
836 		fprintf(stderr, "ndp: internal wrong cmd\n");
837 		exit(1);
838 	case RTM_ADD:
839 		rtm->rtm_addrs |= RTA_GATEWAY;
840 		rtm->rtm_rmx.rmx_expire = expire_time;
841 		rtm->rtm_inits = RTV_EXPIRE;
842 		rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
843 		if (rtm->rtm_flags & RTF_ANNOUNCE) {
844 			rtm->rtm_flags &= ~RTF_HOST;
845 			rtm->rtm_flags |= RTA_NETMASK;
846 		}
847 		/* FALLTHROUGH */
848 	case RTM_GET:
849 		rtm->rtm_addrs |= RTA_DST;
850 	}
851 #define NEXTADDR(w, s) \
852 	if (rtm->rtm_addrs & (w)) { \
853 		bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);}
854 
855 	NEXTADDR(RTA_DST, sin_m);
856 	NEXTADDR(RTA_GATEWAY, sdl_m);
857 	memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr));
858 	NEXTADDR(RTA_NETMASK, so_mask);
859 
860 	rtm->rtm_msglen = cp - (char *)&m_rtmsg;
861 doit:
862 	l = rtm->rtm_msglen;
863 	rtm->rtm_seq = ++seq;
864 	rtm->rtm_type = cmd;
865 	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
866 		if (errno != ESRCH || cmd != RTM_DELETE) {
867 			perror("writing to routing socket");
868 			return (-1);
869 		}
870 	}
871 	do {
872 		l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
873 	} while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
874 	if (l < 0)
875 		fprintf(stderr, "ndp: read from routing socket: %s\n",
876 		    strerror(errno));
877 	return (0);
878 }
879 
880 void
881 ifinfo(int argc, char **argv)
882 {
883 	struct in6_ndireq nd;
884 	int i, s;
885 	char *ifname = argv[0];
886 	u_int32_t newflags;
887 #ifdef IPV6CTL_USETEMPADDR
888 	u_int8_t nullbuf[8];
889 #endif
890 
891 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
892 		perror("ndp: socket");
893 		exit(1);
894 	}
895 	bzero(&nd, sizeof(nd));
896 	strcpy(nd.ifname, ifname);
897 	if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
898  		perror("ioctl (SIOCGIFINFO_IN6)");
899  		exit(1);
900  	}
901 #define ND nd.ndi
902 	newflags = ND.flags;
903 	for (i = 1; i < argc; i++) {
904 		int clear = 0;
905 		char *cp = argv[i];
906 
907 		if (*cp == '-') {
908 			clear = 1;
909 			cp++;
910 		}
911 
912 #define SETFLAG(s, f) \
913 	do {\
914 		if (strcmp(cp, (s)) == 0) {\
915 			if (clear)\
916 				newflags &= ~(f);\
917 			else\
918 				newflags |= (f);\
919 		}\
920 	} while (0)
921 		SETFLAG("nud", ND6_IFF_PERFORMNUD);
922 #ifdef ND6_IFF_ACCEPT_RTADV
923 		SETFLAG("accept_rtadv", ND6_IFF_ACCEPT_RTADV);
924 #endif
925 		ND.flags = newflags;
926 		if (ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd) < 0) {
927 			perror("ioctl(SIOCSIFINFO_FLAGS)");
928 			exit(1);
929 		}
930 #undef SETFLAG
931 	}
932 
933 	printf("linkmtu=%d", ND.linkmtu);
934 	printf(", curhlim=%d", ND.chlim);
935 	printf(", basereachable=%ds%dms",
936 	       ND.basereachable / 1000, ND.basereachable % 1000);
937 	printf(", reachable=%ds", ND.reachable);
938 	printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000);
939 #ifdef IPV6CTL_USETEMPADDR
940 	memset(nullbuf, 0, sizeof(nullbuf));
941 	if (memcmp(nullbuf, ND.randomid, sizeof(nullbuf)) != 0) {
942 		int j;
943 		u_int8_t *rbuf;
944 
945 		for (i = 0; i < 3; i++) {
946 			switch(i) {
947 			case 0:
948 				printf("\nRandom seed(0): ");
949 				rbuf = ND.randomseed0;
950 				break;
951 			case 1:
952 				printf("\nRandom seed(1): ");
953 				rbuf = ND.randomseed1;
954 				break;
955 			case 2:
956 				printf("\nRandom ID:      ");
957 				rbuf = ND.randomid;
958 				break;
959 			}
960 			for (j = 0; j < 8; j++)
961 				printf("%02x", rbuf[j]);
962 		}
963 	}
964 #endif
965 	if (ND.flags) {
966 		printf("\nFlags: ");
967 		if ((ND.flags & ND6_IFF_PERFORMNUD))
968 			printf("nud ");
969 #ifdef ND6_IFF_ACCEPT_RTADV
970 		if ((ND.flags & ND6_IFF_ACCEPT_RTADV))
971 			printf("accept_rtadv ");
972 #endif
973 	}
974 	putc('\n', stdout);
975 #undef ND
976 
977 	close(s);
978 }
979 
980 #ifndef ND_RA_FLAG_RTPREF_MASK	/* XXX: just for compilation on *BSD release */
981 #define ND_RA_FLAG_RTPREF_MASK	0x18 /* 00011000 */
982 #endif
983 
984 void
985 rtrlist(void)
986 {
987 #ifdef ICMPV6CTL_ND6_DRLIST
988 	int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST };
989 	char *buf;
990 	struct in6_defrouter *p, *ep;
991 	size_t l;
992 	struct timeval time;
993 
994 	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
995 		err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
996 		/*NOTREACHED*/
997 	}
998 	buf = malloc(l);
999 	if (!buf) {
1000 		errx(1, "not enough core");
1001 		/*NOTREACHED*/
1002 	}
1003 	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
1004 		err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
1005 		/*NOTREACHED*/
1006 	}
1007 
1008 	ep = (struct in6_defrouter *)(buf + l);
1009 	for (p = (struct in6_defrouter *)buf; p < ep; p++) {
1010 		int rtpref;
1011 
1012 		if (getnameinfo((struct sockaddr *)&p->rtaddr,
1013 		    p->rtaddr.sin6_len, host_buf, sizeof(host_buf), NULL, 0,
1014 		    NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)) != 0)
1015 			strlcpy(host_buf, "?", sizeof(host_buf));
1016 
1017 		printf("%s if=%s", host_buf,
1018 		       if_indextoname(p->if_index, ifix_buf));
1019 		printf(", flags=%s%s",
1020 		       p->flags & ND_RA_FLAG_MANAGED ? "M" : "",
1021 		       p->flags & ND_RA_FLAG_OTHER   ? "O" : "");
1022 		rtpref = ((p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff;
1023 		printf(", pref=%s", rtpref_str[rtpref]);
1024 
1025 		gettimeofday(&time, 0);
1026 		if (p->expire == 0)
1027 			printf(", expire=Never\n");
1028 		else
1029 			printf(", expire=%s\n",
1030 				sec2str(p->expire - time.tv_sec));
1031 	}
1032 	free(buf);
1033 #else
1034 	struct in6_drlist dr;
1035 	int s, i;
1036 	struct timeval time;
1037 
1038 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1039 		perror("ndp: socket");
1040 		exit(1);
1041 	}
1042 	bzero(&dr, sizeof(dr));
1043 	strcpy(dr.ifname, "lo0"); /* dummy */
1044 	if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) {
1045  		perror("ioctl (SIOCGDRLST_IN6)");
1046  		exit(1);
1047  	}
1048 #define DR dr.defrouter[i]
1049 	for (i = 0 ; DR.if_index && i < DRLSTSIZ ; i++) {
1050 		struct sockaddr_in6 sin6;
1051 
1052 		bzero(&sin6, sizeof(sin6));
1053 		sin6.sin6_family = AF_INET6;
1054 		sin6.sin6_len = sizeof(sin6);
1055 		sin6.sin6_addr = DR.rtaddr;
1056 		getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf,
1057 			    sizeof(host_buf), NULL, 0,
1058 			    NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
1059 
1060 		printf("%s if=%s", host_buf,
1061 		       if_indextoname(DR.if_index, ifix_buf));
1062 		printf(", flags=%s%s",
1063 		       DR.flags & ND_RA_FLAG_MANAGED ? "M" : "",
1064 		       DR.flags & ND_RA_FLAG_OTHER   ? "O" : "");
1065 		gettimeofday(&time, 0);
1066 		if (DR.expire == 0)
1067 			printf(", expire=Never\n");
1068 		else
1069 			printf(", expire=%s\n",
1070 				sec2str(DR.expire - time.tv_sec));
1071 	}
1072 #undef DR
1073 	close(s);
1074 #endif
1075 }
1076 
1077 void
1078 plist(void)
1079 {
1080 #ifdef ICMPV6CTL_ND6_PRLIST
1081 	int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST };
1082 	char *buf;
1083 	struct in6_prefix *p, *ep, *n;
1084 	struct sockaddr_in6 *advrtr;
1085 	size_t l;
1086 	struct timeval time;
1087 #ifdef NI_WITHSCOPEID
1088 	const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
1089 	int ninflags = (nflag ? NI_NUMERICHOST : 0) | NI_WITHSCOPEID;
1090 #else
1091 	const int niflags = NI_NUMERICHOST;
1092 	int ninflags = nflag ? NI_NUMERICHOST : 0;
1093 #endif
1094 	char namebuf[NI_MAXHOST];
1095 
1096 	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
1097 		err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
1098 		/*NOTREACHED*/
1099 	}
1100 	buf = malloc(l);
1101 	if (!buf) {
1102 		errx(1, "not enough core");
1103 		/*NOTREACHED*/
1104 	}
1105 	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
1106 		err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
1107 		/*NOTREACHED*/
1108 	}
1109 
1110 	ep = (struct in6_prefix *)(buf + l);
1111 	for (p = (struct in6_prefix *)buf; p < ep; p = n) {
1112 		advrtr = (struct sockaddr_in6 *)(p + 1);
1113 		n = (struct in6_prefix *)&advrtr[p->advrtrs];
1114 
1115 		if (getnameinfo((struct sockaddr *)&p->prefix,
1116 		    p->prefix.sin6_len, namebuf, sizeof(namebuf),
1117 		    NULL, 0, niflags) != 0)
1118 			strlcpy(namebuf, "?", sizeof(namebuf));
1119 		printf("%s/%d if=%s\n", namebuf, p->prefixlen,
1120 		       if_indextoname(p->if_index, ifix_buf));
1121 
1122 		gettimeofday(&time, 0);
1123 		/*
1124 		 * meaning of fields, especially flags, is very different
1125 		 * by origin.  notify the difference to the users.
1126 		 */
1127 		printf("flags=%s%s%s%s%s",
1128 		       p->raflags.onlink ? "L" : "",
1129 		       p->raflags.autonomous ? "A" : "",
1130 		       (p->flags & NDPRF_ONLINK) != 0 ? "O" : "",
1131 		       (p->flags & NDPRF_DETACHED) != 0 ? "D" : "",
1132 #ifdef NDPRF_HOME
1133 		       (p->flags & NDPRF_HOME) != 0 ? "H" : ""
1134 #else
1135 		       ""
1136 #endif
1137 		       );
1138 		if (p->vltime == ND6_INFINITE_LIFETIME)
1139 			printf(" vltime=infinity");
1140 		else
1141 			printf(" vltime=%ld", (long)p->vltime);
1142 		if (p->pltime == ND6_INFINITE_LIFETIME)
1143 			printf(", pltime=infinity");
1144 		else
1145 			printf(", pltime=%ld", (long)p->pltime);
1146 		if (p->expire == 0)
1147 			printf(", expire=Never");
1148 		else if (p->expire >= time.tv_sec)
1149 			printf(", expire=%s",
1150 				sec2str(p->expire - time.tv_sec));
1151 		else
1152 			printf(", expired");
1153 		printf(", ref=%d", p->refcnt);
1154 		printf("\n");
1155 		/*
1156 		 * "advertising router" list is meaningful only if the prefix
1157 		 * information is from RA.
1158 		 */
1159 		if (p->advrtrs) {
1160 			int j;
1161 			struct sockaddr_in6 *sin6;
1162 
1163 			sin6 = (struct sockaddr_in6 *)(p + 1);
1164 			printf("  advertised by\n");
1165 			for (j = 0; j < p->advrtrs; j++) {
1166 				struct in6_nbrinfo *nbi;
1167 
1168 				if (getnameinfo((struct sockaddr *)sin6,
1169 				    sin6->sin6_len, namebuf, sizeof(namebuf),
1170 				    NULL, 0, ninflags) != 0)
1171 					strlcpy(namebuf, "?", sizeof(namebuf));
1172 				printf("    %s", namebuf);
1173 
1174 				nbi = getnbrinfo(&sin6->sin6_addr, p->if_index,
1175 						 0);
1176 				if (nbi) {
1177 					switch(nbi->state) {
1178 					case ND6_LLINFO_REACHABLE:
1179 					case ND6_LLINFO_STALE:
1180 					case ND6_LLINFO_DELAY:
1181 					case ND6_LLINFO_PROBE:
1182 						printf(" (reachable)\n");
1183 						break;
1184 					default:
1185 						printf(" (unreachable)\n");
1186 					}
1187 				} else
1188 					printf(" (no neighbor state)\n");
1189 				sin6++;
1190 			}
1191 		} else
1192 			printf("  No advertising router\n");
1193 	}
1194 	free(buf);
1195 #else
1196 	struct in6_prlist pr;
1197 	int s, i;
1198 	struct timeval time;
1199 
1200 	gettimeofday(&time, 0);
1201 
1202 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1203 		perror("ndp: socket");
1204 		exit(1);
1205 	}
1206 	bzero(&pr, sizeof(pr));
1207 	strcpy(pr.ifname, "lo0"); /* dummy */
1208 	if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) {
1209  		perror("ioctl (SIOCGPRLST_IN6)");
1210  		exit(1);
1211  	}
1212 #define PR pr.prefix[i]
1213 	for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) {
1214 		struct sockaddr_in6 p6;
1215 		char namebuf[NI_MAXHOST];
1216 		int niflags;
1217 
1218 #ifdef NDPRF_ONLINK
1219 		p6 = PR.prefix;
1220 #else
1221 		memset(&p6, 0, sizeof(p6));
1222 		p6.sin6_family = AF_INET6;
1223 		p6.sin6_len = sizeof(p6);
1224 		p6.sin6_addr = PR.prefix;
1225 #endif
1226 
1227 		/*
1228 		 * copy link index to sin6_scope_id field.
1229 		 * XXX: KAME specific.
1230 		 */
1231 		if (IN6_IS_ADDR_LINKLOCAL(&p6.sin6_addr)) {
1232 			u_int16_t linkid;
1233 
1234 			memcpy(&linkid, &p6.sin6_addr.s6_addr[2],
1235 			       sizeof(linkid));
1236 			linkid = ntohs(linkid);
1237 			p6.sin6_scope_id = linkid;
1238 			p6.sin6_addr.s6_addr[2] = 0;
1239 			p6.sin6_addr.s6_addr[3] = 0;
1240 		}
1241 
1242 		niflags = NI_NUMERICHOST;
1243 #ifdef __KAME__
1244 		niflags |= NI_WITHSCOPEID;
1245 #endif
1246 		if (getnameinfo((struct sockaddr *)&p6,
1247 				sizeof(p6), namebuf, sizeof(namebuf),
1248 				NULL, 0, niflags)) {
1249 			warnx("getnameinfo failed");
1250 			continue;
1251 		}
1252 		printf("%s/%d if=%s\n", namebuf, PR.prefixlen,
1253 		       if_indextoname(PR.if_index, ifix_buf));
1254 
1255 		gettimeofday(&time, 0);
1256 		/*
1257 		 * meaning of fields, especially flags, is very different
1258 		 * by origin.  notify the difference to the users.
1259 		 */
1260 #if 0
1261 		printf("  %s",
1262 		       PR.origin == PR_ORIG_RA ? "" : "advertise: ");
1263 #endif
1264 #ifdef NDPRF_ONLINK
1265 		printf("flags=%s%s%s%s%s",
1266 		       PR.raflags.onlink ? "L" : "",
1267 		       PR.raflags.autonomous ? "A" : "",
1268 		       (PR.flags & NDPRF_ONLINK) != 0 ? "O" : "",
1269 		       (PR.flags & NDPRF_DETACHED) != 0 ? "D" : "",
1270 #ifdef NDPRF_HOME
1271 		       (PR.flags & NDPRF_HOME) != 0 ? "H" : ""
1272 #else
1273 		       ""
1274 #endif
1275 		       );
1276 #else
1277 		printf("flags=%s%s",
1278 		       PR.raflags.onlink ? "L" : "",
1279 		       PR.raflags.autonomous ? "A" : "");
1280 #endif
1281 		if (PR.vltime == ND6_INFINITE_LIFETIME)
1282 			printf(" vltime=infinity");
1283 		else
1284 			printf(" vltime=%ld", (long)PR.vltime);
1285 		if (PR.pltime == ND6_INFINITE_LIFETIME)
1286 			printf(", pltime=infinity");
1287 		else
1288 			printf(", pltime=%ld", (long)PR.pltime);
1289 		if (PR.expire == 0)
1290 			printf(", expire=Never");
1291 		else if (PR.expire >= time.tv_sec)
1292 			printf(", expire=%s",
1293 				sec2str(PR.expire - time.tv_sec));
1294 		else
1295 			printf(", expired");
1296 #ifdef NDPRF_ONLINK
1297 		printf(", ref=%d", PR.refcnt);
1298 #endif
1299 #if 0
1300 		switch (PR.origin) {
1301 		case PR_ORIG_RA:
1302 			printf(", origin=RA");
1303 			break;
1304 		case PR_ORIG_RR:
1305 			printf(", origin=RR");
1306 			break;
1307 		case PR_ORIG_STATIC:
1308 			printf(", origin=static");
1309 			break;
1310 		case PR_ORIG_KERNEL:
1311 			printf(", origin=kernel");
1312 			break;
1313 		default:
1314 			printf(", origin=?");
1315 			break;
1316 		}
1317 #endif
1318 		printf("\n");
1319 		/*
1320 		 * "advertising router" list is meaningful only if the prefix
1321 		 * information is from RA.
1322 		 */
1323 		if (0 &&	/* prefix origin is almost obsolted */
1324 		    PR.origin != PR_ORIG_RA)
1325 			;
1326 		else if (PR.advrtrs) {
1327 			int j;
1328 			printf("  advertised by\n");
1329 			for (j = 0; j < PR.advrtrs; j++) {
1330 				struct sockaddr_in6 sin6;
1331 				struct in6_nbrinfo *nbi;
1332 
1333 				bzero(&sin6, sizeof(sin6));
1334 				sin6.sin6_family = AF_INET6;
1335 				sin6.sin6_len = sizeof(sin6);
1336 				sin6.sin6_addr = PR.advrtr[j];
1337 				sin6.sin6_scope_id = PR.if_index; /* XXX */
1338 				getnameinfo((struct sockaddr *)&sin6,
1339 					    sin6.sin6_len, host_buf,
1340 					    sizeof(host_buf), NULL, 0,
1341 					    NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
1342 				printf("    %s", host_buf);
1343 
1344 				nbi = getnbrinfo(&sin6.sin6_addr, PR.if_index,
1345 						 0);
1346 				if (nbi) {
1347 					switch(nbi->state) {
1348 					 case ND6_LLINFO_REACHABLE:
1349 					 case ND6_LLINFO_STALE:
1350 					 case ND6_LLINFO_DELAY:
1351 					 case ND6_LLINFO_PROBE:
1352 						 printf(" (reachable)\n");
1353 						 break;
1354 					 default:
1355 						 printf(" (unreachable)\n");
1356 					}
1357 				} else
1358 					printf(" (no neighbor state)\n");
1359 			}
1360 			if (PR.advrtrs > DRLSTSIZ)
1361 				printf("    and %d routers\n",
1362 				       PR.advrtrs - DRLSTSIZ);
1363 		} else
1364 			printf("  No advertising router\n");
1365 	}
1366 #undef PR
1367 	close(s);
1368 #endif
1369 }
1370 
1371 void
1372 pfx_flush(void)
1373 {
1374 	char dummyif[IFNAMSIZ+8];
1375 	int s;
1376 
1377 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1378 		err(1, "socket");
1379 	strcpy(dummyif, "lo0"); /* dummy */
1380 	if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0)
1381  		err(1, "ioctl(SIOCSPFXFLUSH_IN6)");
1382 }
1383 
1384 void
1385 rtr_flush(void)
1386 {
1387 	char dummyif[IFNAMSIZ+8];
1388 	int s;
1389 
1390 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1391 		err(1, "socket");
1392 	strcpy(dummyif, "lo0"); /* dummy */
1393 	if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0)
1394  		err(1, "ioctl(SIOCSRTRFLUSH_IN6)");
1395 
1396 	close(s);
1397 }
1398 
1399 void
1400 harmonize_rtr(void)
1401 {
1402 	char dummyif[IFNAMSIZ+8];
1403 	int s;
1404 
1405 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1406 		err(1, "socket");
1407 	strcpy(dummyif, "lo0"); /* dummy */
1408 	if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0)
1409  		err(1, "ioctl (SIOCSNDFLUSH_IN6)");
1410 
1411 	close(s);
1412 }
1413 
1414 #ifdef SIOCSDEFIFACE_IN6	/* XXX: check SIOCGDEFIFACE_IN6 as well? */
1415 static void
1416 setdefif(char *ifname)
1417 {
1418 	struct in6_ndifreq ndifreq;
1419 	unsigned int ifindex;
1420 
1421 	if (strcasecmp(ifname, "delete") == 0)
1422 		ifindex = 0;
1423 	else {
1424 		if ((ifindex = if_nametoindex(ifname)) == 0)
1425 			err(1, "failed to resolve i/f index for %s", ifname);
1426 	}
1427 
1428 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1429 		err(1, "socket");
1430 
1431 	strcpy(ndifreq.ifname, "lo0"); /* dummy */
1432 	ndifreq.ifindex = ifindex;
1433 
1434 	if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1435  		err(1, "ioctl (SIOCSDEFIFACE_IN6)");
1436 
1437 	close(s);
1438 }
1439 
1440 static void
1441 getdefif(void)
1442 {
1443 	struct in6_ndifreq ndifreq;
1444 	char ifname[IFNAMSIZ+8];
1445 
1446 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1447 		err(1, "socket");
1448 
1449 	memset(&ndifreq, 0, sizeof(ndifreq));
1450 	strcpy(ndifreq.ifname, "lo0"); /* dummy */
1451 
1452 	if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1453  		err(1, "ioctl (SIOCGDEFIFACE_IN6)");
1454 
1455 	if (ndifreq.ifindex == 0)
1456 		printf("No default interface.\n");
1457 	else {
1458 		if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL)
1459 			err(1, "failed to resolve ifname for index %lu",
1460 			    ndifreq.ifindex);
1461 		printf("ND default interface = %s\n", ifname);
1462 	}
1463 
1464 	close(s);
1465 }
1466 #endif
1467 
1468 static char *
1469 sec2str(time_t total)
1470 {
1471 	static char result[256];
1472 	int days, hours, mins, secs;
1473 	int first = 1;
1474 	char *p = result;
1475 
1476 	days = total / 3600 / 24;
1477 	hours = (total / 3600) % 24;
1478 	mins = (total / 60) % 60;
1479 	secs = total % 60;
1480 
1481 	if (days) {
1482 		first = 0;
1483 		p += sprintf(p, "%dd", days);
1484 	}
1485 	if (!first || hours) {
1486 		first = 0;
1487 		p += sprintf(p, "%dh", hours);
1488 	}
1489 	if (!first || mins) {
1490 		first = 0;
1491 		p += sprintf(p, "%dm", mins);
1492 	}
1493 	sprintf(p, "%ds", secs);
1494 
1495 	return(result);
1496 }
1497 
1498 /*
1499  * Print the timestamp
1500  * from tcpdump/util.c
1501  */
1502 static void
1503 ts_print(const struct timeval *tvp)
1504 {
1505 	int s;
1506 
1507 	/* Default */
1508 	s = (tvp->tv_sec + thiszone) % 86400;
1509 	printf("%02d:%02d:%02d.%06u ",
1510 	    s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec);
1511 }
1512