Home | History | Annotate | Line # | Download | only in ndp
ndp.c revision 1.3
      1 /*	$NetBSD: ndp.c,v 1.3 1999/09/03 03:54:47 itojun Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the project nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 /*
     32  * Copyright (c) 1984, 1993
     33  *	The Regents of the University of California.  All rights reserved.
     34  *
     35  * This code is derived from software contributed to Berkeley by
     36  * Sun Microsystems, Inc.
     37  *
     38  * Redistribution and use in source and binary forms, with or without
     39  * modification, are permitted provided that the following conditions
     40  * are met:
     41  * 1. Redistributions of source code must retain the above copyright
     42  *    notice, this list of conditions and the following disclaimer.
     43  * 2. Redistributions in binary form must reproduce the above copyright
     44  *    notice, this list of conditions and the following disclaimer in the
     45  *    documentation and/or other materials provided with the distribution.
     46  * 3. All advertising materials mentioning features or use of this software
     47  *    must display the following acknowledgement:
     48  *	This product includes software developed by the University of
     49  *	California, Berkeley and its contributors.
     50  * 4. Neither the name of the University nor the names of its contributors
     51  *    may be used to endorse or promote products derived from this software
     52  *    without specific prior written permission.
     53  *
     54  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     55  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     56  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     57  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     58  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     59  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     60  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     61  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     62  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     63  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     64  * SUCH DAMAGE.
     65  */
     66 
     67 /*
     68  * Based on:
     69  * "@(#) Copyright (c) 1984, 1993\n\
     70  *	The Regents of the University of California.  All rights reserved.\n";
     71  *
     72  * "@(#)arp.c	8.2 (Berkeley) 1/2/94";
     73  */
     74 
     75 /*
     76  * ndp - display, set, delete and flush neighbor cache
     77  */
     78 
     79 
     80 #include <sys/param.h>
     81 #include <sys/file.h>
     82 #include <sys/ioctl.h>
     83 #include <sys/socket.h>
     84 #include <sys/sysctl.h>
     85 #include <sys/time.h>
     86 
     87 #include <net/if.h>
     88 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
     89 #include <net/if_var.h>
     90 #endif /* __FreeBSD__ >= 3 */
     91 #include <net/if_dl.h>
     92 #include <net/if_types.h>
     93 #include <net/route.h>
     94 
     95 #include <netinet/in.h>
     96 #ifndef __NetBSD__
     97 #include <netinet/if_ether.h>
     98 #endif
     99 
    100 #include <netinet/icmp6.h>
    101 #include <netinet6/in6_var.h>
    102 #include <netinet6/nd6.h>
    103 
    104 #include <arpa/inet.h>
    105 
    106 #include <netdb.h>
    107 #include <errno.h>
    108 #include <nlist.h>
    109 #include <stdio.h>
    110 #include <string.h>
    111 #include <paths.h>
    112 #include <err.h>
    113 #include <stdlib.h>
    114 #include <fcntl.h>
    115 #include <unistd.h>
    116 #include "gmt2local.h"
    117 
    118 /* packing rule for routing socket */
    119 #define ROUNDUP(a) \
    120 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
    121 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
    122 
    123 extern int errno;
    124 static int pid;
    125 static int fflag;
    126 static int nflag;
    127 static int tflag;
    128 static int32_t thiszone;	/* time difference with gmt */
    129 static int s = -1;
    130 static int repeat = 0;
    131 
    132 char ntop_buf[INET6_ADDRSTRLEN];	/* inet_ntop() */
    133 char ifix_buf[IFNAMSIZ];		/* if_indextoname() */
    134 
    135 int main __P((int, char **));
    136 int file __P((char *));
    137 void getsocket __P((void));
    138 int set __P((int, char **));
    139 void get __P((char *));
    140 int delete __P((char *));
    141 void dump __P((struct in6_addr *));
    142 static struct in6_nbrinfo *getnbrinfo __P((struct in6_addr *addr, int ifindex));
    143 static char *ether_str __P((struct sockaddr_dl *));
    144 int ndp_ether_aton __P((char *, u_char *));
    145 void usage __P((void));
    146 int rtmsg __P((int));
    147 void ifinfo __P((char *));
    148 void rtrlist __P((void));
    149 void plist __P((void));
    150 void pfx_flush __P((void));
    151 void rtr_flush __P((void));
    152 void harmonize_rtr __P((void));
    153 static char *sec2str __P((time_t t));
    154 static char *ether_str __P((struct sockaddr_dl *sdl));
    155 static void ts_print __P((const struct timeval *));
    156 
    157 int
    158 main(argc, argv)
    159 	int argc;
    160 	char **argv;
    161 {
    162 	int ch;
    163 	int aflag = 0, cflag = 0, dflag = 0, sflag = 0, Hflag = 0,
    164 		pflag = 0, rflag = 0, Pflag = 0, Rflag = 0;
    165 	extern char *optarg;
    166 	extern int optind;
    167 
    168 	pid = getpid();
    169 	thiszone = gmt2local(0);
    170 	while ((ch = getopt(argc, argv, "acndfiprstA:HPR")) != EOF)
    171 		switch ((char)ch) {
    172 		case 'a':
    173 			aflag = 1;
    174 			break;
    175 		case 'c':
    176 			fflag = 1;
    177 			cflag = 1;
    178 			break;
    179 		case 'd':
    180 			dflag = 1;
    181 			break;
    182 		case 'i' :
    183 			if (argc != 3)
    184 				usage();
    185 			ifinfo(argv[2]);
    186 			exit(0);
    187 		case 'n':
    188 			nflag = 1;
    189 			continue;
    190 		case 'p':
    191 			pflag = 1;
    192 			break;
    193 		case 'f' :
    194 			if (argc != 3)
    195 				usage();
    196 			file(argv[2]);
    197 			exit(0);
    198 		case 'r' :
    199 			rflag = 1;
    200 			break;
    201 		case 's':
    202 			sflag = 1;
    203 			break;
    204 		case 't':
    205 			tflag = 1;
    206 			break;
    207 		case 'A':
    208 			aflag = 1;
    209 			repeat = atoi(optarg);
    210 			if (repeat < 0)
    211 				usage();
    212 			break;
    213 		case 'H' :
    214 			Hflag = 1;
    215 			break;
    216 		case 'P':
    217 			Pflag = 1;
    218 			break;
    219 		case 'R':
    220 			Rflag = 1;
    221 			break;
    222 		default:
    223 			usage();
    224 		}
    225 
    226 	argc -= optind;
    227 	argv += optind;
    228 
    229 	if (aflag || cflag) {
    230 		dump(0);
    231 		exit(0);
    232 	}
    233 	if (dflag) {
    234 		if (argc != 1)
    235 			usage();
    236 		delete(argv[0]);
    237 	}
    238 	if (pflag) {
    239 		plist();
    240 		exit(0);
    241 	}
    242 	if (rflag) {
    243 		rtrlist();
    244 		exit(0);
    245 	}
    246 	if (sflag) {
    247 		if (argc < 2 || argc > 4)
    248 			usage();
    249 		exit(set(argc, argv) ? 1 : 0);
    250 	}
    251 	if (Hflag) {
    252 		harmonize_rtr();
    253 		exit(0);
    254 	}
    255 	if (Pflag) {
    256 		pfx_flush();
    257 		exit(0);
    258 	}
    259 	if (Rflag) {
    260 		rtr_flush();
    261 		exit(0);
    262 	}
    263 
    264 	if (argc != 1)
    265 		usage();
    266 	get(argv[0]);
    267 	exit(0);
    268 }
    269 
    270 /*
    271  * Process a file to set standard ndp entries
    272  */
    273 int
    274 file(name)
    275 	char *name;
    276 {
    277 	FILE *fp;
    278 	int i, retval;
    279 	char line[100], arg[5][50], *args[5];
    280 
    281 	if ((fp = fopen(name, "r")) == NULL) {
    282 		fprintf(stderr, "ndp: cannot open %s\n", name);
    283 		exit(1);
    284 	}
    285 	args[0] = &arg[0][0];
    286 	args[1] = &arg[1][0];
    287 	args[2] = &arg[2][0];
    288 	args[3] = &arg[3][0];
    289 	args[4] = &arg[4][0];
    290 	retval = 0;
    291 	while(fgets(line, 100, fp) != NULL) {
    292 		i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2],
    293 		    arg[3], arg[4]);
    294 		if (i < 2) {
    295 			fprintf(stderr, "ndp: bad line: %s\n", line);
    296 			retval = 1;
    297 			continue;
    298 		}
    299 		if (set(i, args))
    300 			retval = 1;
    301 	}
    302 	fclose(fp);
    303 	return (retval);
    304 }
    305 
    306 void
    307 getsocket()
    308 {
    309 	if (s < 0) {
    310 		s = socket(PF_ROUTE, SOCK_RAW, 0);
    311 		if (s < 0) {
    312 			perror("ndp: socket");
    313 			exit(1);
    314 		}
    315 	}
    316 }
    317 
    318 struct	sockaddr_in so_mask = {8, 0, 0, { 0xffffffff}};
    319 struct	sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET6 }, sin_m;
    320 struct	sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m;
    321 int	expire_time, flags, found_entry;
    322 struct	{
    323 	struct	rt_msghdr m_rtm;
    324 	char	m_space[512];
    325 }	m_rtmsg;
    326 
    327 /*
    328  * Set an individual neighbor cache entry
    329  */
    330 int
    331 set(argc, argv)
    332 	int argc;
    333 	char **argv;
    334 {
    335 	register struct sockaddr_in6 *sin = &sin_m;
    336 	register struct sockaddr_dl *sdl;
    337 	register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
    338 	struct addrinfo hints, *res;
    339 	int gai_error;
    340 	u_char *ea;
    341 	char *host = argv[0], *eaddr = argv[1];
    342 
    343 	getsocket();
    344 	argc -= 2;
    345 	argv += 2;
    346 	sdl_m = blank_sdl;
    347 	sin_m = blank_sin;
    348 
    349 	bzero(&hints, sizeof(hints));
    350 	hints.ai_family = AF_INET6;
    351 	gai_error = getaddrinfo(host, NULL, &hints, &res);
    352 	if (gai_error) {
    353 		fprintf(stderr, "ndp: %s: %s\n", host,
    354 			gai_strerror(gai_error));
    355 		return 1;
    356 	}
    357 	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
    358 	ea = (u_char *)LLADDR(&sdl_m);
    359 	if (ndp_ether_aton(eaddr, ea) == 0)
    360 		sdl_m.sdl_alen = 6;
    361 	flags = expire_time = 0;
    362 	while (argc-- > 0) {
    363 		if (strncmp(argv[0], "temp", 4) == 0) {
    364 			struct timeval time;
    365 			gettimeofday(&time, 0);
    366 			expire_time = time.tv_sec + 20 * 60;
    367 		}
    368 		argv++;
    369 	}
    370 tryagain:
    371 	if (rtmsg(RTM_GET) < 0) {
    372 		perror(host);
    373 		return (1);
    374 	}
    375 	sin = (struct sockaddr_in6 *)(rtm + 1);
    376 	sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
    377 	if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
    378 		if (sdl->sdl_family == AF_LINK &&
    379 		    (rtm->rtm_flags & RTF_LLINFO) &&
    380 		    !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
    381 		case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
    382 		case IFT_ISO88024: case IFT_ISO88025:
    383 			goto overwrite;
    384 		}
    385 		goto tryagain;
    386 	}
    387 overwrite:
    388 	if (sdl->sdl_family != AF_LINK) {
    389 		printf("cannot intuit interface index and type for %s\n", host);
    390 		return (1);
    391 	}
    392 	sdl_m.sdl_type = sdl->sdl_type;
    393 	sdl_m.sdl_index = sdl->sdl_index;
    394 	return (rtmsg(RTM_ADD));
    395 }
    396 
    397 /*
    398  * Display an individual neighbor cache entry
    399  */
    400 void
    401 get(host)
    402 	char *host;
    403 {
    404 	struct sockaddr_in6 *sin = &sin_m;
    405 	struct addrinfo hints, *res;
    406 	int gai_error;
    407 
    408 	sin_m = blank_sin;
    409 	bzero(&hints, sizeof(hints));
    410 	hints.ai_family = AF_INET6;
    411 	gai_error = getaddrinfo(host, NULL, &hints, &res);
    412 	if (gai_error) {
    413 		fprintf(stderr, "ndp: %s: %s\n", host,
    414 			gai_strerror(gai_error));
    415 		return;
    416 	}
    417 	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
    418 	dump(&sin->sin6_addr);
    419 	if (found_entry == 0) {
    420 		printf("%s (%s) -- no entry\n",
    421 		    host, inet_ntop(AF_INET6, &sin->sin6_addr, ntop_buf,
    422 				sizeof(ntop_buf)));
    423 		exit(1);
    424 	}
    425 }
    426 
    427 /*
    428  * Delete a neighbor cache entry
    429  */
    430 int
    431 delete(host)
    432 	char *host;
    433 {
    434 	register struct sockaddr_in6 *sin = &sin_m;
    435 	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
    436 	struct sockaddr_dl *sdl;
    437 	struct addrinfo hints, *res;
    438 	int gai_error;
    439 
    440 	getsocket();
    441 	sin_m = blank_sin;
    442 
    443 	bzero(&hints, sizeof(hints));
    444 	hints.ai_family = AF_INET6;
    445 	gai_error = getaddrinfo(host, NULL, &hints, &res);
    446 	if (gai_error) {
    447 		fprintf(stderr, "ndp: %s: %s\n", host,
    448 			gai_strerror(gai_error));
    449 		return 1;
    450 	}
    451 	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
    452 /*tryagain:*/
    453 	if (rtmsg(RTM_GET) < 0) {
    454 		perror(host);
    455 		return (1);
    456 	}
    457 	sin = (struct sockaddr_in6 *)(rtm + 1);
    458 	sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
    459 	if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
    460 		if (sdl->sdl_family == AF_LINK &&
    461 		    (rtm->rtm_flags & RTF_LLINFO) &&
    462 		    !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
    463 		case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
    464 		case IFT_ISO88024: case IFT_ISO88025:
    465 			goto delete;
    466 		}
    467 	}
    468 delete:
    469 	if (sdl->sdl_family != AF_LINK) {
    470 		printf("cannot locate %s\n", host);
    471 		return (1);
    472 	}
    473 	if (rtmsg(RTM_DELETE) == 0)
    474 		printf("%s (%s) deleted\n", host,
    475 			inet_ntop(AF_INET6, &sin->sin6_addr, ntop_buf,
    476 					sizeof(ntop_buf)));
    477 	return 0;
    478 }
    479 
    480 /*
    481  * Dump the entire neighbor cache
    482  */
    483 void
    484 dump(addr)
    485 	struct in6_addr *addr;
    486 {
    487 	int mib[6];
    488 	size_t needed;
    489 	char *host, *lim, *buf, *next;
    490 	struct rt_msghdr *rtm;
    491 	struct sockaddr_in6 *sin;
    492 	struct sockaddr_dl *sdl;
    493 	extern int h_errno;
    494 	struct hostent *hp;
    495 	struct in6_nbrinfo *nbi;
    496 	struct timeval time;
    497 
    498 	/* Print header */
    499 	if (!tflag)
    500 		printf("%-29.29s %-18.18s %6.6s %-9.9s %2s %4s %4s\n",
    501 		       "Neighbor", "Linklayer Address", "Netif", "Expire",
    502 		       "St", "Flgs", "Prbs");
    503 
    504 again:;
    505 	mib[0] = CTL_NET;
    506 	mib[1] = PF_ROUTE;
    507 	mib[2] = 0;
    508 	mib[3] = AF_INET6;
    509 	mib[4] = NET_RT_FLAGS;
    510 	mib[5] = RTF_LLINFO;
    511 	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
    512 		err(1, "sysctl(PF_ROUTE estimate)");
    513 	if (needed > 0) {
    514 		if ((buf = malloc(needed)) == NULL)
    515 			errx(1, "malloc");
    516 		if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
    517 			err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
    518 		lim = buf + needed;
    519 	} else
    520 		buf = lim = NULL;
    521 
    522 	for (next = buf; next && next < lim; next += rtm->rtm_msglen) {
    523 		int isrouter = 0, prbs = 0;
    524 
    525 		rtm = (struct rt_msghdr *)next;
    526 		sin = (struct sockaddr_in6 *)(rtm + 1);
    527 		sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len));
    528 		if (addr) {
    529 			if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr))
    530 				continue;
    531 			found_entry = 1;
    532 		} else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
    533 			continue;
    534 		if (fflag == 1) {
    535 			delete((char *)inet_ntop(AF_INET6, &sin->sin6_addr,
    536 						ntop_buf, sizeof(ntop_buf)));
    537 			continue;
    538 		}
    539 		host = NULL;
    540 		if (nflag == 0) {
    541 			hp = gethostbyaddr((char *)&sin->sin6_addr,
    542 					   sizeof(struct in6_addr), AF_INET6);
    543 			if (hp)
    544 				host = hp->h_name;
    545 		}
    546 		if (host == NULL) {
    547 			inet_ntop(AF_INET6, &sin->sin6_addr,
    548 				  ntop_buf, sizeof(ntop_buf));
    549 			host = ntop_buf;
    550 		}
    551 
    552 		gettimeofday(&time, 0);
    553 		if (tflag)
    554 			ts_print(&time);
    555 
    556 		printf("%-29.29s %-18.18s %6.6s", host,
    557 		       ether_str(sdl),
    558 		       if_indextoname(sdl->sdl_index, ifix_buf));
    559 
    560 		/* Print neighbor discovery specific informations */
    561 		putchar(' ');
    562 		nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index);
    563 		if (nbi) {
    564 			if (nbi->expire > time.tv_sec) {
    565 				printf(" %-9.9s",
    566 				       sec2str(nbi->expire - time.tv_sec));
    567 			}
    568 			else if (nbi->expire == 0)
    569 				printf(" %-9.9s", "permanent");
    570 			else
    571 				printf(" %-9.9s", "expired");
    572 
    573 			switch(nbi->state) {
    574 			 case ND6_LLINFO_NOSTATE:
    575 				 printf(" N");
    576 				 break;
    577 			 case ND6_LLINFO_WAITDELETE:
    578 				 printf(" W");
    579 				 break;
    580 			 case ND6_LLINFO_INCOMPLETE:
    581 				 printf(" I");
    582 				 break;
    583 			 case ND6_LLINFO_REACHABLE:
    584 				 printf(" R");
    585 				 break;
    586 			 case ND6_LLINFO_STALE:
    587 				 printf(" S");
    588 				 break;
    589 			 case ND6_LLINFO_DELAY:
    590 				 printf(" D");
    591 				 break;
    592 			 case ND6_LLINFO_PROBE:
    593 				 printf(" P");
    594 				 break;
    595 			 default:
    596 				 printf(" ?");
    597 				 break;
    598 			}
    599 
    600 			isrouter = nbi->isrouter;
    601 			prbs = nbi->asked;
    602 		}
    603 		else {
    604 			warnx("failed to get neighbor information");
    605 			printf("  ");
    606 		}
    607 
    608 		/* other flags */
    609 		putchar(' ');
    610 		{
    611 			u_char flgbuf[8], *p = flgbuf;
    612 
    613 			flgbuf[0] = '\0';
    614 			if (isrouter)
    615 				p += sprintf((char *)p, "R");
    616 #ifndef RADISH
    617 			if (rtm->rtm_addrs & RTA_NETMASK) {
    618 				sin = (struct sockaddr_in6 *)
    619 					(sdl->sdl_len + (char *)sdl);
    620 				if (!IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr))
    621 					p += sprintf((char *)p, "P");
    622 				if (sin->sin6_len != sizeof(struct sockaddr_in6))
    623 					p += sprintf((char *)p, "W");
    624 			}
    625 #endif /*RADISH*/
    626 			printf("%4s", flgbuf);
    627 		}
    628 
    629 		putchar(' ');
    630 		if (prbs)
    631 			printf("% 4d", prbs);
    632 
    633 		printf("\n");
    634 	}
    635 
    636 	if (repeat) {
    637 		printf("\n");
    638 		sleep(repeat);
    639 		goto again;
    640 	}
    641 }
    642 
    643 static struct in6_nbrinfo *
    644 getnbrinfo(addr, ifindex)
    645 	struct in6_addr *addr;
    646 	int ifindex;
    647 {
    648 	static struct in6_nbrinfo nbi;
    649 	int s;
    650 
    651 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
    652 		err(1, "socket");
    653 
    654 	bzero(&nbi, sizeof(nbi));
    655 	if_indextoname(ifindex, nbi.ifname);
    656 	nbi.addr = *addr;
    657 	if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) {
    658 		warn("ioctl");
    659 		close(s);
    660 		return(NULL);
    661 	}
    662 
    663 	close(s);
    664 	return(&nbi);
    665 }
    666 
    667 static char *
    668 ether_str(sdl)
    669 	struct sockaddr_dl *sdl;
    670 {
    671 	static char ebuf[32];
    672 	u_char *cp;
    673 
    674 	if (sdl->sdl_alen) {
    675 		cp = (u_char *)LLADDR(sdl);
    676 		sprintf(ebuf, "%x:%x:%x:%x:%x:%x",
    677 			cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
    678 	}
    679 	else {
    680 		sprintf(ebuf, "(incomplete)");
    681 	}
    682 
    683 	return(ebuf);
    684 }
    685 
    686 int
    687 ndp_ether_aton(a, n)
    688 	char *a;
    689 	u_char *n;
    690 {
    691 	int i, o[6];
    692 
    693 	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
    694 					   &o[3], &o[4], &o[5]);
    695 	if (i != 6) {
    696 		fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a);
    697 		return (1);
    698 	}
    699 	for (i=0; i<6; i++)
    700 		n[i] = o[i];
    701 	return (0);
    702 }
    703 
    704 void
    705 usage()
    706 {
    707 	printf("usage: ndp hostname\n");
    708 	printf("       ndp -a[nt]\n");
    709 	printf("       ndp [-nt] -A wait\n");
    710 	printf("       ndp -c[nt]\n");
    711 	printf("       ndp -d[nt] hostname\n");
    712 	printf("       ndp -f[nt] filename\n");
    713 	printf("       ndp -i interface\n");
    714 	printf("       ndp -p\n");
    715 	printf("       ndp -r\n");
    716 	printf("       ndp -s hostname ether_addr [temp]\n");
    717 	printf("       ndp -H\n");
    718 	printf("       ndp -P\n");
    719 	printf("       ndp -R\n");
    720 	exit(1);
    721 }
    722 
    723 int
    724 rtmsg(cmd)
    725 	int cmd;
    726 {
    727 	static int seq;
    728 	int rlen;
    729 	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
    730 	register char *cp = m_rtmsg.m_space;
    731 	register int l;
    732 
    733 	errno = 0;
    734 	if (cmd == RTM_DELETE)
    735 		goto doit;
    736 	bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
    737 	rtm->rtm_flags = flags;
    738 	rtm->rtm_version = RTM_VERSION;
    739 
    740 	switch (cmd) {
    741 	default:
    742 		fprintf(stderr, "ndp: internal wrong cmd\n");
    743 		exit(1);
    744 	case RTM_ADD:
    745 		rtm->rtm_addrs |= RTA_GATEWAY;
    746 		rtm->rtm_rmx.rmx_expire = expire_time;
    747 		rtm->rtm_inits = RTV_EXPIRE;
    748 		rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
    749 		/* FALLTHROUGH */
    750 	case RTM_GET:
    751 		rtm->rtm_addrs |= RTA_DST;
    752 	}
    753 #define NEXTADDR(w, s) \
    754 	if (rtm->rtm_addrs & (w)) { \
    755 		bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);}
    756 
    757 	NEXTADDR(RTA_DST, sin_m);
    758 	NEXTADDR(RTA_GATEWAY, sdl_m);
    759 	NEXTADDR(RTA_NETMASK, so_mask);
    760 
    761 	rtm->rtm_msglen = cp - (char *)&m_rtmsg;
    762 doit:
    763 	l = rtm->rtm_msglen;
    764 	rtm->rtm_seq = ++seq;
    765 	rtm->rtm_type = cmd;
    766 	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
    767 		if (errno != ESRCH || cmd != RTM_DELETE) {
    768 			perror("writing to routing socket");
    769 			return (-1);
    770 		}
    771 	}
    772 	do {
    773 		l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
    774 	} while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
    775 	if (l < 0)
    776 		(void) fprintf(stderr, "ndp: read from routing socket: %s\n",
    777 		    strerror(errno));
    778 	return (0);
    779 }
    780 
    781 void
    782 ifinfo(ifname)
    783 	char *ifname;
    784 {
    785 	struct in6_ndireq nd;
    786 	int s;
    787 
    788 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
    789 		perror("ndp: socket");
    790 		exit(1);
    791 	}
    792 	bzero(&nd, sizeof(nd));
    793 	strcpy(nd.ifname, ifname);
    794 	if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
    795  		perror("ioctl (SIOCGIFINFO_IN6)");
    796  		exit(1);
    797  	}
    798 #define ND nd.ndi
    799 	printf("linkmtu=%d", ND.linkmtu);
    800 	printf(", curhlim=%d", ND.chlim);
    801 	printf(", basereachable=%ds%dms",
    802 	       ND.basereachable / 1000, ND.basereachable % 1000);
    803 	printf(", reachable=%ds", ND.reachable);
    804 	printf(", retrans=%ds%dms\n", ND.retrans / 1000, ND.retrans % 1000);
    805 #undef ND
    806 	close(s);
    807 }
    808 
    809 void
    810 rtrlist()
    811 {
    812 	struct in6_drlist dr;
    813 	int s, i;
    814 	struct timeval time;
    815 
    816 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
    817 		perror("ndp: socket");
    818 		exit(1);
    819 	}
    820 	bzero(&dr, sizeof(dr));
    821 	strcpy(dr.ifname, "lo0"); /* dummy */
    822 	if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) {
    823  		perror("ioctl (SIOCGDRLST_IN6)");
    824  		exit(1);
    825  	}
    826 #define DR dr.defrouter[i]
    827 	for (i = 0 ; DR.if_index && i < PRLSTSIZ ; i++) {
    828 		printf("%s if=%s", inet_ntop(AF_INET6, &DR.rtaddr,
    829 					     ntop_buf, sizeof(ntop_buf)),
    830 		       if_indextoname(DR.if_index, ifix_buf));
    831 		printf(", flags=%s%s",
    832 		       DR.flags & ND_RA_FLAG_MANAGED ? "M" : "",
    833 		       DR.flags & ND_RA_FLAG_OTHER   ? "O" : "");
    834 		gettimeofday(&time, 0);
    835 		if (DR.expire == 0)
    836 			printf(", expire=Never\n");
    837 		else
    838 			printf(", expire=%s\n",
    839 				sec2str(DR.expire - time.tv_sec));
    840 	}
    841 #undef DR
    842 	close(s);
    843 }
    844 
    845 void
    846 plist()
    847 {
    848 	struct in6_prlist pr;
    849 	int s, i;
    850 	struct timeval time;
    851 
    852 	gettimeofday(&time, 0);
    853 
    854 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
    855 		perror("ndp: socket");
    856 		exit(1);
    857 	}
    858 	bzero(&pr, sizeof(pr));
    859 	strcpy(pr.ifname, "lo0"); /* dummy */
    860 	if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) {
    861  		perror("ioctl (SIOCGPRLST_IN6)");
    862  		exit(1);
    863  	}
    864 #define PR pr.prefix[i]
    865 	for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) {
    866 		printf("%s/%d if=%s\n",
    867 		       inet_ntop(AF_INET6, &PR.prefix, ntop_buf,
    868 				 sizeof(ntop_buf)), PR.prefixlen,
    869 		       if_indextoname(PR.if_index, ifix_buf));
    870 		gettimeofday(&time, 0);
    871 		printf("  flags=%s%s",
    872 		       PR.raflags.onlink ? "L" : "",
    873 		       PR.raflags.autonomous ? "A" : "");
    874 		if (PR.vltime == ND6_INFINITE_LIFETIME)
    875 			printf(" vltime=infinity");
    876 		else
    877 			printf(" vltime=%ld", (long)PR.vltime);
    878 		if (PR.pltime == ND6_INFINITE_LIFETIME)
    879 			printf(", pltime=infinity");
    880 		else
    881 			printf(", pltime=%ld", (long)PR.pltime);
    882 		if (PR.expire == 0)
    883 			printf(", expire=Never\n");
    884 		else if (PR.expire >= time.tv_sec)
    885 			printf(", expire=%s\n",
    886 				sec2str(PR.expire - time.tv_sec));
    887 		else
    888 			printf(", expired\n");
    889 		if (PR.advrtrs) {
    890 			int j;
    891 			printf("  advertised by\n");
    892 			for (j = 0; j < PR.advrtrs; j++) {
    893 				printf("    %s\n",
    894 				       inet_ntop(AF_INET6, &PR.advrtr[j],
    895 						 ntop_buf,
    896 						 sizeof(ntop_buf)));
    897 			}
    898 			if (PR.advrtrs > DRLSTSIZ)
    899 				printf("    and %d routers\n",
    900 				       PR.advrtrs - DRLSTSIZ);
    901 		}
    902 		else
    903 			printf("  No advertising router\n");
    904 	}
    905 #undef PR
    906 	close(s);
    907 }
    908 
    909 void
    910 pfx_flush()
    911 {
    912 	char dummyif[IFNAMSIZ+8];
    913 	int s;
    914 
    915 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
    916 		err(1, "socket");
    917 	strcpy(dummyif, "lo0"); /* dummy */
    918 	if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0)
    919  		err(1, "ioctl(SIOCSPFXFLUSH_IN6)");
    920 }
    921 
    922 void
    923 rtr_flush()
    924 {
    925 	char dummyif[IFNAMSIZ+8];
    926 	int s;
    927 
    928 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
    929 		err(1, "socket");
    930 	strcpy(dummyif, "lo0"); /* dummy */
    931 	if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0)
    932  		err(1, "ioctl(SIOCSRTRFLUSH_IN6)");
    933 }
    934 
    935 void
    936 harmonize_rtr()
    937 {
    938 	char dummyif[IFNAMSIZ+8];
    939 	int s;
    940 
    941 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
    942 		perror("ndp: socket");
    943 		exit(1);
    944 	}
    945 	strcpy(dummyif, "lo0"); /* dummy */
    946 	if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0) {
    947  		perror("ioctl (SIOCSNDFLUSH_IN6)");
    948  		exit(1);
    949  	}
    950 }
    951 
    952 static char *
    953 sec2str(total)
    954 	time_t total;
    955 {
    956 	static char result[256];
    957 	int days, hours, mins, secs;
    958 	int first = 1;
    959 	char *p = result;
    960 
    961 	days = total / 3600 / 24;
    962 	hours = (total / 3600) % 24;
    963 	mins = (total / 60) % 60;
    964 	secs = total % 60;
    965 
    966 	if (days) {
    967 		first = 0;
    968 		p += sprintf(p, "%dd", days);
    969 	}
    970 	if (!first || hours) {
    971 		first = 0;
    972 		p += sprintf(p, "%dh", hours);
    973 	}
    974 	if (!first || mins) {
    975 		first = 0;
    976 		p += sprintf(p, "%dm", mins);
    977 	}
    978 	sprintf(p, "%ds", secs);
    979 
    980 	return(result);
    981 }
    982 
    983 /*
    984  * Print the timestamp
    985  * from tcpdump/util.c
    986  */
    987 static void
    988 ts_print(tvp)
    989 	const struct timeval *tvp;
    990 {
    991 	int s;
    992 
    993 	/* Default */
    994 	s = (tvp->tv_sec + thiszone) % 86400;
    995 	(void)printf("%02d:%02d:%02d.%06u ",
    996 	    s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec);
    997 }
    998