1/*	$NetBSD: inet6.c,v 1.59 2011/05/24 18:07:11 spz Exp $	*/
2/*	BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp	*/
3
4/*
5 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33/*
34 * Copyright (c) 1983, 1988, 1993
35 *	The Regents of the University of California.  All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 *    notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 *    notice, this list of conditions and the following disclaimer in the
44 *    documentation and/or other materials provided with the distribution.
45 * 3. Neither the name of the University nor the names of its contributors
46 *    may be used to endorse or promote products derived from this software
47 *    without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 */
61
62#include <sys/cdefs.h>
63#ifndef lint
64#if 0
65static char sccsid[] = "@(#)inet.c	8.4 (Berkeley) 4/20/94";
66#else
67__RCSID("$NetBSD: inet6.c,v 1.59 2011/05/24 18:07:11 spz Exp $");
68#endif
69#endif /* not lint */
70
71#include <sys/param.h>
72#include <sys/socket.h>
73#include <sys/socketvar.h>
74#include <sys/ioctl.h>
75#include <sys/mbuf.h>
76#include <sys/protosw.h>
77#include <sys/sysctl.h>
78
79#include <net/route.h>
80#include <net/if.h>
81#include <netinet/in.h>
82#include <netinet/ip6.h>
83#include <netinet/icmp6.h>
84#include <netinet/in_systm.h>
85#ifndef TCP6
86#include <netinet/ip.h>
87#include <netinet/ip_var.h>
88#endif
89#include <netinet6/ip6_var.h>
90#include <netinet6/in6_pcb.h>
91#include <netinet6/in6_var.h>
92#ifdef TCP6
93#include <netinet6/tcp6.h>
94#include <netinet6/tcp6_seq.h>
95#define TCP6STATES
96#include <netinet6/tcp6_fsm.h>
97#define TCP6TIMERS
98#include <netinet6/tcp6_timer.h>
99#include <netinet6/tcp6_var.h>
100#include <netinet6/tcp6_debug.h>
101#else
102#include <netinet/tcp.h>
103#include <netinet/tcpip.h>
104#include <netinet/tcp_seq.h>
105/*#define TCPSTATES*/
106#include <netinet/tcp_fsm.h>
107extern const char * const tcpstates[];
108/*#define	TCPTIMERS*/
109#include <netinet/tcp_timer.h>
110#include <netinet/tcp_var.h>
111#include <netinet/tcp_debug.h>
112#endif /*TCP6*/
113#include <netinet6/udp6.h>
114#include <netinet6/udp6_var.h>
115#include <netinet6/pim6_var.h>
116#include <netinet6/raw_ip6.h>
117#include <netinet/tcp_vtw.h>
118
119#include <arpa/inet.h>
120#if 0
121#include "gethostbyname2.h"
122#endif
123#include <netdb.h>
124
125#include <err.h>
126#include <errno.h>
127#include <kvm.h>
128#include <stdio.h>
129#include <stdlib.h>
130#include <string.h>
131#include <unistd.h>
132#include "netstat.h"
133#include "vtw.h"
134#include "prog_ops.h"
135
136#ifdef INET6
137
138struct	in6pcb in6pcb;
139#ifdef TCP6
140struct	tcp6cb tcp6cb;
141#else
142struct	tcpcb tcpcb;
143#endif
144struct	socket sockb;
145
146char	*inet6name(const struct in6_addr *);
147void	inet6print(const struct in6_addr *, int, const char *);
148void	print_vtw_v6(const vtw_t *);
149
150/*
151 * Print a summary of connections related to an Internet
152 * protocol.  For TCP, also give state of connection.
153 * Listening processes (aflag) are suppressed unless the
154 * -a (all) flag is specified.
155 */
156static int width;
157static int compact;
158
159/* VTW-related variables. */
160static struct timeval now;
161
162static void
163ip6protoprhdr(void)
164{
165
166	printf("Active Internet6 connections");
167
168	if (aflag)
169		printf(" (including servers)");
170	putchar('\n');
171
172	if (Aflag) {
173		printf("%-8.8s ", "PCB");
174		width = 18;
175	}
176	printf(
177	    Vflag ? "%-5.5s %-6.6s %-6.6s  %*.*s %*.*s %-13.13s Expires\n"
178	          : "%-5.5s %-6.6s %-6.6s  %*.*s %*.*s %s\n",
179	    "Proto", "Recv-Q", "Send-Q",
180	    -width, width, "Local Address",
181	    -width, width, "Foreign Address", "(state)");
182}
183
184static void
185ip6protopr0(intptr_t ppcb, u_long rcv_sb_cc, u_long snd_sb_cc,
186	const struct in6_addr *laddr, u_int16_t lport,
187	const struct in6_addr *faddr, u_int16_t fport,
188	short t_state, const char *name, const struct timeval *expires)
189{
190	static const char *shorttcpstates[] = {
191		"CLOSED",       "LISTEN",       "SYNSEN",       "SYSRCV",
192		"ESTABL",       "CLWAIT",       "FWAIT1",       "CLOSNG",
193		"LASTAK",       "FWAIT2",       "TMWAIT",
194	};
195	int istcp;
196
197	istcp = strcmp(name, "tcp6") == 0;
198	if (Aflag)
199		printf("%8" PRIxPTR " ", ppcb);
200
201	printf("%-5.5s %6ld %6ld%s", name, rcv_sb_cc, snd_sb_cc,
202	    compact ? "" : " ");
203
204	inet6print(laddr, (int)lport, name);
205	inet6print(faddr, (int)fport, name);
206	if (istcp) {
207#ifdef TCP6
208		if (t_state < 0 || t_state >= TCP6_NSTATES)
209			printf(" %d", t_state);
210		else
211			printf(" %s", tcp6states[t_state]);
212#else
213		if (t_state < 0 || t_state >= TCP_NSTATES)
214			printf(" %d", t_state);
215		else
216			printf(" %s", compact ? shorttcpstates[t_state] :
217			    tcpstates[t_state]);
218#endif
219	}
220	if (Vflag && expires != NULL) {
221		if (expires->tv_sec == 0 && expires->tv_usec == -1)
222			printf(" reclaimed");
223		else {
224			struct timeval delta;
225
226			timersub(expires, &now, &delta);
227			printf(" %.3fms",
228			    delta.tv_sec * 1000.0 + delta.tv_usec / 1000.0);
229		}
230	}
231	putchar('\n');
232}
233
234static void
235dbg_printf(const char *fmt, ...)
236{
237	return;
238}
239
240void
241print_vtw_v6(const vtw_t *vtw)
242{
243	const vtw_v6_t *v6 = (const vtw_v6_t *)vtw;
244	struct timeval delta;
245	char buf[2][128];
246	static const struct timeval zero = {.tv_sec = 0, .tv_usec = 0};
247
248	inet_ntop(AF_INET6, &v6->laddr, buf[0], sizeof(buf[0]));
249	inet_ntop(AF_INET6, &v6->faddr, buf[1], sizeof(buf[1]));
250
251	timersub(&vtw->expire, &now, &delta);
252
253	if (vtw->expire.tv_sec == 0 && vtw->expire.tv_usec == -1) {
254		dbg_printf("%15.15s:%d %15.15s:%d reclaimed\n"
255		    ,buf[0], ntohs(v6->lport)
256		    ,buf[1], ntohs(v6->fport));
257		if (!(Vflag && vflag))
258			return;
259	} else if (vtw->expire.tv_sec == 0)
260		return;
261	else if (timercmp(&delta, &zero, <) && !(Vflag && vflag)) {
262		dbg_printf("%15.15s:%d %15.15s:%d expired\n"
263		    ,buf[0], ntohs(v6->lport)
264		    ,buf[1], ntohs(v6->fport));
265		return;
266	} else {
267		dbg_printf("%15.15s:%d %15.15s:%d expires in %.3fms\n"
268		    ,buf[0], ntohs(v6->lport)
269		    ,buf[1], ntohs(v6->fport)
270		    ,delta.tv_sec * 1000.0 + delta.tv_usec / 1000.0);
271	}
272	ip6protopr0(0, 0, 0,
273		 &v6->laddr, v6->lport,
274		 &v6->faddr, v6->fport,
275		 TCPS_TIME_WAIT, "tcp6", &vtw->expire);
276}
277
278
279static struct kinfo_pcb *
280getpcblist_kmem(u_long off, const char *name, size_t *len) {
281
282	struct inpcbtable table;
283	struct in6pcb *head, *prev, *next;
284	int istcp = strcmp(name, "tcp6") == 0;
285	struct kinfo_pcb *pcblist;
286	size_t size = 100, i;
287	struct sockaddr_in6 sin6;
288
289	if (off == 0) {
290		*len = 0;
291		return NULL;
292	}
293	kread(off, (char *)&table, sizeof (table));
294	head = prev =
295	    (struct in6pcb *)&((struct inpcbtable *)off)->inpt_queue.cqh_first;
296	next = (struct in6pcb *)table.inpt_queue.cqh_first;
297
298	if ((pcblist = malloc(size)) == NULL)
299		err(1, "malloc");
300
301	i = 0;
302	while (next != head) {
303		kread((u_long)next, (char *)&in6pcb, sizeof in6pcb);
304		if ((struct in6pcb *)in6pcb.in6p_queue.cqe_prev != prev) {
305			warnx("bad pcb");
306			break;
307		}
308		prev = next;
309		next = (struct in6pcb *)in6pcb.in6p_queue.cqe_next;
310
311		if (in6pcb.in6p_af != AF_INET6)
312			continue;
313
314		kread((u_long)in6pcb.in6p_socket, (char *)&sockb,
315		    sizeof (sockb));
316		if (istcp) {
317#ifdef TCP6
318			kread((u_long)in6pcb.in6p_ppcb,
319			    (char *)&tcp6cb, sizeof (tcp6cb));
320#else
321			kread((u_long)in6pcb.in6p_ppcb,
322			    (char *)&tcpcb, sizeof (tcpcb));
323#endif
324		}
325		pcblist[i].ki_ppcbaddr =
326		    istcp ? (uintptr_t) in6pcb.in6p_ppcb : (uintptr_t) prev;
327		pcblist[i].ki_rcvq = (uint64_t)sockb.so_rcv.sb_cc;
328		pcblist[i].ki_sndq = (uint64_t)sockb.so_snd.sb_cc;
329		sin6.sin6_addr = in6pcb.in6p_laddr;
330		sin6.sin6_port = in6pcb.in6p_lport;
331		memcpy(&pcblist[i].ki_s, &sin6, sizeof(sin6));
332		sin6.sin6_addr = in6pcb.in6p_faddr;
333		sin6.sin6_port = in6pcb.in6p_fport;
334		memcpy(&pcblist[i].ki_d, &sin6, sizeof(sin6));
335		pcblist[i].ki_tstate = tcpcb.t_state;
336		if (i++ == size) {
337			struct kinfo_pcb *n = realloc(pcblist, size += 100);
338			if (n == NULL)
339				err(1, "realloc");
340			pcblist = n;
341		}
342	}
343	*len = i;
344	return pcblist;
345}
346
347void
348ip6protopr(u_long off, const char *name)
349{
350	struct kinfo_pcb *pcblist;
351	size_t i, len;
352	static int first = 1;
353
354	compact = 0;
355	if (Aflag) {
356		if (!numeric_addr)
357			width = 18;
358		else {
359			width = 21;
360			compact = 1;
361		}
362	} else
363		width = 22;
364
365	if (use_sysctl)
366		pcblist = getpcblist_sysctl(name, &len);
367	else
368		pcblist = getpcblist_kmem(off, name, &len);
369
370	for (i = 0; i < len; i++) {
371		struct sockaddr_in6 src, dst;
372
373		memcpy(&src, &pcblist[i].ki_s, sizeof(src));
374		memcpy(&dst, &pcblist[i].ki_d, sizeof(dst));
375
376		if (!aflag && IN6_IS_ADDR_UNSPECIFIED(&dst.sin6_addr))
377			continue;
378
379		if (first) {
380			ip6protoprhdr();
381			first = 0;
382		}
383
384		ip6protopr0((intptr_t) pcblist[i].ki_ppcbaddr,
385		    pcblist[i].ki_rcvq, pcblist[i].ki_sndq,
386		    &src.sin6_addr, src.sin6_port,
387		    &dst.sin6_addr, dst.sin6_port,
388		    pcblist[i].ki_tstate, name, NULL);
389	}
390
391	free(pcblist);
392
393	if (strcmp(name, "tcp6") == 0) {
394		struct timeval t;
395		timebase(&t);
396		gettimeofday(&now, NULL);
397		timersub(&now, &t, &now);
398		show_vtw_v6(print_vtw_v6);
399	}
400}
401
402#ifdef TCP6
403/*
404 * Dump TCP6 statistics structure.
405 */
406void
407tcp6_stats(u_long off, const char *name)
408{
409	struct tcp6stat tcp6stat;
410
411	if (use_sysctl) {
412		size_t size = sizeof(tcp6stat);
413
414		if (sysctlbyname("net.inet6.tcp6.stats", &tcp6stat, &size,
415		    NULL, 0) == -1)
416			return;
417	} else {
418		warnx("%s stats not available via KVM.", name);
419		return;
420	}
421
422	printf ("%s:\n", name);
423
424#define	p(f, m) if (tcp6stat.f || sflag <= 1) \
425    printf(m, tcp6stat.f, plural(tcp6stat.f))
426#define	p2(f1, f2, m) if (tcp6stat.f1 || tcp6stat.f2 || sflag <= 1) \
427    printf(m, tcp6stat.f1, plural(tcp6stat.f1), tcp6stat.f2, plural(tcp6stat.f2))
428#define	p3(f, m) if (tcp6stat.f || sflag <= 1) \
429    printf(m, tcp6stat.f, plurales(tcp6stat.f))
430
431	p(tcp6s_sndtotal, "\t%ld packet%s sent\n");
432	p2(tcp6s_sndpack,tcp6s_sndbyte,
433		"\t\t%ld data packet%s (%ld byte%s)\n");
434	p2(tcp6s_sndrexmitpack, tcp6s_sndrexmitbyte,
435		"\t\t%ld data packet%s (%ld byte%s) retransmitted\n");
436	p2(tcp6s_sndacks, tcp6s_delack,
437		"\t\t%ld ack-only packet%s (%ld packet%s delayed)\n");
438	p(tcp6s_sndurg, "\t\t%ld URG only packet%s\n");
439	p(tcp6s_sndprobe, "\t\t%ld window probe packet%s\n");
440	p(tcp6s_sndwinup, "\t\t%ld window update packet%s\n");
441	p(tcp6s_sndctrl, "\t\t%ld control packet%s\n");
442	p(tcp6s_rcvtotal, "\t%ld packet%s received\n");
443	p2(tcp6s_rcvackpack, tcp6s_rcvackbyte, "\t\t%ld ack%s (for %ld byte%s)\n");
444	p(tcp6s_rcvdupack, "\t\t%ld duplicate ack%s\n");
445	p(tcp6s_rcvacktoomuch, "\t\t%ld ack%s for unsent data\n");
446	p2(tcp6s_rcvpack, tcp6s_rcvbyte,
447		"\t\t%ld packet%s (%ld byte%s) received in-sequence\n");
448	p2(tcp6s_rcvduppack, tcp6s_rcvdupbyte,
449		"\t\t%ld completely duplicate packet%s (%ld byte%s)\n");
450	p(tcp6s_pawsdrop, "\t\t%ld old duplicate packet%s\n");
451	p2(tcp6s_rcvpartduppack, tcp6s_rcvpartdupbyte,
452		"\t\t%ld packet%s with some dup. data (%ld byte%s duped)\n");
453	p2(tcp6s_rcvoopack, tcp6s_rcvoobyte,
454		"\t\t%ld out-of-order packet%s (%ld byte%s)\n");
455	p2(tcp6s_rcvpackafterwin, tcp6s_rcvbyteafterwin,
456		"\t\t%ld packet%s (%ld byte%s) of data after window\n");
457	p(tcp6s_rcvwinprobe, "\t\t%ld window probe%s\n");
458	p(tcp6s_rcvwinupd, "\t\t%ld window update packet%s\n");
459	p(tcp6s_rcvafterclose, "\t\t%ld packet%s received after close\n");
460	p(tcp6s_rcvbadsum, "\t\t%ld discarded for bad checksum%s\n");
461	p(tcp6s_rcvbadoff, "\t\t%ld discarded for bad header offset field%s\n");
462	p(tcp6s_rcvshort, "\t\t%ld discarded because packet%s too short\n");
463	p(tcp6s_connattempt, "\t%ld connection request%s\n");
464	p(tcp6s_accepts, "\t%ld connection accept%s\n");
465	p(tcp6s_badsyn, "\t%ld bad connection attempt%s\n");
466	p(tcp6s_connects, "\t%ld connection%s established (including accepts)\n");
467	p2(tcp6s_closed, tcp6s_drops,
468		"\t%ld connection%s closed (including %ld drop%s)\n");
469	p(tcp6s_conndrops, "\t%ld embryonic connection%s dropped\n");
470	p2(tcp6s_rttupdated, tcp6s_segstimed,
471		"\t%ld segment%s updated rtt (of %ld attempt%s)\n");
472	p(tcp6s_rexmttimeo, "\t%ld retransmit timeout%s\n");
473	p(tcp6s_timeoutdrop, "\t\t%ld connection%s dropped by rexmit timeout\n");
474	p(tcp6s_persisttimeo, "\t%ld persist timeout%s\n");
475	p(tcp6s_persistdrop, "\t%ld connection%s timed out in persist\n");
476	p(tcp6s_keeptimeo, "\t%ld keepalive timeout%s\n");
477	p(tcp6s_keepprobe, "\t\t%ld keepalive probe%s sent\n");
478	p(tcp6s_keepdrops, "\t\t%ld connection%s dropped by keepalive\n");
479	p(tcp6s_predack, "\t%ld correct ACK header prediction%s\n");
480	p(tcp6s_preddat, "\t%ld correct data packet header prediction%s\n");
481	p3(tcp6s_pcbcachemiss, "\t%ld PCB cache miss%s\n");
482#undef p
483#undef p2
484#undef p3
485}
486#endif
487
488/*
489 * Dump UDP6 statistics structure.
490 */
491void
492udp6_stats(u_long off, const char *name)
493{
494	uint64_t udp6stat[UDP6_NSTATS];
495	u_quad_t delivered;
496
497	if (use_sysctl) {
498		size_t size = sizeof(udp6stat);
499
500		if (sysctlbyname("net.inet6.udp6.stats", udp6stat, &size,
501		    NULL, 0) == -1)
502			return;
503	} else {
504		warnx("%s stats not available via KVM.", name);
505		return;
506	}
507	printf("%s:\n", name);
508#define	p(f, m) if (udp6stat[f] || sflag <= 1) \
509    printf(m, (unsigned long long)udp6stat[f], plural(udp6stat[f]))
510#define	p1(f, m) if (udp6stat[f] || sflag <= 1) \
511    printf(m, (unsigned long long)udp6stat[f])
512	p(UDP6_STAT_IPACKETS, "\t%llu datagram%s received\n");
513	p1(UDP6_STAT_HDROPS, "\t%llu with incomplete header\n");
514	p1(UDP6_STAT_BADLEN, "\t%llu with bad data length field\n");
515	p1(UDP6_STAT_BADSUM, "\t%llu with bad checksum\n");
516	p1(UDP6_STAT_NOSUM, "\t%llu with no checksum\n");
517	p1(UDP6_STAT_NOPORT, "\t%llu dropped due to no socket\n");
518	p(UDP6_STAT_NOPORTMCAST,
519	    "\t%llu multicast datagram%s dropped due to no socket\n");
520	p1(UDP6_STAT_FULLSOCK, "\t%llu dropped due to full socket buffers\n");
521	delivered = udp6stat[UDP6_STAT_IPACKETS] -
522		    udp6stat[UDP6_STAT_HDROPS] -
523		    udp6stat[UDP6_STAT_BADLEN] -
524		    udp6stat[UDP6_STAT_BADSUM] -
525		    udp6stat[UDP6_STAT_NOPORT] -
526		    udp6stat[UDP6_STAT_NOPORTMCAST] -
527		    udp6stat[UDP6_STAT_FULLSOCK];
528	if (delivered || sflag <= 1)
529		printf("\t%llu delivered\n", (unsigned long long)delivered);
530	p(UDP6_STAT_OPACKETS, "\t%llu datagram%s output\n");
531#undef p
532#undef p1
533}
534
535static	const char *ip6nh[] = {
536/*0*/	"hop by hop",
537	"ICMP",
538	"IGMP",
539	NULL,
540	"IP",
541/*5*/	NULL,
542	"TCP",
543	NULL,
544	NULL,
545	NULL,
546/*10*/	NULL, NULL, NULL, NULL, NULL,
547/*15*/	NULL,
548	NULL,
549	"UDP",
550	NULL,
551	NULL,
552/*20*/	NULL,
553	NULL,
554	"IDP",
555	NULL,
556	NULL,
557/*25*/	NULL,
558	NULL,
559	NULL,
560	NULL,
561	"TP",
562/*30*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
563/*40*/	NULL,
564	"IP6",
565	NULL,
566	"routing",
567	"fragment",
568/*45*/	NULL, NULL, NULL, NULL, NULL,
569/*50*/	"ESP",
570	"AH",
571	NULL,
572	NULL,
573	NULL,
574/*55*/	NULL,
575	NULL,
576	NULL,
577	"ICMP6",
578	"no next header",
579/*60*/	"destination option",
580	NULL,
581	NULL,
582	NULL,
583	NULL,
584/*65*/	NULL, NULL, NULL, NULL, NULL,
585/*70*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
586/*80*/	"ISOIP",
587	NULL,
588	NULL,
589	NULL,
590	NULL,
591	NULL,
592	NULL,
593	NULL,
594	NULL,
595	"OSPF",
596/*90*/	NULL, NULL, NULL, NULL, NULL,
597/*95*/	NULL,
598	NULL,
599	"Ethernet",
600	NULL,
601	NULL,
602/*100*/	NULL,
603	NULL,
604	NULL,
605	"PIM",
606	NULL,
607/*105*/	NULL, NULL, NULL, NULL, NULL,
608/*110*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
609/*120*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
610/*130*/	NULL,
611	NULL,
612	"SCTP",
613	NULL,
614	NULL,
615/*135*/	NULL, NULL, NULL, NULL, NULL,
616/*140*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
617	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
618/*160*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
619	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
620/*180*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
621	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
622/*200*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
623	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
624/*220*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
625	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
626/*240*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
627	NULL, NULL, NULL, NULL, NULL, NULL,
628};
629
630/*
631 * Dump IP6 statistics structure.
632 */
633void
634ip6_stats(u_long off, const char *name)
635{
636	uint64_t ip6stat[IP6_NSTATS];
637	int first, i;
638	struct protoent *ep;
639	const char *n;
640
641	if (use_sysctl) {
642		size_t size = sizeof(ip6stat);
643
644		if (sysctlbyname("net.inet6.ip6.stats", ip6stat, &size,
645		    NULL, 0) == -1)
646			return;
647	} else {
648		warnx("%s stats not available via KVM.", name);
649		return;
650	}
651	printf("%s:\n", name);
652
653#define	p(f, m) if (ip6stat[f] || sflag <= 1) \
654    printf(m, (unsigned long long)ip6stat[f], plural(ip6stat[f]))
655#define	p1(f, m) if (ip6stat[f] || sflag <= 1) \
656    printf(m, (unsigned long long)ip6stat[f])
657
658	p(IP6_STAT_TOTAL, "\t%llu total packet%s received\n");
659	p1(IP6_STAT_TOOSMALL, "\t%llu with size smaller than minimum\n");
660	p1(IP6_STAT_TOOSHORT, "\t%llu with data size < data length\n");
661	p1(IP6_STAT_BADOPTIONS, "\t%llu with bad options\n");
662	p1(IP6_STAT_BADVERS, "\t%llu with incorrect version number\n");
663	p(IP6_STAT_FRAGMENTS, "\t%llu fragment%s received\n");
664	p(IP6_STAT_FRAGDROPPED,
665	    "\t%llu fragment%s dropped (dup or out of space)\n");
666	p(IP6_STAT_FRAGTIMEOUT, "\t%llu fragment%s dropped after timeout\n");
667	p(IP6_STAT_FRAGOVERFLOW, "\t%llu fragment%s that exceeded limit\n");
668	p(IP6_STAT_REASSEMBLED, "\t%llu packet%s reassembled ok\n");
669	p(IP6_STAT_DELIVERED, "\t%llu packet%s for this host\n");
670	p(IP6_STAT_FORWARD, "\t%llu packet%s forwarded\n");
671	p(IP6_STAT_FASTFORWARD, "\t%llu packet%s fast forwarded\n");
672	p1(IP6_STAT_FASTFORWARDFLOWS, "\t%llu fast forward flows\n");
673	p(IP6_STAT_CANTFORWARD, "\t%llu packet%s not forwardable\n");
674	p(IP6_STAT_REDIRECTSENT, "\t%llu redirect%s sent\n");
675	p(IP6_STAT_LOCALOUT, "\t%llu packet%s sent from this host\n");
676	p(IP6_STAT_RAWOUT, "\t%llu packet%s sent with fabricated ip header\n");
677	p(IP6_STAT_ODROPPED,
678	    "\t%llu output packet%s dropped due to no bufs, etc.\n");
679	p(IP6_STAT_NOROUTE, "\t%llu output packet%s discarded due to no route\n");
680	p(IP6_STAT_FRAGMENTED, "\t%llu output datagram%s fragmented\n");
681	p(IP6_STAT_OFRAGMENTS, "\t%llu fragment%s created\n");
682	p(IP6_STAT_CANTFRAG, "\t%llu datagram%s that can't be fragmented\n");
683	p(IP6_STAT_BADSCOPE, "\t%llu packet%s that violated scope rules\n");
684	p(IP6_STAT_NOTMEMBER, "\t%llu multicast packet%s which we don't join\n");
685	for (first = 1, i = 0; i < 256; i++)
686		if (ip6stat[IP6_STAT_NXTHIST + i] != 0) {
687			if (first) {
688				printf("\tInput packet histogram:\n");
689				first = 0;
690			}
691			n = NULL;
692			if (ip6nh[i])
693				n = ip6nh[i];
694			else if ((ep = getprotobynumber(i)) != NULL)
695				n = ep->p_name;
696			if (n)
697				printf("\t\t%s: %llu\n", n,
698				    (unsigned long long)ip6stat[IP6_STAT_NXTHIST + i]);
699			else
700				printf("\t\t#%d: %llu\n", i,
701				    (unsigned long long)ip6stat[IP6_STAT_NXTHIST + i]);
702		}
703	printf("\tMbuf statistics:\n");
704	p(IP6_STAT_M1, "\t\t%llu one mbuf%s\n");
705	for (first = 1, i = 0; i < 32; i++) {
706		char ifbuf[IFNAMSIZ];
707		if (ip6stat[IP6_STAT_M2M + i] != 0) {
708			if (first) {
709				printf("\t\ttwo or more mbuf:\n");
710				first = 0;
711			}
712			printf("\t\t\t%s = %llu\n",
713			       if_indextoname(i, ifbuf),
714			       (unsigned long long)ip6stat[IP6_STAT_M2M + i]);
715		}
716	}
717	p(IP6_STAT_MEXT1, "\t\t%llu one ext mbuf%s\n");
718	p(IP6_STAT_MEXT2M, "\t\t%llu two or more ext mbuf%s\n");
719	p(IP6_STAT_EXTHDRTOOLONG,
720	    "\t%llu packet%s whose headers are not continuous\n");
721	p(IP6_STAT_NOGIF, "\t%llu tunneling packet%s that can't find gif\n");
722	p(IP6_STAT_TOOMANYHDR,
723	    "\t%llu packet%s discarded due to too many headers\n");
724
725	/* for debugging source address selection */
726#define PRINT_SCOPESTAT(s,i) do {\
727		switch(i) { /* XXX hardcoding in each case */\
728		case 1:\
729			p(s, "\t\t%llu node-local%s\n");\
730			break;\
731		case 2:\
732			p(s, "\t\t%llu link-local%s\n");\
733			break;\
734		case 5:\
735			p(s, "\t\t%llu site-local%s\n");\
736			break;\
737		case 14:\
738			p(s, "\t\t%llu global%s\n");\
739			break;\
740		default:\
741			printf("\t\t%llu addresses scope=%x\n",\
742			       (unsigned long long)ip6stat[s], i);\
743		}\
744	} while(/*CONSTCOND*/0);
745
746	p(IP6_STAT_SOURCES_NONE,
747	  "\t%llu failure%s of source address selection\n");
748	for (first = 1, i = 0; i < 16; i++) {
749		if (ip6stat[IP6_STAT_SOURCES_SAMEIF + i]) {
750			if (first) {
751				printf("\tsource addresses on an outgoing I/F\n");
752				first = 0;
753			}
754			PRINT_SCOPESTAT(IP6_STAT_SOURCES_SAMEIF + i, i);
755		}
756	}
757	for (first = 1, i = 0; i < 16; i++) {
758		if (ip6stat[IP6_STAT_SOURCES_OTHERIF + i]) {
759			if (first) {
760				printf("\tsource addresses on a non-outgoing I/F\n");
761				first = 0;
762			}
763			PRINT_SCOPESTAT(IP6_STAT_SOURCES_OTHERIF + i, i);
764		}
765	}
766	for (first = 1, i = 0; i < 16; i++) {
767		if (ip6stat[IP6_STAT_SOURCES_SAMESCOPE + i]) {
768			if (first) {
769				printf("\tsource addresses of same scope\n");
770				first = 0;
771			}
772			PRINT_SCOPESTAT(IP6_STAT_SOURCES_SAMESCOPE + i, i);
773		}
774	}
775	for (first = 1, i = 0; i < 16; i++) {
776		if (ip6stat[IP6_STAT_SOURCES_OTHERSCOPE + i]) {
777			if (first) {
778				printf("\tsource addresses of a different scope\n");
779				first = 0;
780			}
781			PRINT_SCOPESTAT(IP6_STAT_SOURCES_OTHERSCOPE + i, i);
782		}
783	}
784	for (first = 1, i = 0; i < 16; i++) {
785		if (ip6stat[IP6_STAT_SOURCES_DEPRECATED + i]) {
786			if (first) {
787				printf("\tdeprecated source addresses\n");
788				first = 0;
789			}
790			PRINT_SCOPESTAT(IP6_STAT_SOURCES_DEPRECATED + i, i);
791		}
792	}
793
794	p1(IP6_STAT_FORWARD_CACHEHIT, "\t%llu forward cache hit\n");
795	p1(IP6_STAT_FORWARD_CACHEMISS, "\t%llu forward cache miss\n");
796#undef p
797#undef p1
798}
799
800/*
801 * Dump IPv6 per-interface statistics based on RFC 2465.
802 */
803void
804ip6_ifstats(const char *ifname)
805{
806	struct in6_ifreq ifr;
807	int s;
808#define	p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
809    printf(m, (unsigned long long)ifr.ifr_ifru.ifru_stat.f, \
810	plural(ifr.ifr_ifru.ifru_stat.f))
811#define	p_5(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
812    printf(m, (unsigned long long)ip6stat.f)
813
814	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
815		perror("Warning: socket(AF_INET6)");
816		return;
817	}
818
819	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
820	printf("ip6 on %s:\n", ifname);
821
822	if (ioctl(s, SIOCGIFSTAT_IN6, (char *)&ifr) < 0) {
823		perror("Warning: ioctl(SIOCGIFSTAT_IN6)");
824		goto end;
825	}
826
827	p(ifs6_in_receive, "\t%llu total input datagram%s\n");
828	p(ifs6_in_hdrerr, "\t%llu datagram%s with invalid header received\n");
829	p(ifs6_in_toobig, "\t%llu datagram%s exceeded MTU received\n");
830	p(ifs6_in_noroute, "\t%llu datagram%s with no route received\n");
831	p(ifs6_in_addrerr, "\t%llu datagram%s with invalid dst received\n");
832	p(ifs6_in_truncated, "\t%llu truncated datagram%s received\n");
833	p(ifs6_in_protounknown, "\t%llu datagram%s with unknown proto received\n");
834	p(ifs6_in_discard, "\t%llu input datagram%s discarded\n");
835	p(ifs6_in_deliver,
836	  "\t%llu datagram%s delivered to an upper layer protocol\n");
837	p(ifs6_out_forward, "\t%llu datagram%s forwarded to this interface\n");
838	p(ifs6_out_request,
839	  "\t%llu datagram%s sent from an upper layer protocol\n");
840	p(ifs6_out_discard, "\t%llu total discarded output datagram%s\n");
841	p(ifs6_out_fragok, "\t%llu output datagram%s fragmented\n");
842	p(ifs6_out_fragfail, "\t%llu output datagram%s failed on fragment\n");
843	p(ifs6_out_fragcreat, "\t%llu output datagram%s succeeded on fragment\n");
844	p(ifs6_reass_reqd, "\t%llu incoming datagram%s fragmented\n");
845	p(ifs6_reass_ok, "\t%llu datagram%s reassembled\n");
846	p(ifs6_reass_fail, "\t%llu datagram%s failed on reassembling\n");
847	p(ifs6_in_mcast, "\t%llu multicast datagram%s received\n");
848	p(ifs6_out_mcast, "\t%llu multicast datagram%s sent\n");
849
850  end:
851	close(s);
852
853#undef p
854#undef p_5
855}
856
857static	const char *icmp6names[] = {
858	"#0",
859	"unreach",
860	"packet too big",
861	"time exceed",
862	"parameter problem",
863	"#5",
864	"#6",
865	"#7",
866	"#8",
867	"#9",
868	"#10",
869	"#11",
870	"#12",
871	"#13",
872	"#14",
873	"#15",
874	"#16",
875	"#17",
876	"#18",
877	"#19",
878	"#20",
879	"#21",
880	"#22",
881	"#23",
882	"#24",
883	"#25",
884	"#26",
885	"#27",
886	"#28",
887	"#29",
888	"#30",
889	"#31",
890	"#32",
891	"#33",
892	"#34",
893	"#35",
894	"#36",
895	"#37",
896	"#38",
897	"#39",
898	"#40",
899	"#41",
900	"#42",
901	"#43",
902	"#44",
903	"#45",
904	"#46",
905	"#47",
906	"#48",
907	"#49",
908	"#50",
909	"#51",
910	"#52",
911	"#53",
912	"#54",
913	"#55",
914	"#56",
915	"#57",
916	"#58",
917	"#59",
918	"#60",
919	"#61",
920	"#62",
921	"#63",
922	"#64",
923	"#65",
924	"#66",
925	"#67",
926	"#68",
927	"#69",
928	"#70",
929	"#71",
930	"#72",
931	"#73",
932	"#74",
933	"#75",
934	"#76",
935	"#77",
936	"#78",
937	"#79",
938	"#80",
939	"#81",
940	"#82",
941	"#83",
942	"#84",
943	"#85",
944	"#86",
945	"#87",
946	"#88",
947	"#89",
948	"#80",
949	"#91",
950	"#92",
951	"#93",
952	"#94",
953	"#95",
954	"#96",
955	"#97",
956	"#98",
957	"#99",
958	"#100",
959	"#101",
960	"#102",
961	"#103",
962	"#104",
963	"#105",
964	"#106",
965	"#107",
966	"#108",
967	"#109",
968	"#110",
969	"#111",
970	"#112",
971	"#113",
972	"#114",
973	"#115",
974	"#116",
975	"#117",
976	"#118",
977	"#119",
978	"#120",
979	"#121",
980	"#122",
981	"#123",
982	"#124",
983	"#125",
984	"#126",
985	"#127",
986	"echo",
987	"echo reply",
988	"multicast listener query",
989	"multicast listener report",
990	"multicast listener done",
991	"router solicitation",
992	"router advertisement",
993	"neighbor solicitation",
994	"neighbor advertisement",
995	"redirect",
996	"router renumbering",
997	"node information request",
998	"node information reply",
999	"#141",
1000	"#142",
1001	"#143",
1002	"#144",
1003	"#145",
1004	"#146",
1005	"#147",
1006	"#148",
1007	"#149",
1008	"#150",
1009	"#151",
1010	"#152",
1011	"#153",
1012	"#154",
1013	"#155",
1014	"#156",
1015	"#157",
1016	"#158",
1017	"#159",
1018	"#160",
1019	"#161",
1020	"#162",
1021	"#163",
1022	"#164",
1023	"#165",
1024	"#166",
1025	"#167",
1026	"#168",
1027	"#169",
1028	"#170",
1029	"#171",
1030	"#172",
1031	"#173",
1032	"#174",
1033	"#175",
1034	"#176",
1035	"#177",
1036	"#178",
1037	"#179",
1038	"#180",
1039	"#181",
1040	"#182",
1041	"#183",
1042	"#184",
1043	"#185",
1044	"#186",
1045	"#187",
1046	"#188",
1047	"#189",
1048	"#180",
1049	"#191",
1050	"#192",
1051	"#193",
1052	"#194",
1053	"#195",
1054	"#196",
1055	"#197",
1056	"#198",
1057	"#199",
1058	"#200",
1059	"#201",
1060	"#202",
1061	"#203",
1062	"#204",
1063	"#205",
1064	"#206",
1065	"#207",
1066	"#208",
1067	"#209",
1068	"#210",
1069	"#211",
1070	"#212",
1071	"#213",
1072	"#214",
1073	"#215",
1074	"#216",
1075	"#217",
1076	"#218",
1077	"#219",
1078	"#220",
1079	"#221",
1080	"#222",
1081	"#223",
1082	"#224",
1083	"#225",
1084	"#226",
1085	"#227",
1086	"#228",
1087	"#229",
1088	"#230",
1089	"#231",
1090	"#232",
1091	"#233",
1092	"#234",
1093	"#235",
1094	"#236",
1095	"#237",
1096	"#238",
1097	"#239",
1098	"#240",
1099	"#241",
1100	"#242",
1101	"#243",
1102	"#244",
1103	"#245",
1104	"#246",
1105	"#247",
1106	"#248",
1107	"#249",
1108	"#250",
1109	"#251",
1110	"#252",
1111	"#253",
1112	"#254",
1113	"#255",
1114};
1115
1116/*
1117 * Dump ICMPv6 statistics.
1118 */
1119void
1120icmp6_stats(u_long off, const char *name)
1121{
1122	uint64_t icmp6stat[ICMP6_NSTATS];
1123	int i, first;
1124
1125	if (use_sysctl) {
1126		size_t size = sizeof(icmp6stat);
1127
1128		if (sysctlbyname("net.inet6.icmp6.stats", icmp6stat, &size,
1129		    NULL, 0) == -1)
1130			return;
1131	} else {
1132		warnx("%s stats not available via KVM.", name);
1133		return;
1134	}
1135
1136	printf("%s:\n", name);
1137
1138#define	p(f, m) if (icmp6stat[f] || sflag <= 1) \
1139    printf(m, (unsigned long long)icmp6stat[f], plural(icmp6stat[f]))
1140#define p_oerr(f, m) if (icmp6stat[ICMP6_STAT_OUTERRHIST + f] || sflag <= 1) \
1141    printf(m, (unsigned long long)icmp6stat[ICMP6_STAT_OUTERRHIST + f])
1142
1143	p(ICMP6_STAT_ERROR, "\t%llu call%s to icmp6_error\n");
1144	p(ICMP6_STAT_CANTERROR,
1145	    "\t%llu error%s not generated because old message was icmp6 or so\n");
1146	p(ICMP6_STAT_TOOFREQ,
1147	    "\t%llu error%s not generated because of rate limitation\n");
1148	for (first = 1, i = 0; i < 256; i++)
1149		if (icmp6stat[ICMP6_STAT_OUTHIST + i] != 0) {
1150			if (first) {
1151				printf("\tOutput packet histogram:\n");
1152				first = 0;
1153			}
1154			printf("\t\t%s: %llu\n", icmp6names[i],
1155			 (unsigned long long)icmp6stat[ICMP6_STAT_OUTHIST + i]);
1156		}
1157	p(ICMP6_STAT_BADCODE, "\t%llu message%s with bad code fields\n");
1158	p(ICMP6_STAT_TOOSHORT, "\t%llu message%s < minimum length\n");
1159	p(ICMP6_STAT_CHECKSUM, "\t%llu bad checksum%s\n");
1160	p(ICMP6_STAT_BADLEN, "\t%llu message%s with bad length\n");
1161	for (first = 1, i = 0; i < ICMP6_MAXTYPE; i++)
1162		if (icmp6stat[ICMP6_STAT_INHIST + i] != 0) {
1163			if (first) {
1164				printf("\tInput packet histogram:\n");
1165				first = 0;
1166			}
1167			printf("\t\t%s: %llu\n", icmp6names[i],
1168			  (unsigned long long)icmp6stat[ICMP6_STAT_INHIST + i]);
1169		}
1170	printf("\tHistogram of error messages to be generated:\n");
1171	p_oerr(ICMP6_ERRSTAT_DST_UNREACH_NOROUTE, "\t\t%llu no route\n");
1172	p_oerr(ICMP6_ERRSTAT_DST_UNREACH_ADMIN, "\t\t%llu administratively prohibited\n");
1173	p_oerr(ICMP6_ERRSTAT_DST_UNREACH_BEYONDSCOPE, "\t\t%llu beyond scope\n");
1174	p_oerr(ICMP6_ERRSTAT_DST_UNREACH_ADDR, "\t\t%llu address unreachable\n");
1175	p_oerr(ICMP6_ERRSTAT_DST_UNREACH_NOPORT, "\t\t%llu port unreachable\n");
1176	p_oerr(ICMP6_ERRSTAT_PACKET_TOO_BIG, "\t\t%llu packet too big\n");
1177	p_oerr(ICMP6_ERRSTAT_TIME_EXCEED_TRANSIT, "\t\t%llu time exceed transit\n");
1178	p_oerr(ICMP6_ERRSTAT_TIME_EXCEED_REASSEMBLY, "\t\t%llu time exceed reassembly\n");
1179	p_oerr(ICMP6_ERRSTAT_PARAMPROB_HEADER, "\t\t%llu erroneous header field\n");
1180	p_oerr(ICMP6_ERRSTAT_PARAMPROB_NEXTHEADER, "\t\t%llu unrecognized next header\n");
1181	p_oerr(ICMP6_ERRSTAT_PARAMPROB_OPTION, "\t\t%llu unrecognized option\n");
1182	p_oerr(ICMP6_ERRSTAT_REDIRECT, "\t\t%llu redirect\n");
1183	p_oerr(ICMP6_ERRSTAT_UNKNOWN, "\t\t%llu unknown\n");
1184
1185	p(ICMP6_STAT_REFLECT, "\t%llu message response%s generated\n");
1186	p(ICMP6_STAT_ND_TOOMANYOPT, "\t%llu message%s with too many ND options\n");
1187	p(ICMP6_STAT_ND_BADOPT, "\t%llu message%s with bad ND options\n");
1188	p(ICMP6_STAT_BADNS, "\t%llu bad neighbor solicitation message%s\n");
1189	p(ICMP6_STAT_BADNA, "\t%llu bad neighbor advertisement message%s\n");
1190	p(ICMP6_STAT_BADRS, "\t%llu bad router solicitation message%s\n");
1191	p(ICMP6_STAT_BADRA, "\t%llu bad router advertisement message%s\n");
1192	p(ICMP6_STAT_DROPPED_RAROUTE, "\t%llu router advertisement route%s dropped\n");
1193	p(ICMP6_STAT_BADREDIRECT, "\t%llu bad redirect message%s\n");
1194	p(ICMP6_STAT_PMTUCHG, "\t%llu path MTU change%s\n");
1195#undef p
1196#undef p_oerr
1197}
1198
1199/*
1200 * Dump ICMPv6 per-interface statistics based on RFC 2466.
1201 */
1202void
1203icmp6_ifstats(const char *ifname)
1204{
1205	struct in6_ifreq ifr;
1206	int s;
1207#define	p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \
1208    printf(m, (unsigned long long)ifr.ifr_ifru.ifru_icmp6stat.f, \
1209	plural(ifr.ifr_ifru.ifru_icmp6stat.f))
1210
1211	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1212		perror("Warning: socket(AF_INET6)");
1213		return;
1214	}
1215
1216	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1217	printf("icmp6 on %s:\n", ifname);
1218
1219	if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) {
1220		perror("Warning: ioctl(SIOCGIFSTAT_ICMP6)");
1221		goto end;
1222	}
1223
1224	p(ifs6_in_msg, "\t%llu total input message%s\n");
1225	p(ifs6_in_error, "\t%llu total input error message%s\n");
1226	p(ifs6_in_dstunreach, "\t%llu input destination unreachable error%s\n");
1227	p(ifs6_in_adminprohib, "\t%llu input administratively prohibited error%s\n");
1228	p(ifs6_in_timeexceed, "\t%llu input time exceeded error%s\n");
1229	p(ifs6_in_paramprob, "\t%llu input parameter problem error%s\n");
1230	p(ifs6_in_pkttoobig, "\t%llu input packet too big error%s\n");
1231	p(ifs6_in_echo, "\t%llu input echo request%s\n");
1232	p(ifs6_in_echoreply, "\t%llu input echo reply%s\n");
1233	p(ifs6_in_routersolicit, "\t%llu input router solicitation%s\n");
1234	p(ifs6_in_routeradvert, "\t%llu input router advertisement%s\n");
1235	p(ifs6_in_neighborsolicit, "\t%llu input neighbor solicitation%s\n");
1236	p(ifs6_in_neighboradvert, "\t%llu input neighbor advertisement%s\n");
1237	p(ifs6_in_redirect, "\t%llu input redirect%s\n");
1238	p(ifs6_in_mldquery, "\t%llu input MLD query%s\n");
1239	p(ifs6_in_mldreport, "\t%llu input MLD report%s\n");
1240	p(ifs6_in_mlddone, "\t%llu input MLD done%s\n");
1241
1242	p(ifs6_out_msg, "\t%llu total output message%s\n");
1243	p(ifs6_out_error, "\t%llu total output error message%s\n");
1244	p(ifs6_out_dstunreach, "\t%llu output destination unreachable error%s\n");
1245	p(ifs6_out_adminprohib, "\t%llu output administratively prohibited error%s\n");
1246	p(ifs6_out_timeexceed, "\t%llu output time exceeded error%s\n");
1247	p(ifs6_out_paramprob, "\t%llu output parameter problem error%s\n");
1248	p(ifs6_out_pkttoobig, "\t%llu output packet too big error%s\n");
1249	p(ifs6_out_echo, "\t%llu output echo request%s\n");
1250	p(ifs6_out_echoreply, "\t%llu output echo reply%s\n");
1251	p(ifs6_out_routersolicit, "\t%llu output router solicitation%s\n");
1252	p(ifs6_out_routeradvert, "\t%llu output router advertisement%s\n");
1253	p(ifs6_out_neighborsolicit, "\t%llu output neighbor solicitation%s\n");
1254	p(ifs6_out_neighboradvert, "\t%llu output neighbor advertisement%s\n");
1255	p(ifs6_out_redirect, "\t%llu output redirect%s\n");
1256	p(ifs6_out_mldquery, "\t%llu output MLD query%s\n");
1257	p(ifs6_out_mldreport, "\t%llu output MLD report%s\n");
1258	p(ifs6_out_mlddone, "\t%llu output MLD done%s\n");
1259
1260  end:
1261	close(s);
1262#undef p
1263}
1264
1265/*
1266 * Dump PIM statistics structure.
1267 */
1268void
1269pim6_stats(u_long off, const char *name)
1270{
1271	uint64_t pim6stat[PIM6_NSTATS];
1272
1273	if (use_sysctl) {
1274		size_t size = sizeof(pim6stat);
1275
1276		if (sysctlbyname("net.inet6.pim6.stats", pim6stat, &size,
1277		    NULL, 0) == -1)
1278			return;
1279        } else {
1280		warnx("%s stats not available via KVM.", name);
1281		return;
1282	}
1283	printf("%s:\n", name);
1284
1285#define	p(f, m) if (pim6stat[f] || sflag <= 1) \
1286    printf(m, (unsigned long long)pim6stat[f], plural(pim6stat[f]))
1287	p(PIM6_STAT_RCV_TOTAL, "\t%llu message%s received\n");
1288	p(PIM6_STAT_RCV_TOOSHORT, "\t%llu message%s received with too few bytes\n");
1289	p(PIM6_STAT_RCV_BADSUM, "\t%llu message%s received with bad checksum\n");
1290	p(PIM6_STAT_RCV_BADVERSION, "\t%llu message%s received with bad version\n");
1291	p(PIM6_STAT_RCV_REGISTERS, "\t%llu register%s received\n");
1292	p(PIM6_STAT_RCV_BADREGISTERS, "\t%llu bad register%s received\n");
1293	p(PIM6_STAT_SND_REGISTERS, "\t%llu register%s sent\n");
1294#undef p
1295}
1296
1297/*
1298 * Dump raw ip6 statistics structure.
1299 */
1300void
1301rip6_stats(u_long off, const char *name)
1302{
1303	uint64_t rip6stat[RIP6_NSTATS];
1304	u_quad_t delivered;
1305
1306	if (use_sysctl) {
1307		size_t size = sizeof(rip6stat);
1308
1309		if (sysctlbyname("net.inet6.raw6.stats", rip6stat, &size,
1310		    NULL, 0) == -1)
1311			return;
1312	} else {
1313		warnx("%s stats not available via KVM.", name);
1314		return;
1315	}
1316	printf("%s:\n", name);
1317
1318#define	p(f, m) if (rip6stat[f] || sflag <= 1) \
1319    printf(m, (unsigned long long)rip6stat[f], plural(rip6stat[f]))
1320	p(RIP6_STAT_IPACKETS, "\t%llu message%s received\n");
1321	p(RIP6_STAT_ISUM, "\t%llu checksum calculation%s on inbound\n");
1322	p(RIP6_STAT_BADSUM, "\t%llu message%s with bad checksum\n");
1323	p(RIP6_STAT_NOSOCK, "\t%llu message%s dropped due to no socket\n");
1324	p(RIP6_STAT_NOSOCKMCAST,
1325	    "\t%llu multicast message%s dropped due to no socket\n");
1326	p(RIP6_STAT_FULLSOCK,
1327	    "\t%llu message%s dropped due to full socket buffers\n");
1328	delivered = rip6stat[RIP6_STAT_IPACKETS] -
1329		    rip6stat[RIP6_STAT_BADSUM] -
1330		    rip6stat[RIP6_STAT_NOSOCK] -
1331		    rip6stat[RIP6_STAT_NOSOCKMCAST] -
1332		    rip6stat[RIP6_STAT_FULLSOCK];
1333	if (delivered || sflag <= 1)
1334		printf("\t%llu delivered\n", (unsigned long long)delivered);
1335	p(RIP6_STAT_OPACKETS, "\t%llu datagram%s output\n");
1336#undef p
1337}
1338
1339/*
1340 * Pretty print an Internet address (net address + port).
1341 * Take numeric_addr and numeric_port into consideration.
1342 */
1343void
1344inet6print(const struct in6_addr *in6, int port, const char *proto)
1345{
1346#define GETSERVBYPORT6(port, proto, ret)\
1347do {\
1348	if (strcmp((proto), "tcp6") == 0)\
1349		(ret) = getservbyport((int)(port), "tcp");\
1350	else if (strcmp((proto), "udp6") == 0)\
1351		(ret) = getservbyport((int)(port), "udp");\
1352	else\
1353		(ret) = getservbyport((int)(port), (proto));\
1354} while (0)
1355	struct servent *sp = 0;
1356	char line[80], *cp;
1357	int lwidth;
1358
1359	lwidth = Aflag ? 12 : 16;
1360	if (vflag && lwidth < (int)strlen(inet6name(in6)))
1361		lwidth = strlen(inet6name(in6));
1362	snprintf(line, sizeof(line), "%.*s.", lwidth, inet6name(in6));
1363	cp = strchr(line, '\0');
1364	if (!numeric_port && port)
1365		GETSERVBYPORT6(port, proto, sp);
1366	if (sp || port == 0)
1367		snprintf(cp, sizeof(line) - (cp - line),
1368		    "%s", sp ? sp->s_name : "*");
1369	else
1370		snprintf(cp, sizeof(line) - (cp - line),
1371		    "%d", ntohs((u_short)port));
1372	lwidth = Aflag ? 18 : 22;
1373	if (vflag && lwidth < (int)strlen(line))
1374		lwidth = strlen(line);
1375	printf(" %-*.*s", lwidth, lwidth, line);
1376}
1377
1378/*
1379 * Construct an Internet address representation.
1380 * If the numeric_addr has been supplied, give
1381 * numeric value, otherwise try for symbolic name.
1382 */
1383
1384char *
1385inet6name(const struct in6_addr *in6p)
1386{
1387	char *cp;
1388	static char line[NI_MAXHOST];
1389	struct hostent *hp;
1390	static char domain[MAXHOSTNAMELEN + 1];
1391	static int first = 1;
1392	char hbuf[NI_MAXHOST];
1393	struct sockaddr_in6 sin6;
1394	const int niflag = NI_NUMERICHOST;
1395
1396	if (first && !numeric_addr) {
1397		first = 0;
1398		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
1399		    (cp = strchr(domain, '.')))
1400			(void) strlcpy(domain, cp + 1, sizeof(domain));
1401		else
1402			domain[0] = 0;
1403	}
1404	cp = 0;
1405	if (!numeric_addr && !IN6_IS_ADDR_UNSPECIFIED(in6p)) {
1406		hp = gethostbyaddr((const char *)in6p, sizeof(*in6p), AF_INET6);
1407		if (hp) {
1408			if ((cp = strchr(hp->h_name, '.')) &&
1409			    !strcmp(cp + 1, domain))
1410				*cp = 0;
1411			cp = hp->h_name;
1412		}
1413	}
1414	if (IN6_IS_ADDR_UNSPECIFIED(in6p))
1415		strlcpy(line, "*", sizeof(line));
1416	else if (cp)
1417		strlcpy(line, cp, sizeof(line));
1418	else {
1419		memset(&sin6, 0, sizeof(sin6));
1420		sin6.sin6_len = sizeof(sin6);
1421		sin6.sin6_family = AF_INET6;
1422		sin6.sin6_addr = *in6p;
1423#ifdef __KAME__
1424		if (IN6_IS_ADDR_LINKLOCAL(in6p) ||
1425		    IN6_IS_ADDR_MC_LINKLOCAL(in6p)) {
1426			sin6.sin6_scope_id =
1427			    ntohs(*(const u_int16_t *)&in6p->s6_addr[2]);
1428			sin6.sin6_addr.s6_addr[2] = 0;
1429			sin6.sin6_addr.s6_addr[3] = 0;
1430		}
1431#endif
1432		if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
1433				hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
1434			strlcpy(hbuf, "?", sizeof(hbuf));
1435		strlcpy(line, hbuf, sizeof(line));
1436	}
1437	return (line);
1438}
1439
1440#ifdef TCP6
1441/*
1442 * Dump the contents of a TCP6 PCB.
1443 */
1444void
1445tcp6_dump(u_long pcbaddr)
1446	u_long pcbaddr;
1447{
1448	struct tcp6cb tcp6cb;
1449	int i;
1450	struct kinfo_pcb *pcblist;
1451	size_t j, len;
1452
1453	if (use_sysctl)
1454		pcblist = getpcblist_sysctl(name, &len);
1455	else
1456		pcblist = getpcblist_kmem(off, name, &len);
1457
1458	for (j = 0; j < len; j++)
1459		if (pcblist[j].ki_ppcbaddr == pcbaddr)
1460			break;
1461	free(pcblist);
1462
1463	if (j == len)
1464		errx(1, "0x%lx is not a valid pcb address", pcbaddr);
1465
1466	kread(pcbaddr, (char *)&tcp6cb, sizeof(tcp6cb));
1467
1468	printf("TCP Protocol Control Block at 0x%08lx:\n\n", pcbaddr);
1469
1470	printf("Timers:\n");
1471	for (i = 0; i < TCP6T_NTIMERS; i++)
1472		printf("\t%s: %u", tcp6timers[i], tcp6cb.t_timer[i]);
1473	printf("\n\n");
1474
1475	if (tcp6cb.t_state < 0 || tcp6cb.t_state >= TCP6_NSTATES)
1476		printf("State: %d", tcp6cb.t_state);
1477	else
1478		printf("State: %s", tcp6states[tcp6cb.t_state]);
1479	printf(", flags 0x%x, in6pcb 0x%lx\n\n", tcp6cb.t_flags,
1480	    (u_long)tcp6cb.t_in6pcb);
1481
1482	printf("rxtshift %d, rxtcur %d, dupacks %d\n", tcp6cb.t_rxtshift,
1483	    tcp6cb.t_rxtcur, tcp6cb.t_dupacks);
1484	printf("peermaxseg %u, maxseg %u, force %d\n\n", tcp6cb.t_peermaxseg,
1485	    tcp6cb.t_maxseg, tcp6cb.t_force);
1486
1487	printf("snd_una %u, snd_nxt %u, snd_up %u\n",
1488	    tcp6cb.snd_una, tcp6cb.snd_nxt, tcp6cb.snd_up);
1489	printf("snd_wl1 %u, snd_wl2 %u, iss %u, snd_wnd %llu\n\n",
1490	    tcp6cb.snd_wl1, tcp6cb.snd_wl2, tcp6cb.iss,
1491	    (unsigned long long)tcp6cb.snd_wnd);
1492
1493	printf("rcv_wnd %llu, rcv_nxt %u, rcv_up %u, irs %u\n\n",
1494	    (unsigned long long)cp6cb.rcv_wnd, tcp6cb.rcv_nxt,
1495	    tcp6cb.rcv_up, tcp6cb.irs);
1496
1497	printf("rcv_adv %u, snd_max %u, snd_cwnd %llu, snd_ssthresh %llu\n",
1498	    tcp6cb.rcv_adv, tcp6cb.snd_max, (unsigned long long)tcp6cb.snd_cwnd,
1499	    (unsigned long long)tcp6cb.snd_ssthresh);
1500
1501	printf("idle %d, rtt %d, rtseq %u, srtt %d, rttvar %d, rttmin %d, "
1502	    "max_sndwnd %llu\n\n", tcp6cb.t_idle, tcp6cb.t_rtt, tcp6cb.t_rtseq,
1503	    tcp6cb.t_srtt, tcp6cb.t_rttvar, tcp6cb.t_rttmin,
1504	    (unsigned long long)tcp6cb.max_sndwnd);
1505
1506	printf("oobflags %d, iobc %d, softerror %d\n\n", tcp6cb.t_oobflags,
1507	    tcp6cb.t_iobc, tcp6cb.t_softerror);
1508
1509	printf("snd_scale %d, rcv_scale %d, req_r_scale %d, req_s_scale %d\n",
1510	    tcp6cb.snd_scale, tcp6cb.rcv_scale, tcp6cb.request_r_scale,
1511	    tcp6cb.requested_s_scale);
1512	printf("ts_recent %u, ts_regent_age %d, last_ack_sent %u\n",
1513	    tcp6cb.ts_recent, tcp6cb.ts_recent_age, tcp6cb.last_ack_sent);
1514}
1515#endif
1516
1517#endif /*INET6*/
1518