Initial import from FreeBSD RELENG_4:
[dragonfly.git] / release / picobsd / tinyware / ns / ns.c
1 /*-
2  * Copyright (c) 1998 Andrzej Bialecki
3  * 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  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD: src/release/picobsd/tinyware/ns/ns.c,v 1.8.2.7 2002/03/27 20:42:03 abial Exp $
27  */
28
29
30 /*
31  * Small replacement for netstat. Uses only sysctl(3) to get the info.
32  */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <sys/time.h>
37 #include <sys/param.h>
38 #include <sys/mbuf.h>
39 #include <sys/sysctl.h>
40 #include <sys/socket.h>
41 #include <sys/un.h>
42
43 #include <net/if.h>
44 #include <net/route.h>
45 #include <net/if_dl.h>
46 #include <netinet/in_systm.h>
47 #include <netinet/in.h>
48 #include <netinet/ip.h>
49 #include <netinet/ip_icmp.h>
50 #include <netinet/icmp_var.h>
51 #include <netinet/ip_var.h>
52 #include <netinet/tcp.h>
53 #include <netinet/tcp_timer.h>
54 #include <netinet/tcp_var.h>
55 #include <netinet/udp.h>
56 #include <netinet/udp_var.h>
57
58 #ifdef BRIDGING
59 #include <net/if_types.h>       /* IFT_ETHER */
60 #include <net/ethernet.h>
61 #include <net/bridge.h>
62 #endif
63
64 #include <err.h>
65 #include <errno.h>
66 #include <osreldate.h>
67 #include <stdio.h>
68 #include <unistd.h>
69
70 char *progname;
71 int iflag = 0;
72 int lflag = 0;                  /* print cpu load info */
73 int rflag = 0;
74 int sflag = 0;
75 int pflag = 0;
76 int mflag = 0;                  /* print mbuf stats */
77 int wflag = 0;                  /* repeat every wait seconds */
78 int delta = 0 ;
79
80 extern char *optarg;
81 extern int optind;
82
83 void
84 usage()
85 {
86         fprintf(stderr, "\n%s [-nmrsil] [-p proto] [-w wait]\n", progname);
87 #ifdef BRIDGING
88         fprintf(stderr, "  proto: {ip|tcp|udp|icmp|bdg}\n\n");
89 #else
90         fprintf(stderr, "  proto: {ip|tcp|udp|icmp}\n\n");
91 #endif
92 }
93
94
95 /*
96  * The following parts related to retrieving the routing table and
97  * interface information, were borrowed from R. Stevens' code examples
98  * accompanying his excellent book. Thanks!
99  */
100 char *
101 sock_ntop(const struct sockaddr *sa, size_t salen)
102 {
103         char    portstr[7];
104         static  char str[128];  /* Unix domain is largest */
105
106         switch (sa->sa_family) {
107         case 255: {
108                 int     i = 0;
109                 u_long  mask;
110                 u_int   index = 1 << 31;
111                 u_short new_mask = 0;
112
113                 mask = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
114
115                 while (mask & index) {
116                         new_mask++;
117                         index >>= 1;
118                 }
119                 sprintf(str, "/%hu", new_mask);
120                 return (str);
121         }
122         case AF_UNSPEC:
123         case AF_INET: {
124                 struct  sockaddr_in *sin = (struct sockaddr_in *)sa;
125
126                 if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str))
127                     == NULL)
128                         return (NULL);
129                 if (ntohs(sin->sin_port) != 0) {
130                         snprintf(portstr, sizeof(portstr), ".%d",
131                             ntohs(sin->sin_port));
132                         strcat(str, portstr);
133                 }
134                 if (strcmp(str, "0.0.0.0") == 0)
135                         sprintf(str, "default");
136                 return (str);
137         }
138
139         case AF_UNIX: {
140                 struct  sockaddr_un *unp = (struct sockaddr_un *)sa;
141
142                 /*
143                  * OK to have no pathname bound to the socket:
144                  * happens on every connect() unless client calls
145                  * bind() first.
146                  */
147                 if (unp->sun_path[0] == 0)
148                         strcpy(str, "(no pathname bound)");
149                 else
150                         snprintf(str, sizeof(str), "%s", unp->sun_path);
151                 return (str);
152         }
153
154         case AF_LINK: {
155                 struct  sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
156
157                 if (sdl->sdl_nlen > 0) {
158                         bcopy(&sdl->sdl_data[0], str, sdl->sdl_nlen);
159                         str[sdl->sdl_nlen] = '\0';
160                 } else
161                         snprintf(str, sizeof(str), "link#%d", sdl->sdl_index);
162                 return (str);
163         }
164
165         default:
166                 snprintf(str, sizeof(str),
167                     "sock_ntop: unknown AF_xxx: %d, len %d", sa->sa_family,
168                     salen);
169                 return (str);
170         }
171         return (NULL);
172 }
173
174 char *
175 Sock_ntop(const struct sockaddr *sa, size_t salen)
176 {
177         char    *ptr;
178
179         if ((ptr = sock_ntop(sa, salen)) == NULL)
180                 err(1, "sock_ntop error");      /* inet_ntop() sets errno */
181         return (ptr);
182 }
183
184
185 #define ROUNDUP(a,size) (((a) & ((size)-1))?(1+((a)|((size)-1))):(a))
186
187 #define NEXT_SA(ap)                                                     \
188         ap=(struct sockaddr *)                                          \
189             ((caddr_t)ap+(ap->sa_len?ROUNDUP(ap->sa_len,sizeof(u_long)):\
190             sizeof(u_long)))
191
192 void
193 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
194 {
195         int     i;
196
197         for (i = 0; i < RTAX_MAX; i++) {
198                 if (addrs & (1 << i)) {
199                         rti_info[i] = sa;
200                         NEXT_SA(sa);
201                 } else
202                         rti_info[i] = NULL;
203         }
204 }
205
206 void
207 get_flags(char *buf, int flags)
208 {
209         if (flags & 0x1)
210                 strcat(buf, "U");
211         if (flags & 0x2)
212                 strcat(buf, "G");
213         if (flags & 0x4)
214                 strcat(buf, "H");
215         if (flags & 0x8)
216                 strcat(buf, "r");
217         if (flags & 0x10)
218                 strcat(buf, "d");
219 #ifdef NEVER
220         if (flags & 0x20)
221                 strcat(buf, "mod,");
222 #endif /*NEVER*/
223         if (flags & 0x100)
224                 strcat(buf, "C");
225         if (flags & 0x400)
226                 strcat(buf, "L");
227         if (flags & 0x800)
228                 strcat(buf, "S");
229         if (flags & 0x10000)
230                 strcat(buf, "c");
231         if (flags & 0x20000)
232                 strcat(buf, "W");
233 #ifdef NEVER
234         if (flags & 0x200000)
235                 strcat(buf, ",LOC");
236 #endif /*NEVER*/
237         if (flags & 0x400000)
238                 strcat(buf, "b");
239 #ifdef NEVER
240         if (flags & 0x800000)
241                 strcat(buf, ",MCA");
242 #endif /*NEVER*/
243 }
244
245 void
246 print_routing(char *proto)
247 {
248         int     mib[6];
249         int     i = 0;
250         int     rt_len;
251         int     if_len;
252         int     if_num;
253         char    *rt_buf;
254         char    *if_buf;
255         char    *next;
256         char    *lim;
257         struct  rt_msghdr *rtm;
258         struct  if_msghdr *ifm;
259         struct  if_msghdr **ifm_table;
260         struct  ifa_msghdr *ifam;
261         struct  sockaddr *sa;
262         struct  sockaddr *sa1;
263         struct  sockaddr *rti_info[RTAX_MAX];
264         struct  sockaddr **if_table;
265         struct  rt_metrics rm;
266         char    fbuf[50];
267
268         /* keep a copy of statistics here for future use */
269         static unsigned *base_stats = NULL ;
270         static unsigned base_len = 0 ;
271
272         /* Get the routing table */
273         mib[0] = CTL_NET;
274         mib[1] = PF_ROUTE;
275         mib[2] = 0;
276         mib[3] = 0;
277         mib[4] = NET_RT_DUMP;
278         mib[5] = 0;
279
280         /*Estimate the size of table */
281         if (sysctl(mib, 6, NULL, &rt_len, NULL, 0) == -1) {
282                 perror("sysctl size");
283                 exit(-1);
284         }
285         if ((rt_buf = (char *)malloc(rt_len)) == NULL) {
286                 perror("malloc");
287                 exit(-1);
288         }
289
290         /* Now get it. */
291         if (sysctl(mib, 6, rt_buf, &rt_len, NULL, 0) == -1) {
292                 perror("sysctl get");
293                 exit(-1);
294         }
295
296         /* Get the interfaces table */
297         mib[0] = CTL_NET;
298         mib[1] = PF_ROUTE;
299         mib[2] = 0;
300         mib[3] = 0;
301         mib[4] = NET_RT_IFLIST;
302         mib[5] = 0;
303
304         /* Estimate the size of table */
305         if (sysctl(mib, 6, NULL, &if_len, NULL, 0) == -1) {
306                 perror("sysctl size");
307                 exit(-1);
308         }
309         if ((if_buf = (char *)malloc(if_len)) == NULL) {
310                 perror("malloc");
311                 exit(-1);
312         }
313
314         /* Now get it. */
315         if (sysctl(mib, 6, if_buf, &if_len, NULL, 0) == -1) {
316                 perror("sysctl get");
317                 exit(-1);
318         }
319         lim = if_buf + if_len;
320         i = 0;
321         for (next = if_buf, i = 0; next < lim; next += ifm->ifm_msglen) {
322                 ifm = (struct if_msghdr *)next;
323                 i++;
324         }
325         if_num = i;
326         if_table = (struct sockaddr **)calloc(i, sizeof(struct sockaddr));
327         ifm_table = (struct if_msghdr **)calloc(i, sizeof(struct if_msghdr));
328         if (iflag) {
329                 printf("\nInterface table:\n");
330                 printf("----------------\n");
331                 printf("Name  Mtu   Network       Address            "
332                     "Ipkts Ierrs    Opkts Oerrs  Coll\n");
333         }
334         /* scan the list and store base values */
335         i = 0 ;
336         for (next = if_buf; next < lim; next += ifm->ifm_msglen) {
337                 ifm = (struct if_msghdr *)next;
338                 i++ ;
339         }
340         if (base_stats == NULL || i != base_len) {
341                 base_stats = calloc(i*5, sizeof(unsigned));
342                 base_len = i ;
343         }
344         i = 0;
345         for (next = if_buf; next < lim; next += ifm->ifm_msglen) {
346                 ifm = (struct if_msghdr *)next;
347                 if_table[i] = (struct sockaddr *)(ifm + 1);
348                 ifm_table[i] = ifm;
349
350                 sa = if_table[i];
351                 if (iflag && sa->sa_family == AF_LINK) {
352                         struct  sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
353                         unsigned *bp = &base_stats[i*5];
354
355                         printf("%-4s  %-5d <Link>   ",
356                             sock_ntop(if_table[i], if_table[i]->sa_len),
357                             ifm->ifm_data.ifi_mtu);
358                         if (sdl->sdl_alen == 6) {
359                                 unsigned char *p =
360                                     sdl->sdl_data + sdl->sdl_nlen;
361                                 printf("%02x:%02x:%02x:%02x:%02x:%02x   ",
362                                     p[0], p[1], p[2], p[3], p[4], p[5]);
363                         } else
364                                 printf("                    ");
365                         printf("%9d%6d%9d%6d%6d\n",
366                             ifm->ifm_data.ifi_ipackets - bp[0],
367                             ifm->ifm_data.ifi_ierrors - bp[1],
368                             ifm->ifm_data.ifi_opackets - bp[2],
369                             ifm->ifm_data.ifi_oerrors - bp[3],
370                             ifm->ifm_data.ifi_collisions -bp[4]);
371                         if (delta > 0) {
372                             bp[0] = ifm->ifm_data.ifi_ipackets ;
373                             bp[1] = ifm->ifm_data.ifi_ierrors ;
374                             bp[2] = ifm->ifm_data.ifi_opackets ;
375                             bp[3] = ifm->ifm_data.ifi_oerrors ;
376                             bp[4] = ifm->ifm_data.ifi_collisions ;
377                         }
378                 }
379                 i++;
380         }
381         if (!rflag) {
382                 free(rt_buf);
383                 free(if_buf);
384                 free(if_table);
385                 free(ifm_table);
386                 return;
387         }
388
389         /* Now dump the routing table */
390         printf("\nRouting table:\n");
391         printf("--------------\n");
392         printf
393             ("Destination        Gateway            Flags       Netif  Use\n");
394         lim = rt_buf + rt_len;
395         for (next = rt_buf; next < lim; next += rtm->rtm_msglen) {
396                 rtm = (struct rt_msghdr *)next;
397                 sa = (struct sockaddr *)(rtm + 1);
398                 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
399                 if (rtm->rtm_flags & RTF_WASCLONED) {
400                         if ((rtm->rtm_flags & RTF_LLINFO) == 0)
401                                 continue;
402                 }
403                 if ((sa = rti_info[RTAX_DST]) != NULL) {
404                         sprintf(fbuf, "%s", sock_ntop(sa, sa->sa_len));
405                         if (((sa1 = rti_info[RTAX_NETMASK]) != NULL)
406                             && sa1->sa_family == 255) {
407                                 strcat(fbuf, sock_ntop(sa1, sa1->sa_len));
408                         }
409                         printf("%-19s", fbuf);
410                 }
411                 if ((sa = rti_info[RTAX_GATEWAY]) != NULL) {
412                         printf("%-19s", sock_ntop(sa, sa->sa_len));
413                 }
414                 memset(fbuf, 0, sizeof(fbuf));
415                 get_flags(fbuf, rtm->rtm_flags);
416                 printf("%-10s", fbuf);
417                 for (i = 0; i < if_num; i++) {
418                         ifm = ifm_table[i];
419                         if ((ifm->ifm_index == rtm->rtm_index) &&
420                             (ifm->ifm_data.ifi_type > 0)) {
421                                 sa = if_table[i];
422                                 break;
423                         }
424                 }
425                 if (ifm->ifm_type == RTM_IFINFO) {
426                         get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
427                         printf("  %s", Sock_ntop(sa, sa->sa_len));
428                 } else if (ifm->ifm_type == RTM_NEWADDR) {
429                         ifam =
430                             (struct ifa_msghdr *)ifm_table[rtm->rtm_index - 1];
431                         sa = (struct sockaddr *)(ifam + 1);
432                         get_rtaddrs(ifam->ifam_addrs, sa, rti_info);
433                         printf("  %s", Sock_ntop(sa, sa->sa_len));
434                 }
435                 printf("    %u", rtm->rtm_use);
436                 printf("\n");
437         }
438         free(rt_buf);
439         free(if_buf);
440         free(if_table);
441         free(ifm_table);
442         return;
443
444 }
445
446 print_ip_stats()
447 {
448         int     mib[4];
449         int     len;
450         struct  ipstat s;
451
452         mib[0] = CTL_NET;
453         mib[1] = PF_INET;
454         mib[2] = IPPROTO_IP;
455 #ifndef IPCTL_STATS
456         printf("sorry, ip stats not available\n");
457         return -1;
458 #else
459         mib[3] = IPCTL_STATS;
460         len = sizeof(struct ipstat);
461         if (sysctl(mib, 4, &s, &len, NULL, 0) < 0) {
462                 perror("sysctl");
463                 return (-1);
464         }
465         printf("\nIP statistics:\n");
466         printf("--------------\n");
467         printf("  %10lu total packets received\n", s.ips_total);
468         printf("* Packets ok:\n");
469         printf("  %10lu fragments received\n", s.ips_fragments);
470         printf("  %10lu forwarded\n", s.ips_forward);
471 #if __FreeBSD_version > 300001
472         printf("  %10lu fast forwarded\n", s.ips_fastforward);
473 #endif
474         printf("  %10lu forwarded on same net (redirect)\n",
475             s.ips_redirectsent);
476         printf("  %10lu delivered to upper level\n", s.ips_delivered);
477         printf("  %10lu total ip packets generated here\n", s.ips_localout);
478         printf("  %10lu total packets reassembled ok\n", s.ips_reassembled);
479         printf("  %10lu total datagrams successfully fragmented\n",
480             s.ips_fragmented);
481         printf("  %10lu output fragments created\n", s.ips_ofragments);
482         printf("  %10lu total raw IP packets generated\n", s.ips_rawout);
483         printf("\n* Bad packets:\n");
484         printf("  %10lu bad checksum\n", s.ips_badsum);
485         printf("  %10lu too short\n", s.ips_tooshort);
486         printf("  %10lu not enough data (too small)\n", s.ips_toosmall);
487         printf("  %10lu more data than declared in header\n", s.ips_badhlen);
488         printf("  %10lu less data than declared in header\n", s.ips_badlen);
489         printf("  %10lu fragments dropped (dups, no mbuf)\n",
490             s.ips_fragdropped);
491         printf("  %10lu fragments timed out in reassembly\n",
492             s.ips_fragtimeout);
493         printf("  %10lu received for unreachable dest.\n", s.ips_cantforward);
494         printf("  %10lu unknown or unsupported protocol\n", s.ips_noproto);
495         printf("  %10lu lost due to no bufs etc.\n", s.ips_odropped);
496         printf("  %10lu couldn't fragment (DF set, etc.)\n", s.ips_cantfrag);
497         printf("  %10lu error in IP options processing\n", s.ips_badoptions);
498         printf("  %10lu dropped due to no route\n", s.ips_noroute);
499         printf("  %10lu bad IP version\n", s.ips_badvers);
500         printf("  %10lu too long (more than max IP size)\n", s.ips_toolong);
501 #if __FreeBSD_version > 300001
502         printf("  %10lu multicast for unregistered groups\n", s.ips_notmember);
503 #endif
504 #endif
505 }
506
507 print_tcp_stats()
508 {
509         int     mib[4];
510         int     len;
511         struct  tcpstat s;
512
513         mib[0] = CTL_NET;
514         mib[1] = PF_INET;
515         mib[2] = IPPROTO_TCP;
516 #ifndef TCPCTL_STATS
517         printf("sorry, tcp stats not available\n");
518         return -1;
519 #else
520         mib[3] = TCPCTL_STATS;
521         len = sizeof(struct tcpstat);
522         if (sysctl(mib, 4, &s, &len, NULL, 0) < 0) {
523                 perror("sysctl");
524                 return (-1);
525         }
526         printf("\nTCP statistics:\n");
527         printf("---------------\n");
528         printf("* Connections:\n");
529         printf("  %10lu initiated\n", s.tcps_connattempt);
530         printf("  %10lu accepted\n", s.tcps_accepts);
531         printf("  %10lu established\n", s.tcps_connects);
532         printf("  %10lu dropped\n", s.tcps_drops);
533         printf("  %10lu embryonic connections dropped\n", s.tcps_conndrops);
534         printf("  %10lu closed (includes dropped)\n", s.tcps_closed);
535         printf("  %10lu segments where we tried to get RTT\n",
536             s.tcps_segstimed);
537         printf("  %10lu times RTT successfully updated\n", s.tcps_rttupdated);
538         printf("  %10lu delayed ACKs sent\n", s.tcps_delack);
539         printf("  %10lu dropped in rxmt timeout\n", s.tcps_timeoutdrop);
540         printf("  %10lu retrasmit timeouts\n", s.tcps_rexmttimeo);
541         printf("  %10lu persist timeouts\n", s.tcps_persisttimeo);
542         printf("  %10lu keepalive timeouts\n", s.tcps_keeptimeo);
543         printf("  %10lu keepalive probes sent\n", s.tcps_keepprobe);
544         printf("  %10lu dropped in keepalive\n", s.tcps_keepdrops);
545
546         printf("* Packets sent:\n");
547         printf("  %10lu total packets sent\n", s.tcps_sndtotal);
548         printf("  %10lu data packets sent\n", s.tcps_sndpack);
549         printf("  %10lu data bytes sent\n", s.tcps_sndbyte);
550         printf("  %10lu data packets retransmitted\n", s.tcps_sndrexmitpack);
551         printf("  %10lu data bytes retransmitted\n", s.tcps_sndrexmitbyte);
552         printf("  %10lu ACK-only packets sent\n", s.tcps_sndacks);
553         printf("  %10lu window probes sent\n", s.tcps_sndprobe);
554         printf("  %10lu URG-only packets sent\n", s.tcps_sndurg);
555         printf("  %10lu window update-only packets sent\n", s.tcps_sndwinup);
556         printf("  %10lu control (SYN,FIN,RST) packets sent\n", s.tcps_sndctrl);
557         printf("* Packets received:\n");
558         printf("  %10lu total packets received\n", s.tcps_rcvtotal);
559         printf("  %10lu packets in sequence\n", s.tcps_rcvpack);
560         printf("  %10lu bytes in sequence\n", s.tcps_rcvbyte);
561         printf("  %10lu packets with bad checksum\n", s.tcps_rcvbadsum);
562         printf("  %10lu packets with bad offset\n", s.tcps_rcvbadoff);
563         printf("  %10lu packets too short\n", s.tcps_rcvshort);
564         printf("  %10lu duplicate-only packets\n", s.tcps_rcvduppack);
565         printf("  %10lu duplicate-only bytes\n", s.tcps_rcvdupbyte);
566         printf("  %10lu packets with some duplicate data\n",
567             s.tcps_rcvpartduppack);
568         printf("  %10lu duplicate bytes in partially dup. packets\n",
569             s.tcps_rcvpartdupbyte);
570         printf("  %10lu out-of-order packets\n", s.tcps_rcvoopack);
571         printf("  %10lu out-of-order bytes\n", s.tcps_rcvoobyte);
572         printf("  %10lu packets with data after window\n",
573             s.tcps_rcvpackafterwin);
574         printf("  %10lu bytes received after window\n",
575             s.tcps_rcvbyteafterwin);
576         printf("  %10lu packets received after 'close'\n",
577             s.tcps_rcvafterclose);
578         printf("  %10lu window probe packets\n", s.tcps_rcvwinprobe);
579         printf("  %10lu duplicate ACKs\n", s.tcps_rcvdupack);
580         printf("  %10lu ACKs for unsent data\n", s.tcps_rcvacktoomuch);
581         printf("  %10lu ACK packets\n", s.tcps_rcvackpack);
582         printf("  %10lu bytes ACKed by received ACKs\n", s.tcps_rcvackbyte);
583         printf("  %10lu window update packets\n", s.tcps_rcvwinupd);
584         printf("  %10lu segments dropped due to PAWS\n", s.tcps_pawsdrop);
585         printf("  %10lu times header predict ok for ACKs\n", s.tcps_predack);
586         printf("  %10lu times header predict ok for data packets\n",
587             s.tcps_preddat);
588         printf("  %10lu PCB cache misses\n", s.tcps_pcbcachemiss);
589         printf("  %10lu times cached RTT in route updated\n",
590             s.tcps_cachedrtt);
591         printf("  %10lu times cached RTTVAR updated\n", s.tcps_cachedrttvar);
592         printf("  %10lu times ssthresh updated\n", s.tcps_cachedssthresh);
593         printf("  %10lu times RTT initialized from route\n", s.tcps_usedrtt);
594         printf("  %10lu times RTTVAR initialized from route\n",
595             s.tcps_usedrttvar);
596         printf("  %10lu times ssthresh initialized from route\n",
597             s.tcps_usedssthresh);
598         printf("  %10lu timeout in persist state\n", s.tcps_persistdrop);
599         printf("  %10lu bogus SYN, e.g. premature ACK\n", s.tcps_badsyn);
600         printf("  %10lu resends due to MTU discovery\n", s.tcps_mturesent);
601         printf("  %10lu listen queue overflows\n", s.tcps_listendrop);
602 #endif
603 }
604
605 print_udp_stats()
606 {
607         int     mib[4];
608         int     len;
609         struct  udpstat s;
610
611         mib[0] = CTL_NET;
612         mib[1] = PF_INET;
613         mib[2] = IPPROTO_UDP;
614         mib[3] = UDPCTL_STATS;
615         len = sizeof(struct udpstat);
616         if (sysctl(mib, 4, &s, &len, NULL, 0) < 0) {
617                 perror("sysctl");
618                 return (-1);
619         }
620         printf("\nUDP statistics:\n");
621         printf("---------------\n");
622         printf("* Packets received:\n");
623         printf("  %10lu total input packets\n", s.udps_ipackets);
624         printf("  %10lu packets shorter than header (dropped)\n",
625             s.udps_hdrops);
626         printf("  %10lu bad checksum\n", s.udps_badsum);
627         printf("  %10lu data length larger than packet\n", s.udps_badlen);
628         printf("  %10lu no socket on specified port\n", s.udps_noport);
629         printf("  %10lu of above, arrived as broadcast\n", s.udps_noportbcast);
630         printf("  %10lu not delivered, input socket full\n", s.udps_fullsock);
631         printf("  %10lu packets missing PCB cache\n", s.udpps_pcbcachemiss);
632         printf("  %10lu packets not for hashed PCBs\n", s.udpps_pcbhashmiss);
633         printf("* Packets sent:\n");
634         printf("  %10lu total output packets\n", s.udps_opackets);
635 #if __FreeBSD_version > 300001
636         printf("  %10lu output packets on fast path\n", s.udps_fastout);
637 #endif
638 }
639
640 char *icmp_names[] = {
641         "echo reply",
642         "#1",
643         "#2",
644         "destination unreachable",
645         "source quench",
646         "routing redirect",
647         "#6",
648         "#7",
649         "echo",
650         "router advertisement",
651         "router solicitation",
652         "time exceeded",
653         "parameter problem",
654         "time stamp",
655         "time stamp reply",
656         "information request",
657         "information request reply",
658         "address mask request",
659         "address mask reply",
660 };
661
662 print_icmp_stats()
663 {
664         int     mib[4];
665         int     len;
666         int     i;
667         struct  icmpstat s;
668
669         mib[0] = CTL_NET;
670         mib[1] = PF_INET;
671         mib[2] = IPPROTO_ICMP;
672         mib[3] = ICMPCTL_STATS;
673         len = sizeof(struct icmpstat);
674         if (sysctl(mib, 4, &s, &len, NULL, 0) < 0) {
675                 perror("sysctl");
676                 return (-1);
677         }
678         printf("\nICMP statistics:\n");
679         printf("----------------\n");
680         printf("* Output histogram:\n");
681         for (i = 0; i < (ICMP_MAXTYPE + 1); i++) {
682                 if (s.icps_outhist[i] > 0)
683                         printf("\t%10lu %s\n",
684                             s.icps_outhist[i], icmp_names[i]);
685         }
686         printf("* Input histogram:\n");
687         for (i = 0; i < (ICMP_MAXTYPE + 1); i++) {
688                 if (s.icps_inhist[i] > 0)
689                         printf("\t%10lu %s\n",
690                             s.icps_inhist[i], icmp_names[i]);
691         }
692         printf("* Other stats:\n");
693         printf("  %10lu calls to icmp_error\n", s.icps_error);
694         printf("  %10lu no error 'cuz old ip too short\n", s.icps_oldshort);
695         printf("  %10lu no error 'cuz old was icmp\n", s.icps_oldicmp);
696
697         printf("  %10lu icmp code out of range\n", s.icps_badcode);
698         printf("  %10lu packets shorter than min length\n", s.icps_tooshort);
699         printf("  %10lu bad checksum\n", s.icps_checksum);
700         printf("  %10lu calculated bound mismatch\n", s.icps_badlen);
701         printf("  %10lu number of responses\n", s.icps_reflect);
702         printf("  %10lu broad/multi-cast echo requests dropped\n",
703             s.icps_bmcastecho);
704         printf("  %10lu broad/multi-cast timestamp requests dropped\n",
705             s.icps_bmcasttstamp);
706 }
707
708 static struct mbtypenames {
709         int     mt_type;
710         char    *mt_name;
711 } mbtypenames[] = {
712         { MT_DATA,      "data" },
713         { MT_OOBDATA,   "oob data" },
714         { MT_CONTROL,   "ancillary data" },
715         { MT_HEADER,    "packet headers" },
716 #ifdef MT_SOCKET
717         { MT_SOCKET,    "socket structures" },                  /* XXX */
718 #endif
719 #ifdef MT_PCB
720         { MT_PCB,       "protocol control blocks" },            /* XXX */
721 #endif
722 #ifdef MT_RTABLE
723         { MT_RTABLE,    "routing table entries" },              /* XXX */
724 #endif
725 #ifdef MT_HTABLE
726         { MT_HTABLE,    "IMP host table entries" },             /* XXX */
727 #endif
728 #ifdef MT_ATABLE
729         { MT_ATABLE,    "address resolution tables" },
730 #endif
731         { MT_FTABLE,    "fragment reassembly queue headers" },  /* XXX */
732         { MT_SONAME,    "socket names and addresses" },
733 #ifdef MT_SOOPTS
734         { MT_SOOPTS,    "socket options" },
735 #endif
736 #ifdef MT_RIGHTS
737         { MT_RIGHTS,    "access rights" },
738 #endif
739 #ifdef MT_IFADDR
740         { MT_IFADDR,    "interface addresses" },                /* XXX */
741 #endif
742         { 0, 0 }
743 };
744
745 void
746 print_mbuf_stats()
747 {
748         u_long totmem, totpossible, totmbufs;
749         register int i;
750         struct mbstat mbstat;
751         struct mbtypenames *mp;
752         int name[3], nmbclusters, nmbufs, nmbtypes;
753         size_t nmbclen, nmbuflen, mbstatlen, mbtypeslen;
754         u_long *mbtypes;
755         int *seen;     /* "have we seen this type yet?" */
756          
757         if (mflag == 0)
758                 return ;
759
760         mbtypes = NULL;
761         seen = NULL;
762
763         if (sysctlbyname("kern.ipc.mbtypes", NULL, &mbtypeslen, NULL, 0) < 0) {
764                 warn("sysctl: retrieving mbtypes length");
765                 goto err;
766         }
767         if ((mbtypes = malloc(mbtypeslen)) == NULL) {
768                 warn("malloc: %lu bytes for mbtypes", (u_long)mbtypeslen);
769                 goto err;
770         }
771                  
772         nmbtypes = mbtypeslen / sizeof(*mbtypes);
773         if ((seen = calloc(nmbtypes, sizeof(*seen))) == NULL) {
774                 warn("calloc");
775                 goto err;
776         }
777                  
778         name[0] = CTL_KERN;
779         name[1] = KERN_IPC;
780         name[2] = KIPC_MBSTAT;
781         mbstatlen = sizeof mbstat;
782         if (sysctl(name, 3, &mbstat, &mbstatlen, 0, 0) < 0) {
783                 warn("sysctl: retrieving mbstat");
784                 goto err;
785         }
786
787         if (sysctlbyname("kern.ipc.mbtypes",mbtypes,&mbtypeslen,NULL,0) < 0) {
788                 warn("sysctl: retrieving mbtypes");
789                 goto err;
790         }
791
792         name[2] = KIPC_NMBCLUSTERS;
793         nmbclen = sizeof(int);
794         if (sysctl(name, 3, &nmbclusters, &nmbclen, 0, 0) < 0) {
795                 warn("sysctl: retrieving nmbclusters");
796                 goto err;
797         }
798
799         nmbuflen = sizeof(int);
800         if (sysctlbyname("kern.ipc.nmbufs", &nmbufs, &nmbuflen, 0, 0) < 0) {
801                 warn("sysctl: retrieving nmbufs");
802                 goto err;
803         }
804
805 #undef MSIZE
806 #define MSIZE           (mbstat.m_msize)
807 #undef MCLBYTES
808 #define MCLBYTES        (mbstat.m_mclbytes)
809
810         totmbufs = 0;
811         for (mp = mbtypenames; mp->mt_name; mp++)
812                 totmbufs += mbtypes[mp->mt_type];
813         printf("%lu/%lu/%u mbufs in use (current/peak/max):\n", totmbufs,
814             mbstat.m_mbufs, nmbufs);
815         for (mp = mbtypenames; mp->mt_name; mp++)
816                 if (mbtypes[mp->mt_type]) {
817                         seen[mp->mt_type] = 1;
818                         printf("\t%lu mbufs allocated to %s\n",
819                             mbtypes[mp->mt_type], mp->mt_name);
820                 }
821         seen[MT_FREE] = 1;
822         for (i = 0; i < nmbtypes; i++)
823                 if (!seen[i] && mbtypes[i]) {
824                         printf("\t%lu mbufs allocated to <mbuf type %d>\n",
825                             mbtypes[i], i);
826                 }
827         printf("%lu/%lu/%u mbuf clusters in use (current/peak/max)\n",
828                 mbstat.m_clusters - mbstat.m_clfree, mbstat.m_clusters,
829                 nmbclusters);
830         totmem = mbstat.m_mbufs * MSIZE + mbstat.m_clusters * MCLBYTES;
831         totpossible = nmbclusters * MCLBYTES + MSIZE * nmbufs;
832         printf("%lu Kbytes allocated to network (%lu%% of mb_map in use)\n",
833                 totmem / 1024, (totmem * 100) / totpossible);
834         printf("%lu requests for memory denied\n", mbstat.m_drops);
835         printf("%lu requests for memory delayed\n", mbstat.m_wait);
836         printf("%lu calls to protocol drain routines\n", mbstat.m_drain);
837
838 err:
839         if (mbtypes != NULL)
840                 free(mbtypes);
841         if (seen != NULL)
842                 free(seen);
843 }
844
845 int
846 stats(char *proto)
847 {
848         print_mbuf_stats();
849         if (!sflag)
850                 return 0;
851         if (pflag) {
852                 if (proto == NULL) {
853                         fprintf(stderr, "Option '-p' requires paramter.\n");
854                         usage();
855                         exit(-1);
856                 }
857                 if (strcmp(proto, "ip") == 0)
858                         print_ip_stats();
859                 if (strcmp(proto, "icmp") == 0)
860                         print_icmp_stats();
861                 if (strcmp(proto, "udp") == 0)
862                         print_udp_stats();
863                 if (strcmp(proto, "tcp") == 0)
864                         print_tcp_stats();
865 #ifdef BRIDGING
866                 if (strcmp(proto, "bdg") == 0)
867                         print_bdg_stats();
868 #endif
869                 return (0);
870         }
871         print_ip_stats();
872         print_icmp_stats();
873         print_udp_stats();
874         print_tcp_stats();
875 #ifdef BRIDGING
876         print_bdg_stats();
877 #endif
878         return (0);
879 }
880
881 int
882 main(int argc, char *argv[])
883 {
884         char    c;
885         char    *proto = NULL;
886         int     have_flags = 0 ;
887
888         progname = argv[0];
889
890         while ((c = getopt(argc, argv, "dilmnrsp:w:")) != -1) {
891                 have_flags++ ;
892                 switch (c) {
893                 case 'd': /* print deltas in stats every w seconds */
894                         delta++ ;
895                         break;
896                 case 'w':
897                         wflag = atoi(optarg);
898                         break;
899                 case 'n': /* ignored, just for compatibility with std netstat */
900                         break;
901                 case 'r':
902                         rflag++;
903                         break;
904                 case 'i':
905                         iflag++;
906                         break;
907                 case 'm':
908                         mflag++;
909                         break;
910                 case 'l':
911                         lflag++;
912                         break;
913                 case 's':
914                         sflag++;
915                         rflag = 0;
916                         break;
917                 case 'p':
918                         pflag++;
919                         sflag++;
920                         proto = optarg;
921                         break;
922                 case '?':
923                 default:
924                         usage();
925                         exit(0);
926                         break;
927                 }
928         }
929         if (have_flags == 0)
930                 rflag = 1;      /* default */
931         argc -= optind;
932
933         if (argc > 0) {
934                 usage();
935                 exit(-1);
936         }
937         if (wflag)
938                 printf("\033[H\033[J");
939 again:
940         if (wflag) {
941                 struct timeval t;
942
943                 gettimeofday(&t, NULL);
944                 printf("\033[H%s", ctime(&t.tv_sec));
945         }
946         print_routing(proto);
947         print_load_stats();
948         stats(proto);
949         if (wflag) {
950                 sleep(wflag);
951                 goto again;
952         }
953         exit(0);
954 }
955
956 int
957 print_load_stats(void)
958 {
959         static u_int32_t cp_time[5];
960         u_int32_t new_cp_time[5];
961         int l;
962         int shz;
963         static int stathz ;
964
965         if (!lflag || !wflag)
966                 return 0;
967         l = sizeof(new_cp_time) ;
968         bzero(new_cp_time, l);
969         if (sysctlbyname("kern.cp_time", new_cp_time, &l, NULL, 0) < 0) {
970                 warn("sysctl: retrieving cp_time length");
971                 return 0;
972         }
973         if (stathz == 0) {
974                 struct clockinfo ci;
975
976                 bzero (&ci, sizeof(ci));
977                 l = sizeof(ci) ;
978                 if (sysctlbyname("kern.clockrate", &ci, &l, NULL, 0) < 0) {
979                         warn("sysctl: retrieving clockinfo length");
980                         return 0;
981                 }
982                 stathz = ci.stathz ;
983                 bcopy(new_cp_time, cp_time, sizeof(cp_time));
984         }
985         shz = stathz * wflag ;
986         if (shz == 0)
987                 shz = 1;
988 #define X(i)   ( (double)(new_cp_time[i] - cp_time[i])*100/shz )
989         printf("\nUSER %5.2f%% NICE %5.2f%% SYS %5.2f%% "
990                         "INTR %5.2f%% IDLE %5.2f%%\n",
991                 X(0), X(1), X(2), X(3), X(4) );
992         bcopy(new_cp_time, cp_time, sizeof(cp_time));
993 }              
994
995 #ifdef BRIDGING
996 /* print bridge statistics */
997 int
998 print_bdg_stats()
999 {
1000         int     i;
1001         int     mib[4];
1002         int     slen;
1003         struct  bdg_stats s;
1004
1005         slen = sizeof(s);
1006
1007         mib[0] = CTL_NET;
1008         mib[1] = PF_LINK;
1009         mib[2] = IFT_ETHER;
1010         mib[3] = PF_BDG;
1011         if (sysctl(mib, 4, &s, &slen, NULL, 0) == -1) {
1012                 return 0;       /* no bridging */
1013         }
1014         printf("-- Bridging statistics --\n");
1015         printf(
1016             "Name          In      Out  Forward     Drop    Bcast"
1017             "Mcast    Local  Unknown\n");
1018         for (i = 0; i < 16; i++) {
1019                 if (s.s[i].name[0])
1020                         printf("%-6s %9d%9d%9d%9d%9d%9d%9d%9d\n",
1021                             s.s[i].name,
1022                             s.s[i].p_in[(int)BDG_IN],
1023                             s.s[i].p_in[(int)BDG_OUT],
1024                             s.s[i].p_in[(int)BDG_FORWARD],
1025                             s.s[i].p_in[(int)BDG_DROP],
1026                             s.s[i].p_in[(int)BDG_BCAST],
1027                             s.s[i].p_in[(int)BDG_MCAST],
1028                             s.s[i].p_in[(int)BDG_LOCAL],
1029                             s.s[i].p_in[(int)BDG_UNKNOWN]);
1030         }
1031 }
1032 #endif