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