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