xref: /freebsd/usr.bin/netstat/inet.c (revision 9b50d9027575220cb6dd09b3e62f03f511e908b8)
19b50d902SRodney W. Grimes /*
29b50d902SRodney W. Grimes  * Copyright (c) 1983, 1988, 1993
39b50d902SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
49b50d902SRodney W. Grimes  *
59b50d902SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
69b50d902SRodney W. Grimes  * modification, are permitted provided that the following conditions
79b50d902SRodney W. Grimes  * are met:
89b50d902SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
99b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
109b50d902SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
119b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
129b50d902SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
139b50d902SRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
149b50d902SRodney W. Grimes  *    must display the following acknowledgement:
159b50d902SRodney W. Grimes  *	This product includes software developed by the University of
169b50d902SRodney W. Grimes  *	California, Berkeley and its contributors.
179b50d902SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
189b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
199b50d902SRodney W. Grimes  *    without specific prior written permission.
209b50d902SRodney W. Grimes  *
219b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
229b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
239b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
249b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
259b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
269b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
279b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
289b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
299b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
309b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
319b50d902SRodney W. Grimes  * SUCH DAMAGE.
329b50d902SRodney W. Grimes  */
339b50d902SRodney W. Grimes 
349b50d902SRodney W. Grimes #ifndef lint
359b50d902SRodney W. Grimes static char sccsid[] = "@(#)inet.c	8.4 (Berkeley) 4/20/94";
369b50d902SRodney W. Grimes #endif /* not lint */
379b50d902SRodney W. Grimes 
389b50d902SRodney W. Grimes #include <sys/param.h>
399b50d902SRodney W. Grimes #include <sys/socket.h>
409b50d902SRodney W. Grimes #include <sys/socketvar.h>
419b50d902SRodney W. Grimes #include <sys/mbuf.h>
429b50d902SRodney W. Grimes #include <sys/protosw.h>
439b50d902SRodney W. Grimes 
449b50d902SRodney W. Grimes #include <net/route.h>
459b50d902SRodney W. Grimes #include <netinet/in.h>
469b50d902SRodney W. Grimes #include <netinet/in_systm.h>
479b50d902SRodney W. Grimes #include <netinet/ip.h>
489b50d902SRodney W. Grimes #include <netinet/in_pcb.h>
499b50d902SRodney W. Grimes #include <netinet/ip_icmp.h>
509b50d902SRodney W. Grimes #include <netinet/icmp_var.h>
519b50d902SRodney W. Grimes #include <netinet/igmp_var.h>
529b50d902SRodney W. Grimes #include <netinet/ip_var.h>
539b50d902SRodney W. Grimes #include <netinet/tcp.h>
549b50d902SRodney W. Grimes #include <netinet/tcpip.h>
559b50d902SRodney W. Grimes #include <netinet/tcp_seq.h>
569b50d902SRodney W. Grimes #define TCPSTATES
579b50d902SRodney W. Grimes #include <netinet/tcp_fsm.h>
589b50d902SRodney W. Grimes #include <netinet/tcp_timer.h>
599b50d902SRodney W. Grimes #include <netinet/tcp_var.h>
609b50d902SRodney W. Grimes #include <netinet/tcp_debug.h>
619b50d902SRodney W. Grimes #include <netinet/udp.h>
629b50d902SRodney W. Grimes #include <netinet/udp_var.h>
639b50d902SRodney W. Grimes 
649b50d902SRodney W. Grimes #include <arpa/inet.h>
659b50d902SRodney W. Grimes #include <netdb.h>
669b50d902SRodney W. Grimes #include <stdio.h>
679b50d902SRodney W. Grimes #include <string.h>
689b50d902SRodney W. Grimes #include <unistd.h>
699b50d902SRodney W. Grimes #include "netstat.h"
709b50d902SRodney W. Grimes 
719b50d902SRodney W. Grimes struct	inpcb inpcb;
729b50d902SRodney W. Grimes struct	tcpcb tcpcb;
739b50d902SRodney W. Grimes struct	socket sockb;
749b50d902SRodney W. Grimes 
759b50d902SRodney W. Grimes char	*inetname __P((struct in_addr *));
769b50d902SRodney W. Grimes void	inetprint __P((struct in_addr *, int, char *));
779b50d902SRodney W. Grimes 
789b50d902SRodney W. Grimes /*
799b50d902SRodney W. Grimes  * Print a summary of connections related to an Internet
809b50d902SRodney W. Grimes  * protocol.  For TCP, also give state of connection.
819b50d902SRodney W. Grimes  * Listening processes (aflag) are suppressed unless the
829b50d902SRodney W. Grimes  * -a (all) flag is specified.
839b50d902SRodney W. Grimes  */
849b50d902SRodney W. Grimes void
859b50d902SRodney W. Grimes protopr(off, name)
869b50d902SRodney W. Grimes 	u_long off;
879b50d902SRodney W. Grimes 	char *name;
889b50d902SRodney W. Grimes {
899b50d902SRodney W. Grimes 	struct inpcb cb;
909b50d902SRodney W. Grimes 	register struct inpcb *prev, *next;
919b50d902SRodney W. Grimes 	int istcp;
929b50d902SRodney W. Grimes 	static int first = 1;
939b50d902SRodney W. Grimes 
949b50d902SRodney W. Grimes 	if (off == 0)
959b50d902SRodney W. Grimes 		return;
969b50d902SRodney W. Grimes 	istcp = strcmp(name, "tcp") == 0;
979b50d902SRodney W. Grimes 	kread(off, (char *)&cb, sizeof (struct inpcb));
989b50d902SRodney W. Grimes 	inpcb = cb;
999b50d902SRodney W. Grimes 	prev = (struct inpcb *)off;
1009b50d902SRodney W. Grimes 	if (inpcb.inp_next == (struct inpcb *)off)
1019b50d902SRodney W. Grimes 		return;
1029b50d902SRodney W. Grimes 	while (inpcb.inp_next != (struct inpcb *)off) {
1039b50d902SRodney W. Grimes 		next = inpcb.inp_next;
1049b50d902SRodney W. Grimes 		kread((u_long)next, (char *)&inpcb, sizeof (inpcb));
1059b50d902SRodney W. Grimes 		if (inpcb.inp_prev != prev) {
1069b50d902SRodney W. Grimes 			printf("???\n");
1079b50d902SRodney W. Grimes 			break;
1089b50d902SRodney W. Grimes 		}
1099b50d902SRodney W. Grimes 		if (!aflag &&
1109b50d902SRodney W. Grimes 		  inet_lnaof(inpcb.inp_laddr) == INADDR_ANY) {
1119b50d902SRodney W. Grimes 			prev = next;
1129b50d902SRodney W. Grimes 			continue;
1139b50d902SRodney W. Grimes 		}
1149b50d902SRodney W. Grimes 		kread((u_long)inpcb.inp_socket, (char *)&sockb, sizeof (sockb));
1159b50d902SRodney W. Grimes 		if (istcp) {
1169b50d902SRodney W. Grimes 			kread((u_long)inpcb.inp_ppcb,
1179b50d902SRodney W. Grimes 			    (char *)&tcpcb, sizeof (tcpcb));
1189b50d902SRodney W. Grimes 		}
1199b50d902SRodney W. Grimes 		if (first) {
1209b50d902SRodney W. Grimes 			printf("Active Internet connections");
1219b50d902SRodney W. Grimes 			if (aflag)
1229b50d902SRodney W. Grimes 				printf(" (including servers)");
1239b50d902SRodney W. Grimes 			putchar('\n');
1249b50d902SRodney W. Grimes 			if (Aflag)
1259b50d902SRodney W. Grimes 				printf("%-8.8s ", "PCB");
1269b50d902SRodney W. Grimes 			printf(Aflag ?
1279b50d902SRodney W. Grimes 				"%-5.5s %-6.6s %-6.6s  %-18.18s %-18.18s %s\n" :
1289b50d902SRodney W. Grimes 				"%-5.5s %-6.6s %-6.6s  %-22.22s %-22.22s %s\n",
1299b50d902SRodney W. Grimes 				"Proto", "Recv-Q", "Send-Q",
1309b50d902SRodney W. Grimes 				"Local Address", "Foreign Address", "(state)");
1319b50d902SRodney W. Grimes 			first = 0;
1329b50d902SRodney W. Grimes 		}
1339b50d902SRodney W. Grimes 		if (Aflag)
1349b50d902SRodney W. Grimes 			if (istcp)
1359b50d902SRodney W. Grimes 				printf("%8x ", inpcb.inp_ppcb);
1369b50d902SRodney W. Grimes 			else
1379b50d902SRodney W. Grimes 				printf("%8x ", next);
1389b50d902SRodney W. Grimes 		printf("%-5.5s %6d %6d ", name, sockb.so_rcv.sb_cc,
1399b50d902SRodney W. Grimes 			sockb.so_snd.sb_cc);
1409b50d902SRodney W. Grimes 		inetprint(&inpcb.inp_laddr, (int)inpcb.inp_lport, name);
1419b50d902SRodney W. Grimes 		inetprint(&inpcb.inp_faddr, (int)inpcb.inp_fport, name);
1429b50d902SRodney W. Grimes 		if (istcp) {
1439b50d902SRodney W. Grimes 			if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES)
1449b50d902SRodney W. Grimes 				printf(" %d", tcpcb.t_state);
1459b50d902SRodney W. Grimes 			else
1469b50d902SRodney W. Grimes 				printf(" %s", tcpstates[tcpcb.t_state]);
1479b50d902SRodney W. Grimes 		}
1489b50d902SRodney W. Grimes 		putchar('\n');
1499b50d902SRodney W. Grimes 		prev = next;
1509b50d902SRodney W. Grimes 	}
1519b50d902SRodney W. Grimes }
1529b50d902SRodney W. Grimes 
1539b50d902SRodney W. Grimes /*
1549b50d902SRodney W. Grimes  * Dump TCP statistics structure.
1559b50d902SRodney W. Grimes  */
1569b50d902SRodney W. Grimes void
1579b50d902SRodney W. Grimes tcp_stats(off, name)
1589b50d902SRodney W. Grimes 	u_long off;
1599b50d902SRodney W. Grimes 	char *name;
1609b50d902SRodney W. Grimes {
1619b50d902SRodney W. Grimes 	struct tcpstat tcpstat;
1629b50d902SRodney W. Grimes 
1639b50d902SRodney W. Grimes 	if (off == 0)
1649b50d902SRodney W. Grimes 		return;
1659b50d902SRodney W. Grimes 	printf ("%s:\n", name);
1669b50d902SRodney W. Grimes 	kread(off, (char *)&tcpstat, sizeof (tcpstat));
1679b50d902SRodney W. Grimes 
1689b50d902SRodney W. Grimes #define	p(f, m) if (tcpstat.f || sflag <= 1) \
1699b50d902SRodney W. Grimes     printf(m, tcpstat.f, plural(tcpstat.f))
1709b50d902SRodney W. Grimes #define	p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
1719b50d902SRodney W. Grimes     printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2, plural(tcpstat.f2))
1729b50d902SRodney W. Grimes #define	p3(f, m) if (tcpstat.f || sflag <= 1) \
1739b50d902SRodney W. Grimes     printf(m, tcpstat.f, plurales(tcpstat.f))
1749b50d902SRodney W. Grimes 
1759b50d902SRodney W. Grimes 	p(tcps_sndtotal, "\t%d packet%s sent\n");
1769b50d902SRodney W. Grimes 	p2(tcps_sndpack,tcps_sndbyte,
1779b50d902SRodney W. Grimes 		"\t\t%d data packet%s (%d byte%s)\n");
1789b50d902SRodney W. Grimes 	p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
1799b50d902SRodney W. Grimes 		"\t\t%d data packet%s (%d byte%s) retransmitted\n");
1809b50d902SRodney W. Grimes 	p2(tcps_sndacks, tcps_delack,
1819b50d902SRodney W. Grimes 		"\t\t%d ack-only packet%s (%d delayed)\n");
1829b50d902SRodney W. Grimes 	p(tcps_sndurg, "\t\t%d URG only packet%s\n");
1839b50d902SRodney W. Grimes 	p(tcps_sndprobe, "\t\t%d window probe packet%s\n");
1849b50d902SRodney W. Grimes 	p(tcps_sndwinup, "\t\t%d window update packet%s\n");
1859b50d902SRodney W. Grimes 	p(tcps_sndctrl, "\t\t%d control packet%s\n");
1869b50d902SRodney W. Grimes 	p(tcps_rcvtotal, "\t%d packet%s received\n");
1879b50d902SRodney W. Grimes 	p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%d ack%s (for %d byte%s)\n");
1889b50d902SRodney W. Grimes 	p(tcps_rcvdupack, "\t\t%d duplicate ack%s\n");
1899b50d902SRodney W. Grimes 	p(tcps_rcvacktoomuch, "\t\t%d ack%s for unsent data\n");
1909b50d902SRodney W. Grimes 	p2(tcps_rcvpack, tcps_rcvbyte,
1919b50d902SRodney W. Grimes 		"\t\t%d packet%s (%d byte%s) received in-sequence\n");
1929b50d902SRodney W. Grimes 	p2(tcps_rcvduppack, tcps_rcvdupbyte,
1939b50d902SRodney W. Grimes 		"\t\t%d completely duplicate packet%s (%d byte%s)\n");
1949b50d902SRodney W. Grimes 	p(tcps_pawsdrop, "\t\t%d old duplicate packet%s\n");
1959b50d902SRodney W. Grimes 	p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
1969b50d902SRodney W. Grimes 		"\t\t%d packet%s with some dup. data (%d byte%s duped)\n");
1979b50d902SRodney W. Grimes 	p2(tcps_rcvoopack, tcps_rcvoobyte,
1989b50d902SRodney W. Grimes 		"\t\t%d out-of-order packet%s (%d byte%s)\n");
1999b50d902SRodney W. Grimes 	p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
2009b50d902SRodney W. Grimes 		"\t\t%d packet%s (%d byte%s) of data after window\n");
2019b50d902SRodney W. Grimes 	p(tcps_rcvwinprobe, "\t\t%d window probe%s\n");
2029b50d902SRodney W. Grimes 	p(tcps_rcvwinupd, "\t\t%d window update packet%s\n");
2039b50d902SRodney W. Grimes 	p(tcps_rcvafterclose, "\t\t%d packet%s received after close\n");
2049b50d902SRodney W. Grimes 	p(tcps_rcvbadsum, "\t\t%d discarded for bad checksum%s\n");
2059b50d902SRodney W. Grimes 	p(tcps_rcvbadoff, "\t\t%d discarded for bad header offset field%s\n");
2069b50d902SRodney W. Grimes 	p(tcps_rcvshort, "\t\t%d discarded because packet too short\n");
2079b50d902SRodney W. Grimes 	p(tcps_connattempt, "\t%d connection request%s\n");
2089b50d902SRodney W. Grimes 	p(tcps_accepts, "\t%d connection accept%s\n");
2099b50d902SRodney W. Grimes 	p(tcps_connects, "\t%d connection%s established (including accepts)\n");
2109b50d902SRodney W. Grimes 	p2(tcps_closed, tcps_drops,
2119b50d902SRodney W. Grimes 		"\t%d connection%s closed (including %d drop%s)\n");
2129b50d902SRodney W. Grimes 	p(tcps_conndrops, "\t%d embryonic connection%s dropped\n");
2139b50d902SRodney W. Grimes 	p2(tcps_rttupdated, tcps_segstimed,
2149b50d902SRodney W. Grimes 		"\t%d segment%s updated rtt (of %d attempt%s)\n");
2159b50d902SRodney W. Grimes 	p(tcps_rexmttimeo, "\t%d retransmit timeout%s\n");
2169b50d902SRodney W. Grimes 	p(tcps_timeoutdrop, "\t\t%d connection%s dropped by rexmit timeout\n");
2179b50d902SRodney W. Grimes 	p(tcps_persisttimeo, "\t%d persist timeout%s\n");
2189b50d902SRodney W. Grimes 	p(tcps_keeptimeo, "\t%d keepalive timeout%s\n");
2199b50d902SRodney W. Grimes 	p(tcps_keepprobe, "\t\t%d keepalive probe%s sent\n");
2209b50d902SRodney W. Grimes 	p(tcps_keepdrops, "\t\t%d connection%s dropped by keepalive\n");
2219b50d902SRodney W. Grimes 	p(tcps_predack, "\t%d correct ACK header prediction%s\n");
2229b50d902SRodney W. Grimes 	p(tcps_preddat, "\t%d correct data packet header prediction%s\n");
2239b50d902SRodney W. Grimes 	p3(tcps_pcbcachemiss, "\t%d PCB cache miss%s\n");
2249b50d902SRodney W. Grimes #undef p
2259b50d902SRodney W. Grimes #undef p2
2269b50d902SRodney W. Grimes #undef p3
2279b50d902SRodney W. Grimes }
2289b50d902SRodney W. Grimes 
2299b50d902SRodney W. Grimes /*
2309b50d902SRodney W. Grimes  * Dump UDP statistics structure.
2319b50d902SRodney W. Grimes  */
2329b50d902SRodney W. Grimes void
2339b50d902SRodney W. Grimes udp_stats(off, name)
2349b50d902SRodney W. Grimes 	u_long off;
2359b50d902SRodney W. Grimes 	char *name;
2369b50d902SRodney W. Grimes {
2379b50d902SRodney W. Grimes 	struct udpstat udpstat;
2389b50d902SRodney W. Grimes 	u_long delivered;
2399b50d902SRodney W. Grimes 
2409b50d902SRodney W. Grimes 	if (off == 0)
2419b50d902SRodney W. Grimes 		return;
2429b50d902SRodney W. Grimes 	kread(off, (char *)&udpstat, sizeof (udpstat));
2439b50d902SRodney W. Grimes 	printf("%s:\n", name);
2449b50d902SRodney W. Grimes #define	p(f, m) if (udpstat.f || sflag <= 1) \
2459b50d902SRodney W. Grimes     printf(m, udpstat.f, plural(udpstat.f))
2469b50d902SRodney W. Grimes 	p(udps_ipackets, "\t%u datagram%s received\n");
2479b50d902SRodney W. Grimes 	p(udps_hdrops, "\t%u with incomplete header\n");
2489b50d902SRodney W. Grimes 	p(udps_badlen, "\t%u with bad data length field\n");
2499b50d902SRodney W. Grimes 	p(udps_badsum, "\t%u with bad checksum\n");
2509b50d902SRodney W. Grimes 	p(udps_noport, "\t%u dropped due to no socket\n");
2519b50d902SRodney W. Grimes 	p(udps_noportbcast, "\t%u broadcast/multicast datagram%s dropped due to no socket\n");
2529b50d902SRodney W. Grimes 	p(udps_fullsock, "\t%u dropped due to full socket buffers\n");
2539b50d902SRodney W. Grimes 	delivered = udpstat.udps_ipackets -
2549b50d902SRodney W. Grimes 		    udpstat.udps_hdrops -
2559b50d902SRodney W. Grimes 		    udpstat.udps_badlen -
2569b50d902SRodney W. Grimes 		    udpstat.udps_badsum -
2579b50d902SRodney W. Grimes 		    udpstat.udps_noport -
2589b50d902SRodney W. Grimes 		    udpstat.udps_noportbcast -
2599b50d902SRodney W. Grimes 		    udpstat.udps_fullsock;
2609b50d902SRodney W. Grimes 	if (delivered || sflag <= 1)
2619b50d902SRodney W. Grimes 		printf("\t%u delivered\n", delivered);
2629b50d902SRodney W. Grimes 	p(udps_opackets, "\t%u datagram%s output\n");
2639b50d902SRodney W. Grimes #undef p
2649b50d902SRodney W. Grimes }
2659b50d902SRodney W. Grimes 
2669b50d902SRodney W. Grimes /*
2679b50d902SRodney W. Grimes  * Dump IP statistics structure.
2689b50d902SRodney W. Grimes  */
2699b50d902SRodney W. Grimes void
2709b50d902SRodney W. Grimes ip_stats(off, name)
2719b50d902SRodney W. Grimes 	u_long off;
2729b50d902SRodney W. Grimes 	char *name;
2739b50d902SRodney W. Grimes {
2749b50d902SRodney W. Grimes 	struct ipstat ipstat;
2759b50d902SRodney W. Grimes 
2769b50d902SRodney W. Grimes 	if (off == 0)
2779b50d902SRodney W. Grimes 		return;
2789b50d902SRodney W. Grimes 	kread(off, (char *)&ipstat, sizeof (ipstat));
2799b50d902SRodney W. Grimes 	printf("%s:\n", name);
2809b50d902SRodney W. Grimes 
2819b50d902SRodney W. Grimes #define	p(f, m) if (ipstat.f || sflag <= 1) \
2829b50d902SRodney W. Grimes     printf(m, ipstat.f, plural(ipstat.f))
2839b50d902SRodney W. Grimes 
2849b50d902SRodney W. Grimes 	p(ips_total, "\t%u total packet%s received\n");
2859b50d902SRodney W. Grimes 	p(ips_badsum, "\t%u bad header checksum%s\n");
2869b50d902SRodney W. Grimes 	p(ips_toosmall, "\t%u with size smaller than minimum\n");
2879b50d902SRodney W. Grimes 	p(ips_tooshort, "\t%u with data size < data length\n");
2889b50d902SRodney W. Grimes 	p(ips_badhlen, "\t%u with header length < data size\n");
2899b50d902SRodney W. Grimes 	p(ips_badlen, "\t%u with data length < header length\n");
2909b50d902SRodney W. Grimes 	p(ips_badoptions, "\t%u with bad options\n");
2919b50d902SRodney W. Grimes 	p(ips_badvers, "\t%u with incorrect version number\n");
2929b50d902SRodney W. Grimes 	p(ips_fragments, "\t%u fragment%s received\n");
2939b50d902SRodney W. Grimes 	p(ips_fragdropped, "\t%u fragment%s dropped (dup or out of space)\n");
2949b50d902SRodney W. Grimes 	p(ips_fragtimeout, "\t%u fragment%s dropped after timeout\n");
2959b50d902SRodney W. Grimes 	p(ips_reassembled, "\t%u packet%s reassembled ok\n");
2969b50d902SRodney W. Grimes 	p(ips_delivered, "\t%u packet%s for this host\n");
2979b50d902SRodney W. Grimes 	p(ips_noproto, "\t%u packet%s for unknown/unsupported protocol\n");
2989b50d902SRodney W. Grimes 	p(ips_forward, "\t%u packet%s forwarded\n");
2999b50d902SRodney W. Grimes 	p(ips_cantforward, "\t%u packet%s not forwardable\n");
3009b50d902SRodney W. Grimes 	p(ips_redirectsent, "\t%u redirect%s sent\n");
3019b50d902SRodney W. Grimes 	p(ips_localout, "\t%u packet%s sent from this host\n");
3029b50d902SRodney W. Grimes 	p(ips_rawout, "\t%u packet%s sent with fabricated ip header\n");
3039b50d902SRodney W. Grimes 	p(ips_odropped, "\t%u output packet%s dropped due to no bufs, etc.\n");
3049b50d902SRodney W. Grimes 	p(ips_noroute, "\t%u output packet%s discarded due to no route\n");
3059b50d902SRodney W. Grimes 	p(ips_fragmented, "\t%u output datagram%s fragmented\n");
3069b50d902SRodney W. Grimes 	p(ips_ofragments, "\t%u fragment%s created\n");
3079b50d902SRodney W. Grimes 	p(ips_cantfrag, "\t%u datagram%s that can't be fragmented\n");
3089b50d902SRodney W. Grimes #undef p
3099b50d902SRodney W. Grimes }
3109b50d902SRodney W. Grimes 
3119b50d902SRodney W. Grimes static	char *icmpnames[] = {
3129b50d902SRodney W. Grimes 	"echo reply",
3139b50d902SRodney W. Grimes 	"#1",
3149b50d902SRodney W. Grimes 	"#2",
3159b50d902SRodney W. Grimes 	"destination unreachable",
3169b50d902SRodney W. Grimes 	"source quench",
3179b50d902SRodney W. Grimes 	"routing redirect",
3189b50d902SRodney W. Grimes 	"#6",
3199b50d902SRodney W. Grimes 	"#7",
3209b50d902SRodney W. Grimes 	"echo",
3219b50d902SRodney W. Grimes 	"#9",
3229b50d902SRodney W. Grimes 	"#10",
3239b50d902SRodney W. Grimes 	"time exceeded",
3249b50d902SRodney W. Grimes 	"parameter problem",
3259b50d902SRodney W. Grimes 	"time stamp",
3269b50d902SRodney W. Grimes 	"time stamp reply",
3279b50d902SRodney W. Grimes 	"information request",
3289b50d902SRodney W. Grimes 	"information request reply",
3299b50d902SRodney W. Grimes 	"address mask request",
3309b50d902SRodney W. Grimes 	"address mask reply",
3319b50d902SRodney W. Grimes };
3329b50d902SRodney W. Grimes 
3339b50d902SRodney W. Grimes /*
3349b50d902SRodney W. Grimes  * Dump ICMP statistics.
3359b50d902SRodney W. Grimes  */
3369b50d902SRodney W. Grimes void
3379b50d902SRodney W. Grimes icmp_stats(off, name)
3389b50d902SRodney W. Grimes 	u_long off;
3399b50d902SRodney W. Grimes 	char *name;
3409b50d902SRodney W. Grimes {
3419b50d902SRodney W. Grimes 	struct icmpstat icmpstat;
3429b50d902SRodney W. Grimes 	register int i, first;
3439b50d902SRodney W. Grimes 
3449b50d902SRodney W. Grimes 	if (off == 0)
3459b50d902SRodney W. Grimes 		return;
3469b50d902SRodney W. Grimes 	kread(off, (char *)&icmpstat, sizeof (icmpstat));
3479b50d902SRodney W. Grimes 	printf("%s:\n", name);
3489b50d902SRodney W. Grimes 
3499b50d902SRodney W. Grimes #define	p(f, m) if (icmpstat.f || sflag <= 1) \
3509b50d902SRodney W. Grimes     printf(m, icmpstat.f, plural(icmpstat.f))
3519b50d902SRodney W. Grimes 
3529b50d902SRodney W. Grimes 	p(icps_error, "\t%u call%s to icmp_error\n");
3539b50d902SRodney W. Grimes 	p(icps_oldicmp,
3549b50d902SRodney W. Grimes 	    "\t%u error%s not generated 'cuz old message was icmp\n");
3559b50d902SRodney W. Grimes 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
3569b50d902SRodney W. Grimes 		if (icmpstat.icps_outhist[i] != 0) {
3579b50d902SRodney W. Grimes 			if (first) {
3589b50d902SRodney W. Grimes 				printf("\tOutput histogram:\n");
3599b50d902SRodney W. Grimes 				first = 0;
3609b50d902SRodney W. Grimes 			}
3619b50d902SRodney W. Grimes 			printf("\t\t%s: %u\n", icmpnames[i],
3629b50d902SRodney W. Grimes 				icmpstat.icps_outhist[i]);
3639b50d902SRodney W. Grimes 		}
3649b50d902SRodney W. Grimes 	p(icps_badcode, "\t%u message%s with bad code fields\n");
3659b50d902SRodney W. Grimes 	p(icps_tooshort, "\t%u message%s < minimum length\n");
3669b50d902SRodney W. Grimes 	p(icps_checksum, "\t%u bad checksum%s\n");
3679b50d902SRodney W. Grimes 	p(icps_badlen, "\t%u message%s with bad length\n");
3689b50d902SRodney W. Grimes 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
3699b50d902SRodney W. Grimes 		if (icmpstat.icps_inhist[i] != 0) {
3709b50d902SRodney W. Grimes 			if (first) {
3719b50d902SRodney W. Grimes 				printf("\tInput histogram:\n");
3729b50d902SRodney W. Grimes 				first = 0;
3739b50d902SRodney W. Grimes 			}
3749b50d902SRodney W. Grimes 			printf("\t\t%s: %u\n", icmpnames[i],
3759b50d902SRodney W. Grimes 				icmpstat.icps_inhist[i]);
3769b50d902SRodney W. Grimes 		}
3779b50d902SRodney W. Grimes 	p(icps_reflect, "\t%u message response%s generated\n");
3789b50d902SRodney W. Grimes #undef p
3799b50d902SRodney W. Grimes }
3809b50d902SRodney W. Grimes 
3819b50d902SRodney W. Grimes /*
3829b50d902SRodney W. Grimes  * Dump IGMP statistics structure.
3839b50d902SRodney W. Grimes  */
3849b50d902SRodney W. Grimes void
3859b50d902SRodney W. Grimes igmp_stats(off, name)
3869b50d902SRodney W. Grimes 	u_long off;
3879b50d902SRodney W. Grimes 	char *name;
3889b50d902SRodney W. Grimes {
3899b50d902SRodney W. Grimes 	struct igmpstat igmpstat;
3909b50d902SRodney W. Grimes 
3919b50d902SRodney W. Grimes 	if (off == 0)
3929b50d902SRodney W. Grimes 		return;
3939b50d902SRodney W. Grimes 	kread(off, (char *)&igmpstat, sizeof (igmpstat));
3949b50d902SRodney W. Grimes 	printf("%s:\n", name);
3959b50d902SRodney W. Grimes 
3969b50d902SRodney W. Grimes #define	p(f, m) if (igmpstat.f || sflag <= 1) \
3979b50d902SRodney W. Grimes     printf(m, igmpstat.f, plural(igmpstat.f))
3989b50d902SRodney W. Grimes #define	py(f, m) if (igmpstat.f || sflag <= 1) \
3999b50d902SRodney W. Grimes     printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
4009b50d902SRodney W. Grimes 	p(igps_rcv_total, "\t%u message%s received\n");
4019b50d902SRodney W. Grimes         p(igps_rcv_tooshort, "\t%u message%s received with too few bytes\n");
4029b50d902SRodney W. Grimes         p(igps_rcv_badsum, "\t%u message%s received with bad checksum\n");
4039b50d902SRodney W. Grimes         py(igps_rcv_queries, "\t%u membership quer%s received\n");
4049b50d902SRodney W. Grimes         py(igps_rcv_badqueries, "\t%u membership quer%s received with invalid field(s)\n");
4059b50d902SRodney W. Grimes         p(igps_rcv_reports, "\t%u membership report%s received\n");
4069b50d902SRodney W. Grimes         p(igps_rcv_badreports, "\t%u membership report%s received with invalid field(s)\n");
4079b50d902SRodney W. Grimes         p(igps_rcv_ourreports, "\t%u membership report%s received for groups to which we belong\n");
4089b50d902SRodney W. Grimes         p(igps_snd_reports, "\t%u membership report%s sent\n");
4099b50d902SRodney W. Grimes #undef p
4109b50d902SRodney W. Grimes #undef py
4119b50d902SRodney W. Grimes }
4129b50d902SRodney W. Grimes 
4139b50d902SRodney W. Grimes /*
4149b50d902SRodney W. Grimes  * Pretty print an Internet address (net address + port).
4159b50d902SRodney W. Grimes  * If the nflag was specified, use numbers instead of names.
4169b50d902SRodney W. Grimes  */
4179b50d902SRodney W. Grimes void
4189b50d902SRodney W. Grimes inetprint(in, port, proto)
4199b50d902SRodney W. Grimes 	register struct in_addr *in;
4209b50d902SRodney W. Grimes 	int port;
4219b50d902SRodney W. Grimes 	char *proto;
4229b50d902SRodney W. Grimes {
4239b50d902SRodney W. Grimes 	struct servent *sp = 0;
4249b50d902SRodney W. Grimes 	char line[80], *cp;
4259b50d902SRodney W. Grimes 	int width;
4269b50d902SRodney W. Grimes 
4279b50d902SRodney W. Grimes 	sprintf(line, "%.*s.", (Aflag && !nflag) ? 12 : 16, inetname(in));
4289b50d902SRodney W. Grimes 	cp = index(line, '\0');
4299b50d902SRodney W. Grimes 	if (!nflag && port)
4309b50d902SRodney W. Grimes 		sp = getservbyport((int)port, proto);
4319b50d902SRodney W. Grimes 	if (sp || port == 0)
4329b50d902SRodney W. Grimes 		sprintf(cp, "%.8s", sp ? sp->s_name : "*");
4339b50d902SRodney W. Grimes 	else
4349b50d902SRodney W. Grimes 		sprintf(cp, "%d", ntohs((u_short)port));
4359b50d902SRodney W. Grimes 	width = Aflag ? 18 : 22;
4369b50d902SRodney W. Grimes 	printf(" %-*.*s", width, width, line);
4379b50d902SRodney W. Grimes }
4389b50d902SRodney W. Grimes 
4399b50d902SRodney W. Grimes /*
4409b50d902SRodney W. Grimes  * Construct an Internet address representation.
4419b50d902SRodney W. Grimes  * If the nflag has been supplied, give
4429b50d902SRodney W. Grimes  * numeric value, otherwise try for symbolic name.
4439b50d902SRodney W. Grimes  */
4449b50d902SRodney W. Grimes char *
4459b50d902SRodney W. Grimes inetname(inp)
4469b50d902SRodney W. Grimes 	struct in_addr *inp;
4479b50d902SRodney W. Grimes {
4489b50d902SRodney W. Grimes 	register char *cp;
4499b50d902SRodney W. Grimes 	static char line[50];
4509b50d902SRodney W. Grimes 	struct hostent *hp;
4519b50d902SRodney W. Grimes 	struct netent *np;
4529b50d902SRodney W. Grimes 	static char domain[MAXHOSTNAMELEN + 1];
4539b50d902SRodney W. Grimes 	static int first = 1;
4549b50d902SRodney W. Grimes 
4559b50d902SRodney W. Grimes 	if (first && !nflag) {
4569b50d902SRodney W. Grimes 		first = 0;
4579b50d902SRodney W. Grimes 		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
4589b50d902SRodney W. Grimes 		    (cp = index(domain, '.')))
4599b50d902SRodney W. Grimes 			(void) strcpy(domain, cp + 1);
4609b50d902SRodney W. Grimes 		else
4619b50d902SRodney W. Grimes 			domain[0] = 0;
4629b50d902SRodney W. Grimes 	}
4639b50d902SRodney W. Grimes 	cp = 0;
4649b50d902SRodney W. Grimes 	if (!nflag && inp->s_addr != INADDR_ANY) {
4659b50d902SRodney W. Grimes 		int net = inet_netof(*inp);
4669b50d902SRodney W. Grimes 		int lna = inet_lnaof(*inp);
4679b50d902SRodney W. Grimes 
4689b50d902SRodney W. Grimes 		if (lna == INADDR_ANY) {
4699b50d902SRodney W. Grimes 			np = getnetbyaddr(net, AF_INET);
4709b50d902SRodney W. Grimes 			if (np)
4719b50d902SRodney W. Grimes 				cp = np->n_name;
4729b50d902SRodney W. Grimes 		}
4739b50d902SRodney W. Grimes 		if (cp == 0) {
4749b50d902SRodney W. Grimes 			hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
4759b50d902SRodney W. Grimes 			if (hp) {
4769b50d902SRodney W. Grimes 				if ((cp = index(hp->h_name, '.')) &&
4779b50d902SRodney W. Grimes 				    !strcmp(cp + 1, domain))
4789b50d902SRodney W. Grimes 					*cp = 0;
4799b50d902SRodney W. Grimes 				cp = hp->h_name;
4809b50d902SRodney W. Grimes 			}
4819b50d902SRodney W. Grimes 		}
4829b50d902SRodney W. Grimes 	}
4839b50d902SRodney W. Grimes 	if (inp->s_addr == INADDR_ANY)
4849b50d902SRodney W. Grimes 		strcpy(line, "*");
4859b50d902SRodney W. Grimes 	else if (cp)
4869b50d902SRodney W. Grimes 		strcpy(line, cp);
4879b50d902SRodney W. Grimes 	else {
4889b50d902SRodney W. Grimes 		inp->s_addr = ntohl(inp->s_addr);
4899b50d902SRodney W. Grimes #define C(x)	((x) & 0xff)
4909b50d902SRodney W. Grimes 		sprintf(line, "%u.%u.%u.%u", C(inp->s_addr >> 24),
4919b50d902SRodney W. Grimes 		    C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
4929b50d902SRodney W. Grimes 	}
4939b50d902SRodney W. Grimes 	return (line);
4949b50d902SRodney W. Grimes }
495