Home | History | Annotate | Line # | Download | only in netstat
inet.c revision 1.65
      1 /*	$NetBSD: inet.c,v 1.65 2005/08/06 17:58:13 elad Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1983, 1988, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #ifndef lint
     34 #if 0
     35 static char sccsid[] = "from: @(#)inet.c	8.4 (Berkeley) 4/20/94";
     36 #else
     37 __RCSID("$NetBSD: inet.c,v 1.65 2005/08/06 17:58:13 elad Exp $");
     38 #endif
     39 #endif /* not lint */
     40 
     41 #include <sys/param.h>
     42 #include <sys/queue.h>
     43 #include <sys/socket.h>
     44 #include <sys/socketvar.h>
     45 #include <sys/mbuf.h>
     46 #include <sys/protosw.h>
     47 #include <sys/sysctl.h>
     48 
     49 #include <net/if_arp.h>
     50 #include <net/route.h>
     51 #include <netinet/in.h>
     52 #include <netinet/in_systm.h>
     53 #include <netinet/ip.h>
     54 #include <netinet/in_pcb.h>
     55 #include <netinet/ip_icmp.h>
     56 
     57 #ifdef INET6
     58 #include <netinet/ip6.h>
     59 #endif
     60 
     61 #include <netinet/icmp_var.h>
     62 #include <netinet/igmp_var.h>
     63 #include <netinet/ip_var.h>
     64 #include <netinet/pim_var.h>
     65 #include <netinet/tcp.h>
     66 #include <netinet/tcpip.h>
     67 #include <netinet/tcp_seq.h>
     68 #define TCPSTATES
     69 #include <netinet/tcp_fsm.h>
     70 #define	TCPTIMERS
     71 #include <netinet/tcp_timer.h>
     72 #include <netinet/tcp_var.h>
     73 #include <netinet/tcp_debug.h>
     74 #include <netinet/udp.h>
     75 #include <netinet/udp_var.h>
     76 
     77 #include <arpa/inet.h>
     78 #include <kvm.h>
     79 #include <netdb.h>
     80 #include <stdio.h>
     81 #include <string.h>
     82 #include <unistd.h>
     83 #include <err.h>
     84 #include "netstat.h"
     85 
     86 struct	inpcb inpcb;
     87 struct	tcpcb tcpcb;
     88 struct	socket sockb;
     89 
     90 char	*inetname __P((struct in_addr *));
     91 void	inetprint __P((struct in_addr *, u_int16_t, const char *, int));
     92 
     93 /*
     94  * Print a summary of connections related to an Internet
     95  * protocol.  For TCP, also give state of connection.
     96  * Listening processes (aflag) are suppressed unless the
     97  * -a (all) flag is specified.
     98  */
     99 static int width;
    100 
    101 void
    102 protopr(off, name)
    103 	u_long off;
    104 	char *name;
    105 {
    106 	struct inpcbtable table;
    107 	struct inpcb *head, *next, *prev;
    108 	struct inpcb inpcb;
    109 	int istcp, compact;
    110 	static int first = 1;
    111 	static char *shorttcpstates[] = {
    112 		"CLOSED",	"LISTEN",	"SYNSEN",	"SYSRCV",
    113 		"ESTABL",	"CLWAIT",	"FWAIT1",	"CLOSNG",
    114 		"LASTAK",	"FWAIT2",	"TMWAIT",
    115 	};
    116 
    117 	if (off == 0)
    118 		return;
    119 	istcp = strcmp(name, "tcp") == 0;
    120 	kread(off, (char *)&table, sizeof table);
    121 	prev = head =
    122 	    (struct inpcb *)&((struct inpcbtable *)off)->inpt_queue.cqh_first;
    123 	next = (struct inpcb *)table.inpt_queue.cqh_first;
    124 
    125 	compact = 0;
    126 	if (Aflag) {
    127 		if (!numeric_addr)
    128 			width = 18;
    129 		else {
    130 			width = 21;
    131 			compact = 1;
    132 		}
    133 	} else
    134 		width = 22;
    135 	while (next != head) {
    136 		kread((u_long)next, (char *)&inpcb, sizeof inpcb);
    137 		if ((struct inpcb *)inpcb.inp_queue.cqe_prev != prev) {
    138 			printf("???\n");
    139 			break;
    140 		}
    141 		prev = next;
    142 		next = (struct inpcb *)inpcb.inp_queue.cqe_next;
    143 
    144 		if (inpcb.inp_af != AF_INET)
    145 			continue;
    146 
    147 		if (!aflag &&
    148 		    inet_lnaof(inpcb.inp_laddr) == INADDR_ANY)
    149 			continue;
    150 		kread((u_long)inpcb.inp_socket, (char *)&sockb, sizeof (sockb));
    151 		if (istcp) {
    152 			kread((u_long)inpcb.inp_ppcb,
    153 			    (char *)&tcpcb, sizeof (tcpcb));
    154 		}
    155 		if (first) {
    156 			printf("Active Internet connections");
    157 			if (aflag)
    158 				printf(" (including servers)");
    159 			putchar('\n');
    160 			if (Aflag)
    161 				printf("%-8.8s ", "PCB");
    162 			printf("%-5.5s %-6.6s %-6.6s %s%-*.*s %-*.*s %s\n",
    163 				"Proto", "Recv-Q", "Send-Q",
    164 				compact ? "" : " ",
    165 				width, width, "Local Address",
    166 				width, width, "Foreign Address", "State");
    167 			first = 0;
    168 		}
    169 		if (Aflag) {
    170 			if (istcp)
    171 				printf("%8lx ", (u_long) inpcb.inp_ppcb);
    172 			else
    173 				printf("%8lx ", (u_long) prev);
    174 		}
    175 		printf("%-5.5s %6ld %6ld%s", name, sockb.so_rcv.sb_cc,
    176 			sockb.so_snd.sb_cc, compact ? "" : " ");
    177 		if (numeric_port) {
    178 			inetprint(&inpcb.inp_laddr, inpcb.inp_lport, name, 1);
    179 			inetprint(&inpcb.inp_faddr, inpcb.inp_fport, name, 1);
    180 		} else if (inpcb.inp_flags & INP_ANONPORT) {
    181 			inetprint(&inpcb.inp_laddr, inpcb.inp_lport, name, 1);
    182 			inetprint(&inpcb.inp_faddr, inpcb.inp_fport, name, 0);
    183 		} else {
    184 			inetprint(&inpcb.inp_laddr, inpcb.inp_lport, name, 0);
    185 			inetprint(&inpcb.inp_faddr, inpcb.inp_fport, name, 0);
    186 		}
    187 		if (istcp) {
    188 			if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES)
    189 				printf(" %d", tcpcb.t_state);
    190 			else
    191 				printf(" %s", compact ?
    192 				    shorttcpstates[tcpcb.t_state] :
    193 				    tcpstates[tcpcb.t_state]);
    194 		}
    195 		putchar('\n');
    196 	}
    197 }
    198 
    199 /*
    200  * Dump TCP statistics structure.
    201  */
    202 void
    203 tcp_stats(off, name)
    204 	u_long off;
    205 	char *name;
    206 {
    207 	struct tcpstat tcpstat;
    208 
    209 	if (use_sysctl) {
    210 		size_t size = sizeof(tcpstat);
    211 
    212 		if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &size,
    213 				 NULL, 0) == -1)
    214 			err(1, "net.inet.tcp.stats");
    215 	} else {
    216 		if (off == 0)
    217 			return;
    218 		kread(off, (char *)&tcpstat, sizeof (tcpstat));
    219 	}
    220 
    221 	printf ("%s:\n", name);
    222 
    223 #define	ps(f, m) if (tcpstat.f || sflag <= 1) \
    224     printf(m, (unsigned long long)tcpstat.f)
    225 #define	p(f, m) if (tcpstat.f || sflag <= 1) \
    226     printf(m, (unsigned long long)tcpstat.f, plural(tcpstat.f))
    227 #define	p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
    228     printf(m, (unsigned long long)tcpstat.f1, plural(tcpstat.f1), \
    229     (unsigned long long)tcpstat.f2, plural(tcpstat.f2))
    230 #define	p2s(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
    231     printf(m, (unsigned long long)tcpstat.f1, plural(tcpstat.f1), \
    232     (unsigned long long)tcpstat.f2)
    233 #define	p3(f, m) if (tcpstat.f || sflag <= 1) \
    234     printf(m, (unsigned long long)tcpstat.f, plurales(tcpstat.f))
    235 
    236 	p(tcps_sndtotal, "\t%llu packet%s sent\n");
    237 	p2(tcps_sndpack,tcps_sndbyte,
    238 		"\t\t%llu data packet%s (%llu byte%s)\n");
    239 	p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
    240 		"\t\t%llu data packet%s (%llu byte%s) retransmitted\n");
    241 	p2s(tcps_sndacks, tcps_delack,
    242 		"\t\t%llu ack-only packet%s (%llu delayed)\n");
    243 	p(tcps_sndurg, "\t\t%llu URG only packet%s\n");
    244 	p(tcps_sndprobe, "\t\t%llu window probe packet%s\n");
    245 	p(tcps_sndwinup, "\t\t%llu window update packet%s\n");
    246 	p(tcps_sndctrl, "\t\t%llu control packet%s\n");
    247 	p(tcps_selfquench,
    248 	    "\t\t%llu send attempt%s resulted in self-quench\n");
    249 	p(tcps_rcvtotal, "\t%llu packet%s received\n");
    250 	p2(tcps_rcvackpack, tcps_rcvackbyte,
    251 		"\t\t%llu ack%s (for %llu byte%s)\n");
    252 	p(tcps_rcvdupack, "\t\t%llu duplicate ack%s\n");
    253 	p(tcps_rcvacktoomuch, "\t\t%llu ack%s for unsent data\n");
    254 	p2(tcps_rcvpack, tcps_rcvbyte,
    255 		"\t\t%llu packet%s (%llu byte%s) received in-sequence\n");
    256 	p2(tcps_rcvduppack, tcps_rcvdupbyte,
    257 		"\t\t%llu completely duplicate packet%s (%llu byte%s)\n");
    258 	p(tcps_pawsdrop, "\t\t%llu old duplicate packet%s\n");
    259 	p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
    260 		"\t\t%llu packet%s with some dup. data (%llu byte%s duped)\n");
    261 	p2(tcps_rcvoopack, tcps_rcvoobyte,
    262 		"\t\t%llu out-of-order packet%s (%llu byte%s)\n");
    263 	p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
    264 		"\t\t%llu packet%s (%llu byte%s) of data after window\n");
    265 	p(tcps_rcvwinprobe, "\t\t%llu window probe%s\n");
    266 	p(tcps_rcvwinupd, "\t\t%llu window update packet%s\n");
    267 	p(tcps_rcvafterclose, "\t\t%llu packet%s received after close\n");
    268 	p(tcps_rcvbadsum, "\t\t%llu discarded for bad checksum%s\n");
    269 	p(tcps_rcvbadoff, "\t\t%llu discarded for bad header offset field%s\n");
    270 	ps(tcps_rcvshort, "\t\t%llu discarded because packet too short\n");
    271 	p(tcps_connattempt, "\t%llu connection request%s\n");
    272 	p(tcps_accepts, "\t%llu connection accept%s\n");
    273 	p(tcps_connects,
    274 		"\t%llu connection%s established (including accepts)\n");
    275 	p2(tcps_closed, tcps_drops,
    276 		"\t%llu connection%s closed (including %llu drop%s)\n");
    277 	p(tcps_conndrops, "\t%llu embryonic connection%s dropped\n");
    278 	p(tcps_delayed_free, "\t%llu delayed free%s of tcpcb\n");
    279 	p2(tcps_rttupdated, tcps_segstimed,
    280 		"\t%llu segment%s updated rtt (of %llu attempt%s)\n");
    281 	p(tcps_rexmttimeo, "\t%llu retransmit timeout%s\n");
    282 	p(tcps_timeoutdrop,
    283 		"\t\t%llu connection%s dropped by rexmit timeout\n");
    284 	p2(tcps_persisttimeo, tcps_persistdrops,
    285 	   "\t%llu persist timeout%s (resulting in %llu dropped "
    286 		"connection%s)\n");
    287 	p(tcps_keeptimeo, "\t%llu keepalive timeout%s\n");
    288 	p(tcps_keepprobe, "\t\t%llu keepalive probe%s sent\n");
    289 	p(tcps_keepdrops, "\t\t%llu connection%s dropped by keepalive\n");
    290 	p(tcps_predack, "\t%llu correct ACK header prediction%s\n");
    291 	p(tcps_preddat, "\t%llu correct data packet header prediction%s\n");
    292 	p3(tcps_pcbhashmiss, "\t%llu PCB hash miss%s\n");
    293 	ps(tcps_noport, "\t%llu dropped due to no socket\n");
    294 	p(tcps_connsdrained, "\t%llu connection%s drained due to memory "
    295 		"shortage\n");
    296 	p(tcps_pmtublackhole, "\t%llu PMTUD blackhole%s detected\n");
    297 
    298 	p(tcps_badsyn, "\t%llu bad connection attempt%s\n");
    299 	ps(tcps_sc_added, "\t%llu SYN cache entries added\n");
    300 	p(tcps_sc_collisions, "\t\t%llu hash collision%s\n");
    301 	ps(tcps_sc_completed, "\t\t%llu completed\n");
    302 	ps(tcps_sc_aborted, "\t\t%llu aborted (no space to build PCB)\n");
    303 	ps(tcps_sc_timed_out, "\t\t%llu timed out\n");
    304 	ps(tcps_sc_overflowed, "\t\t%llu dropped due to overflow\n");
    305 	ps(tcps_sc_bucketoverflow, "\t\t%llu dropped due to bucket overflow\n");
    306 	ps(tcps_sc_reset, "\t\t%llu dropped due to RST\n");
    307 	ps(tcps_sc_unreach, "\t\t%llu dropped due to ICMP unreachable\n");
    308 	ps(tcps_sc_delayed_free, "\t\t%llu delayed free of SYN cache "
    309 		"entries\n");
    310 	p(tcps_sc_retransmitted, "\t%llu SYN,ACK%s retransmitted\n");
    311 	p(tcps_sc_dupesyn, "\t%llu duplicate SYN%s received for entries "
    312 		"already in the cache\n");
    313 	p(tcps_sc_dropped, "\t%llu SYN%s dropped (no route or no space)\n");
    314 	p(tcps_badsig, "\t%llu packet%s with bad signature\n");
    315 	p(tcps_goodsig, "\t%llu packet%s with good signature\n");
    316 
    317 #undef p
    318 #undef ps
    319 #undef p2
    320 #undef p2s
    321 #undef p3
    322 }
    323 
    324 /*
    325  * Dump UDP statistics structure.
    326  */
    327 void
    328 udp_stats(off, name)
    329 	u_long off;
    330 	char *name;
    331 {
    332 	struct udpstat udpstat;
    333 	u_quad_t delivered;
    334 
    335 	if (use_sysctl) {
    336 		size_t size = sizeof(udpstat);
    337 
    338 		if (sysctlbyname("net.inet.udp.stats", &udpstat, &size,
    339 				 NULL, 0) == -1)
    340 			err(1, "net.inet.udp.stats");
    341 	} else {
    342 		if (off == 0)
    343 			return;
    344 		kread(off, (char *)&udpstat, sizeof (udpstat));
    345 	}
    346 
    347 	printf ("%s:\n", name);
    348 
    349 #define	ps(f, m) if (udpstat.f || sflag <= 1) \
    350     printf(m, (unsigned long long)udpstat.f)
    351 #define	p(f, m) if (udpstat.f || sflag <= 1) \
    352     printf(m, (unsigned long long)udpstat.f, plural(udpstat.f))
    353 #define	p3(f, m) if (udpstat.f || sflag <= 1) \
    354     printf(m, (unsigned long long)udpstat.f, plurales(udpstat.f))
    355 
    356 	p(udps_ipackets, "\t%llu datagram%s received\n");
    357 	ps(udps_hdrops, "\t%llu with incomplete header\n");
    358 	ps(udps_badlen, "\t%llu with bad data length field\n");
    359 	ps(udps_badsum, "\t%llu with bad checksum\n");
    360 	ps(udps_noport, "\t%llu dropped due to no socket\n");
    361 	p(udps_noportbcast, "\t%llu broadcast/multicast datagram%s dropped due to no socket\n");
    362 	ps(udps_fullsock, "\t%llu dropped due to full socket buffers\n");
    363 	delivered = udpstat.udps_ipackets -
    364 		    udpstat.udps_hdrops -
    365 		    udpstat.udps_badlen -
    366 		    udpstat.udps_badsum -
    367 		    udpstat.udps_noport -
    368 		    udpstat.udps_noportbcast -
    369 		    udpstat.udps_fullsock;
    370 	if (delivered || sflag <= 1)
    371 		printf("\t%llu delivered\n", (unsigned long long)delivered);
    372 	p3(udps_pcbhashmiss, "\t%llu PCB hash miss%s\n");
    373 	p(udps_opackets, "\t%llu datagram%s output\n");
    374 
    375 #undef ps
    376 #undef p
    377 #undef p3
    378 }
    379 
    380 /*
    381  * Dump IP statistics structure.
    382  */
    383 void
    384 ip_stats(off, name)
    385 	u_long off;
    386 	char *name;
    387 {
    388 	struct ipstat ipstat;
    389 
    390 	if (use_sysctl) {
    391 		size_t size = sizeof(ipstat);
    392 
    393 		if (sysctlbyname("net.inet.ip.stats", &ipstat, &size,
    394 				 NULL, 0) == -1)
    395 			err(1, "net.inet.ip.stats");
    396 	} else {
    397 		if (off == 0)
    398 			return;
    399 		kread(off, (char *)&ipstat, sizeof (ipstat));
    400 	}
    401 
    402 	printf("%s:\n", name);
    403 
    404 #define	ps(f, m) if (ipstat.f || sflag <= 1) \
    405     printf(m, (unsigned long long)ipstat.f)
    406 #define	p(f, m) if (ipstat.f || sflag <= 1) \
    407     printf(m, (unsigned long long)ipstat.f, plural(ipstat.f))
    408 
    409 	p(ips_total, "\t%llu total packet%s received\n");
    410 	p(ips_badsum, "\t%llu bad header checksum%s\n");
    411 	ps(ips_toosmall, "\t%llu with size smaller than minimum\n");
    412 	ps(ips_tooshort, "\t%llu with data size < data length\n");
    413 	ps(ips_toolong, "\t%llu with length > max ip packet size\n");
    414 	ps(ips_badhlen, "\t%llu with header length < data size\n");
    415 	ps(ips_badlen, "\t%llu with data length < header length\n");
    416 	ps(ips_badoptions, "\t%llu with bad options\n");
    417 	ps(ips_badvers, "\t%llu with incorrect version number\n");
    418 	p(ips_fragments, "\t%llu fragment%s received\n");
    419 	p(ips_fragdropped, "\t%llu fragment%s dropped (dup or out of space)\n");
    420 	p(ips_rcvmemdrop, "\t%llu fragment%s dropped (out of ipqent)\n");
    421 	p(ips_badfrags, "\t%llu malformed fragment%s dropped\n");
    422 	p(ips_fragtimeout, "\t%llu fragment%s dropped after timeout\n");
    423 	p(ips_reassembled, "\t%llu packet%s reassembled ok\n");
    424 	p(ips_delivered, "\t%llu packet%s for this host\n");
    425 	p(ips_noproto, "\t%llu packet%s for unknown/unsupported protocol\n");
    426 	p(ips_forward, "\t%llu packet%s forwarded");
    427 	p(ips_fastforward, " (%llu packet%s fast forwarded)");
    428 	if (ipstat.ips_forward || sflag <= 1)
    429 		putchar('\n');
    430 	p(ips_cantforward, "\t%llu packet%s not forwardable\n");
    431 	p(ips_redirectsent, "\t%llu redirect%s sent\n");
    432 	p(ips_nogif, "\t%llu packet%s no matching gif found\n");
    433 	p(ips_localout, "\t%llu packet%s sent from this host\n");
    434 	p(ips_rawout, "\t%llu packet%s sent with fabricated ip header\n");
    435 	p(ips_odropped, "\t%llu output packet%s dropped due to no bufs, etc.\n");
    436 	p(ips_noroute, "\t%llu output packet%s discarded due to no route\n");
    437 	p(ips_fragmented, "\t%llu output datagram%s fragmented\n");
    438 	p(ips_ofragments, "\t%llu fragment%s created\n");
    439 	p(ips_cantfrag, "\t%llu datagram%s that can't be fragmented\n");
    440 	p(ips_badaddr, "\t%llu datagram%s with bad address in header\n");
    441 #undef ps
    442 #undef p
    443 }
    444 
    445 static	char *icmpnames[] = {
    446 	"echo reply",
    447 	"#1",
    448 	"#2",
    449 	"destination unreachable",
    450 	"source quench",
    451 	"routing redirect",
    452 	"alternate host address",
    453 	"#7",
    454 	"echo",
    455 	"router advertisement",
    456 	"router solicitation",
    457 	"time exceeded",
    458 	"parameter problem",
    459 	"time stamp",
    460 	"time stamp reply",
    461 	"information request",
    462 	"information request reply",
    463 	"address mask request",
    464 	"address mask reply",
    465 };
    466 
    467 /*
    468  * Dump ICMP statistics.
    469  */
    470 void
    471 icmp_stats(off, name)
    472 	u_long off;
    473 	char *name;
    474 {
    475 	struct icmpstat icmpstat;
    476 	int i, first;
    477 
    478 	if (use_sysctl) {
    479 		size_t size = sizeof(icmpstat);
    480 
    481 		if (sysctlbyname("net.inet.icmp.stats", &icmpstat, &size,
    482 				 NULL, 0) == -1)
    483 			err(1, "net.inet.icmp.stats");
    484 	} else {
    485 		if (off == 0)
    486 			return;
    487 		kread(off, (char *)&icmpstat, sizeof (icmpstat));
    488 	}
    489 
    490 	printf("%s:\n", name);
    491 
    492 #define	p(f, m) if (icmpstat.f || sflag <= 1) \
    493     printf(m, (unsigned long long)icmpstat.f, plural(icmpstat.f))
    494 
    495 	p(icps_error, "\t%llu call%s to icmp_error\n");
    496 	p(icps_oldicmp,
    497 	    "\t%llu error%s not generated because old message was icmp\n");
    498 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
    499 		if (icmpstat.icps_outhist[i] != 0) {
    500 			if (first) {
    501 				printf("\tOutput histogram:\n");
    502 				first = 0;
    503 			}
    504 			printf("\t\t%s: %llu\n", icmpnames[i],
    505 				(unsigned long long)icmpstat.icps_outhist[i]);
    506 		}
    507 	p(icps_badcode, "\t%llu message%s with bad code fields\n");
    508 	p(icps_tooshort, "\t%llu message%s < minimum length\n");
    509 	p(icps_checksum, "\t%llu bad checksum%s\n");
    510 	p(icps_badlen, "\t%llu message%s with bad length\n");
    511 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
    512 		if (icmpstat.icps_inhist[i] != 0) {
    513 			if (first) {
    514 				printf("\tInput histogram:\n");
    515 				first = 0;
    516 			}
    517 			printf("\t\t%s: %llu\n", icmpnames[i],
    518 				(unsigned long long)icmpstat.icps_inhist[i]);
    519 		}
    520 	p(icps_reflect, "\t%llu message response%s generated\n");
    521 	p(icps_pmtuchg, "\t%llu path MTU change%s\n");
    522 #undef p
    523 }
    524 
    525 /*
    526  * Dump IGMP statistics structure.
    527  */
    528 void
    529 igmp_stats(off, name)
    530 	u_long off;
    531 	char *name;
    532 {
    533 	struct igmpstat igmpstat;
    534 
    535 	if (off == 0)
    536 		return;
    537 	kread(off, (char *)&igmpstat, sizeof (igmpstat));
    538 	printf("%s:\n", name);
    539 
    540 #define	p(f, m) if (igmpstat.f || sflag <= 1) \
    541     printf(m, (unsigned long long)igmpstat.f, plural(igmpstat.f))
    542 #define	py(f, m) if (igmpstat.f || sflag <= 1) \
    543     printf(m, (unsigned long long)igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
    544 	p(igps_rcv_total, "\t%llu message%s received\n");
    545         p(igps_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
    546         p(igps_rcv_badsum, "\t%llu message%s received with bad checksum\n");
    547         py(igps_rcv_queries, "\t%llu membership quer%s received\n");
    548         py(igps_rcv_badqueries, "\t%llu membership quer%s received with invalid field(s)\n");
    549         p(igps_rcv_reports, "\t%llu membership report%s received\n");
    550         p(igps_rcv_badreports, "\t%llu membership report%s received with invalid field(s)\n");
    551         p(igps_rcv_ourreports, "\t%llu membership report%s received for groups to which we belong\n");
    552         p(igps_snd_reports, "\t%llu membership report%s sent\n");
    553 #undef p
    554 #undef py
    555 }
    556 
    557 /*
    558  * Dump PIM statistics structure.
    559  */
    560 void
    561 pim_stats(off, name)
    562 	u_long off;
    563 	char *name;
    564 {
    565 	struct pimstat pimstat;
    566 
    567 	if (off == 0)
    568 		return;
    569 	if (kread(off, (char *)&pimstat, sizeof (pimstat)) != 0) {
    570 		/* XXX: PIM is probably not enabled in the kernel */
    571 		return;
    572 	}
    573 
    574 	printf("%s:\n", name);
    575 
    576 #define	p(f, m) if (pimstat.f || sflag <= 1) \
    577 	printf(m, (unsigned long long)pimstat.f, plural(pimstat.f))
    578 
    579 	p(pims_rcv_total_msgs, "\t%llu message%s received\n");
    580 	p(pims_rcv_total_bytes, "\t%llu byte%s received\n");
    581 	p(pims_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
    582         p(pims_rcv_badsum, "\t%llu message%s received with bad checksum\n");
    583 	p(pims_rcv_badversion, "\t%llu message%s received with bad version\n");
    584 	p(pims_rcv_registers_msgs, "\t%llu data register message%s received\n");
    585 	p(pims_rcv_registers_bytes, "\t%llu data register byte%s received\n");
    586 	p(pims_rcv_registers_wrongiif, "\t%llu data register message%s received on wrong iif\n");
    587 	p(pims_rcv_badregisters, "\t%llu bad register%s received\n");
    588 	p(pims_snd_registers_msgs, "\t%llu data register message%s sent\n");
    589 	p(pims_snd_registers_bytes, "\t%llu data register byte%s sent\n");
    590 #undef p
    591 }
    592 
    593 /*
    594  * Dump the ARP statistics structure.
    595  */
    596 void
    597 arp_stats(off, name)
    598 	u_long off;
    599 	char *name;
    600 {
    601 	struct arpstat arpstat;
    602 
    603 	if (off == 0)
    604 		return;
    605 	kread(off, (char *)&arpstat, sizeof (arpstat));
    606 	printf("%s:\n", name);
    607 
    608 #define	ps(f, m) if (arpstat.f || sflag <= 1) \
    609     printf(m, (unsigned long long)arpstat.f)
    610 #define	p(f, m) if (arpstat.f || sflag <= 1) \
    611     printf(m, (unsigned long long)arpstat.f, plural(arpstat.f))
    612 
    613 	p(as_sndtotal, "\t%llu packet%s sent\n");
    614 	p(as_sndreply, "\t\t%llu reply packet%s\n");
    615 	p(as_sndrequest, "\t\t%llu request packet%s\n");
    616 
    617 	p(as_rcvtotal, "\t%llu packet%s received\n");
    618 	p(as_rcvreply, "\t\t%llu reply packet%s\n");
    619 	p(as_rcvrequest, "\t\t%llu valid request packet%s\n");
    620 	p(as_rcvmcast, "\t\t%llu broadcast/multicast packet%s\n");
    621 	p(as_rcvbadproto, "\t\t%llu packet%s with unknown protocol type\n");
    622 	p(as_rcvbadlen, "\t\t%llu packet%s with bad (short) length\n");
    623 	p(as_rcvzerotpa, "\t\t%llu packet%s with null target IP address\n");
    624 	p(as_rcvzerospa, "\t\t%llu packet%s with null source IP address\n");
    625 	ps(as_rcvnoint, "\t\t%llu could not be mapped to an interface\n");
    626 	p(as_rcvlocalsha, "\t\t%llu packet%s sourced from a local hardware "
    627 	    "address\n");
    628 	p(as_rcvbcastsha, "\t\t%llu packet%s with a broadcast "
    629 	    "source hardware address\n");
    630 	p(as_rcvlocalspa, "\t\t%llu duplicate%s for a local IP address\n");
    631 	p(as_rcvoverperm, "\t\t%llu attempt%s to overwrite a static entry\n");
    632 	p(as_rcvoverint, "\t\t%llu packet%s received on wrong interface\n");
    633 	p(as_rcvover, "\t\t%llu entry%s overwritten\n");
    634 	p(as_rcvlenchg, "\t\t%llu change%s in hardware address length\n");
    635 
    636 	p(as_dfrtotal, "\t%llu packet%s deferred pending ARP resolution\n");
    637 	ps(as_dfrsent, "\t\t%llu sent\n");
    638 	ps(as_dfrdropped, "\t\t%llu dropped\n");
    639 
    640 	p(as_allocfail, "\t%llu failure%s to allocate llinfo\n");
    641 
    642 #undef ps
    643 #undef p
    644 }
    645 
    646 /*
    647  * Pretty print an Internet address (net address + port).
    648  * Take numeric_addr and numeric_port into consideration.
    649  */
    650 void
    651 inetprint(in, port, proto, numeric_port)
    652 	struct in_addr *in;
    653 	u_int16_t port;
    654 	const char *proto;
    655 	int numeric_port;
    656 {
    657 	struct servent *sp = 0;
    658 	char line[80], *cp;
    659 	size_t space;
    660 
    661 	(void)snprintf(line, sizeof line, "%.*s.",
    662 	    (Aflag && !numeric_addr) ? 12 : 16, inetname(in));
    663 	cp = strchr(line, '\0');
    664 	if (!numeric_port && port)
    665 		sp = getservbyport((int)port, proto);
    666 	space = sizeof line - (cp-line);
    667 	if (sp || port == 0)
    668 		(void)snprintf(cp, space, "%s", sp ? sp->s_name : "*");
    669 	else
    670 		(void)snprintf(cp, space, "%u", ntohs(port));
    671 	(void)printf(" %-*.*s", width, width, line);
    672 }
    673 
    674 /*
    675  * Construct an Internet address representation.
    676  * If numeric_addr has been supplied, give
    677  * numeric value, otherwise try for symbolic name.
    678  */
    679 char *
    680 inetname(inp)
    681 	struct in_addr *inp;
    682 {
    683 	char *cp;
    684 	static char line[50];
    685 	struct hostent *hp;
    686 	struct netent *np;
    687 	static char domain[MAXHOSTNAMELEN + 1];
    688 	static int first = 1;
    689 
    690 	if (first && !numeric_addr) {
    691 		first = 0;
    692 		if (gethostname(domain, sizeof domain) == 0) {
    693 			domain[sizeof(domain) - 1] = '\0';
    694 			if ((cp = strchr(domain, '.')))
    695 				(void) strlcpy(domain, cp + 1, sizeof(domain));
    696 			else
    697 				domain[0] = 0;
    698 		} else
    699 			domain[0] = 0;
    700 	}
    701 	cp = 0;
    702 	if (!numeric_addr && inp->s_addr != INADDR_ANY) {
    703 		int net = inet_netof(*inp);
    704 		int lna = inet_lnaof(*inp);
    705 
    706 		if (lna == INADDR_ANY) {
    707 			np = getnetbyaddr(net, AF_INET);
    708 			if (np)
    709 				cp = np->n_name;
    710 		}
    711 		if (cp == 0) {
    712 			hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
    713 			if (hp) {
    714 				if ((cp = strchr(hp->h_name, '.')) &&
    715 				    !strcmp(cp + 1, domain))
    716 					*cp = 0;
    717 				cp = hp->h_name;
    718 			}
    719 		}
    720 	}
    721 	if (inp->s_addr == INADDR_ANY)
    722 		strlcpy(line, "*", sizeof line);
    723 	else if (cp)
    724 		strlcpy(line, cp, sizeof line);
    725 	else {
    726 		inp->s_addr = ntohl(inp->s_addr);
    727 #define C(x)	((x) & 0xff)
    728 		(void)snprintf(line, sizeof line, "%u.%u.%u.%u",
    729 		    C(inp->s_addr >> 24), C(inp->s_addr >> 16),
    730 		    C(inp->s_addr >> 8), C(inp->s_addr));
    731 #undef C
    732 	}
    733 	return (line);
    734 }
    735 
    736 /*
    737  * Dump the contents of a TCP PCB.
    738  */
    739 void
    740 tcp_dump(pcbaddr)
    741 	u_long pcbaddr;
    742 {
    743 	struct tcpcb tcpcb;
    744 	int i, hardticks;
    745 
    746 	kread(pcbaddr, (char *)&tcpcb, sizeof(tcpcb));
    747 	hardticks = get_hardticks();
    748 
    749 	printf("TCP Protocol Control Block at 0x%08lx:\n\n", pcbaddr);
    750 
    751 	printf("Timers:\n");
    752 	for (i = 0; i < TCPT_NTIMERS; i++) {
    753 		printf("\t%s: %d", tcptimers[i],
    754 		    (tcpcb.t_timer[i].c_flags & CALLOUT_PENDING) ?
    755 		    tcpcb.t_timer[i].c_time - hardticks : 0);
    756 	}
    757 	printf("\n\n");
    758 
    759 	if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES)
    760 		printf("State: %d", tcpcb.t_state);
    761 	else
    762 		printf("State: %s", tcpstates[tcpcb.t_state]);
    763 	printf(", flags 0x%x, inpcb 0x%lx, in6pcb 0x%lx\n\n", tcpcb.t_flags,
    764 	    (u_long)tcpcb.t_inpcb, (u_long)tcpcb.t_in6pcb);
    765 
    766 	printf("rxtshift %d, rxtcur %d, dupacks %d\n", tcpcb.t_rxtshift,
    767 	    tcpcb.t_rxtcur, tcpcb.t_dupacks);
    768 	printf("peermss %u, ourmss %u, segsz %u\n\n", tcpcb.t_peermss,
    769 	    tcpcb.t_ourmss, tcpcb.t_segsz);
    770 
    771 	printf("snd_una %u, snd_nxt %u, snd_up %u\n",
    772 	    tcpcb.snd_una, tcpcb.snd_nxt, tcpcb.snd_up);
    773 	printf("snd_wl1 %u, snd_wl2 %u, iss %u, snd_wnd %lu\n\n",
    774 	    tcpcb.snd_wl1, tcpcb.snd_wl2, tcpcb.iss, tcpcb.snd_wnd);
    775 
    776 	printf("rcv_wnd %lu, rcv_nxt %u, rcv_up %u, irs %u\n\n",
    777 	    tcpcb.rcv_wnd, tcpcb.rcv_nxt, tcpcb.rcv_up, tcpcb.irs);
    778 
    779 	printf("rcv_adv %u, snd_max %u, snd_cwnd %lu, snd_ssthresh %lu\n",
    780 	    tcpcb.rcv_adv, tcpcb.snd_max, tcpcb.snd_cwnd, tcpcb.snd_ssthresh);
    781 
    782 	printf("rcvtime %u, rtttime %u, rtseq %u, srtt %d, rttvar %d, "
    783 	    "rttmin %d, max_sndwnd %lu\n\n", tcpcb.t_rcvtime, tcpcb.t_rtttime,
    784 	    tcpcb.t_rtseq, tcpcb.t_srtt, tcpcb.t_rttvar, tcpcb.t_rttmin,
    785 	    tcpcb.max_sndwnd);
    786 
    787 	printf("oobflags %d, iobc %d, softerror %d\n\n", tcpcb.t_oobflags,
    788 	    tcpcb.t_iobc, tcpcb.t_softerror);
    789 
    790 	printf("snd_scale %d, rcv_scale %d, req_r_scale %d, req_s_scale %d\n",
    791 	    tcpcb.snd_scale, tcpcb.rcv_scale, tcpcb.request_r_scale,
    792 	    tcpcb.requested_s_scale);
    793 	printf("ts_recent %u, ts_regent_age %d, last_ack_sent %u\n",
    794 	    tcpcb.ts_recent, tcpcb.ts_recent_age, tcpcb.last_ack_sent);
    795 }
    796