1 /* $NetBSD: if.c,v 1.34 1999/12/13 15:22:55 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 39 static char sccsid[] = "from: @(#)if.c 8.2 (Berkeley) 2/21/94"; 40 #else 41 __RCSID("$NetBSD: if.c,v 1.34 1999/12/13 15:22:55 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 71 static void sidewaysintpr __P((u_int, u_long)); 72 static void catchalarm __P((int)); 73 74 #ifdef INET6 75 char *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 */ 83 void 84 intpr(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 printf("%-5.5s %-5llu ", name, 178 (unsigned long long)ifnet.if_mtu); 179 if (ifaddraddr == 0) { 180 printf("%-13.13s ", "none"); 181 printf("%-17.17s ", "none"); 182 } else { 183 char hexsep = '.'; /* for hexprint */ 184 const char *hexfmt = "%x%c"; /* for hexprint */ 185 if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) { 186 ifaddraddr = 0; 187 continue; 188 } 189 #define CP(x) ((char *)(x)) 190 cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) + 191 CP(&ifaddr); sa = (struct sockaddr *)cp; 192 switch (sa->sa_family) { 193 case AF_UNSPEC: 194 printf("%-13.13s ", "none"); 195 printf("%-17.17s ", "none"); 196 break; 197 case AF_INET: 198 sin = (struct sockaddr_in *)sa; 199 #ifdef notdef 200 /* 201 * can't use inet_makeaddr because kernel 202 * keeps nets unshifted. 203 */ 204 in = inet_makeaddr(ifaddr.in.ia_subnet, 205 INADDR_ANY); 206 printf("%-13.13s ", netname(in.s_addr, 207 ifaddr.in.ia_subnetmask)); 208 #else 209 printf("%-13.13s ", 210 netname(ifaddr.in.ia_subnet, 211 ifaddr.in.ia_subnetmask)); 212 #endif 213 printf("%-17.17s ", 214 routename(sin->sin_addr.s_addr)); 215 216 if (aflag) { 217 u_long multiaddr; 218 struct in_multi inm; 219 220 multiaddr = (u_long) 221 ifaddr.in.ia_multiaddrs.lh_first; 222 while (multiaddr != 0) { 223 kread(multiaddr, (char *)&inm, 224 sizeof inm); 225 printf("\n%25s %-17.17s ", "", 226 routename( 227 inm.inm_addr.s_addr)); 228 multiaddr = 229 (u_long)inm.inm_list.le_next; 230 } 231 } 232 break; 233 #ifdef INET6 234 case AF_INET6: 235 sin6 = (struct sockaddr_in6 *)sa; 236 cp = netname6(&ifaddr.in6.ia_addr, 237 &ifaddr.in6.ia_prefixmask.sin6_addr); 238 if (vflag) 239 n = strlen(cp) < 13 ? 13 : strlen(cp); 240 else 241 n = 13; 242 printf("%-*.*s ", n, n, cp); 243 #if 0 /* KAME_SCOPEID: don't do it twice */ 244 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 245 sin6->sin6_scope_id = 246 ntohs(*(u_int16_t *) 247 &sin6->sin6_addr.s6_addr[2]); 248 sin6->sin6_addr.s6_addr[2] = 0; 249 sin6->sin6_addr.s6_addr[3] = 0; 250 } 251 #endif 252 if (getnameinfo((struct sockaddr *)sin6, 253 sin6->sin6_len, 254 hbuf, sizeof(hbuf), NULL, 0, 255 niflag) != 0) { 256 cp = "?"; 257 } else 258 cp = hbuf; 259 if (vflag) 260 n = strlen(cp) < 17 ? 17 : strlen(cp); 261 else 262 n = 17; 263 printf("%-*.*s ", n, n, cp); 264 break; 265 #endif /*INET6*/ 266 #ifndef SMALL 267 case AF_APPLETALK: 268 printf("atalk:%-7.7s ", 269 atalk_print(sa,0x10)); 270 printf("%-17.17s ", atalk_print(sa,0x0b)); 271 break; 272 case AF_NS: 273 { 274 struct sockaddr_ns *sns = 275 (struct sockaddr_ns *)sa; 276 u_long net; 277 char netnum[8]; 278 279 *(union ns_net *)&net = sns->sns_addr.x_net; 280 (void)sprintf(netnum, "%xH", 281 (u_int32_t)ntohl(net)); 282 upHex(netnum); 283 printf("ns:%-10s ", netnum); 284 printf("%-17.17s ", 285 ns_phost((struct sockaddr *)sns)); 286 } 287 break; 288 #endif 289 case AF_LINK: 290 { 291 struct sockaddr_dl *sdl = 292 (struct sockaddr_dl *)sa; 293 cp = (char *)LLADDR(sdl); 294 if (sdl->sdl_type == IFT_FDDI 295 || sdl->sdl_type == IFT_ETHER) 296 hexsep = ':', hexfmt = "%02x%c"; 297 n = sdl->sdl_alen; 298 } 299 m = printf("%-13.13s ", "<Link>"); 300 goto hexprint; 301 default: 302 m = printf("(%d)", sa->sa_family); 303 for (cp = sa->sa_len + (char *)sa; 304 --cp > sa->sa_data && (*cp == 0);) {} 305 n = cp - sa->sa_data + 1; 306 cp = sa->sa_data; 307 hexprint: 308 while (--n >= 0) 309 m += printf(hexfmt, *cp++ & 0xff, 310 n > 0 ? hexsep : ' '); 311 m = 32 - m; 312 while (m-- > 0) 313 putchar(' '); 314 break; 315 } 316 ifaddraddr = (u_long)ifaddr.ifa.ifa_list.tqe_next; 317 } 318 if (bflag) { 319 printf("%10llu %10llu", 320 (unsigned long long)ifnet.if_ibytes, 321 (unsigned long long)ifnet.if_obytes); 322 } else { 323 printf("%8llu %5llu %8llu %5llu %5llu", 324 (unsigned long long)ifnet.if_ipackets, 325 (unsigned long long)ifnet.if_ierrors, 326 (unsigned long long)ifnet.if_opackets, 327 (unsigned long long)ifnet.if_oerrors, 328 (unsigned long long)ifnet.if_collisions); 329 } 330 if (tflag) 331 printf(" %4d", ifnet.if_timer); 332 if (dflag) 333 printf(" %5d", ifnet.if_snd.ifq_drops); 334 putchar('\n'); 335 } 336 } 337 338 #define MAXIF 100 339 struct iftot { 340 char ift_name[IFNAMSIZ]; /* interface name */ 341 u_long ift_ip; /* input packets */ 342 u_long ift_ib; /* input bytes */ 343 u_long ift_ie; /* input errors */ 344 u_long ift_op; /* output packets */ 345 u_long ift_ob; /* output bytes */ 346 u_long ift_oe; /* output errors */ 347 u_long ift_co; /* collisions */ 348 int ift_dr; /* drops */ 349 } iftot[MAXIF]; 350 351 u_char signalled; /* set if alarm goes off "early" */ 352 353 /* 354 * Print a running summary of interface statistics. 355 * Repeat display every interval seconds, showing statistics 356 * collected over that interval. Assumes that interval is non-zero. 357 * First line printed at top of screen is always cumulative. 358 */ 359 static void 360 sidewaysintpr(interval, off) 361 unsigned interval; 362 u_long off; 363 { 364 struct ifnet ifnet; 365 u_long firstifnet; 366 struct iftot *ip, *total; 367 int line; 368 struct iftot *lastif, *sum, *interesting; 369 struct ifnet_head ifhead; /* TAILQ_HEAD */ 370 int oldmask; 371 372 /* 373 * Find the pointer to the first ifnet structure. Replace 374 * the pointer to the TAILQ_HEAD with the actual pointer 375 * to the first list element. 376 */ 377 if (kread(off, (char *)&ifhead, sizeof ifhead)) 378 return; 379 firstifnet = (u_long)ifhead.tqh_first; 380 381 lastif = iftot; 382 sum = iftot + MAXIF - 1; 383 total = sum - 1; 384 interesting = (interface == NULL) ? iftot : NULL; 385 for (off = firstifnet, ip = iftot; off;) { 386 if (kread(off, (char *)&ifnet, sizeof ifnet)) 387 break; 388 memset(ip->ift_name, 0, sizeof(ip->ift_name)); 389 snprintf(ip->ift_name, IFNAMSIZ, "%s", ifnet.if_xname); 390 if (interface && strcmp(ifnet.if_xname, interface) == 0) 391 interesting = ip; 392 ip++; 393 if (ip >= iftot + MAXIF - 2) 394 break; 395 off = (u_long)ifnet.if_list.tqe_next; 396 } 397 if (interesting == NULL) { 398 fprintf(stderr, "%s: %s: unknown interface\n", 399 __progname, interface); 400 exit(1); 401 } 402 lastif = ip; 403 404 (void)signal(SIGALRM, catchalarm); 405 signalled = NO; 406 (void)alarm(interval); 407 banner: 408 if (bflag) 409 printf("%7.7s in %8.8s %6.6s out %5.5s", 410 interesting->ift_name, " ", 411 interesting->ift_name, " "); 412 else 413 printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s", 414 interesting->ift_name, " ", 415 interesting->ift_name, " ", " "); 416 if (dflag) 417 printf(" %5.5s", " "); 418 if (lastif - iftot > 0) { 419 if (bflag) 420 printf(" %7.7s in %8.8s %6.6s out %5.5s", 421 "total", " ", "total", " "); 422 else 423 printf(" %5.5s in %5.5s%5.5s out %5.5s %5.5s", 424 "total", " ", "total", " ", " "); 425 if (dflag) 426 printf(" %5.5s", " "); 427 } 428 for (ip = iftot; ip < iftot + MAXIF; ip++) { 429 ip->ift_ip = 0; 430 ip->ift_ib = 0; 431 ip->ift_ie = 0; 432 ip->ift_op = 0; 433 ip->ift_ob = 0; 434 ip->ift_oe = 0; 435 ip->ift_co = 0; 436 ip->ift_dr = 0; 437 } 438 putchar('\n'); 439 if (bflag) 440 printf("%10.10s %8.8s %10.10s %5.5s", 441 "bytes", " ", "bytes", " "); 442 else 443 printf("%8.8s %5.5s %8.8s %5.5s %5.5s", 444 "packets", "errs", "packets", "errs", "colls"); 445 if (dflag) 446 printf(" %5.5s", "drops"); 447 if (lastif - iftot > 0) { 448 if (bflag) 449 printf(" %10.10s %8.8s %10.10s %5.5s", 450 "bytes", " ", "bytes", " "); 451 else 452 printf(" %8.8s %5.5s %8.8s %5.5s %5.5s", 453 "packets", "errs", "packets", "errs", "colls"); 454 if (dflag) 455 printf(" %5.5s", "drops"); 456 } 457 putchar('\n'); 458 fflush(stdout); 459 line = 0; 460 loop: 461 sum->ift_ip = 0; 462 sum->ift_ib = 0; 463 sum->ift_ie = 0; 464 sum->ift_op = 0; 465 sum->ift_ob = 0; 466 sum->ift_oe = 0; 467 sum->ift_co = 0; 468 sum->ift_dr = 0; 469 for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) { 470 if (kread(off, (char *)&ifnet, sizeof ifnet)) { 471 off = 0; 472 continue; 473 } 474 if (ip == interesting) { 475 if (bflag) { 476 printf("%10llu %8.8s %10llu %5.5s", 477 (unsigned long long)(ifnet.if_ibytes - 478 ip->ift_ib), " ", 479 (unsigned long long)(ifnet.if_obytes - 480 ip->ift_ob), " "); 481 } else { 482 printf("%8llu %5llu %8llu %5llu %5llu", 483 (unsigned long long) 484 (ifnet.if_ipackets - ip->ift_ip), 485 (unsigned long long) 486 (ifnet.if_ierrors - ip->ift_ie), 487 (unsigned long long) 488 (ifnet.if_opackets - ip->ift_op), 489 (unsigned long long) 490 (ifnet.if_oerrors - ip->ift_oe), 491 (unsigned long long) 492 (ifnet.if_collisions - ip->ift_co)); 493 } 494 if (dflag) 495 printf(" %5llu", 496 (unsigned long long) 497 (ifnet.if_snd.ifq_drops - ip->ift_dr)); 498 } 499 ip->ift_ip = ifnet.if_ipackets; 500 ip->ift_ib = ifnet.if_ibytes; 501 ip->ift_ie = ifnet.if_ierrors; 502 ip->ift_op = ifnet.if_opackets; 503 ip->ift_ob = ifnet.if_obytes; 504 ip->ift_oe = ifnet.if_oerrors; 505 ip->ift_co = ifnet.if_collisions; 506 ip->ift_dr = ifnet.if_snd.ifq_drops; 507 sum->ift_ip += ip->ift_ip; 508 sum->ift_ib += ip->ift_ib; 509 sum->ift_ie += ip->ift_ie; 510 sum->ift_op += ip->ift_op; 511 sum->ift_ob += ip->ift_ob; 512 sum->ift_oe += ip->ift_oe; 513 sum->ift_co += ip->ift_co; 514 sum->ift_dr += ip->ift_dr; 515 off = (u_long)ifnet.if_list.tqe_next; 516 } 517 if (lastif - iftot > 0) { 518 if (bflag) { 519 printf(" %10llu %8.8s %10llu %5.5s", 520 (unsigned long long) 521 (sum->ift_ib - total->ift_ib), " ", 522 (unsigned long long) 523 (sum->ift_ob - total->ift_ob), " "); 524 } else { 525 printf(" %8llu %5llu %8llu %5llu %5llu", 526 (unsigned long long) 527 (sum->ift_ip - total->ift_ip), 528 (unsigned long long) 529 (sum->ift_ie - total->ift_ie), 530 (unsigned long long) 531 (sum->ift_op - total->ift_op), 532 (unsigned long long) 533 (sum->ift_oe - total->ift_oe), 534 (unsigned long long) 535 (sum->ift_co - total->ift_co)); 536 } 537 if (dflag) 538 printf(" %5llu", 539 (unsigned long long)(sum->ift_dr - total->ift_dr)); 540 } 541 *total = *sum; 542 putchar('\n'); 543 fflush(stdout); 544 line++; 545 oldmask = sigblock(sigmask(SIGALRM)); 546 if (! signalled) { 547 sigpause(0); 548 } 549 sigsetmask(oldmask); 550 signalled = NO; 551 (void)alarm(interval); 552 if (line == 21) 553 goto banner; 554 goto loop; 555 /*NOTREACHED*/ 556 } 557 558 /* 559 * Called if an interval expires before sidewaysintpr has completed a loop. 560 * Sets a flag to not wait for the alarm. 561 */ 562 static void 563 catchalarm(signo) 564 int signo; 565 { 566 567 signalled = YES; 568 } 569