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