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