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