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