b8d3700e197d9818629ce5c3f7c6707d08df4dd8
[dragonfly.git] / usr.bin / netstat / if.c
1 /*
2  * Copyright (c) 1983, 1988, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#)if.c     8.3 (Berkeley) 4/28/95
34  * $FreeBSD: src/usr.bin/netstat/if.c,v 1.32.2.9 2001/09/17 14:35:46 ru Exp $
35  * $DragonFly: src/usr.bin/netstat/if.c,v 1.11 2006/08/03 16:40:48 swildner Exp $
36  */
37
38 #include <sys/param.h>
39 #include <sys/protosw.h>
40 #include <sys/socket.h>
41 #include <sys/sysctl.h>
42 #include <sys/time.h>
43
44 #include <net/if.h>
45 #include <net/if_var.h>
46 #include <net/if_dl.h>
47 #include <net/if_types.h>
48 #include <net/ethernet.h>
49 #include <netinet/in.h>
50 #include <netinet/in_var.h>
51 #include <netproto/ipx/ipx.h>
52 #include <netproto/ipx/ipx_if.h>
53 #ifdef NS
54 #include <netproto/ns/ns.h>
55 #include <netproto/ns/ns_if.h>
56 #endif
57 #ifdef ISO
58 #include <netiso/iso.h>
59 #include <netiso/iso_var.h>
60 #endif
61 #include <arpa/inet.h>
62
63 #include <signal.h>
64 #include <stdio.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <unistd.h>
68
69 #include "netstat.h"
70
71 #define YES     1
72 #define NO      0
73
74 static void sidewaysintpr (u_int, u_long);
75 static void catchalarm (int);
76
77 #ifdef INET6
78 char *netname6 (struct sockaddr_in6 *, struct in6_addr *);
79 static char ntop_buf[INET6_ADDRSTRLEN];         /* for inet_ntop() */
80 #endif
81
82
83 /*
84  * Display a formatted value, or a '-' in the same space.
85  */
86 static void
87 show_stat(const char *fmt, int width, u_long value, short showvalue)
88 {
89         char newfmt[32];
90
91         /* Construct the format string */
92         if (showvalue) {
93                 sprintf(newfmt, "%%%d%s", width, fmt);
94                 printf(newfmt, value);
95         } else {
96                 sprintf(newfmt, "%%%ds", width);
97                 printf(newfmt, "-");
98         }
99 }
100
101
102
103 /*
104  * Print a description of the network interfaces.
105  */
106 void
107 intpr(int interval, u_long ifnetaddr, void (*pfunc)(char *))
108 {
109         struct ifnet ifnet;
110         struct ifnethead ifnethead;
111         union {
112                 struct ifaddr ifa;
113                 struct in_ifaddr in;
114 #ifdef INET6
115                 struct in6_ifaddr in6;
116 #endif
117                 struct ipx_ifaddr ipx;
118 #ifdef NS
119                 struct ns_ifaddr ns;
120 #endif
121 #ifdef ISO
122                 struct iso_ifaddr iso;
123 #endif
124         } ifaddr;
125         u_long ifaddraddr;
126         u_long ifaddrfound;
127         u_long ifnetfound;
128         u_long opackets;
129         u_long ipackets;
130         u_long obytes;
131         u_long ibytes;
132         u_long oerrors;
133         u_long ierrors;
134         u_long collisions;
135         short timer;
136         int drops;
137         struct sockaddr *sa = NULL;
138         char name[IFNAMSIZ];
139         short network_layer;
140         short link_layer;
141
142         if (ifnetaddr == 0) {
143                 printf("ifnet: symbol not defined\n");
144                 return;
145         }
146         if (interval) {
147                 sidewaysintpr((unsigned)interval, ifnetaddr);
148                 return;
149         }
150         if (kread(ifnetaddr, (char *)&ifnethead, sizeof ifnethead))
151                 return;
152         ifnetaddr = (u_long)TAILQ_FIRST(&ifnethead);
153         if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet))
154                 return;
155
156         if (!pfunc) {
157                 printf("%-7.7s %-5.5s %-13.13s %-15.15s %8.8s %5.5s",
158                        "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs");
159                 if (bflag)
160                         printf(" %10.10s","Ibytes");
161                 printf(" %8.8s %5.5s", "Opkts", "Oerrs");
162                 if (bflag)
163                         printf(" %10.10s","Obytes");
164                 printf(" %5s", "Coll");
165                 if (tflag)
166                         printf(" %s", "Time");
167                 if (dflag)
168                         printf(" %s", "Drop");
169                 putchar('\n');
170         }
171         ifaddraddr = 0;
172         while (ifnetaddr || ifaddraddr) {
173                 struct sockaddr_in *sin;
174 #ifdef INET6
175                 struct sockaddr_in6 *sin6;
176 #endif
177                 char *cp;
178                 int n, m;
179
180                 network_layer = 0;
181                 link_layer = 0;
182
183                 if (ifaddraddr == 0) {
184                         ifnetfound = ifnetaddr;
185                         if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet))
186                                 return;
187                         strlcpy(name, ifnet.if_xname, sizeof(name));
188                         ifnetaddr = (u_long)TAILQ_NEXT(&ifnet, if_link);
189                         if (interface != 0 && (strcmp(name, interface) != 0))
190                                 continue;
191                         cp = strchr(name, '\0');
192
193                         if (pfunc) {
194                                 (*pfunc)(name);
195                                 continue;
196                         }
197
198                         if ((ifnet.if_flags&IFF_UP) == 0)
199                                 *cp++ = '*';
200                         *cp = '\0';
201                         ifaddraddr = (u_long)TAILQ_FIRST(&ifnet.if_addrhead);
202                 }
203                 ifaddrfound = ifaddraddr;
204
205                 /*
206                  * Get the interface stats.  These may get
207                  * overriden below on a per-interface basis.
208                  */
209                 opackets = ifnet.if_opackets;
210                 ipackets = ifnet.if_ipackets;
211                 obytes = ifnet.if_obytes;
212                 ibytes = ifnet.if_ibytes;
213                 oerrors = ifnet.if_oerrors;
214                 ierrors = ifnet.if_ierrors;
215                 collisions = ifnet.if_collisions;
216                 timer = ifnet.if_timer;
217                 drops = ifnet.if_snd.ifq_drops;
218
219                 if (ifaddraddr == 0) {
220                         printf("%-7.7s %-5lu ", name, ifnet.if_mtu);
221                         printf("%-13.13s ", "none");
222                         printf("%-15.15s ", "none");
223                 } else {
224                         if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) {
225                                 ifaddraddr = 0;
226                                 continue;
227                         }
228 #define CP(x) ((char *)(x))
229                         cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) +
230                                 CP(&ifaddr);
231                         sa = (struct sockaddr *)cp;
232                         if (af != AF_UNSPEC && sa->sa_family != af) {
233                                 ifaddraddr =
234                                     (u_long)TAILQ_NEXT(&ifaddr.ifa, ifa_link);
235                                 continue;
236                         }
237                         printf("%-7.7s %-5lu ", name, ifnet.if_mtu);
238                         switch (sa->sa_family) {
239                         case AF_UNSPEC:
240                                 printf("%-13.13s ", "none");
241                                 printf("%-15.15s ", "none");
242                                 break;
243                         case AF_INET:
244                                 sin = (struct sockaddr_in *)sa;
245 #ifdef notdef
246                                 /* can't use inet_makeaddr because kernel
247                                  * keeps nets unshifted.
248                                  */
249                                 in = inet_makeaddr(ifaddr.in.ia_subnet,
250                                         INADDR_ANY);
251                                 printf("%-13.13s ", netname(in.s_addr,
252                                     ifaddr.in.ia_subnetmask));
253 #else
254                                 printf("%-13.13s ",
255                                     netname(htonl(ifaddr.in.ia_subnet),
256                                     ifaddr.in.ia_subnetmask));
257 #endif
258                                 printf("%-15.15s ",
259                                     routename(sin->sin_addr.s_addr));
260
261                                 network_layer = 1;
262                                 break;
263 #ifdef INET6
264                         case AF_INET6:
265                                 sin6 = (struct sockaddr_in6 *)sa;
266                                 printf("%-11.11s ",
267                                        netname6(&ifaddr.in6.ia_addr,
268                                                 &ifaddr.in6.ia_prefixmask.sin6_addr));
269                                 printf("%-17.17s ",
270                                     (char *)inet_ntop(AF_INET6,
271                                         &sin6->sin6_addr,
272                                         ntop_buf, sizeof(ntop_buf)));
273
274                                 network_layer = 1;
275                                 break;
276 #endif /*INET6*/
277                         case AF_IPX:
278                                 {
279                                 struct sockaddr_ipx *sipx =
280                                         (struct sockaddr_ipx *)sa;
281                                 u_long net;
282                                 char netnum[10];
283
284                                 *(union ipx_net *) &net = sipx->sipx_addr.x_net;
285                                 sprintf(netnum, "%lx", (u_long)ntohl(net));
286                                 printf("ipx:%-8s  ", netnum);
287 /*                              printf("ipx:%-8s ", netname(net, 0L)); */
288                                 printf("%-15s ",
289                                     ipx_phost((struct sockaddr *)sipx));
290                                 }
291                                 break;
292
293                         case AF_APPLETALK:
294                                 printf("atalk:%-12.12s ",atalk_print(sa,0x10) );
295                                 printf("%-9.9s  ",atalk_print(sa,0x0b) );
296                                 break;
297 #ifdef NS
298                         case AF_NS:
299                                 {
300                                 struct sockaddr_ns *sns =
301                                         (struct sockaddr_ns *)sa;
302                                 u_long net;
303                                 char netnum[10];
304
305                                 *(union ns_net *) &net = sns->sns_addr.x_net;
306                                 sprintf(netnum, "%lxH", ntohl(net));
307                                 upHex(netnum);
308                                 printf("ns:%-8s ", netnum);
309                                 printf("%-15s ",
310                                     ns_phost((struct sockaddr *)sns));
311                                 }
312                                 break;
313 #endif
314                         case AF_LINK:
315                                 {
316                                 struct sockaddr_dl *sdl =
317                                         (struct sockaddr_dl *)sa;
318                                 char linknum[10];
319                                 cp = (char *)LLADDR(sdl);
320                                 n = sdl->sdl_alen;
321                                 sprintf(linknum, "<Link#%d>", sdl->sdl_index);
322                                 m = printf("%-11.11s ", linknum);
323                                 }
324                                 goto hexprint;
325                         default:
326                                 m = printf("(%d)", sa->sa_family);
327                                 for (cp = sa->sa_len + (char *)sa;
328                                         --cp > sa->sa_data && (*cp == 0);) {}
329                                 n = cp - sa->sa_data + 1;
330                                 cp = sa->sa_data;
331                         hexprint:
332                                 while (--n >= 0)
333                                         m += printf("%02x%c", *cp++ & 0xff,
334                                                     n > 0 ? ':' : ' ');
335                                 m = 30 - m;
336                                 while (m-- > 0)
337                                         putchar(' ');
338
339                                 link_layer = 1;
340                                 break;
341                         }
342
343                         /*
344                          * Fixup the statistics for interfaces that
345                          * update stats for their network addresses
346                          */
347                         if (network_layer) {
348                                 opackets = ifaddr.in.ia_ifa.if_opackets;
349                                 ipackets = ifaddr.in.ia_ifa.if_ipackets;
350                                 obytes = ifaddr.in.ia_ifa.if_obytes;
351                                 ibytes = ifaddr.in.ia_ifa.if_ibytes;
352                         }
353
354                         ifaddraddr = (u_long)TAILQ_NEXT(&ifaddr.ifa, ifa_link);
355                 }
356
357                 show_stat("lu", 8, ipackets, link_layer|network_layer);
358                 printf(" ");
359                 show_stat("lu", 5, ierrors, link_layer);
360                 printf(" ");
361                 if (bflag) {
362                         show_stat("lu", 10, ibytes, link_layer|network_layer);
363                         printf(" ");
364                 }
365                 show_stat("lu", 8, opackets, link_layer|network_layer);
366                 printf(" ");
367                 show_stat("lu", 5, oerrors, link_layer);
368                 printf(" ");
369                 if (bflag) {
370                         show_stat("lu", 10, obytes, link_layer|network_layer);
371                         printf(" ");
372                 }
373                 show_stat("lu", 5, collisions, link_layer);
374                 if (tflag) {
375                         printf(" ");
376                         show_stat("d", 3, timer, link_layer);
377                 }
378                 if (dflag) {
379                         printf(" ");
380                         show_stat("d", 3, drops, link_layer);
381                 }
382                 putchar('\n');
383                 if (aflag && ifaddrfound) {
384                         /*
385                          * Print family's multicast addresses
386                          */
387                         u_long multiaddr;
388                         struct ifmultiaddr ifma;
389                         union {
390                                 struct sockaddr sa;
391                                 struct sockaddr_in in;
392 #ifdef INET6
393                                 struct sockaddr_in6 in6;
394 #endif /* INET6 */
395                                 struct sockaddr_dl dl;
396                         } msa;
397                         const char *fmt;
398
399                         for(multiaddr = (u_long)ifnet.if_multiaddrs.lh_first;
400                             multiaddr;
401                             multiaddr = (u_long)ifma.ifma_link.le_next) {
402                                 if (kread(multiaddr, (char *)&ifma,
403                                           sizeof ifma))
404                                         break;
405                                 if (kread((u_long)ifma.ifma_addr, (char *)&msa,
406                                           sizeof msa))
407                                         break;
408                                 if (msa.sa.sa_family != sa->sa_family)
409                                         continue;
410                                 
411                                 fmt = 0;
412                                 switch (msa.sa.sa_family) {
413                                 case AF_INET:
414                                         fmt = routename(msa.in.sin_addr.s_addr);
415                                         break;
416 #ifdef INET6
417                                 case AF_INET6:
418                                         printf("%23s %-19.19s(refs: %d)\n", "",
419                                                inet_ntop(AF_INET6,
420                                                          &msa.in6.sin6_addr,
421                                                          ntop_buf,
422                                                          sizeof(ntop_buf)),
423                                                ifma.ifma_refcount);
424                                         break;
425 #endif /* INET6 */
426                                 case AF_LINK:
427                                         switch (msa.dl.sdl_type) {
428                                         case IFT_ETHER:
429                                         case IFT_FDDI:
430                                                 fmt = ether_ntoa(
431                                                         (struct ether_addr *)
432                                                         LLADDR(&msa.dl));
433                                                 break;
434                                         }
435                                         break;
436                                 }
437                                 if (fmt)
438                                         printf("%23s %s\n", "", fmt);
439                         }
440                 }
441         }
442 }
443
444 struct  iftot {
445         SLIST_ENTRY(iftot) chain;
446         char    ift_name[IFNAMSIZ];     /* interface name */
447         u_long  ift_ip;                 /* input packets */
448         u_long  ift_ie;                 /* input errors */
449         u_long  ift_op;                 /* output packets */
450         u_long  ift_oe;                 /* output errors */
451         u_long  ift_co;                 /* collisions */
452         u_int   ift_dr;                 /* drops */
453         u_long  ift_ib;                 /* input bytes */
454         u_long  ift_ob;                 /* output bytes */
455 };
456
457 u_char  signalled;                      /* set if alarm goes off "early" */
458
459 /*
460  * Print a running summary of interface statistics.
461  * Repeat display every interval seconds, showing statistics
462  * collected over that interval.  Assumes that interval is non-zero.
463  * First line printed at top of screen is always cumulative.
464  * XXX - should be rewritten to use ifmib(4).
465  */
466 static void
467 sidewaysintpr(unsigned interval, u_long off)
468 {
469         struct ifnet ifnet;
470         u_long firstifnet;
471         struct ifnethead ifnethead;
472         struct iftot *iftot, *ip, *ipn, *total, *sum, *interesting;
473         int line;
474         int oldmask, first;
475         u_long interesting_off;
476
477         if (kread(off, (char *)&ifnethead, sizeof ifnethead))
478                 return;
479         firstifnet = (u_long)TAILQ_FIRST(&ifnethead);
480
481         if ((iftot = malloc(sizeof(struct iftot))) == NULL) {
482                 printf("malloc failed\n");
483                 exit(1);
484         }
485         memset(iftot, 0, sizeof(struct iftot));
486
487         interesting = NULL;
488         interesting_off = 0;
489         for (off = firstifnet, ip = iftot; off;) {
490                 char name[IFNAMSIZ];
491
492                 if (kread(off, (char *)&ifnet, sizeof ifnet))
493                         break;
494                 strlcpy(name, ifnet.if_xname, sizeof(name));
495                 if (interface && strcmp(name, interface) == 0) {
496                         interesting = ip;
497                         interesting_off = off;
498                 }
499                 snprintf(ip->ift_name, 16, "(%s)", name);
500                 if ((ipn = malloc(sizeof(struct iftot))) == NULL) {
501                         printf("malloc failed\n");
502                         exit(1);
503                 }
504                 memset(ipn, 0, sizeof(struct iftot));
505                 SLIST_NEXT(ip, chain) = ipn;
506                 ip = ipn;
507                 off = (u_long)TAILQ_NEXT(&ifnet, if_link);
508         }
509         if ((total = malloc(sizeof(struct iftot))) == NULL) {
510                 printf("malloc failed\n");
511                 exit(1);
512         }
513         memset(total, 0, sizeof(struct iftot));
514         if ((sum = malloc(sizeof(struct iftot))) == NULL) {
515                 printf("malloc failed\n");
516                 exit(1);
517         }
518         memset(sum, 0, sizeof(struct iftot));
519
520
521         (void)signal(SIGALRM, catchalarm);
522         signalled = NO;
523         (void)alarm(interval);
524         first = 1;
525 banner:
526         printf("%17s %14s %16s", "input",
527             interesting ? interesting->ift_name : "(Total)", "output");
528         putchar('\n');
529         printf("%10s %5s %10s %10s %5s %10s %5s",
530             "packets", "errs", "bytes", "packets", "errs", "bytes", "colls");
531         if (dflag)
532                 printf(" %5.5s", "drops");
533         putchar('\n');
534         fflush(stdout);
535         line = 0;
536 loop:
537         if (interesting != NULL) {
538                 ip = interesting;
539                 if (kread(interesting_off, (char *)&ifnet, sizeof ifnet)) {
540                         printf("???\n");
541                         exit(1);
542                 };
543                 if (!first) {
544                         printf("%10lu %5lu %10lu %10lu %5lu %10lu %5lu",
545                                 ifnet.if_ipackets - ip->ift_ip,
546                                 ifnet.if_ierrors - ip->ift_ie,
547                                 ifnet.if_ibytes - ip->ift_ib,
548                                 ifnet.if_opackets - ip->ift_op,
549                                 ifnet.if_oerrors - ip->ift_oe,
550                                 ifnet.if_obytes - ip->ift_ob,
551                                 ifnet.if_collisions - ip->ift_co);
552                         if (dflag)
553                                 printf(" %5u", ifnet.if_snd.ifq_drops - ip->ift_dr);
554                 }
555                 ip->ift_ip = ifnet.if_ipackets;
556                 ip->ift_ie = ifnet.if_ierrors;
557                 ip->ift_ib = ifnet.if_ibytes;
558                 ip->ift_op = ifnet.if_opackets;
559                 ip->ift_oe = ifnet.if_oerrors;
560                 ip->ift_ob = ifnet.if_obytes;
561                 ip->ift_co = ifnet.if_collisions;
562                 ip->ift_dr = ifnet.if_snd.ifq_drops;
563         } else {
564                 sum->ift_ip = 0;
565                 sum->ift_ie = 0;
566                 sum->ift_ib = 0;
567                 sum->ift_op = 0;
568                 sum->ift_oe = 0;
569                 sum->ift_ob = 0;
570                 sum->ift_co = 0;
571                 sum->ift_dr = 0;
572                 for (off = firstifnet, ip = iftot;
573                      off && SLIST_NEXT(ip, chain) != NULL;
574                      ip = SLIST_NEXT(ip, chain)) {
575                         if (kread(off, (char *)&ifnet, sizeof ifnet)) {
576                                 off = 0;
577                                 continue;
578                         }
579                         sum->ift_ip += ifnet.if_ipackets;
580                         sum->ift_ie += ifnet.if_ierrors;
581                         sum->ift_ib += ifnet.if_ibytes;
582                         sum->ift_op += ifnet.if_opackets;
583                         sum->ift_oe += ifnet.if_oerrors;
584                         sum->ift_ob += ifnet.if_obytes;
585                         sum->ift_co += ifnet.if_collisions;
586                         sum->ift_dr += ifnet.if_snd.ifq_drops;
587                         off = (u_long)TAILQ_NEXT(&ifnet, if_link);
588                 }
589                 if (!first) {
590                         printf("%10lu %5lu %10lu %10lu %5lu %10lu %5lu",
591                                 sum->ift_ip - total->ift_ip,
592                                 sum->ift_ie - total->ift_ie,
593                                 sum->ift_ib - total->ift_ib,
594                                 sum->ift_op - total->ift_op,
595                                 sum->ift_oe - total->ift_oe,
596                                 sum->ift_ob - total->ift_ob,
597                                 sum->ift_co - total->ift_co);
598                         if (dflag)
599                                 printf(" %5u", sum->ift_dr - total->ift_dr);
600                 }
601                 *total = *sum;
602         }
603         if (!first)
604                 putchar('\n');
605         fflush(stdout);
606         oldmask = sigblock(sigmask(SIGALRM));
607         if (! signalled) {
608                 sigpause(0);
609         }
610         sigsetmask(oldmask);
611         signalled = NO;
612         (void)alarm(interval);
613         line++;
614         first = 0;
615         if (line == 21)
616                 goto banner;
617         else
618                 goto loop;
619         /*NOTREACHED*/
620 }
621
622 /*
623  * Called if an interval expires before sidewaysintpr has completed a loop.
624  * Sets a flag to not wait for the alarm.
625  */
626 static void
627 catchalarm(int signo __unused)
628 {
629         signalled = YES;
630 }