1 /* $NetBSD: if.c,v 1.26 1998/03/19 02:42:57 kml 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.26 1998/03/19 02:42:57 kml 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 65 #include "netstat.h" 66 67 #define YES 1 68 #define NO 0 69 70 static void sidewaysintpr __P((u_int, u_long)); 71 static void catchalarm __P((int)); 72 73 /* 74 * Print a description of the network interfaces. 75 * NOTE: ifnetaddr is the location of the kernel global "ifnet", 76 * which is a TAILQ_HEAD. 77 */ 78 void 79 intpr(interval, ifnetaddr) 80 int interval; 81 u_long ifnetaddr; 82 { 83 struct ifnet ifnet; 84 union { 85 struct ifaddr ifa; 86 struct in_ifaddr in; 87 struct ns_ifaddr ns; 88 struct iso_ifaddr iso; 89 } ifaddr; 90 u_long ifaddraddr; 91 struct sockaddr *sa; 92 struct ifnet_head ifhead; /* TAILQ_HEAD */ 93 char name[IFNAMSIZ]; 94 95 if (ifnetaddr == 0) { 96 printf("ifnet: symbol not defined\n"); 97 return; 98 } 99 if (interval) { 100 sidewaysintpr((unsigned)interval, ifnetaddr); 101 return; 102 } 103 104 /* 105 * Find the pointer to the first ifnet structure. Replace 106 * the pointer to the TAILQ_HEAD with the actual pointer 107 * to the first list element. 108 */ 109 if (kread(ifnetaddr, (char *)&ifhead, sizeof ifhead)) 110 return; 111 ifnetaddr = (u_long)ifhead.tqh_first; 112 113 if (bflag) { 114 printf("%-5.5s %-5.5s %-13.13s %-17.17s " 115 "%10.10s %10.10s", 116 "Name", "Mtu", "Network", "Address", 117 "Ibytes", "Obytes"); 118 } else { 119 printf("%-5.5s %-5.5s %-13.13s %-17.17s " 120 "%8.8s %5.5s %8.8s %5.5s", 121 "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs", 122 "Opkts", "Oerrs"); 123 printf(" %5s", "Coll"); 124 } 125 if (tflag) 126 printf(" %s", "Time"); 127 if (dflag) 128 printf(" %s", "Drop"); 129 putchar('\n'); 130 ifaddraddr = 0; 131 while (ifnetaddr || ifaddraddr) { 132 struct sockaddr_in *sin; 133 char *cp; 134 int n, m; 135 136 if (ifaddraddr == 0) { 137 if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet)) 138 return; 139 memmove(name, ifnet.if_xname, IFNAMSIZ); 140 name[IFNAMSIZ - 1] = '\0'; /* sanity */ 141 ifnetaddr = (u_long)ifnet.if_list.tqe_next; 142 if (interface != 0 && strcmp(name, interface) != 0) 143 continue; 144 cp = strchr(name, '\0'); 145 if ((ifnet.if_flags & IFF_UP) == 0) 146 *cp++ = '*'; 147 *cp = '\0'; 148 ifaddraddr = (u_long)ifnet.if_addrlist.tqh_first; 149 } 150 printf("%-5.5s %-5ld ", name, ifnet.if_mtu); 151 if (ifaddraddr == 0) { 152 printf("%-13.13s ", "none"); 153 printf("%-17.17s ", "none"); 154 } else { 155 char hexsep = '.'; /* for hexprint */ 156 const char *hexfmt = "%x%c"; /* for hexprint */ 157 if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) { 158 ifaddraddr = 0; 159 continue; 160 } 161 #define CP(x) ((char *)(x)) 162 cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) + 163 CP(&ifaddr); sa = (struct sockaddr *)cp; 164 switch (sa->sa_family) { 165 case AF_UNSPEC: 166 printf("%-13.13s ", "none"); 167 printf("%-17.17s ", "none"); 168 break; 169 case AF_INET: 170 sin = (struct sockaddr_in *)sa; 171 #ifdef notdef 172 /* can't use inet_makeaddr because kernel 173 * keeps nets unshifted. 174 */ 175 in = inet_makeaddr(ifaddr.in.ia_subnet, 176 INADDR_ANY); 177 printf("%-13.13s ", netname(in.s_addr, 178 ifaddr.in.ia_subnetmask)); 179 #else 180 printf("%-13.13s ", 181 netname(ifaddr.in.ia_subnet, 182 ifaddr.in.ia_subnetmask)); 183 #endif 184 printf("%-17.17s ", 185 routename(sin->sin_addr.s_addr)); 186 187 if (aflag) { 188 u_long multiaddr; 189 struct in_multi inm; 190 191 multiaddr = (u_long)ifaddr.in.ia_multiaddrs.lh_first; 192 while (multiaddr != 0) { 193 kread(multiaddr, (char *)&inm, 194 sizeof inm); 195 printf("\n%25s %-17.17s ", "", 196 routename(inm.inm_addr.s_addr)); 197 multiaddr = (u_long)inm.inm_list.le_next; 198 } 199 } 200 break; 201 case AF_APPLETALK: 202 printf("atalk:%-7.7s ", 203 atalk_print(sa,0x10)); 204 printf("%-17.17s ", atalk_print(sa,0x0b)); 205 break; 206 case AF_NS: 207 { 208 struct sockaddr_ns *sns = 209 (struct sockaddr_ns *)sa; 210 u_long net; 211 char netnum[8]; 212 213 *(union ns_net *) &net = sns->sns_addr.x_net; 214 sprintf(netnum, "%xH", (u_int32_t) ntohl(net)); 215 upHex(netnum); 216 printf("ns:%-10s ", netnum); 217 printf("%-17.17s ", 218 ns_phost((struct sockaddr *)sns)); 219 } 220 break; 221 case AF_LINK: 222 { 223 struct sockaddr_dl *sdl = 224 (struct sockaddr_dl *)sa; 225 cp = (char *)LLADDR(sdl); 226 if (sdl->sdl_type == IFT_FDDI 227 || sdl->sdl_type == IFT_ETHER) 228 hexsep = ':', hexfmt = "%02x%c"; 229 n = sdl->sdl_alen; 230 } 231 m = printf("%-13.13s ", "<Link>"); 232 goto hexprint; 233 default: 234 m = printf("(%d)", sa->sa_family); 235 for (cp = sa->sa_len + (char *)sa; 236 --cp > sa->sa_data && (*cp == 0);) {} 237 n = cp - sa->sa_data + 1; 238 cp = sa->sa_data; 239 hexprint: 240 while (--n >= 0) 241 m += printf(hexfmt, *cp++ & 0xff, 242 n > 0 ? hexsep : ' '); 243 m = 32 - m; 244 while (m-- > 0) 245 putchar(' '); 246 break; 247 } 248 ifaddraddr = (u_long)ifaddr.ifa.ifa_list.tqe_next; 249 } 250 if (bflag) { 251 printf("%10ld %10ld", 252 ifnet.if_ibytes, ifnet.if_obytes); 253 } else { 254 printf("%8ld %5ld %8ld %5ld %5ld", 255 ifnet.if_ipackets, ifnet.if_ierrors, 256 ifnet.if_opackets, ifnet.if_oerrors, 257 ifnet.if_collisions); 258 } 259 if (tflag) 260 printf(" %3d", ifnet.if_timer); 261 if (dflag) 262 printf(" %3d", ifnet.if_snd.ifq_drops); 263 putchar('\n'); 264 } 265 } 266 267 #define MAXIF 100 268 struct iftot { 269 char ift_name[IFNAMSIZ]; /* interface name */ 270 int ift_ip; /* input packets */ 271 int ift_ib; /* input bytes */ 272 int ift_ie; /* input errors */ 273 int ift_op; /* output packets */ 274 int ift_ob; /* output bytes */ 275 int ift_oe; /* output errors */ 276 int ift_co; /* collisions */ 277 int ift_dr; /* drops */ 278 } iftot[MAXIF]; 279 280 u_char signalled; /* set if alarm goes off "early" */ 281 282 /* 283 * Print a running summary of interface statistics. 284 * Repeat display every interval seconds, showing statistics 285 * collected over that interval. Assumes that interval is non-zero. 286 * First line printed at top of screen is always cumulative. 287 */ 288 static void 289 sidewaysintpr(interval, off) 290 unsigned interval; 291 u_long off; 292 { 293 struct ifnet ifnet; 294 u_long firstifnet; 295 struct iftot *ip, *total; 296 int line; 297 struct iftot *lastif, *sum, *interesting; 298 struct ifnet_head ifhead; /* TAILQ_HEAD */ 299 int oldmask; 300 301 /* 302 * Find the pointer to the first ifnet structure. Replace 303 * the pointer to the TAILQ_HEAD with the actual pointer 304 * to the first list element. 305 */ 306 if (kread(off, (char *)&ifhead, sizeof ifhead)) 307 return; 308 firstifnet = (u_long)ifhead.tqh_first; 309 310 lastif = iftot; 311 sum = iftot + MAXIF - 1; 312 total = sum - 1; 313 interesting = (interface == NULL) ? iftot : NULL; 314 for (off = firstifnet, ip = iftot; off;) { 315 if (kread(off, (char *)&ifnet, sizeof ifnet)) 316 break; 317 memset(ip->ift_name, 0, sizeof(ip->ift_name)); 318 snprintf(ip->ift_name, IFNAMSIZ, "(%s)", ifnet.if_xname); 319 if (interface && strcmp(ifnet.if_xname, interface) == 0) 320 interesting = ip; 321 ip++; 322 if (ip >= iftot + MAXIF - 2) 323 break; 324 off = (u_long)ifnet.if_list.tqe_next; 325 } 326 if (interesting == NULL) { 327 fprintf(stderr, "%s: %s: unknown interface\n", 328 __progname, interface); 329 exit(1); 330 } 331 lastif = ip; 332 333 (void)signal(SIGALRM, catchalarm); 334 signalled = NO; 335 (void)alarm(interval); 336 banner: 337 printf(" input %-6.6s output ", interesting->ift_name); 338 if (lastif - iftot > 0) { 339 if (dflag) 340 printf(" "); 341 printf(" input (Total) output"); 342 } 343 for (ip = iftot; ip < iftot + MAXIF; ip++) { 344 ip->ift_ip = 0; 345 ip->ift_ib = 0; 346 ip->ift_ie = 0; 347 ip->ift_op = 0; 348 ip->ift_ob = 0; 349 ip->ift_oe = 0; 350 ip->ift_co = 0; 351 ip->ift_dr = 0; 352 } 353 putchar('\n'); 354 if (bflag) { 355 printf("%10.10s %8.8s %10.10s %5.5s", 356 "bytes", " ", "bytes", " "); 357 } else { 358 printf("%8.8s %5.5s %8.8s %5.5s %5.5s ", 359 "packets", "errs", "packets", "errs", "colls"); 360 } 361 if (dflag) 362 printf("%5.5s ", "drops"); 363 if (lastif - iftot > 0) 364 if (bflag) { 365 printf("%10.10s %8.8s %10.10s %5.5s", 366 "bytes", " ", "bytes", " "); 367 } else { 368 printf("%8.8s %5.5s %8.8s %5.5s %5.5s ", 369 "packets", "errs", "packets", "errs", "colls"); 370 } 371 if (dflag) 372 printf(" %5.5s", "drops"); 373 putchar('\n'); 374 fflush(stdout); 375 line = 0; 376 loop: 377 sum->ift_ip = 0; 378 sum->ift_ib = 0; 379 sum->ift_ie = 0; 380 sum->ift_op = 0; 381 sum->ift_ob = 0; 382 sum->ift_oe = 0; 383 sum->ift_co = 0; 384 sum->ift_dr = 0; 385 for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) { 386 if (kread(off, (char *)&ifnet, sizeof ifnet)) { 387 off = 0; 388 continue; 389 } 390 if (ip == interesting) { 391 if (bflag) { 392 printf("%10ld %8.8s %10ld %5.5s", 393 ifnet.if_ibytes - ip->ift_ib, " ", 394 ifnet.if_obytes - ip->ift_ob, " "); 395 } else { 396 printf("%8ld %5ld %8ld %5ld %5ld", 397 ifnet.if_ipackets - ip->ift_ip, 398 ifnet.if_ierrors - ip->ift_ie, 399 ifnet.if_opackets - ip->ift_op, 400 ifnet.if_oerrors - ip->ift_oe, 401 ifnet.if_collisions - ip->ift_co); 402 } 403 if (dflag) 404 printf(" %5d", 405 ifnet.if_snd.ifq_drops - ip->ift_dr); 406 } 407 ip->ift_ip = ifnet.if_ipackets; 408 ip->ift_ib = ifnet.if_ibytes; 409 ip->ift_ie = ifnet.if_ierrors; 410 ip->ift_op = ifnet.if_opackets; 411 ip->ift_ob = ifnet.if_obytes; 412 ip->ift_oe = ifnet.if_oerrors; 413 ip->ift_co = ifnet.if_collisions; 414 ip->ift_dr = ifnet.if_snd.ifq_drops; 415 sum->ift_ip += ip->ift_ip; 416 sum->ift_ib += ip->ift_ib; 417 sum->ift_ie += ip->ift_ie; 418 sum->ift_op += ip->ift_op; 419 sum->ift_ob += ip->ift_ob; 420 sum->ift_oe += ip->ift_oe; 421 sum->ift_co += ip->ift_co; 422 sum->ift_dr += ip->ift_dr; 423 off = (u_long)ifnet.if_list.tqe_next; 424 } 425 if (lastif - iftot > 0) { 426 if (bflag) { 427 printf(" %10d %8.8s %10d %5.5s", 428 sum->ift_ib - total->ift_ib, " ", 429 sum->ift_ob - total->ift_ob, " "); 430 } else { 431 printf(" %8d %5d %8d %5d %5d", 432 sum->ift_ip - total->ift_ip, 433 sum->ift_ie - total->ift_ie, 434 sum->ift_op - total->ift_op, 435 sum->ift_oe - total->ift_oe, 436 sum->ift_co - total->ift_co); 437 } 438 if (dflag) 439 printf(" %5d", sum->ift_dr - total->ift_dr); 440 } 441 *total = *sum; 442 putchar('\n'); 443 fflush(stdout); 444 line++; 445 oldmask = sigblock(sigmask(SIGALRM)); 446 if (! signalled) { 447 sigpause(0); 448 } 449 sigsetmask(oldmask); 450 signalled = NO; 451 (void)alarm(interval); 452 if (line == 21) 453 goto banner; 454 goto loop; 455 /*NOTREACHED*/ 456 } 457 458 /* 459 * Called if an interval expires before sidewaysintpr has completed a loop. 460 * Sets a flag to not wait for the alarm. 461 */ 462 static void 463 catchalarm(signo) 464 int signo; 465 { 466 signalled = YES; 467 } 468