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