xref: /netbsd-src/usr.bin/netstat/inet.c (revision 8e6ab8837d8d6b9198e67c1c445300b483e2f304)
1 /*	$NetBSD: inet.c,v 1.57 2003/07/20 16:35:11 he 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. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "from: @(#)inet.c	8.4 (Berkeley) 4/20/94";
40 #else
41 __RCSID("$NetBSD: inet.c,v 1.57 2003/07/20 16:35:11 he Exp $");
42 #endif
43 #endif /* not lint */
44 
45 #include <sys/param.h>
46 #include <sys/queue.h>
47 #include <sys/socket.h>
48 #include <sys/socketvar.h>
49 #include <sys/mbuf.h>
50 #include <sys/protosw.h>
51 
52 #include <net/if_arp.h>
53 #include <net/route.h>
54 #include <netinet/in.h>
55 #include <netinet/in_systm.h>
56 #include <netinet/ip.h>
57 #include <netinet/in_pcb.h>
58 #include <netinet/ip_icmp.h>
59 
60 #ifdef INET6
61 #include <netinet/ip6.h>
62 #endif
63 
64 #include <netinet/icmp_var.h>
65 #include <netinet/igmp_var.h>
66 #include <netinet/ip_var.h>
67 #include <netinet/tcp.h>
68 #include <netinet/tcpip.h>
69 #include <netinet/tcp_seq.h>
70 #define TCPSTATES
71 #include <netinet/tcp_fsm.h>
72 #define	TCPTIMERS
73 #include <netinet/tcp_timer.h>
74 #include <netinet/tcp_var.h>
75 #include <netinet/tcp_debug.h>
76 #include <netinet/udp.h>
77 #include <netinet/udp_var.h>
78 
79 #include <arpa/inet.h>
80 #include <netdb.h>
81 #include <stdio.h>
82 #include <string.h>
83 #include <unistd.h>
84 #include "netstat.h"
85 
86 struct	inpcb inpcb;
87 struct	tcpcb tcpcb;
88 struct	socket sockb;
89 
90 char	*inetname __P((struct in_addr *));
91 void	inetprint __P((struct in_addr *, u_int16_t, const char *, int));
92 
93 /*
94  * Print a summary of connections related to an Internet
95  * protocol.  For TCP, also give state of connection.
96  * Listening processes (aflag) are suppressed unless the
97  * -a (all) flag is specified.
98  */
99 static int width;
100 
101 void
102 protopr(off, name)
103 	u_long off;
104 	char *name;
105 {
106 	struct inpcbtable table;
107 	struct inpcb *head, *next, *prev;
108 	struct inpcb inpcb;
109 	int istcp, compact;
110 	static int first = 1;
111 	static char *shorttcpstates[] = {
112 		"CLOSED",	"LISTEN",	"SYNSEN",	"SYSRCV",
113 		"ESTABL",	"CLWAIT",	"FWAIT1",	"CLOSNG",
114 		"LASTAK",	"FWAIT2",	"TMWAIT",
115 	};
116 
117 	if (off == 0)
118 		return;
119 	istcp = strcmp(name, "tcp") == 0;
120 	kread(off, (char *)&table, sizeof table);
121 	prev = head =
122 	    (struct inpcb *)&((struct inpcbtable *)off)->inpt_queue.cqh_first;
123 	next = table.inpt_queue.cqh_first;
124 
125 	compact = 0;
126 	if (Aflag) {
127 		if (!numeric_addr)
128 			width = 18;
129 		else {
130 			width = 21;
131 			compact = 1;
132 		}
133 	} else
134 		width = 22;
135 	while (next != head) {
136 		kread((u_long)next, (char *)&inpcb, sizeof inpcb);
137 		if (inpcb.inp_queue.cqe_prev != prev) {
138 			printf("???\n");
139 			break;
140 		}
141 		prev = next;
142 		next = inpcb.inp_queue.cqe_next;
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 
303 #undef p
304 #undef ps
305 #undef p2
306 #undef p2s
307 #undef p3
308 }
309 
310 /*
311  * Dump UDP statistics structure.
312  */
313 void
314 udp_stats(off, name)
315 	u_long off;
316 	char *name;
317 {
318 	struct udpstat udpstat;
319 	u_quad_t delivered;
320 
321 	if (off == 0)
322 		return;
323 	printf("%s:\n", name);
324 	kread(off, (char *)&udpstat, sizeof (udpstat));
325 
326 #define	ps(f, m) if (udpstat.f || sflag <= 1) \
327     printf(m, (unsigned long long)udpstat.f)
328 #define	p(f, m) if (udpstat.f || sflag <= 1) \
329     printf(m, (unsigned long long)udpstat.f, plural(udpstat.f))
330 #define	p3(f, m) if (udpstat.f || sflag <= 1) \
331     printf(m, (unsigned long long)udpstat.f, plurales(udpstat.f))
332 
333 	p(udps_ipackets, "\t%llu datagram%s received\n");
334 	ps(udps_hdrops, "\t%llu with incomplete header\n");
335 	ps(udps_badlen, "\t%llu with bad data length field\n");
336 	ps(udps_badsum, "\t%llu with bad checksum\n");
337 	ps(udps_noport, "\t%llu dropped due to no socket\n");
338 	p(udps_noportbcast, "\t%llu broadcast/multicast datagram%s dropped due to no socket\n");
339 	ps(udps_fullsock, "\t%llu dropped due to full socket buffers\n");
340 	delivered = udpstat.udps_ipackets -
341 		    udpstat.udps_hdrops -
342 		    udpstat.udps_badlen -
343 		    udpstat.udps_badsum -
344 		    udpstat.udps_noport -
345 		    udpstat.udps_noportbcast -
346 		    udpstat.udps_fullsock;
347 	if (delivered || sflag <= 1)
348 		printf("\t%llu delivered\n", (unsigned long long)delivered);
349 	p3(udps_pcbhashmiss, "\t%llu PCB hash miss%s\n");
350 	p(udps_opackets, "\t%llu datagram%s output\n");
351 
352 #undef ps
353 #undef p
354 #undef p3
355 }
356 
357 /*
358  * Dump IP statistics structure.
359  */
360 void
361 ip_stats(off, name)
362 	u_long off;
363 	char *name;
364 {
365 	struct ipstat ipstat;
366 
367 	if (off == 0)
368 		return;
369 	kread(off, (char *)&ipstat, sizeof (ipstat));
370 	printf("%s:\n", name);
371 
372 #define	ps(f, m) if (ipstat.f || sflag <= 1) \
373     printf(m, (unsigned long long)ipstat.f)
374 #define	p(f, m) if (ipstat.f || sflag <= 1) \
375     printf(m, (unsigned long long)ipstat.f, plural(ipstat.f))
376 
377 	p(ips_total, "\t%llu total packet%s received\n");
378 	p(ips_badsum, "\t%llu bad header checksum%s\n");
379 	ps(ips_toosmall, "\t%llu with size smaller than minimum\n");
380 	ps(ips_tooshort, "\t%llu with data size < data length\n");
381 	ps(ips_toolong, "\t%llu with length > max ip packet size\n");
382 	ps(ips_badhlen, "\t%llu with header length < data size\n");
383 	ps(ips_badlen, "\t%llu with data length < header length\n");
384 	ps(ips_badoptions, "\t%llu with bad options\n");
385 	ps(ips_badvers, "\t%llu with incorrect version number\n");
386 	p(ips_fragments, "\t%llu fragment%s received\n");
387 	p(ips_fragdropped, "\t%llu fragment%s dropped (dup or out of space)\n");
388 	p(ips_badfrags, "\t%llu malformed fragment%s dropped\n");
389 	p(ips_fragtimeout, "\t%llu fragment%s dropped after timeout\n");
390 	p(ips_reassembled, "\t%llu packet%s reassembled ok\n");
391 	p(ips_delivered, "\t%llu packet%s for this host\n");
392 	p(ips_noproto, "\t%llu packet%s for unknown/unsupported protocol\n");
393 	p(ips_forward, "\t%llu packet%s forwarded");
394 	p(ips_fastforward, " (%llu packet%s fast forwarded)");
395 	if (ipstat.ips_forward || sflag <= 1)
396 		putchar('\n');
397 	p(ips_cantforward, "\t%llu packet%s not forwardable\n");
398 	p(ips_redirectsent, "\t%llu redirect%s sent\n");
399 	p(ips_localout, "\t%llu packet%s sent from this host\n");
400 	p(ips_rawout, "\t%llu packet%s sent with fabricated ip header\n");
401 	p(ips_odropped, "\t%llu output packet%s dropped due to no bufs, etc.\n");
402 	p(ips_noroute, "\t%llu output packet%s discarded due to no route\n");
403 	p(ips_fragmented, "\t%llu output datagram%s fragmented\n");
404 	p(ips_ofragments, "\t%llu fragment%s created\n");
405 	p(ips_cantfrag, "\t%llu datagram%s that can't be fragmented\n");
406 	p(ips_badaddr, "\t%llu datagram%s with bad address in header\n");
407 #undef ps
408 #undef p
409 }
410 
411 static	char *icmpnames[] = {
412 	"echo reply",
413 	"#1",
414 	"#2",
415 	"destination unreachable",
416 	"source quench",
417 	"routing redirect",
418 	"alternate host address",
419 	"#7",
420 	"echo",
421 	"router advertisement",
422 	"router solicitation",
423 	"time exceeded",
424 	"parameter problem",
425 	"time stamp",
426 	"time stamp reply",
427 	"information request",
428 	"information request reply",
429 	"address mask request",
430 	"address mask reply",
431 };
432 
433 /*
434  * Dump ICMP statistics.
435  */
436 void
437 icmp_stats(off, name)
438 	u_long off;
439 	char *name;
440 {
441 	struct icmpstat icmpstat;
442 	int i, first;
443 
444 	if (off == 0)
445 		return;
446 	kread(off, (char *)&icmpstat, sizeof (icmpstat));
447 	printf("%s:\n", name);
448 
449 #define	p(f, m) if (icmpstat.f || sflag <= 1) \
450     printf(m, (unsigned long long)icmpstat.f, plural(icmpstat.f))
451 
452 	p(icps_error, "\t%llu call%s to icmp_error\n");
453 	p(icps_oldicmp,
454 	    "\t%llu error%s not generated because old message was icmp\n");
455 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
456 		if (icmpstat.icps_outhist[i] != 0) {
457 			if (first) {
458 				printf("\tOutput histogram:\n");
459 				first = 0;
460 			}
461 			printf("\t\t%s: %llu\n", icmpnames[i],
462 				(unsigned long long)icmpstat.icps_outhist[i]);
463 		}
464 	p(icps_badcode, "\t%llu message%s with bad code fields\n");
465 	p(icps_tooshort, "\t%llu message%s < minimum length\n");
466 	p(icps_checksum, "\t%llu bad checksum%s\n");
467 	p(icps_badlen, "\t%llu message%s with bad length\n");
468 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
469 		if (icmpstat.icps_inhist[i] != 0) {
470 			if (first) {
471 				printf("\tInput histogram:\n");
472 				first = 0;
473 			}
474 			printf("\t\t%s: %llu\n", icmpnames[i],
475 				(unsigned long long)icmpstat.icps_inhist[i]);
476 		}
477 	p(icps_reflect, "\t%llu message response%s generated\n");
478 	p(icps_pmtuchg, "\t%llu path MTU change%s\n");
479 #undef p
480 }
481 
482 /*
483  * Dump IGMP statistics structure.
484  */
485 void
486 igmp_stats(off, name)
487 	u_long off;
488 	char *name;
489 {
490 	struct igmpstat igmpstat;
491 
492 	if (off == 0)
493 		return;
494 	kread(off, (char *)&igmpstat, sizeof (igmpstat));
495 	printf("%s:\n", name);
496 
497 #define	p(f, m) if (igmpstat.f || sflag <= 1) \
498     printf(m, (unsigned long long)igmpstat.f, plural(igmpstat.f))
499 #define	py(f, m) if (igmpstat.f || sflag <= 1) \
500     printf(m, (unsigned long long)igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
501 	p(igps_rcv_total, "\t%llu message%s received\n");
502         p(igps_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
503         p(igps_rcv_badsum, "\t%llu message%s received with bad checksum\n");
504         py(igps_rcv_queries, "\t%llu membership quer%s received\n");
505         py(igps_rcv_badqueries, "\t%llu membership quer%s received with invalid field(s)\n");
506         p(igps_rcv_reports, "\t%llu membership report%s received\n");
507         p(igps_rcv_badreports, "\t%llu membership report%s received with invalid field(s)\n");
508         p(igps_rcv_ourreports, "\t%llu membership report%s received for groups to which we belong\n");
509         p(igps_snd_reports, "\t%llu membership report%s sent\n");
510 #undef p
511 #undef py
512 }
513 
514 /*
515  * Dump the ARP statistics structure.
516  */
517 void
518 arp_stats(off, name)
519 	u_long off;
520 	char *name;
521 {
522 	struct arpstat arpstat;
523 
524 	if (off == 0)
525 		return;
526 	kread(off, (char *)&arpstat, sizeof (arpstat));
527 	printf("%s:\n", name);
528 
529 #define	ps(f, m) if (arpstat.f || sflag <= 1) \
530     printf(m, (unsigned long long)arpstat.f)
531 #define	p(f, m) if (arpstat.f || sflag <= 1) \
532     printf(m, (unsigned long long)arpstat.f, plural(arpstat.f))
533 
534 	p(as_sndtotal, "\t%llu packet%s sent\n");
535 	p(as_sndreply, "\t\t%llu reply packet%s\n");
536 	p(as_sndrequest, "\t\t%llu request packet%s\n");
537 
538 	p(as_rcvtotal, "\t%llu packet%s received\n");
539 	p(as_rcvreply, "\t\t%llu reply packet%s\n");
540 	p(as_rcvrequest, "\t\t%llu valid request packet%s\n");
541 	p(as_rcvmcast, "\t\t%llu broadcast/multicast packet%s\n");
542 	p(as_rcvbadproto, "\t\t%llu packet%s with unknown protocol type\n");
543 	p(as_rcvbadlen, "\t\t%llu packet%s with bad (short) length\n");
544 	p(as_rcvzerotpa, "\t\t%llu packet%s with null target IP address\n");
545 	p(as_rcvzerospa, "\t\t%llu packet%s with null source IP address\n");
546 	ps(as_rcvnoint, "\t\t%llu could not be mapped to an interface\n");
547 	p(as_rcvlocalsha, "\t\t%llu packet%s sourced from a local hardware "
548 	    "address\n");
549 	p(as_rcvbcastsha, "\t\t%llu packet%s with a broadcast "
550 	    "source hardware address\n");
551 	p(as_rcvlocalspa, "\t\t%llu duplicate%s for a local IP address\n");
552 	p(as_rcvoverperm, "\t\t%llu attempt%s to overwrite a static entry\n");
553 	p(as_rcvoverint, "\t\t%llu packet%s received on wrong interface\n");
554 	p(as_rcvover, "\t\t%llu entry%s overwritten\n");
555 	p(as_rcvlenchg, "\t\t%llu change%s in hardware address length\n");
556 
557 	p(as_dfrtotal, "\t%llu packet%s deferred pending ARP resolution\n");
558 	ps(as_dfrsent, "\t\t%llu sent\n");
559 	ps(as_dfrdropped, "\t\t%llu dropped\n");
560 
561 	p(as_allocfail, "\t%llu failure%s to allocate llinfo\n");
562 
563 #undef ps
564 #undef p
565 }
566 
567 /*
568  * Pretty print an Internet address (net address + port).
569  * Take numeric_addr and numeric_port into consideration.
570  */
571 void
572 inetprint(in, port, proto, numeric_port)
573 	struct in_addr *in;
574 	u_int16_t port;
575 	const char *proto;
576 	int numeric_port;
577 {
578 	struct servent *sp = 0;
579 	char line[80], *cp;
580 	size_t space;
581 
582 	(void)snprintf(line, sizeof line, "%.*s.",
583 	    (Aflag && !numeric_addr) ? 12 : 16, inetname(in));
584 	cp = strchr(line, '\0');
585 	if (!numeric_port && port)
586 		sp = getservbyport((int)port, proto);
587 	space = sizeof line - (cp-line);
588 	if (sp || port == 0)
589 		(void)snprintf(cp, space, "%s", sp ? sp->s_name : "*");
590 	else
591 		(void)snprintf(cp, space, "%u", ntohs(port));
592 	(void)printf(" %-*.*s", width, width, line);
593 }
594 
595 /*
596  * Construct an Internet address representation.
597  * If numeric_addr has been supplied, give
598  * numeric value, otherwise try for symbolic name.
599  */
600 char *
601 inetname(inp)
602 	struct in_addr *inp;
603 {
604 	char *cp;
605 	static char line[50];
606 	struct hostent *hp;
607 	struct netent *np;
608 	static char domain[MAXHOSTNAMELEN + 1];
609 	static int first = 1;
610 
611 	if (first && !numeric_addr) {
612 		first = 0;
613 		if (gethostname(domain, sizeof domain) == 0) {
614 			domain[sizeof(domain) - 1] = '\0';
615 			if ((cp = strchr(domain, '.')))
616 				(void) strlcpy(domain, cp + 1, sizeof(domain));
617 			else
618 				domain[0] = 0;
619 		} else
620 			domain[0] = 0;
621 	}
622 	cp = 0;
623 	if (!numeric_addr && inp->s_addr != INADDR_ANY) {
624 		int net = inet_netof(*inp);
625 		int lna = inet_lnaof(*inp);
626 
627 		if (lna == INADDR_ANY) {
628 			np = getnetbyaddr(net, AF_INET);
629 			if (np)
630 				cp = np->n_name;
631 		}
632 		if (cp == 0) {
633 			hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
634 			if (hp) {
635 				if ((cp = strchr(hp->h_name, '.')) &&
636 				    !strcmp(cp + 1, domain))
637 					*cp = 0;
638 				cp = hp->h_name;
639 			}
640 		}
641 	}
642 	if (inp->s_addr == INADDR_ANY)
643 		strlcpy(line, "*", sizeof line);
644 	else if (cp)
645 		strlcpy(line, cp, sizeof line);
646 	else {
647 		inp->s_addr = ntohl(inp->s_addr);
648 #define C(x)	((x) & 0xff)
649 		(void)snprintf(line, sizeof line, "%u.%u.%u.%u",
650 		    C(inp->s_addr >> 24), C(inp->s_addr >> 16),
651 		    C(inp->s_addr >> 8), C(inp->s_addr));
652 #undef C
653 	}
654 	return (line);
655 }
656 
657 /*
658  * Dump the contents of a TCP PCB.
659  */
660 void
661 tcp_dump(pcbaddr)
662 	u_long pcbaddr;
663 {
664 	struct tcpcb tcpcb;
665 	int i, hardticks;
666 
667 	kread(pcbaddr, (char *)&tcpcb, sizeof(tcpcb));
668 	hardticks = get_hardticks();
669 
670 	printf("TCP Protocol Control Block at 0x%08lx:\n\n", pcbaddr);
671 
672 	printf("Timers:\n");
673 	for (i = 0; i < TCPT_NTIMERS; i++) {
674 		printf("\t%s: %d", tcptimers[i],
675 		    (tcpcb.t_timer[i].c_flags & CALLOUT_PENDING) ?
676 		    tcpcb.t_timer[i].c_time - hardticks : 0);
677 	}
678 	printf("\n\n");
679 
680 	if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES)
681 		printf("State: %d", tcpcb.t_state);
682 	else
683 		printf("State: %s", tcpstates[tcpcb.t_state]);
684 	printf(", flags 0x%x, inpcb 0x%lx, in6pcb 0x%lx\n\n", tcpcb.t_flags,
685 	    (u_long)tcpcb.t_inpcb, (u_long)tcpcb.t_in6pcb);
686 
687 	printf("rxtshift %d, rxtcur %d, dupacks %d\n", tcpcb.t_rxtshift,
688 	    tcpcb.t_rxtcur, tcpcb.t_dupacks);
689 	printf("peermss %u, ourmss %u, segsz %u\n\n", tcpcb.t_peermss,
690 	    tcpcb.t_ourmss, tcpcb.t_segsz);
691 
692 	printf("snd_una %u, snd_nxt %u, snd_up %u\n",
693 	    tcpcb.snd_una, tcpcb.snd_nxt, tcpcb.snd_up);
694 	printf("snd_wl1 %u, snd_wl2 %u, iss %u, snd_wnd %lu\n\n",
695 	    tcpcb.snd_wl1, tcpcb.snd_wl2, tcpcb.iss, tcpcb.snd_wnd);
696 
697 	printf("rcv_wnd %lu, rcv_nxt %u, rcv_up %u, irs %u\n\n",
698 	    tcpcb.rcv_wnd, tcpcb.rcv_nxt, tcpcb.rcv_up, tcpcb.irs);
699 
700 	printf("rcv_adv %u, snd_max %u, snd_cwnd %lu, snd_ssthresh %lu\n",
701 	    tcpcb.rcv_adv, tcpcb.snd_max, tcpcb.snd_cwnd, tcpcb.snd_ssthresh);
702 
703 	printf("rcvtime %u, rtttime %u, rtseq %u, srtt %d, rttvar %d, "
704 	    "rttmin %d, max_sndwnd %lu\n\n", tcpcb.t_rcvtime, tcpcb.t_rtttime,
705 	    tcpcb.t_rtseq, tcpcb.t_srtt, tcpcb.t_rttvar, tcpcb.t_rttmin,
706 	    tcpcb.max_sndwnd);
707 
708 	printf("oobflags %d, iobc %d, softerror %d\n\n", tcpcb.t_oobflags,
709 	    tcpcb.t_iobc, tcpcb.t_softerror);
710 
711 	printf("snd_scale %d, rcv_scale %d, req_r_scale %d, req_s_scale %d\n",
712 	    tcpcb.snd_scale, tcpcb.rcv_scale, tcpcb.request_r_scale,
713 	    tcpcb.requested_s_scale);
714 	printf("ts_recent %u, ts_regent_age %d, last_ack_sent %u\n",
715 	    tcpcb.ts_recent, tcpcb.ts_recent_age, tcpcb.last_ack_sent);
716 }
717