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