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