xref: /netbsd/usr.bin/netstat/inet.c (revision bf9ec67e)
1 /*	$NetBSD: inet.c,v 1.52 2002/05/26 16:05:45 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. 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.52 2002/05/26 16:05:45 itojun 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 	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 	p(tcps_sc_retransmitted, "\t%llu SYN,ACK%s retransmitted\n");
296 	p(tcps_sc_dupesyn, "\t%llu duplicate SYN%s received for entries "
297 		"already in the cache\n");
298 	p(tcps_sc_dropped, "\t%llu SYN%s dropped (no route or no space)\n");
299 
300 #undef p
301 #undef ps
302 #undef p2
303 #undef p2s
304 #undef p3
305 }
306 
307 /*
308  * Dump UDP statistics structure.
309  */
310 void
311 udp_stats(off, name)
312 	u_long off;
313 	char *name;
314 {
315 	struct udpstat udpstat;
316 	u_quad_t delivered;
317 
318 	if (off == 0)
319 		return;
320 	printf("%s:\n", name);
321 	kread(off, (char *)&udpstat, sizeof (udpstat));
322 
323 #define	ps(f, m) if (udpstat.f || sflag <= 1) \
324     printf(m, (unsigned long long)udpstat.f)
325 #define	p(f, m) if (udpstat.f || sflag <= 1) \
326     printf(m, (unsigned long long)udpstat.f, plural(udpstat.f))
327 #define	p3(f, m) if (udpstat.f || sflag <= 1) \
328     printf(m, (unsigned long long)udpstat.f, plurales(udpstat.f))
329 
330 	p(udps_ipackets, "\t%llu datagram%s received\n");
331 	ps(udps_hdrops, "\t%llu with incomplete header\n");
332 	ps(udps_badlen, "\t%llu with bad data length field\n");
333 	ps(udps_badsum, "\t%llu with bad checksum\n");
334 	ps(udps_noport, "\t%llu dropped due to no socket\n");
335 	p(udps_noportbcast, "\t%llu broadcast/multicast datagram%s dropped due to no socket\n");
336 	ps(udps_fullsock, "\t%llu dropped due to full socket buffers\n");
337 	delivered = udpstat.udps_ipackets -
338 		    udpstat.udps_hdrops -
339 		    udpstat.udps_badlen -
340 		    udpstat.udps_badsum -
341 		    udpstat.udps_noport -
342 		    udpstat.udps_noportbcast -
343 		    udpstat.udps_fullsock;
344 	if (delivered || sflag <= 1)
345 		printf("\t%llu delivered\n", (unsigned long long)delivered);
346 	p3(udps_pcbhashmiss, "\t%llu PCB hash miss%s\n");
347 	p(udps_opackets, "\t%llu datagram%s output\n");
348 
349 #undef ps
350 #undef p
351 #undef p3
352 }
353 
354 /*
355  * Dump IP statistics structure.
356  */
357 void
358 ip_stats(off, name)
359 	u_long off;
360 	char *name;
361 {
362 	struct ipstat ipstat;
363 
364 	if (off == 0)
365 		return;
366 	kread(off, (char *)&ipstat, sizeof (ipstat));
367 	printf("%s:\n", name);
368 
369 #define	ps(f, m) if (ipstat.f || sflag <= 1) \
370     printf(m, (unsigned long long)ipstat.f)
371 #define	p(f, m) if (ipstat.f || sflag <= 1) \
372     printf(m, (unsigned long long)ipstat.f, plural(ipstat.f))
373 
374 	p(ips_total, "\t%llu total packet%s received\n");
375 	p(ips_badsum, "\t%llu bad header checksum%s\n");
376 	ps(ips_toosmall, "\t%llu with size smaller than minimum\n");
377 	ps(ips_tooshort, "\t%llu with data size < data length\n");
378 	ps(ips_toolong, "\t%llu with length > max ip packet size\n");
379 	ps(ips_badhlen, "\t%llu with header length < data size\n");
380 	ps(ips_badlen, "\t%llu with data length < header length\n");
381 	ps(ips_badoptions, "\t%llu with bad options\n");
382 	ps(ips_badvers, "\t%llu with incorrect version number\n");
383 	p(ips_fragments, "\t%llu fragment%s received\n");
384 	p(ips_fragdropped, "\t%llu fragment%s dropped (dup or out of space)\n");
385 	p(ips_badfrags, "\t%llu malformed fragment%s dropped\n");
386 	p(ips_fragtimeout, "\t%llu fragment%s dropped after timeout\n");
387 	p(ips_reassembled, "\t%llu packet%s reassembled ok\n");
388 	p(ips_delivered, "\t%llu packet%s for this host\n");
389 	p(ips_noproto, "\t%llu packet%s for unknown/unsupported protocol\n");
390 	p(ips_forward, "\t%llu packet%s forwarded");
391 	p(ips_fastforward, " (%llu packet%s fast forwarded)");
392 	if (ipstat.ips_forward || sflag <= 1)
393 		putchar('\n');
394 	p(ips_cantforward, "\t%llu packet%s not forwardable\n");
395 	p(ips_redirectsent, "\t%llu redirect%s sent\n");
396 	p(ips_localout, "\t%llu packet%s sent from this host\n");
397 	p(ips_rawout, "\t%llu packet%s sent with fabricated ip header\n");
398 	p(ips_odropped, "\t%llu output packet%s dropped due to no bufs, etc.\n");
399 	p(ips_noroute, "\t%llu output packet%s discarded due to no route\n");
400 	p(ips_fragmented, "\t%llu output datagram%s fragmented\n");
401 	p(ips_ofragments, "\t%llu fragment%s created\n");
402 	p(ips_cantfrag, "\t%llu datagram%s that can't be fragmented\n");
403 	p(ips_badaddr, "\t%llu datagram%s with bad address in header\n");
404 #undef ps
405 #undef p
406 }
407 
408 static	char *icmpnames[] = {
409 	"echo reply",
410 	"#1",
411 	"#2",
412 	"destination unreachable",
413 	"source quench",
414 	"routing redirect",
415 	"alternate host address",
416 	"#7",
417 	"echo",
418 	"router advertisement",
419 	"router solicitation",
420 	"time exceeded",
421 	"parameter problem",
422 	"time stamp",
423 	"time stamp reply",
424 	"information request",
425 	"information request reply",
426 	"address mask request",
427 	"address mask reply",
428 };
429 
430 /*
431  * Dump ICMP statistics.
432  */
433 void
434 icmp_stats(off, name)
435 	u_long off;
436 	char *name;
437 {
438 	struct icmpstat icmpstat;
439 	int i, first;
440 
441 	if (off == 0)
442 		return;
443 	kread(off, (char *)&icmpstat, sizeof (icmpstat));
444 	printf("%s:\n", name);
445 
446 #define	p(f, m) if (icmpstat.f || sflag <= 1) \
447     printf(m, (unsigned long long)icmpstat.f, plural(icmpstat.f))
448 
449 	p(icps_error, "\t%llu call%s to icmp_error\n");
450 	p(icps_oldicmp,
451 	    "\t%llu error%s not generated because old message was icmp\n");
452 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
453 		if (icmpstat.icps_outhist[i] != 0) {
454 			if (first) {
455 				printf("\tOutput histogram:\n");
456 				first = 0;
457 			}
458 			printf("\t\t%s: %llu\n", icmpnames[i],
459 				(unsigned long long)icmpstat.icps_outhist[i]);
460 		}
461 	p(icps_badcode, "\t%llu message%s with bad code fields\n");
462 	p(icps_tooshort, "\t%llu message%s < minimum length\n");
463 	p(icps_checksum, "\t%llu bad checksum%s\n");
464 	p(icps_badlen, "\t%llu message%s with bad length\n");
465 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
466 		if (icmpstat.icps_inhist[i] != 0) {
467 			if (first) {
468 				printf("\tInput histogram:\n");
469 				first = 0;
470 			}
471 			printf("\t\t%s: %llu\n", icmpnames[i],
472 				(unsigned long long)icmpstat.icps_inhist[i]);
473 		}
474 	p(icps_reflect, "\t%llu message response%s generated\n");
475 	p(icps_pmtuchg, "\t%llu path MTU change%s\n");
476 #undef p
477 }
478 
479 /*
480  * Dump IGMP statistics structure.
481  */
482 void
483 igmp_stats(off, name)
484 	u_long off;
485 	char *name;
486 {
487 	struct igmpstat igmpstat;
488 
489 	if (off == 0)
490 		return;
491 	kread(off, (char *)&igmpstat, sizeof (igmpstat));
492 	printf("%s:\n", name);
493 
494 #define	p(f, m) if (igmpstat.f || sflag <= 1) \
495     printf(m, (unsigned long long)igmpstat.f, plural(igmpstat.f))
496 #define	py(f, m) if (igmpstat.f || sflag <= 1) \
497     printf(m, (unsigned long long)igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
498 	p(igps_rcv_total, "\t%llu message%s received\n");
499         p(igps_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
500         p(igps_rcv_badsum, "\t%llu message%s received with bad checksum\n");
501         py(igps_rcv_queries, "\t%llu membership quer%s received\n");
502         py(igps_rcv_badqueries, "\t%llu membership quer%s received with invalid field(s)\n");
503         p(igps_rcv_reports, "\t%llu membership report%s received\n");
504         p(igps_rcv_badreports, "\t%llu membership report%s received with invalid field(s)\n");
505         p(igps_rcv_ourreports, "\t%llu membership report%s received for groups to which we belong\n");
506         p(igps_snd_reports, "\t%llu membership report%s sent\n");
507 #undef p
508 #undef py
509 }
510 
511 /*
512  * Dump the ARP statistics structure.
513  */
514 void
515 arp_stats(off, name)
516 	u_long off;
517 	char *name;
518 {
519 	struct arpstat arpstat;
520 
521 	if (off == 0)
522 		return;
523 	kread(off, (char *)&arpstat, sizeof (arpstat));
524 	printf("%s:\n", name);
525 
526 #define	ps(f, m) if (arpstat.f || sflag <= 1) \
527     printf(m, (unsigned long long)arpstat.f)
528 #define	p(f, m) if (arpstat.f || sflag <= 1) \
529     printf(m, (unsigned long long)arpstat.f, plural(arpstat.f))
530 
531 	p(as_sndtotal, "\t%llu packet%s sent\n");
532 	p(as_sndreply, "\t\t%llu reply packet%s\n");
533 	p(as_sndrequest, "\t\t%llu request packet%s\n");
534 
535 	p(as_rcvtotal, "\t%llu packet%s received\n");
536 	p(as_rcvreply, "\t\t%llu reply packet%s\n");
537 	p(as_rcvrequest, "\t\t%llu valid request packet%s\n");
538 	p(as_rcvmcast, "\t\t%llu broadcast/multicast packet%s\n");
539 	p(as_rcvbadproto, "\t\t%llu packet%s with unknown protocol type\n");
540 	p(as_rcvbadlen, "\t\t%llu packet%s with bad (short) length\n");
541 	p(as_rcvzerotpa, "\t\t%llu packet%s with null target IP address\n");
542 	p(as_rcvzerospa, "\t\t%llu packet%s with null source IP address\n");
543 	ps(as_rcvnoint, "\t\t%llu could not be mapped to an interface\n");
544 	p(as_rcvlocalsha, "\t\t%llu packet%s sourced from a local hardware "
545 	    "address\n");
546 	p(as_rcvbcastsha, "\t\t%llu packet%s with a broadcast "
547 	    "source hardware address\n");
548 	p(as_rcvlocalspa, "\t\t%llu duplicate%s for a local IP address\n");
549 	p(as_rcvoverperm, "\t\t%llu attempt%s to overwrite a static entry\n");
550 	p(as_rcvoverint, "\t\t%llu packet%s received on wrong interface\n");
551 	p(as_rcvover, "\t\t%llu entry%s overwritten\n");
552 	p(as_rcvlenchg, "\t\t%llu change%s in hardware address length\n");
553 
554 	p(as_dfrtotal, "\t%llu packet%s deferred pending ARP resolution\n");
555 	ps(as_dfrsent, "\t\t%llu sent\n");
556 	ps(as_dfrdropped, "\t\t%llu dropped\n");
557 
558 	p(as_allocfail, "\t%llu failure%s to allocate llinfo\n");
559 
560 #undef ps
561 #undef p
562 }
563 
564 /*
565  * Pretty print an Internet address (net address + port).
566  * Take numeric_addr and numeric_port into consideration.
567  */
568 void
569 inetprint(in, port, proto, numeric_port)
570 	struct in_addr *in;
571 	u_int16_t port;
572 	const char *proto;
573 	int numeric_port;
574 {
575 	struct servent *sp = 0;
576 	char line[80], *cp;
577 	size_t space;
578 
579 	(void)snprintf(line, sizeof line, "%.*s.",
580 	    (Aflag && !numeric_addr) ? 12 : 16, inetname(in));
581 	cp = strchr(line, '\0');
582 	if (!numeric_port && port)
583 		sp = getservbyport((int)port, proto);
584 	space = sizeof line - (cp-line);
585 	if (sp || port == 0)
586 		(void)snprintf(cp, space, "%.8s", sp ? sp->s_name : "*");
587 	else
588 		(void)snprintf(cp, space, "%u", ntohs(port));
589 	(void)printf(" %-*.*s", width, width, line);
590 }
591 
592 /*
593  * Construct an Internet address representation.
594  * If numeric_addr has been supplied, give
595  * numeric value, otherwise try for symbolic name.
596  */
597 char *
598 inetname(inp)
599 	struct in_addr *inp;
600 {
601 	char *cp;
602 	static char line[50];
603 	struct hostent *hp;
604 	struct netent *np;
605 	static char domain[MAXHOSTNAMELEN + 1];
606 	static int first = 1;
607 
608 	if (first && !numeric_addr) {
609 		first = 0;
610 		if (gethostname(domain, sizeof domain) == 0) {
611 			domain[sizeof(domain) - 1] = '\0';
612 			if ((cp = strchr(domain, '.')))
613 				(void) strlcpy(domain, cp + 1, sizeof(domain));
614 			else
615 				domain[0] = 0;
616 		} else
617 			domain[0] = 0;
618 	}
619 	cp = 0;
620 	if (!numeric_addr && inp->s_addr != INADDR_ANY) {
621 		int net = inet_netof(*inp);
622 		int lna = inet_lnaof(*inp);
623 
624 		if (lna == INADDR_ANY) {
625 			np = getnetbyaddr(net, AF_INET);
626 			if (np)
627 				cp = np->n_name;
628 		}
629 		if (cp == 0) {
630 			hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
631 			if (hp) {
632 				if ((cp = strchr(hp->h_name, '.')) &&
633 				    !strcmp(cp + 1, domain))
634 					*cp = 0;
635 				cp = hp->h_name;
636 			}
637 		}
638 	}
639 	if (inp->s_addr == INADDR_ANY)
640 		strncpy(line, "*", sizeof line);
641 	else if (cp)
642 		strncpy(line, cp, sizeof line);
643 	else {
644 		inp->s_addr = ntohl(inp->s_addr);
645 #define C(x)	((x) & 0xff)
646 		(void)snprintf(line, sizeof line, "%u.%u.%u.%u",
647 		    C(inp->s_addr >> 24), C(inp->s_addr >> 16),
648 		    C(inp->s_addr >> 8), C(inp->s_addr));
649 #undef C
650 	}
651 	line[sizeof(line) - 1] = '\0';
652 	return (line);
653 }
654 
655 /*
656  * Dump the contents of a TCP PCB.
657  */
658 void
659 tcp_dump(pcbaddr)
660 	u_long pcbaddr;
661 {
662 	struct tcpcb tcpcb;
663 	int i;
664 
665 	kread(pcbaddr, (char *)&tcpcb, sizeof(tcpcb));
666 
667 	printf("TCP Protocol Control Block at 0x%08lx:\n\n", pcbaddr);
668 
669 	printf("Timers:\n");
670 	for (i = 0; i < TCPT_NTIMERS; i++) {
671 		printf("\t%s: %llu", tcptimers[i],
672 		    (tcpcb.t_timer[i].c_flags & CALLOUT_ACTIVE) ?
673 		    (unsigned long long) tcpcb.t_timer[i].c_time : 0);
674 	}
675 	printf("\n\n");
676 
677 	if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES)
678 		printf("State: %d", tcpcb.t_state);
679 	else
680 		printf("State: %s", tcpstates[tcpcb.t_state]);
681 	printf(", flags 0x%x, inpcb 0x%lx, in6pcb 0x%lx\n\n", tcpcb.t_flags,
682 	    (u_long)tcpcb.t_inpcb, (u_long)tcpcb.t_in6pcb);
683 
684 	printf("rxtshift %d, rxtcur %d, dupacks %d\n", tcpcb.t_rxtshift,
685 	    tcpcb.t_rxtcur, tcpcb.t_dupacks);
686 	printf("peermss %u, ourmss %u, segsz %u\n\n", tcpcb.t_peermss,
687 	    tcpcb.t_ourmss, tcpcb.t_segsz);
688 
689 	printf("snd_una %u, snd_nxt %u, snd_up %u\n",
690 	    tcpcb.snd_una, tcpcb.snd_nxt, tcpcb.snd_up);
691 	printf("snd_wl1 %u, snd_wl2 %u, iss %u, snd_wnd %lu\n\n",
692 	    tcpcb.snd_wl1, tcpcb.snd_wl2, tcpcb.iss, tcpcb.snd_wnd);
693 
694 	printf("rcv_wnd %lu, rcv_nxt %u, rcv_up %u, irs %u\n\n",
695 	    tcpcb.rcv_wnd, tcpcb.rcv_nxt, tcpcb.rcv_up, tcpcb.irs);
696 
697 	printf("rcv_adv %u, snd_max %u, snd_cwnd %lu, snd_ssthresh %lu\n",
698 	    tcpcb.rcv_adv, tcpcb.snd_max, tcpcb.snd_cwnd, tcpcb.snd_ssthresh);
699 
700 	printf("rcvtime %u, rtttime %u, rtseq %u, srtt %d, rttvar %d, "
701 	    "rttmin %d, max_sndwnd %lu\n\n", tcpcb.t_rcvtime, tcpcb.t_rtttime,
702 	    tcpcb.t_rtseq, tcpcb.t_srtt, tcpcb.t_rttvar, tcpcb.t_rttmin,
703 	    tcpcb.max_sndwnd);
704 
705 	printf("oobflags %d, iobc %d, softerror %d\n\n", tcpcb.t_oobflags,
706 	    tcpcb.t_iobc, tcpcb.t_softerror);
707 
708 	printf("snd_scale %d, rcv_scale %d, req_r_scale %d, req_s_scale %d\n",
709 	    tcpcb.snd_scale, tcpcb.rcv_scale, tcpcb.request_r_scale,
710 	    tcpcb.requested_s_scale);
711 	printf("ts_recent %u, ts_regent_age %d, last_ack_sent %u\n",
712 	    tcpcb.ts_recent, tcpcb.ts_recent_age, tcpcb.last_ack_sent);
713 }
714