inet6.c revision 302408
1290931Srodrigc/*	BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp	*/
2290931Srodrigc/*-
3290931Srodrigc * Copyright (c) 1983, 1988, 1993
4290931Srodrigc *	The Regents of the University of California.  All rights reserved.
5290931Srodrigc *
6290931Srodrigc * Redistribution and use in source and binary forms, with or without
7290931Srodrigc * modification, are permitted provided that the following conditions
8290931Srodrigc * are met:
9290931Srodrigc * 1. Redistributions of source code must retain the above copyright
10290931Srodrigc *    notice, this list of conditions and the following disclaimer.
11290931Srodrigc * 2. Redistributions in binary form must reproduce the above copyright
12290931Srodrigc *    notice, this list of conditions and the following disclaimer in the
13290931Srodrigc *    documentation and/or other materials provided with the distribution.
14290931Srodrigc * 4. Neither the name of the University nor the names of its contributors
15290931Srodrigc *    may be used to endorse or promote products derived from this software
16290931Srodrigc *    without specific prior written permission.
17290931Srodrigc *
18290931Srodrigc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19290931Srodrigc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20290931Srodrigc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21290931Srodrigc * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22290931Srodrigc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23290931Srodrigc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24290931Srodrigc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25290931Srodrigc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26290931Srodrigc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27290931Srodrigc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28290931Srodrigc * SUCH DAMAGE.
29290931Srodrigc */
30290931Srodrigc
31290931Srodrigc#if 0
32290931Srodrigc#ifndef lint
33290931Srodrigcstatic char sccsid[] = "@(#)inet6.c	8.4 (Berkeley) 4/20/94";
34290931Srodrigc#endif /* not lint */
35290931Srodrigc#endif
36290931Srodrigc
37290931Srodrigc#include <sys/cdefs.h>
38290931Srodrigc__FBSDID("$FreeBSD: stable/11/usr.bin/netstat/inet6.c 287649 2015-09-11 04:37:01Z markj $");
39290931Srodrigc
40290931Srodrigc#ifdef INET6
41290931Srodrigc#include <sys/param.h>
42290931Srodrigc#include <sys/socket.h>
43290931Srodrigc#include <sys/socketvar.h>
44290931Srodrigc#include <sys/ioctl.h>
45290931Srodrigc#include <sys/mbuf.h>
46290931Srodrigc#include <sys/protosw.h>
47290931Srodrigc
48290931Srodrigc#include <net/route.h>
49290931Srodrigc#include <net/if.h>
50290931Srodrigc#include <netinet/in.h>
51290931Srodrigc#include <netinet/ip6.h>
52290931Srodrigc#include <netinet/icmp6.h>
53290931Srodrigc#include <netinet/in_systm.h>
54290931Srodrigc#include <netinet6/in6_pcb.h>
55290931Srodrigc#include <netinet6/in6_var.h>
56290931Srodrigc#include <netinet6/ip6_var.h>
57290931Srodrigc#include <netinet6/pim6_var.h>
58290931Srodrigc#include <netinet6/raw_ip6.h>
59290931Srodrigc
60290931Srodrigc#include <arpa/inet.h>
61290931Srodrigc#include <netdb.h>
62290931Srodrigc
63290931Srodrigc#include <err.h>
64290931Srodrigc#include <stdint.h>
65290931Srodrigc#include <stdio.h>
66290931Srodrigc#include <stdbool.h>
67290931Srodrigc#include <errno.h>
68290931Srodrigc#include <string.h>
69290931Srodrigc#include <unistd.h>
70290931Srodrigc#include <libxo/xo.h>
71290931Srodrigc#include "netstat.h"
72290931Srodrigc
73290931Srodrigcchar	*inet6name(struct in6_addr *);
74290940Srodrigc
75290931Srodrigcstatic char ntop_buf[INET6_ADDRSTRLEN];
76290931Srodrigc
77290931Srodrigcstatic	const char *ip6nh[] = {
78290931Srodrigc	"hop by hop",
79290931Srodrigc	"ICMP",
80290931Srodrigc	"IGMP",
81290940Srodrigc	"#3",
82290931Srodrigc	"IP",
83290931Srodrigc	"#5",
84290931Srodrigc	"TCP",
85290931Srodrigc	"#7",
86290931Srodrigc	"#8",
87290931Srodrigc	"#9",
88290931Srodrigc	"#10",
89290931Srodrigc	"#11",
90290931Srodrigc	"#12",
91290931Srodrigc	"#13",
92290931Srodrigc	"#14",
93290931Srodrigc	"#15",
94290931Srodrigc	"#16",
95290931Srodrigc	"UDP",
96290931Srodrigc	"#18",
97290931Srodrigc	"#19",
98290931Srodrigc	"#20",
99290931Srodrigc	"#21",
100290931Srodrigc	"IDP",
101290931Srodrigc	"#23",
102290931Srodrigc	"#24",
103290931Srodrigc	"#25",
104290931Srodrigc	"#26",
105290931Srodrigc	"#27",
106290931Srodrigc	"#28",
107290931Srodrigc	"TP",
108290931Srodrigc	"#30",
109290931Srodrigc	"#31",
110290931Srodrigc	"#32",
111290931Srodrigc	"#33",
112290931Srodrigc	"#34",
113290931Srodrigc	"#35",
114290931Srodrigc	"#36",
115290931Srodrigc	"#37",
116290931Srodrigc	"#38",
117290931Srodrigc	"#39",
118290931Srodrigc	"#40",
119290931Srodrigc	"IP6",
120290931Srodrigc	"#42",
121290931Srodrigc	"routing",
122290931Srodrigc	"fragment",
123290931Srodrigc	"#45",
124290931Srodrigc	"#46",
125290931Srodrigc	"#47",
126290931Srodrigc	"#48",
127290931Srodrigc	"#49",
128290931Srodrigc	"ESP",
129290931Srodrigc	"AH",
130290931Srodrigc	"#52",
131290931Srodrigc	"#53",
132290931Srodrigc	"#54",
133290931Srodrigc	"#55",
134290931Srodrigc	"#56",
135290931Srodrigc	"#57",
136290931Srodrigc	"ICMP6",
137290931Srodrigc	"no next header",
138290931Srodrigc	"destination option",
139290931Srodrigc	"#61",
140290931Srodrigc	"mobility",
141290931Srodrigc	"#63",
142290931Srodrigc	"#64",
143290931Srodrigc	"#65",
144290931Srodrigc	"#66",
145290931Srodrigc	"#67",
146290931Srodrigc	"#68",
147290931Srodrigc	"#69",
148290931Srodrigc	"#70",
149290931Srodrigc	"#71",
150290931Srodrigc	"#72",
151290931Srodrigc	"#73",
152290931Srodrigc	"#74",
153290931Srodrigc	"#75",
154290931Srodrigc	"#76",
155290931Srodrigc	"#77",
156290931Srodrigc	"#78",
157290931Srodrigc	"#79",
158290931Srodrigc	"ISOIP",
159290931Srodrigc	"#81",
160290931Srodrigc	"#82",
161290931Srodrigc	"#83",
162290931Srodrigc	"#84",
163290931Srodrigc	"#85",
164290931Srodrigc	"#86",
165290931Srodrigc	"#87",
166290931Srodrigc	"#88",
167290931Srodrigc	"OSPF",
168290931Srodrigc	"#80",
169290931Srodrigc	"#91",
170290931Srodrigc	"#92",
171290931Srodrigc	"#93",
172290931Srodrigc	"#94",
173290931Srodrigc	"#95",
174290931Srodrigc	"#96",
175290931Srodrigc	"Ethernet",
176290931Srodrigc	"#98",
177290931Srodrigc	"#99",
178290931Srodrigc	"#100",
179290931Srodrigc	"#101",
180290931Srodrigc	"#102",
181290931Srodrigc	"PIM",
182290931Srodrigc	"#104",
183290931Srodrigc	"#105",
184290931Srodrigc	"#106",
185290931Srodrigc	"#107",
186290931Srodrigc	"#108",
187290931Srodrigc	"#109",
188290931Srodrigc	"#110",
189290931Srodrigc	"#111",
190290931Srodrigc	"#112",
191290931Srodrigc	"#113",
192290931Srodrigc	"#114",
193290931Srodrigc	"#115",
194290931Srodrigc	"#116",
195290931Srodrigc	"#117",
196290931Srodrigc	"#118",
197290931Srodrigc	"#119",
198290931Srodrigc	"#120",
199290931Srodrigc	"#121",
200290931Srodrigc	"#122",
201290931Srodrigc	"#123",
202290931Srodrigc	"#124",
203290931Srodrigc	"#125",
204290931Srodrigc	"#126",
205290931Srodrigc	"#127",
206290931Srodrigc	"#128",
207290931Srodrigc	"#129",
208290931Srodrigc	"#130",
209290931Srodrigc	"#131",
210290931Srodrigc	"#132",
211290931Srodrigc	"#133",
212290931Srodrigc	"#134",
213290931Srodrigc	"#135",
214290931Srodrigc	"#136",
215290931Srodrigc	"#137",
216290931Srodrigc	"#138",
217290931Srodrigc	"#139",
218290931Srodrigc	"#140",
219290931Srodrigc	"#141",
220290931Srodrigc	"#142",
221290931Srodrigc	"#143",
222290931Srodrigc	"#144",
223290931Srodrigc	"#145",
224290931Srodrigc	"#146",
225290931Srodrigc	"#147",
226290931Srodrigc	"#148",
227290931Srodrigc	"#149",
228290931Srodrigc	"#150",
229290931Srodrigc	"#151",
230290931Srodrigc	"#152",
231290931Srodrigc	"#153",
232290931Srodrigc	"#154",
233290931Srodrigc	"#155",
234290931Srodrigc	"#156",
235290931Srodrigc	"#157",
236290931Srodrigc	"#158",
237290931Srodrigc	"#159",
238290931Srodrigc	"#160",
239290931Srodrigc	"#161",
240290931Srodrigc	"#162",
241290931Srodrigc	"#163",
242290931Srodrigc	"#164",
243290931Srodrigc	"#165",
244290931Srodrigc	"#166",
245290931Srodrigc	"#167",
246290931Srodrigc	"#168",
247290931Srodrigc	"#169",
248290931Srodrigc	"#170",
249290931Srodrigc	"#171",
250290931Srodrigc	"#172",
251290931Srodrigc	"#173",
252290931Srodrigc	"#174",
253290931Srodrigc	"#175",
254290931Srodrigc	"#176",
255290931Srodrigc	"#177",
256290931Srodrigc	"#178",
257290931Srodrigc	"#179",
258290931Srodrigc	"#180",
259290931Srodrigc	"#181",
260290931Srodrigc	"#182",
261290931Srodrigc	"#183",
262290931Srodrigc	"#184",
263290931Srodrigc	"#185",
264290931Srodrigc	"#186",
265290931Srodrigc	"#187",
266290931Srodrigc	"#188",
267290931Srodrigc	"#189",
268290931Srodrigc	"#180",
269290931Srodrigc	"#191",
270290931Srodrigc	"#192",
271290931Srodrigc	"#193",
272290931Srodrigc	"#194",
273290931Srodrigc	"#195",
274290931Srodrigc	"#196",
275290931Srodrigc	"#197",
276290931Srodrigc	"#198",
277290931Srodrigc	"#199",
278290931Srodrigc	"#200",
279290931Srodrigc	"#201",
280290931Srodrigc	"#202",
281290931Srodrigc	"#203",
282290931Srodrigc	"#204",
283290931Srodrigc	"#205",
284290931Srodrigc	"#206",
285290931Srodrigc	"#207",
286290931Srodrigc	"#208",
287290931Srodrigc	"#209",
288290931Srodrigc	"#210",
289290931Srodrigc	"#211",
290290931Srodrigc	"#212",
291290931Srodrigc	"#213",
292290931Srodrigc	"#214",
293290931Srodrigc	"#215",
294290931Srodrigc	"#216",
295290931Srodrigc	"#217",
296290931Srodrigc	"#218",
297290931Srodrigc	"#219",
298290931Srodrigc	"#220",
299290931Srodrigc	"#221",
300290931Srodrigc	"#222",
301290931Srodrigc	"#223",
302290931Srodrigc	"#224",
303290931Srodrigc	"#225",
304290931Srodrigc	"#226",
305290931Srodrigc	"#227",
306290931Srodrigc	"#228",
307290931Srodrigc	"#229",
308290931Srodrigc	"#230",
309290931Srodrigc	"#231",
310290931Srodrigc	"#232",
311290931Srodrigc	"#233",
312290931Srodrigc	"#234",
313290931Srodrigc	"#235",
314290931Srodrigc	"#236",
315290931Srodrigc	"#237",
316290931Srodrigc	"#238",
317290931Srodrigc	"#239",
318290931Srodrigc	"#240",
319290931Srodrigc	"#241",
320290931Srodrigc	"#242",
321290931Srodrigc	"#243",
322290931Srodrigc	"#244",
323290931Srodrigc	"#245",
324290931Srodrigc	"#246",
325290931Srodrigc	"#247",
326290931Srodrigc	"#248",
327290931Srodrigc	"#249",
328290931Srodrigc	"#250",
329290931Srodrigc	"#251",
330290931Srodrigc	"#252",
331290931Srodrigc	"#253",
332290931Srodrigc	"#254",
333290931Srodrigc	"#255",
334290931Srodrigc};
335290931Srodrigc
336290931Srodrigcstatic const char *srcrule_str[] = {
337290931Srodrigc	"first candidate",
338290931Srodrigc	"same address",
339290931Srodrigc	"appropriate scope",
340290931Srodrigc	"deprecated address",
341290931Srodrigc	"home address",
342290931Srodrigc	"outgoing interface",
343290931Srodrigc	"matching label",
344290931Srodrigc	"public/temporary address",
345290931Srodrigc	"alive interface",
346290931Srodrigc	"better virtual status",
347290931Srodrigc	"preferred source",
348290931Srodrigc	"rule #11",
349290931Srodrigc	"rule #12",
350290931Srodrigc	"rule #13",
351290931Srodrigc	"longest match",
352290931Srodrigc	"rule #15",
353290931Srodrigc};
354290931Srodrigc
355290931Srodrigc/*
356290931Srodrigc * Dump IP6 statistics structure.
357290931Srodrigc */
358290931Srodrigcvoid
359290931Srodrigcip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
360290931Srodrigc{
361290931Srodrigc	struct ip6stat ip6stat;
362290931Srodrigc	int first, i;
363290931Srodrigc
364290931Srodrigc	if (fetch_stats("net.inet6.ip6.stats", off, &ip6stat,
365290931Srodrigc	    sizeof(ip6stat), kread_counters) != 0)
366290931Srodrigc		return;
367290931Srodrigc
368290931Srodrigc	xo_open_container(name);
369290931Srodrigc	xo_emit("{T:/%s}:\n", name);
370290931Srodrigc
371290931Srodrigc#define	p(f, m) if (ip6stat.f || sflag <= 1) \
372290931Srodrigc	xo_emit(m, (uintmax_t)ip6stat.f, plural(ip6stat.f))
373290931Srodrigc#define	p1a(f, m) if (ip6stat.f || sflag <= 1) \
374290931Srodrigc	xo_emit(m, (uintmax_t)ip6stat.f)
375290931Srodrigc
376290931Srodrigc	p(ip6s_total, "\t{:received-packets/%ju} "
377290931Srodrigc	    "{N:/total packet%s received}\n");
378290931Srodrigc	p1a(ip6s_toosmall, "\t{:dropped-below-minimum-size/%ju} "
379290931Srodrigc	    "{N:/with size smaller than minimum}\n");
380290931Srodrigc	p1a(ip6s_tooshort, "\t{:dropped-short-packets/%ju} "
381290931Srodrigc	    "{N:/with data size < data length}\n");
382290931Srodrigc	p1a(ip6s_badoptions, "\t{:dropped-bad-options/%ju} "
383290931Srodrigc	    "{N:/with bad options}\n");
384290931Srodrigc	p1a(ip6s_badvers, "\t{:dropped-bad-version/%ju} "
385290931Srodrigc	    "{N:/with incorrect version number}\n");
386290931Srodrigc	p(ip6s_fragments, "\t{:received-fragments/%ju} "
387290931Srodrigc	    "{N:/fragment%s received}\n");
388290931Srodrigc	p(ip6s_fragdropped, "\t{:dropped-fragment/%ju} "
389290931Srodrigc	    "{N:/fragment%s dropped (dup or out of space)}\n");
390290931Srodrigc	p(ip6s_fragtimeout, "\t{:dropped-fragment-after-timeout/%ju} "
391290931Srodrigc	    "{N:/fragment%s dropped after timeout}\n");
392290931Srodrigc	p(ip6s_fragoverflow, "\t{:dropped-fragments-overflow/%ju} "
393290931Srodrigc	    "{N:/fragment%s that exceeded limit}\n");
394290931Srodrigc	p(ip6s_reassembled, "\t{:reassembled-packets/%ju} "
395290931Srodrigc	    "{N:/packet%s reassembled ok}\n");
396290931Srodrigc	p(ip6s_delivered, "\t{:received-local-packets/%ju} "
397290931Srodrigc	    "{N:/packet%s for this host}\n");
398290931Srodrigc	p(ip6s_forward, "\t{:forwarded-packets/%ju} "
399290931Srodrigc	    "{N:/packet%s forwarded}\n");
400290931Srodrigc	p(ip6s_cantforward, "\t{:packets-not-forwardable/%ju} "
401290931Srodrigc	    "{N:/packet%s not forwardable}\n");
402290931Srodrigc	p(ip6s_redirectsent, "\t{:sent-redirects/%ju} "
403290931Srodrigc	    "{N:/redirect%s sent}\n");
404290931Srodrigc	p(ip6s_localout, "\t{:sent-packets/%ju} "
405290931Srodrigc	    "{N:/packet%s sent from this host}\n");
406290931Srodrigc	p(ip6s_rawout, "\t{:send-packets-fabricated-header/%ju} "
407290931Srodrigc	    "{N:/packet%s sent with fabricated ip header}\n");
408290931Srodrigc	p(ip6s_odropped, "\t{:discard-no-mbufs/%ju} "
409290931Srodrigc	    "{N:/output packet%s dropped due to no bufs, etc.}\n");
410290931Srodrigc	p(ip6s_noroute, "\t{:discard-no-route/%ju} "
411290931Srodrigc	    "{N:/output packet%s discarded due to no route}\n");
412290931Srodrigc	p(ip6s_fragmented, "\t{:sent-fragments/%ju} "
413290931Srodrigc	    "{N:/output datagram%s fragmented}\n");
414290931Srodrigc	p(ip6s_ofragments, "\t{:fragments-created/%ju} "
415290931Srodrigc	    "{N:/fragment%s created}\n");
416290931Srodrigc	p(ip6s_cantfrag, "\t{:discard-cannot-fragment/%ju} "
417290931Srodrigc	    "{N:/datagram%s that can't be fragmented}\n");
418290931Srodrigc	p(ip6s_badscope, "\t{:discard-scope-violations/%ju} "
419290931Srodrigc	    "{N:/packet%s that violated scope rules}\n");
420290931Srodrigc	p(ip6s_notmember, "\t{:multicast-no-join-packets/%ju} "
421290931Srodrigc	    "{N:/multicast packet%s which we don't join}\n");
422290931Srodrigc	for (first = 1, i = 0; i < IP6S_HDRCNT; i++)
423290931Srodrigc		if (ip6stat.ip6s_nxthist[i] != 0) {
424290931Srodrigc			if (first) {
425290931Srodrigc				xo_emit("\t{T:Input histogram}:\n");
426290931Srodrigc				xo_open_list("input-histogram");
427290931Srodrigc				first = 0;
428290931Srodrigc			}
429290931Srodrigc			xo_open_instance("input-histogram");
430290931Srodrigc			xo_emit("\t\t{k:name/%s}: {:count/%ju}\n", ip6nh[i],
431290931Srodrigc			    (uintmax_t)ip6stat.ip6s_nxthist[i]);
432290931Srodrigc			xo_close_instance("input-histogram");
433290931Srodrigc		}
434290931Srodrigc	if (!first)
435290931Srodrigc		xo_close_list("input-histogram");
436290931Srodrigc
437290931Srodrigc	xo_open_container("mbuf-statistics");
438290931Srodrigc	xo_emit("\t{T:Mbuf statistics}:\n");
439290931Srodrigc	xo_emit("\t\t{:one-mbuf/%ju} {N:/one mbuf}\n",
440290931Srodrigc	    (uintmax_t)ip6stat.ip6s_m1);
441290931Srodrigc	for (first = 1, i = 0; i < IP6S_M2MMAX; i++) {
442290931Srodrigc		char ifbuf[IFNAMSIZ];
443290931Srodrigc		if (ip6stat.ip6s_m2m[i] != 0) {
444290931Srodrigc			if (first) {
445290931Srodrigc				xo_emit("\t\t{N:two or more mbuf}:\n");
446290931Srodrigc				xo_open_list("mbuf-data");
447290931Srodrigc				first = 0;
448290931Srodrigc			}
449290931Srodrigc			xo_open_instance("mbuf-data");
450290931Srodrigc			xo_emit("\t\t\t{k:name/%s}= {:count/%ju}\n",
451290931Srodrigc			    if_indextoname(i, ifbuf),
452290931Srodrigc			    (uintmax_t)ip6stat.ip6s_m2m[i]);
453290931Srodrigc			xo_close_instance("mbuf-data");
454290931Srodrigc		}
455290931Srodrigc	}
456290931Srodrigc	if (!first)
457290931Srodrigc		xo_close_list("mbuf-data");
458290931Srodrigc	xo_emit("\t\t{:one-extra-mbuf/%ju} {N:one ext mbuf}\n",
459290931Srodrigc	    (uintmax_t)ip6stat.ip6s_mext1);
460290931Srodrigc	xo_emit("\t\t{:two-or-more-extra-mbufs/%ju} "
461290931Srodrigc	    "{N:/two or more ext mbuf}\n", (uintmax_t)ip6stat.ip6s_mext2m);
462290931Srodrigc	xo_close_container("mbuf-statistics");
463290931Srodrigc
464290931Srodrigc	p(ip6s_exthdrtoolong, "\t{:dropped-header-too-long/%ju} "
465290931Srodrigc	    "{N:/packet%s whose headers are not contiguous}\n");
466290931Srodrigc	p(ip6s_nogif, "\t{:discard-tunnel-no-gif/%ju} "
467290931Srodrigc	    "{N:/tunneling packet%s that can't find gif}\n");
468290931Srodrigc	p(ip6s_toomanyhdr, "\t{:dropped-too-many-headers/%ju} "
469290931Srodrigc	    "{N:/packet%s discarded because of too many headers}\n");
470290931Srodrigc
471290931Srodrigc	/* for debugging source address selection */
472290931Srodrigc#define	PRINT_SCOPESTAT(s,i) do {\
473290931Srodrigc		switch(i) { /* XXX hardcoding in each case */\
474290931Srodrigc		case 1:\
475290931Srodrigc			p(s, "\t\t{ke:name/interface-locals}{:count/%ju} " \
476290931Srodrigc			  "{N:/interface-local%s}\n");	\
477290931Srodrigc			break;\
478290931Srodrigc		case 2:\
479290931Srodrigc			p(s,"\t\t{ke:name/link-locals}{:count/%ju} " \
480290931Srodrigc			"{N:/link-local%s}\n"); \
481290931Srodrigc			break;\
482290931Srodrigc		case 5:\
483290931Srodrigc			p(s,"\t\t{ke:name/site-locals}{:count/%ju} " \
484290931Srodrigc			  "{N:/site-local%s}\n");\
485290931Srodrigc			break;\
486290931Srodrigc		case 14:\
487290931Srodrigc			p(s,"\t\t{ke:name/globals}{:count/%ju} " \
488290931Srodrigc			  "{N:/global%s}\n");\
489290931Srodrigc			break;\
490290931Srodrigc		default:\
491290931Srodrigc			xo_emit("\t\t{qke:name/%x}{:count/%ju} " \
492290931Srodrigc				"addresses scope=%x\n",\
493290931Srodrigc				i, (uintmax_t)ip6stat.s, i);	   \
494290931Srodrigc		}\
495290931Srodrigc	} while (0);
496290931Srodrigc
497290931Srodrigc	xo_open_container("source-address-selection");
498290931Srodrigc	p(ip6s_sources_none, "\t{:address-selection-failures/%ju} "
499290931Srodrigc	    "{N:/failure%s of source address selection}\n");
500290931Srodrigc
501290931Srodrigc	for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) {
502290931Srodrigc		if (ip6stat.ip6s_sources_sameif[i]) {
503290931Srodrigc			if (first) {
504290931Srodrigc				xo_open_list("outgoing-interface");
505290931Srodrigc				xo_emit("\tsource addresses on an outgoing "
506290931Srodrigc				    "I/F\n");
507290931Srodrigc				first = 0;
508290931Srodrigc			}
509290931Srodrigc			xo_open_instance("outgoing-interface");
510290931Srodrigc			PRINT_SCOPESTAT(ip6s_sources_sameif[i], i);
511290931Srodrigc			xo_close_instance("outgoing-interface");
512290931Srodrigc		}
513290931Srodrigc	}
514290931Srodrigc	if (!first)
515290931Srodrigc		xo_close_list("outgoing-interface");
516290931Srodrigc
517290931Srodrigc	for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) {
518290931Srodrigc		if (ip6stat.ip6s_sources_otherif[i]) {
519290931Srodrigc			if (first) {
520290931Srodrigc				xo_open_list("non-outgoing-interface");
521290931Srodrigc				xo_emit("\tsource addresses on a non-outgoing "
522290931Srodrigc				    "I/F\n");
523290931Srodrigc				first = 0;
524290931Srodrigc			}
525290931Srodrigc			xo_open_instance("non-outgoing-interface");
526290931Srodrigc			PRINT_SCOPESTAT(ip6s_sources_otherif[i], i);
527290931Srodrigc			xo_close_instance("non-outgoing-interface");
528290931Srodrigc		}
529290931Srodrigc	}
530290931Srodrigc	if (!first)
531290931Srodrigc		xo_close_list("non-outgoing-interface");
532290931Srodrigc
533290931Srodrigc	for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) {
534290931Srodrigc		if (ip6stat.ip6s_sources_samescope[i]) {
535290931Srodrigc			if (first) {
536290931Srodrigc				xo_open_list("same-source");
537290931Srodrigc				xo_emit("\tsource addresses of same scope\n");
538290931Srodrigc				first = 0;
539290931Srodrigc			}
540290931Srodrigc			xo_open_instance("same-source");
541290931Srodrigc			PRINT_SCOPESTAT(ip6s_sources_samescope[i], i);
542290931Srodrigc			xo_close_instance("same-source");
543290931Srodrigc		}
544290931Srodrigc	}
545290931Srodrigc	if (!first)
546290931Srodrigc		xo_close_list("same-source");
547290931Srodrigc
548290931Srodrigc	for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) {
549290931Srodrigc		if (ip6stat.ip6s_sources_otherscope[i]) {
550290931Srodrigc			if (first) {
551290931Srodrigc				xo_open_list("different-scope");
552290931Srodrigc				xo_emit("\tsource addresses of a different "
553290931Srodrigc				    "scope\n");
554290931Srodrigc				first = 0;
555290931Srodrigc			}
556290931Srodrigc			xo_open_instance("different-scope");
557290931Srodrigc			PRINT_SCOPESTAT(ip6s_sources_otherscope[i], i);
558290931Srodrigc			xo_close_instance("different-scope");
559290931Srodrigc		}
560290931Srodrigc	}
561290931Srodrigc	if (!first)
562290931Srodrigc		xo_close_list("different-scope");
563290931Srodrigc
564290931Srodrigc	for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) {
565290931Srodrigc		if (ip6stat.ip6s_sources_deprecated[i]) {
566290931Srodrigc			if (first) {
567290931Srodrigc				xo_open_list("deprecated-source");
568290931Srodrigc				xo_emit("\tdeprecated source addresses\n");
569290931Srodrigc				first = 0;
570290931Srodrigc			}
571290931Srodrigc			xo_open_instance("deprecated-source");
572290931Srodrigc			PRINT_SCOPESTAT(ip6s_sources_deprecated[i], i);
573290931Srodrigc			xo_close_instance("deprecated-source");
574290931Srodrigc		}
575290931Srodrigc	}
576290931Srodrigc	if (!first)
577290931Srodrigc		xo_close_list("deprecated-source");
578290931Srodrigc
579290931Srodrigc	for (first = 1, i = 0; i < IP6S_RULESMAX; i++) {
580290931Srodrigc		if (ip6stat.ip6s_sources_rule[i]) {
581290931Srodrigc			if (first) {
582290931Srodrigc				xo_open_list("rules-applied");
583290931Srodrigc				xo_emit("\t{T:Source addresses selection "
584290931Srodrigc				    "rule applied}:\n");
585290931Srodrigc				first = 0;
586290931Srodrigc			}
587290931Srodrigc			xo_open_instance("rules-applied");
588290931Srodrigc			xo_emit("\t\t{ke:name/%s}{:count/%ju} {d:name/%s}\n",
589290931Srodrigc			    srcrule_str[i],
590290931Srodrigc			    (uintmax_t)ip6stat.ip6s_sources_rule[i],
591290931Srodrigc			    srcrule_str[i]);
592290931Srodrigc			xo_close_instance("rules-applied");
593290931Srodrigc		}
594290931Srodrigc	}
595290931Srodrigc	if (!first)
596290931Srodrigc		xo_close_list("rules-applied");
597290931Srodrigc
598290931Srodrigc	xo_close_container("source-address-selection");
599290931Srodrigc
600290931Srodrigc#undef p
601290931Srodrigc#undef p1a
602290931Srodrigc	xo_close_container(name);
603290931Srodrigc}
604290931Srodrigc
605290931Srodrigc/*
606290931Srodrigc * Dump IPv6 per-interface statistics based on RFC 2465.
607290931Srodrigc */
608290931Srodrigcvoid
609290931Srodrigcip6_ifstats(char *ifname)
610290931Srodrigc{
611290931Srodrigc	struct in6_ifreq ifr;
612290931Srodrigc	int s;
613290931Srodrigc
614290931Srodrigc#define	p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1)	\
615290931Srodrigc	xo_emit(m, (uintmax_t)ifr.ifr_ifru.ifru_stat.f,		\
616290931Srodrigc	    plural(ifr.ifr_ifru.ifru_stat.f))
617290931Srodrigc
618290931Srodrigc	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
619290931Srodrigc		xo_warn("Warning: socket(AF_INET6)");
620290931Srodrigc		return;
621290931Srodrigc	}
622290931Srodrigc
623290931Srodrigc	strcpy(ifr.ifr_name, ifname);
624290931Srodrigc	if (ioctl(s, SIOCGIFSTAT_IN6, (char *)&ifr) < 0) {
625290931Srodrigc		if (errno != EPFNOSUPPORT)
626290931Srodrigc			xo_warn("Warning: ioctl(SIOCGIFSTAT_IN6)");
627290931Srodrigc		goto end;
628290931Srodrigc	}
629290931Srodrigc
630290931Srodrigc	xo_emit("{T:/ip6 on %s}:\n", ifr.ifr_name);
631290931Srodrigc
632290931Srodrigc	xo_open_instance("ip6-interface-statistics");
633290931Srodrigc	xo_emit("{ke:name/%s}", ifr.ifr_name);
634290931Srodrigc
635290931Srodrigc	p(ifs6_in_receive, "\t{:received-packets/%ju} "
636290931Srodrigc	    "{N:/total input datagram%s}\n");
637290931Srodrigc	p(ifs6_in_hdrerr, "\t{:dropped-invalid-header/%ju} "
638290931Srodrigc	    "{N:/datagram%s with invalid header received}\n");
639290931Srodrigc	p(ifs6_in_toobig, "\t{:dropped-mtu-exceeded/%ju} "
640290931Srodrigc	    "{N:/datagram%s exceeded MTU received}\n");
641290931Srodrigc	p(ifs6_in_noroute, "\t{:dropped-no-route/%ju} "
642290931Srodrigc	    "{N:/datagram%s with no route received}\n");
643290931Srodrigc	p(ifs6_in_addrerr, "\t{:dropped-invalid-destination/%ju} "
644290931Srodrigc	    "{N:/datagram%s with invalid dst received}\n");
645290931Srodrigc	p(ifs6_in_protounknown, "\t{:dropped-unknown-protocol/%ju} "
646290931Srodrigc	    "{N:/datagram%s with unknown proto received}\n");
647290931Srodrigc	p(ifs6_in_truncated, "\t{:dropped-truncated/%ju} "
648290931Srodrigc	    "{N:/truncated datagram%s received}\n");
649290931Srodrigc	p(ifs6_in_discard, "\t{:dropped-discarded/%ju} "
650290931Srodrigc	    "{N:/input datagram%s discarded}\n");
651290931Srodrigc 	p(ifs6_in_deliver, "\t{:received-valid-packets/%ju} "
652290931Srodrigc	    "{N:/datagram%s delivered to an upper layer protocol}\n");
653290931Srodrigc	p(ifs6_out_forward, "\t{:sent-forwarded/%ju} "
654290931Srodrigc	    "{N:/datagram%s forwarded to this interface}\n");
655290931Srodrigc 	p(ifs6_out_request, "\t{:sent-packets/%ju} "
656290931Srodrigc	    "{N:/datagram%s sent from an upper layer protocol}\n");
657290931Srodrigc	p(ifs6_out_discard, "\t{:discard-packets/%ju} "
658290931Srodrigc	    "{N:/total discarded output datagram%s}\n");
659290931Srodrigc	p(ifs6_out_fragok, "\t{:discard-fragments/%ju} "
660290931Srodrigc	    "{N:/output datagram%s fragmented}\n");
661290931Srodrigc	p(ifs6_out_fragfail, "\t{:fragments-failed/%ju} "
662290931Srodrigc	    "{N:/output datagram%s failed on fragment}\n");
663290931Srodrigc	p(ifs6_out_fragcreat, "\t{:fragments-created/%ju} "
664290931Srodrigc	    "{N:/output datagram%s succeeded on fragment}\n");
665290931Srodrigc	p(ifs6_reass_reqd, "\t{:reassembly-required/%ju} "
666290931Srodrigc	    "{N:/incoming datagram%s fragmented}\n");
667290931Srodrigc	p(ifs6_reass_ok, "\t{:reassembled-packets/%ju} "
668290931Srodrigc	    "{N:/datagram%s reassembled}\n");
669290931Srodrigc	p(ifs6_reass_fail, "\t{:reassembly-failed/%ju} "
670290931Srodrigc	    "{N:/datagram%s failed on reassembly}\n");
671290931Srodrigc	p(ifs6_in_mcast, "\t{:received-multicast/%ju} "
672290931Srodrigc	    "{N:/multicast datagram%s received}\n");
673290931Srodrigc	p(ifs6_out_mcast, "\t{:sent-multicast/%ju} "
674290931Srodrigc	    "{N:/multicast datagram%s sent}\n");
675290931Srodrigc
676290931Srodrigc end:
677290931Srodrigc	xo_close_instance("ip6-interface-statistics");
678290931Srodrigc 	close(s);
679290931Srodrigc
680290931Srodrigc#undef p
681290931Srodrigc}
682290931Srodrigc
683290931Srodrigcstatic	const char *icmp6names[] = {
684290931Srodrigc	"#0",
685290931Srodrigc	"unreach",
686290931Srodrigc	"packet too big",
687290931Srodrigc	"time exceed",
688290931Srodrigc	"parameter problem",
689290931Srodrigc	"#5",
690290931Srodrigc	"#6",
691290931Srodrigc	"#7",
692290931Srodrigc	"#8",
693290931Srodrigc	"#9",
694290931Srodrigc	"#10",
695290931Srodrigc	"#11",
696290931Srodrigc	"#12",
697290931Srodrigc	"#13",
698290931Srodrigc	"#14",
699290931Srodrigc	"#15",
700290931Srodrigc	"#16",
701290931Srodrigc	"#17",
702290931Srodrigc	"#18",
703290931Srodrigc	"#19",
704290931Srodrigc	"#20",
705	"#21",
706	"#22",
707	"#23",
708	"#24",
709	"#25",
710	"#26",
711	"#27",
712	"#28",
713	"#29",
714	"#30",
715	"#31",
716	"#32",
717	"#33",
718	"#34",
719	"#35",
720	"#36",
721	"#37",
722	"#38",
723	"#39",
724	"#40",
725	"#41",
726	"#42",
727	"#43",
728	"#44",
729	"#45",
730	"#46",
731	"#47",
732	"#48",
733	"#49",
734	"#50",
735	"#51",
736	"#52",
737	"#53",
738	"#54",
739	"#55",
740	"#56",
741	"#57",
742	"#58",
743	"#59",
744	"#60",
745	"#61",
746	"#62",
747	"#63",
748	"#64",
749	"#65",
750	"#66",
751	"#67",
752	"#68",
753	"#69",
754	"#70",
755	"#71",
756	"#72",
757	"#73",
758	"#74",
759	"#75",
760	"#76",
761	"#77",
762	"#78",
763	"#79",
764	"#80",
765	"#81",
766	"#82",
767	"#83",
768	"#84",
769	"#85",
770	"#86",
771	"#87",
772	"#88",
773	"#89",
774	"#80",
775	"#91",
776	"#92",
777	"#93",
778	"#94",
779	"#95",
780	"#96",
781	"#97",
782	"#98",
783	"#99",
784	"#100",
785	"#101",
786	"#102",
787	"#103",
788	"#104",
789	"#105",
790	"#106",
791	"#107",
792	"#108",
793	"#109",
794	"#110",
795	"#111",
796	"#112",
797	"#113",
798	"#114",
799	"#115",
800	"#116",
801	"#117",
802	"#118",
803	"#119",
804	"#120",
805	"#121",
806	"#122",
807	"#123",
808	"#124",
809	"#125",
810	"#126",
811	"#127",
812	"echo",
813	"echo reply",
814	"multicast listener query",
815	"MLDv1 listener report",
816	"MLDv1 listener done",
817	"router solicitation",
818	"router advertisement",
819	"neighbor solicitation",
820	"neighbor advertisement",
821	"redirect",
822	"router renumbering",
823	"node information request",
824	"node information reply",
825	"inverse neighbor solicitation",
826	"inverse neighbor advertisement",
827	"MLDv2 listener report",
828	"#144",
829	"#145",
830	"#146",
831	"#147",
832	"#148",
833	"#149",
834	"#150",
835	"#151",
836	"#152",
837	"#153",
838	"#154",
839	"#155",
840	"#156",
841	"#157",
842	"#158",
843	"#159",
844	"#160",
845	"#161",
846	"#162",
847	"#163",
848	"#164",
849	"#165",
850	"#166",
851	"#167",
852	"#168",
853	"#169",
854	"#170",
855	"#171",
856	"#172",
857	"#173",
858	"#174",
859	"#175",
860	"#176",
861	"#177",
862	"#178",
863	"#179",
864	"#180",
865	"#181",
866	"#182",
867	"#183",
868	"#184",
869	"#185",
870	"#186",
871	"#187",
872	"#188",
873	"#189",
874	"#180",
875	"#191",
876	"#192",
877	"#193",
878	"#194",
879	"#195",
880	"#196",
881	"#197",
882	"#198",
883	"#199",
884	"#200",
885	"#201",
886	"#202",
887	"#203",
888	"#204",
889	"#205",
890	"#206",
891	"#207",
892	"#208",
893	"#209",
894	"#210",
895	"#211",
896	"#212",
897	"#213",
898	"#214",
899	"#215",
900	"#216",
901	"#217",
902	"#218",
903	"#219",
904	"#220",
905	"#221",
906	"#222",
907	"#223",
908	"#224",
909	"#225",
910	"#226",
911	"#227",
912	"#228",
913	"#229",
914	"#230",
915	"#231",
916	"#232",
917	"#233",
918	"#234",
919	"#235",
920	"#236",
921	"#237",
922	"#238",
923	"#239",
924	"#240",
925	"#241",
926	"#242",
927	"#243",
928	"#244",
929	"#245",
930	"#246",
931	"#247",
932	"#248",
933	"#249",
934	"#250",
935	"#251",
936	"#252",
937	"#253",
938	"#254",
939	"#255",
940};
941
942/*
943 * Dump ICMP6 statistics.
944 */
945void
946icmp6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
947{
948	struct icmp6stat icmp6stat;
949	int i, first;
950
951	if (fetch_stats("net.inet6.icmp6.stats", off, &icmp6stat,
952	    sizeof(icmp6stat), kread_counters) != 0)
953		return;
954
955	xo_emit("{T:/%s}:\n", name);
956	xo_open_container(name);
957
958#define	p(f, m) if (icmp6stat.f || sflag <= 1) \
959	xo_emit(m, (uintmax_t)icmp6stat.f, plural(icmp6stat.f))
960#define	p_5(f, m) if (icmp6stat.f || sflag <= 1) \
961	xo_emit(m, (uintmax_t)icmp6stat.f)
962
963	p(icp6s_error, "\t{:icmp6-calls/%ju} "
964	    "{N:/call%s to icmp6_error}\n");
965	p(icp6s_canterror, "\t{:errors-not-generated-from-message/%ju} "
966	    "{N:/error%s not generated in response to an icmp6 message}\n");
967	p(icp6s_toofreq, "\t{:errors-discarded-by-rate-limitation/%ju} "
968	    "{N:/error%s not generated because of rate limitation}\n");
969#define	NELEM (int)(sizeof(icmp6stat.icp6s_outhist)/sizeof(icmp6stat.icp6s_outhist[0]))
970	for (first = 1, i = 0; i < NELEM; i++)
971		if (icmp6stat.icp6s_outhist[i] != 0) {
972			if (first) {
973				xo_open_list("output-histogram");
974				xo_emit("\t{T:Output histogram}:\n");
975				first = 0;
976			}
977			xo_open_instance("output-histogram");
978			xo_emit("\t\t{k:name/%s}: {:count/%ju}\n",
979			    icmp6names[i],
980			    (uintmax_t)icmp6stat.icp6s_outhist[i]);
981			xo_close_instance("output-histogram");
982		}
983	if (!first)
984		xo_close_list("output-histogram");
985#undef NELEM
986
987	p(icp6s_badcode, "\t{:dropped-bad-code/%ju} "
988	    "{N:/message%s with bad code fields}\n");
989	p(icp6s_tooshort, "\t{:dropped-too-short/%ju} "
990	    "{N:/message%s < minimum length}\n");
991	p(icp6s_checksum, "\t{:dropped-bad-checksum/%ju} "
992	    "{N:/bad checksum%s}\n");
993	p(icp6s_badlen, "\t{:dropped-bad-length/%ju} "
994	    "{N:/message%s with bad length}\n");
995#define	NELEM (int)(sizeof(icmp6stat.icp6s_inhist)/sizeof(icmp6stat.icp6s_inhist[0]))
996	for (first = 1, i = 0; i < NELEM; i++)
997		if (icmp6stat.icp6s_inhist[i] != 0) {
998			if (first) {
999				xo_open_list("input-histogram");
1000				xo_emit("\t{T:Input histogram}:\n");
1001				first = 0;
1002			}
1003			xo_open_instance("input-histogram");
1004			xo_emit("\t\t{k:name/%s}: {:count/%ju}\n",
1005			    icmp6names[i],
1006			    (uintmax_t)icmp6stat.icp6s_inhist[i]);
1007			xo_close_instance("input-histogram");
1008		}
1009	if (!first)
1010		xo_close_list("input-histogram");
1011#undef NELEM
1012	xo_emit("\t{T:Histogram of error messages to be generated}:\n");
1013	xo_open_container("errors");
1014	p_5(icp6s_odst_unreach_noroute, "\t\t{:no-route/%ju} "
1015	    "{N:/no route}\n");
1016	p_5(icp6s_odst_unreach_admin, "\t\t{:admin-prohibited/%ju} "
1017	    "{N:/administratively prohibited}\n");
1018	p_5(icp6s_odst_unreach_beyondscope, "\t\t{:beyond-scope/%ju} "
1019	    "{N:/beyond scope}\n");
1020	p_5(icp6s_odst_unreach_addr, "\t\t{:address-unreachable/%ju} "
1021	    "{N:/address unreachable}\n");
1022	p_5(icp6s_odst_unreach_noport, "\t\t{:port-unreachable/%ju} "
1023	    "{N:/port unreachable}\n");
1024	p_5(icp6s_opacket_too_big, "\t\t{:packet-too-big/%ju} "
1025	    "{N:/packet too big}\n");
1026	p_5(icp6s_otime_exceed_transit, "\t\t{:time-exceed-transmit/%ju} "
1027	    "{N:/time exceed transit}\n");
1028	p_5(icp6s_otime_exceed_reassembly, "\t\t{:time-exceed-reassembly/%ju} "
1029	    "{N:/time exceed reassembly}\n");
1030	p_5(icp6s_oparamprob_header, "\t\t{:bad-header/%ju} "
1031	    "{N:/erroneous header field}\n");
1032	p_5(icp6s_oparamprob_nextheader, "\t\t{:bad-next-header/%ju} "
1033	    "{N:/unrecognized next header}\n");
1034	p_5(icp6s_oparamprob_option, "\t\t{:bad-option/%ju} "
1035	    "{N:/unrecognized option}\n");
1036	p_5(icp6s_oredirect, "\t\t{:redirects/%ju} "
1037	    "{N:/redirect}\n");
1038	p_5(icp6s_ounknown, "\t\t{:unknown/%ju} {N:unknown}\n");
1039
1040	p(icp6s_reflect, "\t{:reflect/%ju} "
1041	    "{N:/message response%s generated}\n");
1042	p(icp6s_nd_toomanyopt, "\t{:too-many-nd-options/%ju} "
1043	    "{N:/message%s with too many ND options}\n");
1044	p(icp6s_nd_badopt, "\t{:bad-nd-options/%ju} "
1045	    "{N:/message%s with bad ND options}\n");
1046	p(icp6s_badns, "\t{:bad-neighbor-solicitation/%ju} "
1047	    "{N:/bad neighbor solicitation message%s}\n");
1048	p(icp6s_badna, "\t{:bad-neighbor-advertisement/%ju} "
1049	    "{N:/bad neighbor advertisement message%s}\n");
1050	p(icp6s_badrs, "\t{:bad-router-solicitation/%ju} "
1051	    "{N:/bad router solicitation message%s}\n");
1052	p(icp6s_badra, "\t{:bad-router-advertisement/%ju} "
1053	    "{N:/bad router advertisement message%s}\n");
1054	p(icp6s_badredirect, "\t{:bad-redirect/%ju} "
1055	    "{N:/bad redirect message%s}\n");
1056	xo_close_container("errors");
1057	p(icp6s_pmtuchg, "\t{:path-mtu-changes/%ju} {N:/path MTU change%s}\n");
1058#undef p
1059#undef p_5
1060	xo_close_container(name);
1061}
1062
1063/*
1064 * Dump ICMPv6 per-interface statistics based on RFC 2466.
1065 */
1066void
1067icmp6_ifstats(char *ifname)
1068{
1069	struct in6_ifreq ifr;
1070	int s;
1071
1072#define	p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1)	\
1073	xo_emit(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f,		\
1074	    plural(ifr.ifr_ifru.ifru_icmp6stat.f))
1075#define	p2(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1)	\
1076	xo_emit(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f,		\
1077	    pluralies(ifr.ifr_ifru.ifru_icmp6stat.f))
1078
1079	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1080		xo_warn("Warning: socket(AF_INET6)");
1081		return;
1082	}
1083
1084	strcpy(ifr.ifr_name, ifname);
1085	if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) {
1086		if (errno != EPFNOSUPPORT)
1087			xo_warn("Warning: ioctl(SIOCGIFSTAT_ICMP6)");
1088		goto end;
1089	}
1090
1091	xo_emit("{T:/icmp6 on %s}:\n", ifr.ifr_name);
1092
1093	xo_open_instance("icmp6-interface-statistics");
1094	xo_emit("{ke:name/%s}", ifr.ifr_name);
1095	p(ifs6_in_msg, "\t{:received-packets/%ju} "
1096	    "{N:/total input message%s}\n");
1097	p(ifs6_in_error, "\t{:received-errors/%ju} "
1098	    "{N:/total input error message%s}\n");
1099	p(ifs6_in_dstunreach, "\t{:received-destination-unreachable/%ju} "
1100	    "{N:/input destination unreachable error%s}\n");
1101	p(ifs6_in_adminprohib, "\t{:received-admin-prohibited/%ju} "
1102	    "{N:/input administratively prohibited error%s}\n");
1103	p(ifs6_in_timeexceed, "\t{:received-time-exceeded/%ju} "
1104	    "{N:/input time exceeded error%s}\n");
1105	p(ifs6_in_paramprob, "\t{:received-bad-parameter/%ju} "
1106	    "{N:/input parameter problem error%s}\n");
1107	p(ifs6_in_pkttoobig, "\t{:received-packet-too-big/%ju} "
1108	    "{N:/input packet too big error%s}\n");
1109	p(ifs6_in_echo, "\t{:received-echo-requests/%ju} "
1110	    "{N:/input echo request%s}\n");
1111	p2(ifs6_in_echoreply, "\t{:received-echo-replies/%ju} "
1112	    "{N:/input echo repl%s}\n");
1113	p(ifs6_in_routersolicit, "\t{:received-router-solicitation/%ju} "
1114	    "{N:/input router solicitation%s}\n");
1115	p(ifs6_in_routeradvert, "\t{:received-router-advertisement/%ju} "
1116	    "{N:/input router advertisement%s}\n");
1117	p(ifs6_in_neighborsolicit, "\t{:received-neighbor-solicitation/%ju} "
1118	    "{N:/input neighbor solicitation%s}\n");
1119	p(ifs6_in_neighboradvert, "\t{:received-neighbor-advertisement/%ju} "
1120	    "{N:/input neighbor advertisement%s}\n");
1121	p(ifs6_in_redirect, "\t{received-redirects/%ju} "
1122	    "{N:/input redirect%s}\n");
1123	p2(ifs6_in_mldquery, "\t{:received-mld-queries/%ju} "
1124	    "{N:/input MLD quer%s}\n");
1125	p(ifs6_in_mldreport, "\t{:received-mld-reports/%ju} "
1126	    "{N:/input MLD report%s}\n");
1127	p(ifs6_in_mlddone, "\t{:received-mld-done/%ju} "
1128	    "{N:/input MLD done%s}\n");
1129
1130	p(ifs6_out_msg, "\t{:sent-packets/%ju} "
1131	    "{N:/total output message%s}\n");
1132	p(ifs6_out_error, "\t{:sent-errors/%ju} "
1133	    "{N:/total output error message%s}\n");
1134	p(ifs6_out_dstunreach, "\t{:sent-destination-unreachable/%ju} "
1135	    "{N:/output destination unreachable error%s}\n");
1136	p(ifs6_out_adminprohib, "\t{:sent-admin-prohibited/%ju} "
1137	    "{N:/output administratively prohibited error%s}\n");
1138	p(ifs6_out_timeexceed, "\t{:sent-time-exceeded/%ju} "
1139	    "{N:/output time exceeded error%s}\n");
1140	p(ifs6_out_paramprob, "\t{:sent-bad-parameter/%ju} "
1141	    "{N:/output parameter problem error%s}\n");
1142	p(ifs6_out_pkttoobig, "\t{:sent-packet-too-big/%ju} "
1143	    "{N:/output packet too big error%s}\n");
1144	p(ifs6_out_echo, "\t{:sent-echo-requests/%ju} "
1145	    "{N:/output echo request%s}\n");
1146	p2(ifs6_out_echoreply, "\t{:sent-echo-replies/%ju} "
1147	    "{N:/output echo repl%s}\n");
1148	p(ifs6_out_routersolicit, "\t{:sent-router-solicitation/%ju} "
1149	    "{N:/output router solicitation%s}\n");
1150	p(ifs6_out_routeradvert, "\t{:sent-router-advertisement/%ju} "
1151	    "{N:/output router advertisement%s}\n");
1152	p(ifs6_out_neighborsolicit, "\t{:sent-neighbor-solicitation/%ju} "
1153	    "{N:/output neighbor solicitation%s}\n");
1154	p(ifs6_out_neighboradvert, "\t{:sent-neighbor-advertisement/%ju} "
1155	    "{N:/output neighbor advertisement%s}\n");
1156	p(ifs6_out_redirect, "\t{:sent-redirects/%ju} "
1157	    "{N:/output redirect%s}\n");
1158	p2(ifs6_out_mldquery, "\t{:sent-mld-queries/%ju} "
1159	    "{N:/output MLD quer%s}\n");
1160	p(ifs6_out_mldreport, "\t{:sent-mld-reports/%ju} "
1161	    "{N:/output MLD report%s}\n");
1162	p(ifs6_out_mlddone, "\t{:sent-mld-dones/%ju} "
1163	    "{N:/output MLD done%s}\n");
1164
1165end:
1166	xo_close_instance("icmp6-interface-statistics");
1167	close(s);
1168#undef p
1169}
1170
1171/*
1172 * Dump PIM statistics structure.
1173 */
1174void
1175pim6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
1176{
1177	struct pim6stat pim6stat;
1178
1179	if (fetch_stats("net.inet6.pim.stats", off, &pim6stat,
1180	    sizeof(pim6stat), kread) != 0)
1181		return;
1182
1183	xo_emit("{T:/%s}:\n", name);
1184	xo_open_container(name);
1185
1186#define	p(f, m) if (pim6stat.f || sflag <= 1) \
1187	xo_emit(m, (uintmax_t)pim6stat.f, plural(pim6stat.f))
1188
1189	p(pim6s_rcv_total, "\t{:received-packets/%ju} "
1190	    "{N:/message%s received}\n");
1191	p(pim6s_rcv_tooshort, "\t{:dropped-too-short/%ju} "
1192	    "{N:/message%s received with too few bytes}\n");
1193	p(pim6s_rcv_badsum, "\t{:dropped-bad-checksum/%ju} "
1194	    "{N:/message%s received with bad checksum}\n");
1195	p(pim6s_rcv_badversion, "\t{:dropped-bad-version/%ju} "
1196	    "{N:/message%s received with bad version}\n");
1197	p(pim6s_rcv_registers, "\t{:received-registers/%ju} "
1198	    "{N:/register%s received}\n");
1199	p(pim6s_rcv_badregisters, "\t{:received-bad-registers/%ju} "
1200	    "{N:/bad register%s received}\n");
1201	p(pim6s_snd_registers, "\t{:sent-registers/%ju} "
1202	    "{N:/register%s sent}\n");
1203#undef p
1204	xo_close_container(name);
1205}
1206
1207/*
1208 * Dump raw ip6 statistics structure.
1209 */
1210void
1211rip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
1212{
1213	struct rip6stat rip6stat;
1214	u_quad_t delivered;
1215
1216	if (fetch_stats("net.inet6.ip6.rip6stats", off, &rip6stat,
1217	    sizeof(rip6stat), kread_counters) != 0)
1218		return;
1219
1220	xo_emit("{T:/%s}:\n", name);
1221	xo_open_container(name);
1222
1223#define	p(f, m) if (rip6stat.f || sflag <= 1) \
1224	xo_emit(m, (uintmax_t)rip6stat.f, plural(rip6stat.f))
1225
1226	p(rip6s_ipackets, "\t{:received-packets/%ju} "
1227	    "{N:/message%s received}\n");
1228	p(rip6s_isum, "\t{:input-checksum-computation/%ju} "
1229	    "{N:/checksum calculation%s on inbound}\n");
1230	p(rip6s_badsum, "\t{:received-bad-checksum/%ju} "
1231	    "{N:/message%s with bad checksum}\n");
1232	p(rip6s_nosock, "\t{:dropped-no-socket/%ju} "
1233	    "{N:/message%s dropped due to no socket}\n");
1234	p(rip6s_nosockmcast, "\t{:dropped-multicast-no-socket/%ju} "
1235	    "{N:/multicast message%s dropped due to no socket}\n");
1236	p(rip6s_fullsock, "\t{:dropped-full-socket-buffer/%ju} "
1237	    "{N:/message%s dropped due to full socket buffers}\n");
1238	delivered = rip6stat.rip6s_ipackets -
1239		    rip6stat.rip6s_badsum -
1240		    rip6stat.rip6s_nosock -
1241		    rip6stat.rip6s_nosockmcast -
1242		    rip6stat.rip6s_fullsock;
1243	if (delivered || sflag <= 1)
1244		xo_emit("\t{:delivered-packets/%ju} {N:/delivered}\n",
1245		    (uintmax_t)delivered);
1246	p(rip6s_opackets, "\t{:sent-packets/%ju} "
1247	    "{N:/datagram%s output}\n");
1248#undef p
1249	xo_close_container(name);
1250}
1251
1252/*
1253 * Pretty print an Internet address (net address + port).
1254 * Take numeric_addr and numeric_port into consideration.
1255 */
1256#define	GETSERVBYPORT6(port, proto, ret)\
1257{\
1258	if (strcmp((proto), "tcp6") == 0)\
1259		(ret) = getservbyport((int)(port), "tcp");\
1260	else if (strcmp((proto), "udp6") == 0)\
1261		(ret) = getservbyport((int)(port), "udp");\
1262	else\
1263		(ret) = getservbyport((int)(port), (proto));\
1264};
1265
1266void
1267inet6print(const char *container, struct in6_addr *in6, int port,
1268    const char *proto, int numeric)
1269{
1270	struct servent *sp = 0;
1271	char line[80], *cp;
1272	int width;
1273
1274	if (container)
1275		xo_open_container(container);
1276
1277	sprintf(line, "%.*s.", Wflag ? 39 : (Aflag && !numeric) ? 12 : 16,
1278	    inet6name(in6));
1279	cp = strchr(line, '\0');
1280	if (!numeric && port)
1281		GETSERVBYPORT6(port, proto, sp);
1282	if (sp || port == 0)
1283		sprintf(cp, "%.15s", sp ? sp->s_name : "*");
1284	else
1285		sprintf(cp, "%d", ntohs((u_short)port));
1286	width = Wflag ? 45 : Aflag ? 18 : 22;
1287
1288	xo_emit("{d:target/%-*.*s} ", width, width, line);
1289
1290	int alen = cp - line - 1, plen = strlen(cp) - 1;
1291	xo_emit("{e:address/%*.*s}{e:port/%*.*s}", alen, alen, line, plen,
1292	    plen, cp);
1293
1294	if (container)
1295		xo_close_container(container);
1296}
1297
1298/*
1299 * Construct an Internet address representation.
1300 * If the numeric_addr has been supplied, give
1301 * numeric value, otherwise try for symbolic name.
1302 */
1303
1304char *
1305inet6name(struct in6_addr *in6p)
1306{
1307	struct sockaddr_in6 sin6;
1308	char hbuf[NI_MAXHOST], *cp;
1309	static char line[50];
1310	static char domain[MAXHOSTNAMELEN];
1311	static int first = 1;
1312	int flags, error;
1313
1314	if (IN6_IS_ADDR_UNSPECIFIED(in6p)) {
1315		strcpy(line, "*");
1316		return (line);
1317	}
1318	if (first && !numeric_addr) {
1319		first = 0;
1320		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
1321		    (cp = strchr(domain, '.')))
1322			(void) strcpy(domain, cp + 1);
1323		else
1324			domain[0] = 0;
1325	}
1326	memset(&sin6, 0, sizeof(sin6));
1327	memcpy(&sin6.sin6_addr, in6p, sizeof(*in6p));
1328	sin6.sin6_family = AF_INET6;
1329	/* XXX: in6p.s6_addr[2] can contain scopeid. */
1330	in6_fillscopeid(&sin6);
1331	flags = (numeric_addr) ? NI_NUMERICHOST : 0;
1332	error = getnameinfo((struct sockaddr *)&sin6, sizeof(sin6), hbuf,
1333	    sizeof(hbuf), NULL, 0, flags);
1334	if (error == 0) {
1335		if ((flags & NI_NUMERICHOST) == 0 &&
1336		    (cp = strchr(hbuf, '.')) &&
1337		    !strcmp(cp + 1, domain))
1338			*cp = 0;
1339		strcpy(line, hbuf);
1340	} else {
1341		/* XXX: this should not happen. */
1342		sprintf(line, "%s",
1343			inet_ntop(AF_INET6, (void *)&sin6.sin6_addr, ntop_buf,
1344				sizeof(ntop_buf)));
1345	}
1346	return (line);
1347}
1348#endif /*INET6*/
1349