aboutsummaryrefslogtreecommitdiff
path: root/release/picobsd/tinyware/ns
diff options
context:
space:
mode:
authorAndrzej Bialecki <abial@FreeBSD.org>1998-08-27 17:38:45 +0000
committerAndrzej Bialecki <abial@FreeBSD.org>1998-08-27 17:38:45 +0000
commitc9d8fd0a7bb8ae40b9da7c52caec851ca9d0cf3e (patch)
tree0f9c1dcefca21fb605aaf84b621c2813f01fa5e4 /release/picobsd/tinyware/ns
parent0b0c1554a87b20eb1377566bce8833788ec96394 (diff)
downloadsrc-c9d8fd0a7bb8ae40b9da7c52caec851ca9d0cf3e.tar.gz
src-c9d8fd0a7bb8ae40b9da7c52caec851ca9d0cf3e.zip
Initial import of PicoBSD v0.4 tree.
Notes
Notes: svn path=/cvs2svn/branches/PICOBSD/; revision=38589
Diffstat (limited to 'release/picobsd/tinyware/ns')
-rw-r--r--release/picobsd/tinyware/ns/Makefile9
-rw-r--r--release/picobsd/tinyware/ns/README41
-rw-r--r--release/picobsd/tinyware/ns/ns.c628
3 files changed, 678 insertions, 0 deletions
diff --git a/release/picobsd/tinyware/ns/Makefile b/release/picobsd/tinyware/ns/Makefile
new file mode 100644
index 000000000000..b75d81303f3c
--- /dev/null
+++ b/release/picobsd/tinyware/ns/Makefile
@@ -0,0 +1,9 @@
+# $Id: Makefile,v 1.1 1998/08/01 18:26:02 abial Exp $
+#
+PROG=ns
+SRCS= ns.c
+NOMAN=yes
+
+.include <bsd.prog.mk>
+
+
diff --git a/release/picobsd/tinyware/ns/README b/release/picobsd/tinyware/ns/README
new file mode 100644
index 000000000000..d81bcd74b1f1
--- /dev/null
+++ b/release/picobsd/tinyware/ns/README
@@ -0,0 +1,41 @@
+Warsaw, 1998.07.20
+
+ Small replacement for netstat
+ -----------------------------
+
+This program implements some basic functionality subset of normal netstat -
+it can display the routing table and protocol statistics.
+
+Large part of the code dealing with retrieving the routing table via sysctl(3)
+was taken from code examples written by Richard Stevens to accompany his
+excellent book.
+
+Usage
+-----
+
+ ns [-r] [-s [-p ip|tcp|udp|icmp]]
+
+where
+
+ -r print routing table (default)
+ -s print protocol statistics
+ Options:
+ -p proto display only statistics related to this
+ protocol, where 'proto' is one of:
+ - ip
+ - tcp
+ - udp
+ - icmp
+
+Bugs
+----
+
+* The link layer information is still missing.
+* 'ns' doesn't resolve IP adresses to names
+* well, real netstat provides _much_ more information... but this one needs
+ to be small, right? :-)
+
+Andrzej Bialecki
+<abial@nask.pl>
+
+$Id: README,v 1.1 1998/08/19 17:21:50 abial Exp $
diff --git a/release/picobsd/tinyware/ns/ns.c b/release/picobsd/tinyware/ns/ns.c
new file mode 100644
index 000000000000..6ec15d3744e7
--- /dev/null
+++ b/release/picobsd/tinyware/ns/ns.c
@@ -0,0 +1,628 @@
+/*-
+ * Copyright (c) 1998 Andrzej Bialecki
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: ns.c,v 1.2 1998/08/09 18:52:07 abial Exp $
+ */
+
+
+/*
+ * Small replacement for netstat. Uses only sysctl(3) to get the info.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <err.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/sysctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp_var.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <sys/un.h>
+
+char *progname;
+int rflag=1; /* print routing by default */
+int sflag=0;
+int pflag=0;
+
+extern char *optarg;
+extern int optind;
+
+void
+usage()
+{
+ fprintf(stderr,"\n%s [-r | -s] [-p proto]\n",progname);
+ fprintf(stderr," proto: {ip|tcp|udp|icmp}\n\n");
+}
+
+int if_num;
+
+/*
+ * The following parts related to retrieving the routing table and
+ * interface information, were borrowed from R. Stevens' code examples
+ * accompanying his excellent book. Thanks!
+ */
+
+char *
+sock_ntop(const struct sockaddr *sa, size_t salen)
+{
+ char portstr[7];
+ static char str[128]; /* Unix domain is largest */
+
+ switch (sa->sa_family) {
+ case 255: {
+ struct sockaddr_in *sin = (struct sockaddr_in *) sa;
+ int i;
+
+ i=0;
+ while(sin->sin_addr.s_addr & (0x800000>>i)) i++;
+ sprintf(str,"/%d",i);
+ return(str);
+ }
+ case AF_UNSPEC:
+ case AF_INET: {
+ struct sockaddr_in *sin = (struct sockaddr_in *) sa;
+
+ if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)) == NULL)
+ return(NULL);
+ if (ntohs(sin->sin_port)!=0) {
+ snprintf(portstr, sizeof(portstr), ".%d", ntohs(sin->sin_port));
+ strcat(str, portstr);
+ }
+ if(strcmp(str,"0.0.0.0")==0) sprintf(str,"default");
+ return(str);
+ }
+ case AF_UNIX: {
+ struct sockaddr_un *unp = (struct sockaddr_un *) sa;
+
+ /* OK to have no pathname bound to the socket: happens on
+ every connect() unless client calls bind() first. */
+ if (unp->sun_path[0] == 0)
+ strcpy(str, "(no pathname bound)");
+ else
+ snprintf(str, sizeof(str), "%s", unp->sun_path);
+ return(str);
+ }
+ case AF_LINK: {
+ struct sockaddr_dl *sdl = (struct sockaddr_dl *) sa;
+
+ if (sdl->sdl_nlen > 0)
+ snprintf(str, sizeof(str), "%*s",
+ sdl->sdl_nlen, &sdl->sdl_data[0]);
+ else
+ snprintf(str, sizeof(str), "link#%d", sdl->sdl_index);
+ return(str);
+ }
+ default:
+ snprintf(str, sizeof(str), "sock_ntop: unknown AF_xxx: %d, len %d",
+ sa->sa_family, salen);
+ return(str);
+ }
+ return (NULL);
+}
+
+char *
+Sock_ntop(const struct sockaddr *sa, size_t salen)
+{
+ char *ptr;
+
+ if ( (ptr = sock_ntop(sa, salen)) == NULL)
+ err(1,"sock_ntop error"); /* inet_ntop() sets errno */
+ return(ptr);
+}
+
+
+#define ROUNDUP(a,size) (((a) & ((size)-1))?(1+((a)|((size)-1))):(a))
+
+#define NEXT_SA(ap) ap=(struct sockaddr *) \
+ ((caddr_t)ap+(ap->sa_len?ROUNDUP(ap->sa_len,sizeof(u_long)):\
+ sizeof(u_long)))
+
+void
+get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
+{
+ int i;
+
+ for(i=0;i<RTAX_MAX;i++) {
+ if(addrs &(1<<i)) {
+ rti_info[i]=sa;
+ NEXT_SA(sa);
+ } else
+ rti_info[i]=NULL;
+ }
+}
+
+void
+get_flags(char *buf, int flags)
+{
+ if(flags & 0x1) {
+ strcat(buf,"U");
+ }
+ if(flags & 0x2) {
+ strcat(buf,"G");
+ }
+ if(flags & 0x4) {
+ strcat(buf,"H");
+ }
+ if(flags & 0x8) {
+ strcat(buf,"r");
+ }
+ if(flags & 0x10) {
+ strcat(buf,"d");
+ }
+ /*
+ if(flags & 0x20) {
+ strcat(buf,"mod,");
+ }
+ */
+ if(flags & 0x100) {
+ strcat(buf,"C");
+ }
+ if(flags & 0x400) {
+ strcat(buf,"L");
+ }
+ if(flags & 0x800) {
+ strcat(buf,"S");
+ }
+ if(flags & 0x10000) {
+ strcat(buf,"c");
+ }
+ if(flags & 0x20000) {
+ strcat(buf,"W");
+ }
+ /*
+ if(flags & 0x200000) {
+ strcat(buf,",LOC");
+ }
+ */
+ if(flags & 0x400000) {
+ strcat(buf,"b");
+ }
+ /*
+ if(flags & 0x800000) {
+ strcat(buf,",MCA");
+ }
+ */
+}
+
+int
+routing(char *proto)
+{
+ int mib[6],i=0,rt_len,if_len;
+ char *rt_buf,*if_buf,*next,*lim;
+ struct rt_msghdr *rtm;
+ struct if_msghdr *ifm,**ifm_table;
+ struct ifa_msghdr *ifam;
+ struct sockaddr *sa,*sa1,*rti_info[RTAX_MAX],**if_table;
+ struct rt_metrics rm;
+ char fbuf[50];
+
+ /* Get the routing table */
+ mib[0]=CTL_NET;
+ mib[1]=PF_ROUTE;
+ mib[2]=0;
+ mib[3]=0;
+ mib[4]=NET_RT_DUMP;
+ mib[5]=0;
+ /* Estimate the size of table */
+ if(sysctl(mib,6,NULL,&rt_len,NULL,0)==-1) {
+ perror("sysctl size");
+ exit(-1);
+ }
+ if((rt_buf=(char *)malloc(rt_len))==NULL) {
+ perror("malloc");
+ exit(-1);
+ }
+ /* Now get it. */
+ if(sysctl(mib,6,rt_buf,&rt_len,NULL,0)==-1) {
+ perror("sysctl get");
+ exit(-1);
+ }
+ /* Get the interfaces table */
+ mib[0]=CTL_NET;
+ mib[1]=PF_ROUTE;
+ mib[2]=0;
+ mib[3]=0;
+ mib[4]=NET_RT_IFLIST;
+ mib[5]=0;
+ /* Estimate the size of table */
+ if(sysctl(mib,6,NULL,&if_len,NULL,0)==-1) {
+ perror("sysctl size");
+ exit(-1);
+ }
+ if((if_buf=(char *)malloc(if_len))==NULL) {
+ perror("malloc");
+ exit(-1);
+ }
+ /* Now get it. */
+ if(sysctl(mib,6,if_buf,&if_len,NULL,0)==-1) {
+ perror("sysctl get");
+ exit(-1);
+ }
+ lim=if_buf+if_len;
+ i=0;
+ for(next=if_buf,i=0;next<lim;next+=ifm->ifm_msglen) {
+ ifm=(struct if_msghdr *)next;
+ i++;
+ }
+ if_num=i;
+ if_table=(struct sockaddr **)malloc(i*sizeof(struct sockaddr));
+ ifm_table=(struct if_msghdr **)malloc(i*sizeof(struct if_msghdr));
+ memset(ifm_table,0,sizeof(ifm_table));
+ i=0;
+ for(next=if_buf;next<lim;next+=ifm->ifm_msglen) {
+ ifm=(struct if_msghdr *)next;
+ if_table[i]=(struct sockaddr *)(ifm+1);
+ ifm_table[i]=ifm;
+ i++;
+ }
+ /* Now dump the routing table */
+ printf("\nRouting table:\n");
+ printf("--------------\n");
+ printf("Destination Gateway Flags Netif Use\n");
+ lim=rt_buf+rt_len;
+ for(next=rt_buf;next<lim;next+=rtm->rtm_msglen) {
+ rtm=(struct rt_msghdr *)next;
+ sa=(struct sockaddr *)(rtm+1);
+ get_rtaddrs(rtm->rtm_addrs,sa,rti_info);
+ if(rtm->rtm_flags & RTF_WASCLONED) {
+ if((rtm->rtm_flags & RTF_LLINFO)==0)continue;
+ }
+ if((sa=rti_info[RTAX_DST])!=NULL) {
+ sprintf(fbuf,"%s",sock_ntop(sa,sa->sa_len));
+ if(((sa1=rti_info[RTAX_NETMASK])!=NULL) && sa1->sa_family==255) {
+ strcat(fbuf,sock_ntop(sa1,sa1->sa_len));
+ }
+ printf("%-19s",fbuf);
+ }
+ if((sa=rti_info[RTAX_GATEWAY])!=NULL) {
+ printf("%-19s",sock_ntop(sa,sa->sa_len));
+ }
+ memset(fbuf,0,sizeof(fbuf));
+ get_flags(fbuf,rtm->rtm_flags);
+ printf("%-10s",fbuf);
+ for(i=0;i<if_num;i++) {
+ ifm=ifm_table[i];
+ if((ifm->ifm_index==rtm->rtm_index) &&
+ (ifm->ifm_data.ifi_type>0)) {
+ sa=if_table[i];
+ break;
+ }
+ }
+ if(ifm->ifm_type==RTM_IFINFO) {
+ get_rtaddrs(ifm->ifm_addrs,sa,rti_info);
+ printf(" %s",Sock_ntop(sa,sa->sa_len));
+ } else if(ifm->ifm_type==RTM_NEWADDR) {
+ ifam=(struct ifa_msghdr *)ifm_table[rtm->rtm_index-1];
+ sa=(struct sockaddr *)(ifam+1);
+ get_rtaddrs(ifam->ifam_addrs,sa,rti_info);
+ printf(" %s",Sock_ntop(sa,sa->sa_len));
+ }
+ printf(" %u",rtm->rtm_use);
+ printf("\n");
+ }
+ return(0);
+
+}
+
+print_ip_stats()
+{
+ int mib[4],len;
+ struct ipstat s;
+
+ mib[0]=CTL_NET;
+ mib[1]=PF_INET;
+ mib[2]=IPPROTO_IP;
+ mib[3]=IPCTL_STATS;
+ len=sizeof(struct ipstat);
+ if(sysctl(mib,4,&s,&len,NULL,0)<0) {
+ perror("sysctl");
+ return(-1);
+ }
+ printf("\nIP statistics:\n");
+ printf("--------------\n");
+ printf(" %10lu total packets received\n",s.ips_total);
+ printf("* Packets ok:\n");
+ printf(" %10lu fragments received\n",s.ips_fragments);
+ printf(" %10lu forwarded\n",s.ips_forward);
+ printf(" %10lu fast forwarded\n",s.ips_fastforward);
+ printf(" %10lu forwarded on same net (redirect)\n",s.ips_redirectsent);
+ printf(" %10lu delivered to upper level\n",s.ips_delivered);
+ printf(" %10lu total ip packets generated here\n",s.ips_localout);
+ printf(" %10lu total packets reassembled ok\n",s.ips_reassembled);
+ printf(" %10lu total datagrams successfully fragmented\n",s.ips_fragmented);
+ printf(" %10lu output fragments created\n",s.ips_ofragments);
+ printf(" %10lu total raw IP packets generated\n",s.ips_rawout);
+ printf("\n* Bad packets:\n");
+ printf(" %10lu bad checksum\n",s.ips_badsum);
+ printf(" %10lu too short\n",s.ips_tooshort);
+ printf(" %10lu not enough data (too small)\n",s.ips_toosmall);
+ printf(" %10lu more data than declared in header\n",s.ips_badhlen);
+ printf(" %10lu less data than declared in header\n",s.ips_badlen);
+ printf(" %10lu fragments dropped (dups, no mbuf)\n",s.ips_fragdropped);
+ printf(" %10lu fragments timed out in reassembly\n",s.ips_fragtimeout);
+ printf(" %10lu received for unreachable dest.\n",s.ips_cantforward);
+ printf(" %10lu unknown or unsupported protocol\n",s.ips_noproto);
+ printf(" %10lu lost due to no bufs etc.\n",s.ips_odropped);
+ printf(" %10lu couldn't fragment (DF set, etc.)\n",s.ips_cantfrag);
+ printf(" %10lu error in IP options processing\n",s.ips_badoptions);
+ printf(" %10lu dropped due to no route\n",s.ips_noroute);
+ printf(" %10lu bad IP version\n",s.ips_badvers);
+ printf(" %10lu too long (more than max IP size)\n",s.ips_toolong);
+ printf(" %10lu multicast for unregistered groups\n",s.ips_notmember);
+}
+
+print_tcp_stats()
+{
+ int mib[4],len;
+ struct tcpstat s;
+
+ mib[0]=CTL_NET;
+ mib[1]=PF_INET;
+ mib[2]=IPPROTO_TCP;
+ mib[3]=TCPCTL_STATS;
+ len=sizeof(struct tcpstat);
+ if(sysctl(mib,4,&s,&len,NULL,0)<0) {
+ perror("sysctl");
+ return(-1);
+ }
+ printf("\nTCP statistics:\n");
+ printf("---------------\n");
+ printf("* Connections:\n");
+ printf(" %10lu initiated\n",s.tcps_connattempt);
+ printf(" %10lu accepted\n",s.tcps_accepts);
+ printf(" %10lu established\n",s.tcps_connects);
+ printf(" %10lu dropped\n",s.tcps_drops);
+ printf(" %10lu embryonic connections dropped\n",s.tcps_conndrops);
+ printf(" %10lu closed (includes dropped)\n",s.tcps_closed);
+ printf(" %10lu segments where we tried to get RTT\n",s.tcps_segstimed);
+ printf(" %10lu times RTT successfully updated\n",s.tcps_rttupdated);
+ printf(" %10lu delayed ACKs sent\n",s.tcps_delack);
+ printf(" %10lu dropped in rxmt timeout\n",s.tcps_timeoutdrop);
+ printf(" %10lu retrasmit timeouts\n",s.tcps_rexmttimeo);
+ printf(" %10lu persist timeouts\n",s.tcps_persisttimeo);
+ printf(" %10lu keepalive timeouts\n",s.tcps_keeptimeo);
+ printf(" %10lu keepalive probes sent\n",s.tcps_keepprobe);
+ printf(" %10lu dropped in keepalive\n",s.tcps_keepdrops);
+
+ printf("* Packets sent:\n");
+ printf(" %10lu total packets sent\n",s.tcps_sndtotal);
+ printf(" %10lu data packets sent\n",s.tcps_sndpack);
+ printf(" %10lu data bytes sent\n",s.tcps_sndbyte);
+ printf(" %10lu data packets retransmitted\n",s.tcps_sndrexmitpack);
+ printf(" %10lu data bytes retransmitted\n",s.tcps_sndrexmitbyte);
+ printf(" %10lu ACK-only packets sent\n",s.tcps_sndacks);
+ printf(" %10lu window probes sent\n",s.tcps_sndprobe);
+ printf(" %10lu URG-only packets sent\n",s.tcps_sndurg);
+ printf(" %10lu window update-only packets sent\n",s.tcps_sndwinup);
+ printf(" %10lu control (SYN,FIN,RST) packets sent\n",s.tcps_sndctrl);
+ printf("* Packets received:\n");
+ printf(" %10lu total packets received\n",s.tcps_rcvtotal);
+ printf(" %10lu packets in sequence\n",s.tcps_rcvpack);
+ printf(" %10lu bytes in sequence\n",s.tcps_rcvbyte);
+ printf(" %10lu packets with bad checksum\n",s.tcps_rcvbadsum);
+ printf(" %10lu packets with bad offset\n",s.tcps_rcvbadoff);
+ printf(" %10lu packets too short\n",s.tcps_rcvshort);
+ printf(" %10lu duplicate-only packets\n",s.tcps_rcvduppack);
+ printf(" %10lu duplicate-only bytes\n",s.tcps_rcvdupbyte);
+ printf(" %10lu packets with some duplicate data\n",s.tcps_rcvpartduppack);
+ printf(" %10lu duplicate bytes in partially dup. packets\n",s.tcps_rcvpartdupbyte);
+ printf(" %10lu out-of-order packets\n",s.tcps_rcvoopack);
+ printf(" %10lu out-of-order bytes\n",s.tcps_rcvoobyte);
+ printf(" %10lu packets with data after window\n",s.tcps_rcvpackafterwin);
+ printf(" %10lu bytes received after window\n",s.tcps_rcvbyteafterwin);
+ printf(" %10lu packets received after 'close'\n",s.tcps_rcvafterclose);
+ printf(" %10lu window probe packets\n",s.tcps_rcvwinprobe);
+ printf(" %10lu duplicate ACKs\n",s.tcps_rcvdupack);
+ printf(" %10lu ACKs for unsent data\n",s.tcps_rcvacktoomuch);
+ printf(" %10lu ACK packets\n",s.tcps_rcvackpack);
+ printf(" %10lu bytes ACKed by received ACKs\n",s.tcps_rcvackbyte);
+ printf(" %10lu window update packets\n",s.tcps_rcvwinupd);
+ printf(" %10lu segments dropped due to PAWS\n",s.tcps_pawsdrop);
+ printf(" %10lu times header predict ok for ACKs\n",s.tcps_predack);
+ printf(" %10lu times header predict ok for data packets\n",s.tcps_preddat);
+ printf(" %10lu PCB cache misses\n",s.tcps_pcbcachemiss);
+ printf(" %10lu times cached RTT in route updated\n",s.tcps_cachedrtt);
+ printf(" %10lu times cached RTTVAR updated\n",s.tcps_cachedrttvar);
+ printf(" %10lu times ssthresh updated\n",s.tcps_cachedssthresh);
+ printf(" %10lu times RTT initialized from route\n",s.tcps_usedrtt);
+ printf(" %10lu times RTTVAR initialized from route\n",s.tcps_usedrttvar);
+ printf(" %10lu times ssthresh initialized from route\n",s.tcps_usedssthresh);
+ printf(" %10lu timeout in persist state\n",s.tcps_persistdrop);
+ printf(" %10lu bogus SYN, e.g. premature ACK\n",s.tcps_badsyn);
+ printf(" %10lu resends due to MTU discovery\n",s.tcps_mturesent);
+ printf(" %10lu listen queue overflows\n",s.tcps_listendrop);
+}
+
+print_udp_stats()
+{
+ int mib[4],len;
+ struct udpstat s;
+
+ mib[0]=CTL_NET;
+ mib[1]=PF_INET;
+ mib[2]=IPPROTO_UDP;
+ mib[3]=UDPCTL_STATS;
+ len=sizeof(struct udpstat);
+ if(sysctl(mib,4,&s,&len,NULL,0)<0) {
+ perror("sysctl");
+ return(-1);
+ }
+ printf("\nUDP statistics:\n");
+ printf("---------------\n");
+ printf("* Packets received:\n");
+ printf(" %10lu total input packets\n",s.udps_ipackets);
+ printf(" %10lu packets shorter than header (dropped)\n",s.udps_hdrops);
+ printf(" %10lu bad checksum\n",s.udps_badsum);
+ printf(" %10lu data length larger than packet\n",s.udps_badlen);
+ printf(" %10lu no socket on specified port\n",s.udps_noport);
+ printf(" %10lu of above, arrived as broadcast\n",s.udps_noportbcast);
+ printf(" %10lu not delivered, input socket full\n",s.udps_fullsock);
+ printf(" %10lu packets missing PCB cache\n",s.udpps_pcbcachemiss);
+ printf(" %10lu packets not for hashed PCBs\n",s.udpps_pcbhashmiss);
+ printf("* Packets sent:\n");
+ printf(" %10lu total output packets\n",s.udps_opackets);
+ printf(" %10lu output packets on fast path\n",s.udps_fastout);
+}
+
+char *icmp_names[]={
+ "echo reply",
+ "#1",
+ "#2",
+ "destination unreachable",
+ "source quench",
+ "routing redirect",
+ "#6",
+ "#7",
+ "echo",
+ "router advertisement",
+ "router solicitation",
+ "time exceeded",
+ "parameter problem",
+ "time stamp",
+ "time stamp reply",
+ "information request",
+ "information request reply",
+ "address mask request",
+ "address mask reply",
+};
+
+print_icmp_stats()
+{
+ int mib[4],len,i;
+ struct icmpstat s;
+
+ mib[0]=CTL_NET;
+ mib[1]=PF_INET;
+ mib[2]=IPPROTO_ICMP;
+ mib[3]=ICMPCTL_STATS;
+ len=sizeof(struct icmpstat);
+ if(sysctl(mib,4,&s,&len,NULL,0)<0) {
+ perror("sysctl");
+ return(-1);
+ }
+ printf("\nICMP statistics:\n");
+ printf("----------------\n");
+ printf("* Output histogram:\n");
+ for(i=0;i<(ICMP_MAXTYPE+1);i++) {
+ if(s.icps_outhist[i]>0)
+ printf("\t%10lu %s\n",
+ s.icps_outhist[i],icmp_names[i]);
+ }
+ printf("* Input histogram:\n");
+ for(i=0;i<(ICMP_MAXTYPE+1);i++) {
+ if(s.icps_inhist[i]>0)
+ printf("\t%10lu %s\n",
+ s.icps_inhist[i],icmp_names[i]);
+ }
+ printf("* Other stats:\n");
+ printf(" %10lu calls to icmp_error\n",s.icps_error);
+ printf(" %10lu no error 'cuz old ip too short\n",s.icps_oldshort);
+ printf(" %10lu no error 'cuz old was icmp\n",s.icps_oldicmp);
+
+ printf(" %10lu icmp code out of range\n",s.icps_badcode);
+ printf(" %10lu packets shorter than min length\n",s.icps_tooshort);
+ printf(" %10lu bad checksum\n",s.icps_checksum);
+ printf(" %10lu calculated bound mismatch\n",s.icps_badlen);
+ printf(" %10lu number of responses\n",s.icps_reflect);
+ printf(" %10lu broad/multi-cast echo requests dropped\n",s.icps_bmcastecho);
+ printf(" %10lu broad/multi-cast timestamp requests dropped\n",s.icps_bmcasttstamp);
+}
+
+int
+stats(char *proto)
+{
+ if(pflag) {
+ if(proto==NULL) {
+ fprintf(stderr,"Option '-p' requires paramter.\n");
+ usage();
+ exit(-1);
+ }
+ if(strcmp(proto,"ip")==0) print_ip_stats();
+ if(strcmp(proto,"icmp")==0) print_icmp_stats();
+ if(strcmp(proto,"udp")==0) print_udp_stats();
+ if(strcmp(proto,"tcp")==0) print_tcp_stats();
+ return(0);
+ }
+ print_ip_stats();
+ print_icmp_stats();
+ print_udp_stats();
+ print_tcp_stats();
+ return(0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ char c;
+ char *proto=NULL;
+
+ progname=argv[0];
+
+ while((c=getopt(argc,argv,"rsp:"))!=-1) {
+ switch(c) {
+ case 'r':
+ rflag++;
+ break;
+ case 's':
+ sflag++;
+ rflag=0;
+ break;
+ case 'p':
+ pflag++;
+ proto=optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ exit(0);
+ break;
+ }
+ }
+ argc-=optind;
+ if(argc>0) {
+ usage();
+ exit(-1);
+ }
+ if(rflag) {
+ routing(proto);
+ } else {
+ stats(proto);
+ }
+ exit(0);
+}