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