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