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