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