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