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