main.c revision 1.94 1 /* $NetBSD: main.c,v 1.94 2014/11/07 12:42:27 christos Exp $ */
2
3 /*
4 * Copyright (c) 1983, 1988, 1993
5 * Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993\
35 Regents of the University of California. All rights reserved.");
36 #endif /* not lint */
37
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "from: @(#)main.c 8.4 (Berkeley) 3/1/94";
41 #else
42 __RCSID("$NetBSD: main.c,v 1.94 2014/11/07 12:42:27 christos Exp $");
43 #endif
44 #endif /* not lint */
45
46 #include <sys/param.h>
47 #include <sys/file.h>
48 #include <sys/protosw.h>
49 #include <sys/socket.h>
50
51 #include <net/if.h>
52 #include <netinet/in.h>
53
54 #include <ctype.h>
55 #include <err.h>
56 #include <errno.h>
57 #include <kvm.h>
58 #include <limits.h>
59 #include <netdb.h>
60 #include <nlist.h>
61 #include <paths.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <unistd.h>
66 #include "netstat.h"
67 #include "rtutil.h"
68 #include "prog_ops.h"
69
70 struct nlist nl[] = {
71 #define N_MBSTAT 0
72 { "_mbstat", 0, 0, 0, 0 },
73 #define N_IPSTAT 1
74 { "_ipstat", 0, 0, 0, 0 }, /* not available via kvm */
75 #define N_TCBTABLE 2
76 { "_tcbtable", 0, 0, 0, 0 },
77 #define N_TCPSTAT 3
78 { "_tcpstat", 0, 0, 0, 0 }, /* not available via kvm */
79 #define N_UDBTABLE 4
80 { "_udbtable", 0, 0, 0, 0 },
81 #define N_UDPSTAT 5
82 { "_udpstat", 0, 0, 0, 0 }, /* not available via kvm */
83 #define N_IFNET_LIST 6
84 { "_ifnet_list", 0, 0, 0, 0 },
85 #define N_ICMPSTAT 7
86 { "_icmpstat", 0, 0, 0, 0 }, /* not available via kvm */
87 #define N_RTSTAT 8
88 { "_rtstat", 0, 0, 0, 0 },
89 #define N_UNIXSW 9
90 { "_unixsw", 0, 0, 0, 0 },
91 #define N_RTREE 10
92 { "_rt_tables", 0, 0, 0, 0 },
93 #define N_NFILE 11
94 { "_nfile", 0, 0, 0, 0 },
95 #define N_IGMPSTAT 12
96 { "_igmpstat", 0, 0, 0, 0 }, /* not available via kvm */
97 #define N_MRTPROTO 13
98 { "_ip_mrtproto", 0, 0, 0, 0 },
99 #define N_MRTSTAT 14
100 { "_mrtstat", 0, 0, 0, 0 },
101 #define N_MFCHASHTBL 15
102 { "_mfchashtbl", 0, 0, 0, 0 },
103 #define N_MFCHASH 16
104 { "_mfchash", 0, 0, 0, 0 },
105 #define N_VIFTABLE 17
106 { "_viftable", 0, 0, 0, 0 },
107 #define N_MSIZE 18
108 { "_msize", 0, 0, 0, 0 },
109 #define N_MCLBYTES 19
110 { "_mclbytes", 0, 0, 0, 0 },
111 #define N_DDPSTAT 20
112 { "_ddpstat", 0, 0, 0, 0 }, /* not available via kvm */
113 #define N_DDPCB 21
114 { "_ddpcb", 0, 0, 0, 0 },
115 #define N_MBPOOL 22
116 { "_mbpool", 0, 0, 0, 0 },
117 #define N_MCLPOOL 23
118 { "_mclpool", 0, 0, 0, 0 },
119 #define N_IP6STAT 24
120 { "_ip6stat", 0, 0, 0, 0 }, /* not available via kvm */
121 #define N_TCP6STAT 25
122 { "_tcp6stat", 0, 0, 0, 0 }, /* not available via kvm */
123 #define N_UDP6STAT 26
124 { "_udp6stat", 0, 0, 0, 0 }, /* not available via kvm */
125 #define N_ICMP6STAT 27
126 { "_icmp6stat", 0, 0, 0, 0 }, /* not available via kvm */
127 #define N_IPSECSTAT 28
128 { "_ipsecstat", 0, 0, 0, 0 }, /* not available via kvm */
129 #define N_IPSEC6STAT 29
130 { "_ipsec6stat", 0, 0, 0, 0 }, /* not available via kvm */
131 #define N_PIM6STAT 30
132 { "_pim6stat", 0, 0, 0, 0 }, /* not available via kvm */
133 #define N_MRT6PROTO 31
134 { "_ip6_mrtproto", 0, 0, 0, 0 },
135 #define N_MRT6STAT 32
136 { "_mrt6stat", 0, 0, 0, 0 },
137 #define N_MF6CTABLE 33
138 { "_mf6ctable", 0, 0, 0, 0 },
139 #define N_MIF6TABLE 34
140 { "_mif6table", 0, 0, 0, 0 },
141 #define N_PFKEYSTAT 35
142 { "_pfkeystat", 0, 0, 0, 0 }, /* not available via kvm */
143 #define N_ARPSTAT 36
144 { "_arpstat", 0, 0, 0, 0 }, /* not available via kvm */
145 #define N_RIP6STAT 37
146 { "_rip6stat", 0, 0, 0, 0 }, /* not available via kvm */
147 #define N_ARPINTRQ 38
148 { "_arpintrq", 0, 0, 0, 0 },
149 #define N_IPINTRQ 39
150 { "_ipintrq", 0, 0, 0, 0 },
151 #define N_IP6INTRQ 40
152 { "_ip6intrq", 0, 0, 0, 0 },
153 #define N_ATINTRQ1 41
154 { "_atintrq1", 0, 0, 0, 0 },
155 #define N_ATINTRQ2 42
156 { "_atintrq2", 0, 0, 0, 0 },
157 #define N_NSINTRQ 43
158 { "_nsintrq", 0, 0, 0, 0 },
159 #define N_LLCINTRQ 44
160 { "_llcintrq", 0, 0, 0, 0 },
161 #define N_HDINTRQ 45
162 { "_hdintrq", 0, 0, 0, 0 },
163 #define N_NATMINTRQ 46
164 { "_natmintrq", 0, 0, 0, 0 },
165 #define N_PPPOEDISCINQ 47
166 { "_ppoediscinq", 0, 0, 0, 0 },
167 #define N_PPPOEINQ 48
168 { "_ppoeinq", 0, 0, 0, 0 },
169 #define N_PKINTRQ 49
170 { "_pkintrq", 0, 0, 0, 0 },
171 #define N_HARDCLOCK_TICKS 50
172 { "_hardclock_ticks", 0, 0, 0, 0 },
173 #define N_PIMSTAT 51
174 { "_pimstat", 0, 0, 0, 0 },
175 #define N_CARPSTAT 52
176 { "_carpstats", 0, 0, 0, 0 }, /* not available via kvm */
177 #define N_PFSYNCSTAT 53
178 { "_pfsyncstats", 0, 0, 0, 0}, /* not available via kvm */
179 { "", 0, 0, 0, 0 },
180 };
181
182 struct protox {
183 u_char pr_index; /* index into nlist of cb head */
184 u_char pr_sindex; /* index into nlist of stat block */
185 u_char pr_wanted; /* 1 if wanted, 0 otherwise */
186 void (*pr_cblocks) /* control blocks printing routine */
187 __P((u_long, const char *));
188 void (*pr_stats) /* statistics printing routine */
189 __P((u_long, const char *));
190 void (*pr_istats)
191 __P((const char *)); /* per/if statistics printing routine */
192 void (*pr_dump) /* PCB state dump routine */
193 __P((u_long, const char *, u_long));
194 const char *pr_name; /* well-known name */
195 } protox[] = {
196 { N_TCBTABLE, N_TCPSTAT, 1, protopr,
197 tcp_stats, NULL, tcp_dump, "tcp" },
198 { N_UDBTABLE, N_UDPSTAT, 1, protopr,
199 udp_stats, NULL, 0, "udp" },
200 { -1, N_IPSTAT, 1, 0,
201 ip_stats, NULL, 0, "ip" },
202 { -1, N_ICMPSTAT, 1, 0,
203 icmp_stats, NULL, 0, "icmp" },
204 { -1, N_IGMPSTAT, 1, 0,
205 igmp_stats, NULL, 0, "igmp" },
206 { -1, N_CARPSTAT, 1, 0,
207 carp_stats, NULL, 0, "carp" },
208 #ifdef IPSEC
209 { -1, N_IPSECSTAT, 1, 0,
210 fast_ipsec_stats, NULL, 0, "ipsec" },
211 #endif
212 { -1, N_PIMSTAT, 1, 0,
213 pim_stats, NULL, 0, "pim" },
214 { -1, N_PFSYNCSTAT, 1, 0,
215 pfsync_stats, NULL, 0, "pfsync" },
216 { -1, -1, 0, 0,
217 0, NULL, 0, 0 }
218 };
219
220 #ifdef INET6
221 struct protox ip6protox[] = {
222 { -1, N_IP6STAT, 1, 0,
223 ip6_stats, ip6_ifstats, 0, "ip6" },
224 { -1, N_ICMP6STAT, 1, 0,
225 icmp6_stats, icmp6_ifstats, 0, "icmp6" },
226 #ifdef TCP6
227 { N_TCBTABLE, N_TCP6STAT, 1, ip6protopr,
228 tcp6_stats, NULL, tcp6_dump, "tcp6" },
229 #else
230 { N_TCBTABLE, N_TCP6STAT, 1, ip6protopr,
231 tcp_stats, NULL, tcp6_dump, "tcp6" },
232 #endif
233 { N_UDBTABLE, N_UDP6STAT, 1, ip6protopr,
234 udp6_stats, NULL, 0, "udp6" },
235 #ifdef IPSEC
236 { -1, N_IPSEC6STAT, 1, 0,
237 fast_ipsec_stats, NULL, 0, "ipsec6" },
238 #endif
239 { -1, N_PIM6STAT, 1, 0,
240 pim6_stats, NULL, 0, "pim6" },
241 { -1, N_RIP6STAT, 1, 0,
242 rip6_stats, NULL, 0, "rip6" },
243 { -1, -1, 0, 0,
244 0, NULL, 0, 0 }
245 };
246 #endif
247
248 struct protox arpprotox[] = {
249 { -1, N_ARPSTAT, 1, 0,
250 arp_stats, NULL, 0, "arp" },
251 { -1, -1, 0, 0,
252 0, NULL, 0, 0 }
253 };
254
255 #ifdef IPSEC
256 struct protox pfkeyprotox[] = {
257 { -1, N_PFKEYSTAT, 1, 0,
258 pfkey_stats, NULL, 0, "pfkey" },
259 { -1, -1, 0, 0,
260 0, NULL, 0, 0 }
261 };
262 #endif
263
264 #ifndef SMALL
265 struct protox atalkprotox[] = {
266 { N_DDPCB, N_DDPSTAT, 1, atalkprotopr,
267 ddp_stats, NULL, 0, "ddp" },
268 { -1, -1, 0, 0,
269 0, NULL, 0, NULL }
270 };
271 #endif
272
273 struct protox *protoprotox[] = { protox,
274 #ifdef INET6
275 ip6protox,
276 #endif
277 arpprotox,
278 #ifdef IPSEC
279 pfkeyprotox,
280 #endif
281 #ifndef SMALL
282 atalkprotox,
283 #endif
284 NULL };
285
286 const struct softintrq {
287 const char *siq_name;
288 int siq_index;
289 } softintrq[] = {
290 { "arpintrq", N_ARPINTRQ },
291 { "ipintrq", N_IPINTRQ },
292 { "ip6intrq", N_IP6INTRQ },
293 { "atintrq1", N_ATINTRQ1 },
294 { "atintrq2", N_ATINTRQ2 },
295 { "llcintrq", N_LLCINTRQ },
296 { "hdintrq", N_HDINTRQ },
297 { "natmintrq", N_NATMINTRQ },
298 { "ppoediscinq", N_PPPOEDISCINQ },
299 { "ppoeinq", N_PPPOEINQ },
300 { "pkintrq", N_PKINTRQ },
301 { NULL, -1 },
302 };
303
304 int main __P((int, char *[]));
305 static void printproto __P((struct protox *, const char *));
306 static void print_softintrq __P((void));
307 __dead static void usage(void);
308 static struct protox *name2protox __P((const char *));
309 static struct protox *knownname __P((const char *));
310 static void prepare(const char *, const char *, struct protox *tp);
311 static kvm_t *prepare_kvmd(const char *, const char *, char *);
312
313 static kvm_t *kvmd = NULL;
314 gid_t egid;
315 int interval; /* repeat interval for i/f stats */
316 static const char *nlistf = NULL, *memf = NULL;
317
318 kvm_t *
319 get_kvmd(void)
320 {
321 char buf[_POSIX2_LINE_MAX];
322
323 if (kvmd != NULL)
324 return kvmd;
325 if ((kvmd = prepare_kvmd(nlistf, memf, buf)) == NULL)
326 errx(1, "kvm error: %s", buf);
327 return kvmd;
328 }
329
330 static kvm_t *
331 prepare_kvmd(const char *nf, const char *mf, char *errbuf)
332 {
333 kvm_t *k;
334
335 (void)setegid(egid);
336 k = kvm_openfiles(nf, mf, NULL, O_RDONLY, errbuf);
337 (void)setgid(getgid());
338 return k;
339 }
340
341 void
342 prepare(const char *nf, const char *mf, struct protox *tp)
343 {
344 char buf[_POSIX2_LINE_MAX];
345 /*
346 * Try to figure out if we can use sysctl or not.
347 */
348 if (nf != NULL || mf != NULL) {
349 /* Of course, we can't use sysctl with dumps. */
350 if (force_sysctl)
351 errx(EXIT_FAILURE, "can't use sysctl with dumps");
352
353 /*
354 * If we have -M or -N, we're not dealing with live memory
355 * or want to use kvm interface explicitly. It is sometimes
356 * useful to dig inside of kernel without extending
357 * sysctl interface (i.e., without rebuilding kernel).
358 */
359 use_sysctl = 0;
360 } else if (qflag ||
361 iflag ||
362 #ifndef SMALL
363 gflag ||
364 #endif
365 (pflag && tp->pr_sindex == N_PIMSTAT) ||
366 Pflag) {
367 /* These flags are not yet supported via sysctl(3). */
368 use_sysctl = 0;
369 } else {
370 /* We can use sysctl(3). */
371 use_sysctl = 1;
372 }
373
374 if (force_sysctl && !use_sysctl) {
375 /* Let the user know what's about to happen. */
376 warnx("forcing sysctl usage even though it might not be "\
377 "supported");
378 use_sysctl = 1;
379 }
380
381 kvmd = prepare_kvmd(nf, mf, buf);
382
383 if (!use_sysctl) {
384
385 if (kvmd == NULL)
386 errx(1, "kvm error: %s", buf);
387 if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) {
388 if (nf)
389 errx(1, "%s: no namelist", nf);
390 else
391 errx(1, "no namelist");
392 }
393 } else
394 (void)setgid(getgid());
395 }
396
397 int
398 main(int argc, char *argv[])
399 {
400 struct protoent *p;
401 struct protox *tp; /* for printing cblocks & stats */
402 int ch;
403 char *cp;
404 char *afname, *afnames;
405 u_long pcbaddr;
406
407 if (prog_init) {
408 if (prog_init() == -1)
409 err(1, "init failed");
410 force_sysctl = 1; /* cheap trick */
411 }
412
413 egid = getegid();
414 (void)setegid(getgid());
415 tp = NULL;
416 af = AF_UNSPEC;
417 afnames = NULL;
418 pcbaddr = 0;
419
420 while ((ch = getopt(argc, argv,
421 "AabBdf:ghI:LliM:mN:nP:p:qrsStTuVvw:X")) != -1)
422 switch (ch) {
423 case 'A':
424 Aflag = RT_AFLAG;
425 break;
426 case 'a':
427 aflag = 1;
428 break;
429 case 'b':
430 bflag = 1;
431 break;
432 case 'B':
433 Bflag = 1;
434 break;
435 case 'd':
436 dflag = 1;
437 break;
438 case 'f':
439 afnames = optarg;
440 break;
441 #ifndef SMALL
442 case 'g':
443 gflag = 1;
444 break;
445 #endif
446 case 'h':
447 hflag = 1;
448 break;
449 case 'I':
450 iflag = 1;
451 interface = optarg;
452 break;
453 case 'i':
454 iflag = 1;
455 break;
456 case 'L':
457 Lflag = 1;
458 break;
459 case 'l':
460 lflag = 1;
461 break;
462 case 'M':
463 memf = optarg;
464 break;
465 case 'm':
466 mflag = 1;
467 break;
468 case 'N':
469 nlistf = optarg;
470 break;
471 case 'n':
472 numeric_addr = numeric_port = nflag = RT_NFLAG;
473 break;
474 case 'P':
475 errno = 0;
476 pcbaddr = strtoul(optarg, &cp, 16);
477 if (*cp != '\0' || errno == ERANGE)
478 errx(1, "invalid PCB address %s",
479 optarg);
480 Pflag = 1;
481 break;
482 case 'p':
483 if ((tp = name2protox(optarg)) == NULL)
484 errx(1, "%s: unknown or uninstrumented protocol",
485 optarg);
486 pflag = 1;
487 break;
488 case 'q':
489 qflag = 1;
490 break;
491 case 'r':
492 rflag = 1;
493 break;
494 case 's':
495 ++sflag;
496 break;
497 case 'S':
498 numeric_addr = 1;
499 break;
500 case 't':
501 tflag = 1;
502 break;
503 case 'T':
504 tagflag = RT_TFLAG;
505 break;
506 case 'u':
507 af = AF_LOCAL;
508 break;
509 case 'V':
510 Vflag++;
511 break;
512 case 'v':
513 vflag = RT_VFLAG;
514 break;
515 case 'w':
516 interval = atoi(optarg);
517 iflag = 1;
518 break;
519 case 'X':
520 force_sysctl = 1;
521 break;
522 case '?':
523 default:
524 usage();
525 }
526 argv += optind;
527 argc -= optind;
528
529 #define BACKWARD_COMPATIBILITY
530 #ifdef BACKWARD_COMPATIBILITY
531 if (*argv) {
532 if (isdigit((unsigned char)**argv)) {
533 interval = atoi(*argv);
534 if (interval <= 0)
535 usage();
536 ++argv;
537 iflag = 1;
538 }
539 if (*argv) {
540 nlistf = *argv;
541 if (*++argv)
542 memf = *argv;
543 }
544 }
545 #endif
546
547 prepare(nlistf, memf, tp);
548
549 #ifndef SMALL
550 if (Bflag) {
551 if (sflag)
552 bpf_stats();
553 else
554 bpf_dump(interface);
555 exit(0);
556 }
557 #endif
558
559 if (mflag) {
560 mbpr(nl[N_MBSTAT].n_value, nl[N_MSIZE].n_value,
561 nl[N_MCLBYTES].n_value, nl[N_MBPOOL].n_value,
562 nl[N_MCLPOOL].n_value);
563 exit(0);
564 }
565 if (Pflag) {
566 if (tp == NULL) {
567 /* Default to TCP. */
568 tp = name2protox("tcp");
569 }
570 if (tp->pr_dump)
571 (*tp->pr_dump)(nl[tp->pr_index].n_value, tp->pr_name,
572 pcbaddr);
573 else
574 printf("%s: no PCB dump routine\n", tp->pr_name);
575 exit(0);
576 }
577 if (pflag) {
578 if (iflag && tp->pr_istats)
579 intpr(interval, nl[N_IFNET_LIST].n_value, tp->pr_istats);
580 else if (tp->pr_stats)
581 (*tp->pr_stats)(nl[tp->pr_sindex].n_value,
582 tp->pr_name);
583 else
584 printf("%s: no stats routine\n", tp->pr_name);
585 exit(0);
586 }
587 if (qflag) {
588 print_softintrq();
589 exit(0);
590 }
591 /*
592 * Keep file descriptors open to avoid overhead
593 * of open/close on each call to get* routines.
594 */
595 sethostent(1);
596 setnetent(1);
597 /*
598 * If -f was used afnames != NULL, loop over the address families.
599 * Otherwise do this at least once (with af == AF_UNSPEC).
600 */
601 afname = NULL;
602 do {
603 if (afnames != NULL) {
604 afname = strsep(&afnames, ",");
605 if (afname == NULL)
606 break; /* Exit early */
607 if (strcmp(afname, "inet") == 0)
608 af = AF_INET;
609 else if (strcmp(afname, "inet6") == 0)
610 af = AF_INET6;
611 else if (strcmp(afname, "arp") == 0)
612 af = AF_ARP;
613 else if (strcmp(afname, "pfkey") == 0)
614 af = PF_KEY;
615 else if (strcmp(afname, "unix") == 0
616 || strcmp(afname, "local") == 0)
617 af = AF_LOCAL;
618 else if (strcmp(afname, "atalk") == 0)
619 af = AF_APPLETALK;
620 else if (strcmp(afname, "mpls") == 0)
621 af = AF_MPLS;
622 else {
623 warnx("%s: unknown address family",
624 afname);
625 continue;
626 }
627 }
628
629 if (iflag) {
630 if (af != AF_UNSPEC)
631 goto protostat;
632
633 intpr(interval, nl[N_IFNET_LIST].n_value, NULL);
634 break;
635 }
636 if (rflag) {
637 if (sflag)
638 rt_stats(use_sysctl ? 0 : nl[N_RTSTAT].n_value);
639 else {
640 if (use_sysctl)
641 p_rttables(af,
642 nflag|tagflag|vflag, 0, ~0);
643 else
644 routepr(nl[N_RTREE].n_value);
645 }
646 break;
647 }
648 #ifndef SMALL
649 if (gflag) {
650 if (sflag) {
651 if (af == AF_INET || af == AF_UNSPEC)
652 mrt_stats(nl[N_MRTPROTO].n_value,
653 nl[N_MRTSTAT].n_value);
654 #ifdef INET6
655 if (af == AF_INET6 || af == AF_UNSPEC)
656 mrt6_stats(nl[N_MRT6PROTO].n_value,
657 nl[N_MRT6STAT].n_value);
658 #endif
659 }
660 else {
661 if (af == AF_INET || af == AF_UNSPEC)
662 mroutepr(nl[N_MRTPROTO].n_value,
663 nl[N_MFCHASHTBL].n_value,
664 nl[N_MFCHASH].n_value,
665 nl[N_VIFTABLE].n_value);
666 #ifdef INET6
667 if (af == AF_INET6 || af == AF_UNSPEC)
668 mroute6pr(nl[N_MRT6PROTO].n_value,
669 nl[N_MF6CTABLE].n_value,
670 nl[N_MIF6TABLE].n_value);
671 #endif
672 }
673 break;
674 }
675 #endif
676 protostat:
677 if (af == AF_INET || af == AF_UNSPEC) {
678 setprotoent(1);
679 setservent(1);
680 /* ugh, this is O(MN) ... why do we do this? */
681 while ((p = getprotoent()) != NULL) {
682 for (tp = protox; tp->pr_name; tp++)
683 if (strcmp(tp->pr_name, p->p_name) == 0)
684 break;
685 if (tp->pr_name == 0 || tp->pr_wanted == 0)
686 continue;
687 printproto(tp, p->p_name);
688 tp->pr_wanted = 0;
689 }
690 endprotoent();
691 for (tp = protox; tp->pr_name; tp++)
692 if (tp->pr_wanted)
693 printproto(tp, tp->pr_name);
694 }
695 #ifdef INET6
696 if (af == AF_INET6 || af == AF_UNSPEC)
697 for (tp = ip6protox; tp->pr_name; tp++)
698 printproto(tp, tp->pr_name);
699 #endif
700 if (af == AF_ARP || af == AF_UNSPEC)
701 for (tp = arpprotox; tp->pr_name; tp++)
702 printproto(tp, tp->pr_name);
703 #ifdef IPSEC
704 if (af == PF_KEY || af == AF_UNSPEC)
705 for (tp = pfkeyprotox; tp->pr_name; tp++)
706 printproto(tp, tp->pr_name);
707 #endif
708 #ifndef SMALL
709 if (af == AF_APPLETALK || af == AF_UNSPEC)
710 for (tp = atalkprotox; tp->pr_name; tp++)
711 printproto(tp, tp->pr_name);
712 if ((af == AF_LOCAL || af == AF_UNSPEC) && !sflag)
713 unixpr(nl[N_UNIXSW].n_value);
714 #endif
715 } while (afnames != NULL && afname != NULL);
716 exit(0);
717 }
718
719 /*
720 * Print out protocol statistics or control blocks (per sflag).
721 * If the interface was not specifically requested, and the symbol
722 * is not in the namelist, ignore this one.
723 */
724 static void
725 printproto(struct protox *tp, const char *name)
726 {
727 void (*pr) __P((u_long, const char *));
728 u_long off;
729
730 if (sflag) {
731 if (iflag) {
732 if (tp->pr_istats)
733 intpr(interval, nl[N_IFNET_LIST].n_value,
734 tp->pr_istats);
735 return;
736 }
737 else {
738 pr = tp->pr_stats;
739 off = nl[tp->pr_sindex].n_value;
740 }
741 } else {
742 pr = tp->pr_cblocks;
743 off = nl[tp->pr_index].n_value;
744 }
745 if (pr != NULL && ((off || af != AF_UNSPEC) || use_sysctl)) {
746 (*pr)(off, name);
747 }
748 }
749
750 /*
751 * Print softintrq status.
752 */
753 void
754 print_softintrq(void)
755 {
756 struct ifqueue intrq, *ifq = &intrq;
757 const struct softintrq *siq;
758 u_long off;
759
760 for (siq = softintrq; siq->siq_name != NULL; siq++) {
761 off = nl[siq->siq_index].n_value;
762 if (off == 0)
763 continue;
764
765 kread(off, (char *)ifq, sizeof(*ifq));
766 printf("%s:\n", siq->siq_name);
767 printf("\tqueue length: %d\n", ifq->ifq_len);
768 printf("\tmaximum queue length: %d\n", ifq->ifq_maxlen);
769 printf("\tpackets dropped: %d\n", ifq->ifq_drops);
770 }
771 }
772
773 /*
774 * Read kernel memory, return 0 on success.
775 */
776 int
777 kread(u_long addr, char *buf, int size)
778 {
779
780 if (kvm_read(kvmd, addr, buf, size) != size) {
781 warnx("%s", kvm_geterr(kvmd));
782 return (-1);
783 }
784 return (0);
785 }
786
787 const char *
788 plural(int n)
789 {
790
791 return (n != 1 ? "s" : "");
792 }
793
794 const char *
795 plurales(int n)
796 {
797
798 return (n != 1 ? "es" : "");
799 }
800
801 int
802 get_hardticks(void)
803 {
804 int hardticks;
805
806 kread(nl[N_HARDCLOCK_TICKS].n_value, (char *)&hardticks,
807 sizeof(hardticks));
808 return (hardticks);
809 }
810
811 /*
812 * Find the protox for the given "well-known" name.
813 */
814 static struct protox *
815 knownname(const char *name)
816 {
817 struct protox **tpp, *tp;
818
819 for (tpp = protoprotox; *tpp; tpp++)
820 for (tp = *tpp; tp->pr_name; tp++)
821 if (strcmp(tp->pr_name, name) == 0)
822 return (tp);
823 return (NULL);
824 }
825
826 /*
827 * Find the protox corresponding to name.
828 */
829 static struct protox *
830 name2protox(const char *name)
831 {
832 struct protox *tp;
833 char **alias; /* alias from p->aliases */
834 struct protoent *p;
835
836 /*
837 * Try to find the name in the list of "well-known" names. If that
838 * fails, check if name is an alias for an Internet protocol.
839 */
840 if ((tp = knownname(name)) != NULL)
841 return (tp);
842
843 setprotoent(1); /* make protocol lookup cheaper */
844 while ((p = getprotoent()) != NULL) {
845 /* assert: name not same as p->name */
846 for (alias = p->p_aliases; *alias; alias++)
847 if (strcmp(name, *alias) == 0) {
848 endprotoent();
849 return (knownname(p->p_name));
850 }
851 }
852 endprotoent();
853 return (NULL);
854 }
855
856 static void
857 usage(void)
858 {
859 const char *progname = getprogname();
860
861 (void)fprintf(stderr,
862 "usage: %s [-Aan] [-f address_family[,family ...]] [-M core] [-N system]\n", progname);
863 (void)fprintf(stderr,
864 " %s [-bdgiLmnqrsSv] [-f address_family[,family ...]] [-M core] [-N system]\n",
865 progname);
866 (void)fprintf(stderr,
867 " %s [-dn] [-I interface] [-M core] [-N system] [-w wait]\n", progname);
868 (void)fprintf(stderr,
869 " %s [-p protocol] [-M core] [-N system]\n", progname);
870 (void)fprintf(stderr,
871 " %s [-p protocol] [-M core] [-N system] -P pcbaddr\n", progname);
872 (void)fprintf(stderr,
873 " %s [-p protocol] [-i] [-I Interface] \n", progname);
874 (void)fprintf(stderr,
875 " %s [-s] [-f address_family[,family ...]] [-i] [-I Interface]\n", progname);
876 (void)fprintf(stderr,
877 " %s [-s] [-B] [-I interface]\n", progname);
878 exit(1);
879 }
880