if.c revision 1.56
1/* $NetBSD: if.c,v 1.56 2003/08/19 12:52:13 itojun Exp $ */ 2 3/* 4 * Copyright (c) 1983, 1988, 1993 5 * The 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#if 0 35static char sccsid[] = "from: @(#)if.c 8.2 (Berkeley) 2/21/94"; 36#else 37__RCSID("$NetBSD: if.c,v 1.56 2003/08/19 12:52:13 itojun Exp $"); 38#endif 39#endif /* not lint */ 40 41#include <sys/types.h> 42#include <sys/protosw.h> 43#include <sys/socket.h> 44 45#include <net/if.h> 46#include <net/if_dl.h> 47#include <net/if_types.h> 48#include <netinet/in.h> 49#include <netinet/in_var.h> 50#include <netns/ns.h> 51#include <netns/ns_if.h> 52#include <netiso/iso.h> 53#include <netiso/iso_var.h> 54#include <arpa/inet.h> 55 56#include <signal.h> 57#include <stdio.h> 58#include <stdlib.h> 59#include <string.h> 60#include <unistd.h> 61#include <netdb.h> 62 63#include "netstat.h" 64 65#define YES 1 66#define NO 0 67 68static void sidewaysintpr __P((u_int, u_long)); 69static void catchalarm __P((int)); 70 71/* 72 * Print a description of the network interfaces. 73 * NOTE: ifnetaddr is the location of the kernel global "ifnet", 74 * which is a TAILQ_HEAD. 75 */ 76void 77intpr(interval, ifnetaddr, pfunc) 78 int interval; 79 u_long ifnetaddr; 80 void (*pfunc)(char *); 81{ 82 struct ifnet ifnet; 83 union { 84 struct ifaddr ifa; 85 struct in_ifaddr in; 86#ifdef INET6 87 struct in6_ifaddr in6; 88#endif /* INET6 */ 89 struct ns_ifaddr ns; 90 struct iso_ifaddr iso; 91 } ifaddr; 92 u_long ifaddraddr; 93 struct sockaddr *sa; 94 struct ifnet_head ifhead; /* TAILQ_HEAD */ 95 char name[IFNAMSIZ + 1]; /* + 1 for `*' */ 96 char hbuf[NI_MAXHOST]; /* for getnameinfo() */ 97#ifdef INET6 98#ifdef NI_WITHSCOPEID 99 const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID; 100#else 101 const int niflag = NI_NUMERICHOST; 102#endif 103#endif 104 105 if (ifnetaddr == 0) { 106 printf("ifnet: symbol not defined\n"); 107 return; 108 } 109 if (interval) { 110 sidewaysintpr((unsigned)interval, ifnetaddr); 111 return; 112 } 113 114 /* 115 * Find the pointer to the first ifnet structure. Replace 116 * the pointer to the TAILQ_HEAD with the actual pointer 117 * to the first list element. 118 */ 119 if (kread(ifnetaddr, (char *)&ifhead, sizeof ifhead)) 120 return; 121 ifnetaddr = (u_long)ifhead.tqh_first; 122 123 if (!sflag & !pflag) { 124 if (bflag) { 125 printf("%-5.5s %-5.5s %-13.13s %-17.17s " 126 "%10.10s %10.10s", 127 "Name", "Mtu", "Network", "Address", 128 "Ibytes", "Obytes"); 129 } else { 130 printf("%-5.5s %-5.5s %-13.13s %-17.17s " 131 "%8.8s %5.5s %8.8s %5.5s %5.5s", 132 "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs", 133 "Opkts", "Oerrs", "Colls"); 134 } 135 if (tflag) 136 printf(" %4.4s", "Time"); 137 if (dflag) 138 printf(" %5.5s", "Drops"); 139 putchar('\n'); 140 } 141 ifaddraddr = 0; 142 while (ifnetaddr || ifaddraddr) { 143 struct sockaddr_in *sin; 144#ifdef INET6 145 struct sockaddr_in6 *sin6; 146#endif /* INET6 */ 147 char *cp; 148 int n, m; 149 150 if (ifaddraddr == 0) { 151 if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet)) 152 return; 153 memmove(name, ifnet.if_xname, IFNAMSIZ); 154 name[IFNAMSIZ - 1] = '\0'; /* sanity */ 155 ifnetaddr = (u_long)ifnet.if_list.tqe_next; 156 if (interface != 0 && strcmp(name, interface) != 0) 157 continue; 158 cp = strchr(name, '\0'); 159 160 if (pfunc) { 161 (*pfunc)(name); 162 continue; 163 } 164 165 if ((ifnet.if_flags & IFF_UP) == 0) 166 *cp++ = '*'; 167 *cp = '\0'; 168 ifaddraddr = (u_long)ifnet.if_addrlist.tqh_first; 169 } 170 if (vflag) 171 n = strlen(name) < 5 ? 5 : strlen(name); 172 else 173 n = 5; 174 printf("%-*.*s %-5llu ", n, n, name, 175 (unsigned long long)ifnet.if_mtu); 176 if (ifaddraddr == 0) { 177 printf("%-13.13s ", "none"); 178 printf("%-17.17s ", "none"); 179 } else { 180 char hexsep = '.'; /* for hexprint */ 181 static const char hexfmt[] = "%02x%c"; /* for hexprint */ 182 if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) { 183 ifaddraddr = 0; 184 continue; 185 } 186#define CP(x) ((char *)(x)) 187 cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) + 188 CP(&ifaddr); 189 sa = (struct sockaddr *)cp; 190 switch (sa->sa_family) { 191 case AF_UNSPEC: 192 printf("%-13.13s ", "none"); 193 printf("%-17.17s ", "none"); 194 break; 195 case AF_INET: 196 sin = (struct sockaddr_in *)sa; 197#ifdef notdef 198 /* 199 * can't use inet_makeaddr because kernel 200 * keeps nets unshifted. 201 */ 202 in = inet_makeaddr(ifaddr.in.ia_subnet, 203 INADDR_ANY); 204 cp = netname(in.s_addr, 205 ifaddr.in.ia_subnetmask); 206#else 207 cp = netname(ifaddr.in.ia_subnet, 208 ifaddr.in.ia_subnetmask); 209#endif 210 if (vflag) 211 n = strlen(cp) < 13 ? 13 : strlen(cp); 212 else 213 n = 13; 214 printf("%-*.*s ", n, n, cp); 215 cp = routename(sin->sin_addr.s_addr); 216 if (vflag) 217 n = strlen(cp) < 17 ? 17 : strlen(cp); 218 else 219 n = 17; 220 printf("%-*.*s ", n, n, cp); 221 if (aflag) { 222 u_long multiaddr; 223 struct in_multi inm; 224 225 multiaddr = (u_long) 226 ifaddr.in.ia_multiaddrs.lh_first; 227 while (multiaddr != 0) { 228 kread(multiaddr, (char *)&inm, 229 sizeof inm); 230 printf("\n%25s %-17.17s ", "", 231 routename( 232 inm.inm_addr.s_addr)); 233 multiaddr = 234 (u_long)inm.inm_list.le_next; 235 } 236 } 237 break; 238#ifdef INET6 239 case AF_INET6: 240 sin6 = (struct sockaddr_in6 *)sa; 241#ifdef __KAME__ 242 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 243 sin6->sin6_scope_id = 244 ntohs(*(u_int16_t *) 245 &sin6->sin6_addr.s6_addr[2]); 246 /* too little width */ 247 if (!vflag) 248 sin6->sin6_scope_id = 0; 249 sin6->sin6_addr.s6_addr[2] = 0; 250 sin6->sin6_addr.s6_addr[3] = 0; 251 } 252#endif 253 cp = netname6(&ifaddr.in6.ia_addr, 254 &ifaddr.in6.ia_prefixmask.sin6_addr); 255 if (vflag) 256 n = strlen(cp) < 13 ? 13 : strlen(cp); 257 else 258 n = 13; 259 printf("%-*.*s ", n, n, cp); 260 if (getnameinfo((struct sockaddr *)sin6, 261 sin6->sin6_len, 262 hbuf, sizeof(hbuf), NULL, 0, 263 niflag) != 0) { 264 cp = "?"; 265 } else 266 cp = hbuf; 267 if (vflag) 268 n = strlen(cp) < 17 ? 17 : strlen(cp); 269 else 270 n = 17; 271 printf("%-*.*s ", n, n, cp); 272 if (aflag) { 273 u_long multiaddr; 274 struct in6_multi inm; 275 struct sockaddr_in6 sin6; 276 277 multiaddr = (u_long) 278 ifaddr.in6.ia6_multiaddrs.lh_first; 279 while (multiaddr != 0) { 280 kread(multiaddr, (char *)&inm, 281 sizeof inm); 282 memset(&sin6, 0, sizeof(sin6)); 283 sin6.sin6_len = sizeof(struct sockaddr_in6); 284 sin6.sin6_family = AF_INET6; 285 sin6.sin6_addr = inm.in6m_addr; 286#ifdef __KAME__ 287 if (IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) { 288 sin6.sin6_scope_id = 289 ntohs(*(u_int16_t *) 290 &sin6.sin6_addr.s6_addr[2]); 291 sin6.sin6_addr.s6_addr[2] = 0; 292 sin6.sin6_addr.s6_addr[3] = 0; 293 } 294#endif 295 if (getnameinfo((struct sockaddr *)&sin6, 296 sin6.sin6_len, hbuf, 297 sizeof(hbuf), NULL, 0, 298 niflag) != 0) { 299 strlcpy(hbuf, "??", 300 sizeof(hbuf)); 301 } 302 cp = hbuf; 303 if (vflag) 304 n = strlen(cp) < 17 305 ? 17 : strlen(cp); 306 else 307 n = 17; 308 printf("\n%25s %-*.*s ", "", 309 n, n, cp); 310 multiaddr = 311 (u_long)inm.in6m_entry.le_next; 312 } 313 } 314 break; 315#endif /*INET6*/ 316#ifndef SMALL 317 case AF_APPLETALK: 318 printf("atalk:%-7.7s ", 319 atalk_print(sa,0x10)); 320 printf("%-17.17s ", atalk_print(sa,0x0b)); 321 break; 322 case AF_NS: 323 { 324 struct sockaddr_ns *sns = 325 (struct sockaddr_ns *)sa; 326 u_long net; 327 char netnum[10]; 328 329 *(union ns_net *)&net = sns->sns_addr.x_net; 330 (void)snprintf(netnum, sizeof(netnum), "%xH", 331 (u_int32_t)ntohl(net)); 332 upHex(netnum); 333 printf("ns:%-10s ", netnum); 334 printf("%-17.17s ", 335 ns_phost((struct sockaddr *)sns)); 336 } 337 break; 338#endif 339 case AF_LINK: 340 printf("%-13.13s ", "<Link>"); 341 if (getnameinfo(sa, sa->sa_len, 342 hbuf, sizeof(hbuf), NULL, 0, 343 NI_NUMERICHOST) != 0) { 344 cp = "?"; 345 } else 346 cp = hbuf; 347 if (vflag) 348 n = strlen(cp) < 17 ? 17 : strlen(cp); 349 else 350 n = 17; 351 printf("%-*.*s ", n, n, cp); 352 break; 353 354 default: 355 m = printf("(%d)", sa->sa_family); 356 for (cp = sa->sa_len + (char *)sa; 357 --cp > sa->sa_data && (*cp == 0);) {} 358 n = cp - sa->sa_data + 1; 359 cp = sa->sa_data; 360 while (--n >= 0) 361 m += printf(hexfmt, *cp++ & 0xff, 362 n > 0 ? hexsep : ' '); 363 m = 32 - m; 364 while (m-- > 0) 365 putchar(' '); 366 break; 367 } 368 ifaddraddr = (u_long)ifaddr.ifa.ifa_list.tqe_next; 369 } 370 if (bflag) { 371 printf("%10llu %10llu", 372 (unsigned long long)ifnet.if_ibytes, 373 (unsigned long long)ifnet.if_obytes); 374 } else { 375 printf("%8llu %5llu %8llu %5llu %5llu", 376 (unsigned long long)ifnet.if_ipackets, 377 (unsigned long long)ifnet.if_ierrors, 378 (unsigned long long)ifnet.if_opackets, 379 (unsigned long long)ifnet.if_oerrors, 380 (unsigned long long)ifnet.if_collisions); 381 } 382 if (tflag) 383 printf(" %4d", ifnet.if_timer); 384 if (dflag) 385 printf(" %5d", ifnet.if_snd.ifq_drops); 386 putchar('\n'); 387 } 388} 389 390#define MAXIF 100 391struct iftot { 392 char ift_name[IFNAMSIZ]; /* interface name */ 393 u_quad_t ift_ip; /* input packets */ 394 u_quad_t ift_ib; /* input bytes */ 395 u_quad_t ift_ie; /* input errors */ 396 u_quad_t ift_op; /* output packets */ 397 u_quad_t ift_ob; /* output bytes */ 398 u_quad_t ift_oe; /* output errors */ 399 u_quad_t ift_co; /* collisions */ 400 int ift_dr; /* drops */ 401} iftot[MAXIF]; 402 403u_char signalled; /* set if alarm goes off "early" */ 404 405/* 406 * Print a running summary of interface statistics. 407 * Repeat display every interval seconds, showing statistics 408 * collected over that interval. Assumes that interval is non-zero. 409 * First line printed at top of screen is always cumulative. 410 */ 411static void 412sidewaysintpr(interval, off) 413 unsigned interval; 414 u_long off; 415{ 416 struct ifnet ifnet; 417 u_long firstifnet; 418 struct iftot *ip, *total; 419 int line; 420 struct iftot *lastif, *sum, *interesting; 421 struct ifnet_head ifhead; /* TAILQ_HEAD */ 422 int oldmask; 423 424 /* 425 * Find the pointer to the first ifnet structure. Replace 426 * the pointer to the TAILQ_HEAD with the actual pointer 427 * to the first list element. 428 */ 429 if (kread(off, (char *)&ifhead, sizeof ifhead)) 430 return; 431 firstifnet = (u_long)ifhead.tqh_first; 432 433 lastif = iftot; 434 sum = iftot + MAXIF - 1; 435 total = sum - 1; 436 interesting = (interface == NULL) ? iftot : NULL; 437 for (off = firstifnet, ip = iftot; off;) { 438 if (kread(off, (char *)&ifnet, sizeof ifnet)) 439 break; 440 memset(ip->ift_name, 0, sizeof(ip->ift_name)); 441 snprintf(ip->ift_name, IFNAMSIZ, "%s", ifnet.if_xname); 442 if (interface && strcmp(ifnet.if_xname, interface) == 0) 443 interesting = ip; 444 ip++; 445 if (ip >= iftot + MAXIF - 2) 446 break; 447 off = (u_long)ifnet.if_list.tqe_next; 448 } 449 if (interesting == NULL) { 450 fprintf(stderr, "%s: %s: unknown interface\n", 451 getprogname(), interface); 452 exit(1); 453 } 454 lastif = ip; 455 456 (void)signal(SIGALRM, catchalarm); 457 signalled = NO; 458 (void)alarm(interval); 459banner: 460 if (bflag) 461 printf("%7.7s in %8.8s %6.6s out %5.5s", 462 interesting->ift_name, " ", 463 interesting->ift_name, " "); 464 else 465 printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s", 466 interesting->ift_name, " ", 467 interesting->ift_name, " ", " "); 468 if (dflag) 469 printf(" %5.5s", " "); 470 if (lastif - iftot > 0) { 471 if (bflag) 472 printf(" %7.7s in %8.8s %6.6s out %5.5s", 473 "total", " ", "total", " "); 474 else 475 printf(" %5.5s in %5.5s%5.5s out %5.5s %5.5s", 476 "total", " ", "total", " ", " "); 477 if (dflag) 478 printf(" %5.5s", " "); 479 } 480 for (ip = iftot; ip < iftot + MAXIF; ip++) { 481 ip->ift_ip = 0; 482 ip->ift_ib = 0; 483 ip->ift_ie = 0; 484 ip->ift_op = 0; 485 ip->ift_ob = 0; 486 ip->ift_oe = 0; 487 ip->ift_co = 0; 488 ip->ift_dr = 0; 489 } 490 putchar('\n'); 491 if (bflag) 492 printf("%10.10s %8.8s %10.10s %5.5s", 493 "bytes", " ", "bytes", " "); 494 else 495 printf("%8.8s %5.5s %8.8s %5.5s %5.5s", 496 "packets", "errs", "packets", "errs", "colls"); 497 if (dflag) 498 printf(" %5.5s", "drops"); 499 if (lastif - iftot > 0) { 500 if (bflag) 501 printf(" %10.10s %8.8s %10.10s %5.5s", 502 "bytes", " ", "bytes", " "); 503 else 504 printf(" %8.8s %5.5s %8.8s %5.5s %5.5s", 505 "packets", "errs", "packets", "errs", "colls"); 506 if (dflag) 507 printf(" %5.5s", "drops"); 508 } 509 putchar('\n'); 510 fflush(stdout); 511 line = 0; 512loop: 513 sum->ift_ip = 0; 514 sum->ift_ib = 0; 515 sum->ift_ie = 0; 516 sum->ift_op = 0; 517 sum->ift_ob = 0; 518 sum->ift_oe = 0; 519 sum->ift_co = 0; 520 sum->ift_dr = 0; 521 for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) { 522 if (kread(off, (char *)&ifnet, sizeof ifnet)) { 523 off = 0; 524 continue; 525 } 526 if (ip == interesting) { 527 if (bflag) { 528 printf("%10llu %8.8s %10llu %5.5s", 529 (unsigned long long)(ifnet.if_ibytes - 530 ip->ift_ib), " ", 531 (unsigned long long)(ifnet.if_obytes - 532 ip->ift_ob), " "); 533 } else { 534 printf("%8llu %5llu %8llu %5llu %5llu", 535 (unsigned long long) 536 (ifnet.if_ipackets - ip->ift_ip), 537 (unsigned long long) 538 (ifnet.if_ierrors - ip->ift_ie), 539 (unsigned long long) 540 (ifnet.if_opackets - ip->ift_op), 541 (unsigned long long) 542 (ifnet.if_oerrors - ip->ift_oe), 543 (unsigned long long) 544 (ifnet.if_collisions - ip->ift_co)); 545 } 546 if (dflag) 547 printf(" %5llu", 548 (unsigned long long) 549 (ifnet.if_snd.ifq_drops - ip->ift_dr)); 550 } 551 ip->ift_ip = ifnet.if_ipackets; 552 ip->ift_ib = ifnet.if_ibytes; 553 ip->ift_ie = ifnet.if_ierrors; 554 ip->ift_op = ifnet.if_opackets; 555 ip->ift_ob = ifnet.if_obytes; 556 ip->ift_oe = ifnet.if_oerrors; 557 ip->ift_co = ifnet.if_collisions; 558 ip->ift_dr = ifnet.if_snd.ifq_drops; 559 sum->ift_ip += ip->ift_ip; 560 sum->ift_ib += ip->ift_ib; 561 sum->ift_ie += ip->ift_ie; 562 sum->ift_op += ip->ift_op; 563 sum->ift_ob += ip->ift_ob; 564 sum->ift_oe += ip->ift_oe; 565 sum->ift_co += ip->ift_co; 566 sum->ift_dr += ip->ift_dr; 567 off = (u_long)ifnet.if_list.tqe_next; 568 } 569 if (lastif - iftot > 0) { 570 if (bflag) { 571 printf(" %10llu %8.8s %10llu %5.5s", 572 (unsigned long long) 573 (sum->ift_ib - total->ift_ib), " ", 574 (unsigned long long) 575 (sum->ift_ob - total->ift_ob), " "); 576 } else { 577 printf(" %8llu %5llu %8llu %5llu %5llu", 578 (unsigned long long) 579 (sum->ift_ip - total->ift_ip), 580 (unsigned long long) 581 (sum->ift_ie - total->ift_ie), 582 (unsigned long long) 583 (sum->ift_op - total->ift_op), 584 (unsigned long long) 585 (sum->ift_oe - total->ift_oe), 586 (unsigned long long) 587 (sum->ift_co - total->ift_co)); 588 } 589 if (dflag) 590 printf(" %5llu", 591 (unsigned long long)(sum->ift_dr - total->ift_dr)); 592 } 593 *total = *sum; 594 putchar('\n'); 595 fflush(stdout); 596 line++; 597 oldmask = sigblock(sigmask(SIGALRM)); 598 if (! signalled) { 599 sigpause(0); 600 } 601 sigsetmask(oldmask); 602 signalled = NO; 603 (void)alarm(interval); 604 if (line == 21) 605 goto banner; 606 goto loop; 607 /*NOTREACHED*/ 608} 609 610/* 611 * Called if an interval expires before sidewaysintpr has completed a loop. 612 * Sets a flag to not wait for the alarm. 613 */ 614static void 615catchalarm(signo) 616 int signo; 617{ 618 619 signalled = YES; 620} 621