xref: /f-stack/tools/netstat/inet6.c (revision 10c1fea8)
1 /*	BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp	*/
2 /*-
3  * SPDX-License-Identifier: BSD-3-Clause
4  *
5  * Copyright (c) 1983, 1988, 1993
6  *	The Regents of the University of California.  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 University 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 REGENTS 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 REGENTS 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 #if 0
34 #ifndef lint
35 static char sccsid[] = "@(#)inet6.c	8.4 (Berkeley) 4/20/94";
36 #endif /* not lint */
37 #endif
38 
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
41 
42 #ifdef INET6
43 #include <sys/param.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 #include <sys/ioctl.h>
47 #include <sys/mbuf.h>
48 #include <sys/protosw.h>
49 
50 #include <net/route.h>
51 #include <net/if.h>
52 #include <netinet/in.h>
53 #include <netinet/ip6.h>
54 #include <netinet/icmp6.h>
55 #include <netinet/in_systm.h>
56 #include <netinet6/in6_pcb.h>
57 #include <netinet6/in6_var.h>
58 #include <netinet6/ip6_var.h>
59 #include <netinet6/pim6_var.h>
60 #include <netinet6/raw_ip6.h>
61 
62 #include <arpa/inet.h>
63 #include <netdb.h>
64 
65 #include <err.h>
66 #include <stdint.h>
67 #include <stdio.h>
68 #include <stdbool.h>
69 #include <errno.h>
70 #include <string.h>
71 #include <unistd.h>
72 #include <libxo/xo.h>
73 #include "netstat.h"
74 
75 static char ntop_buf[INET6_ADDRSTRLEN];
76 
77 static	const char *ip6nh[] = {
78 	"hop by hop",
79 	"ICMP",
80 	"IGMP",
81 	"#3",
82 	"IP",
83 	"#5",
84 	"TCP",
85 	"#7",
86 	"#8",
87 	"#9",
88 	"#10",
89 	"#11",
90 	"#12",
91 	"#13",
92 	"#14",
93 	"#15",
94 	"#16",
95 	"UDP",
96 	"#18",
97 	"#19",
98 	"#20",
99 	"#21",
100 	"IDP",
101 	"#23",
102 	"#24",
103 	"#25",
104 	"#26",
105 	"#27",
106 	"#28",
107 	"TP",
108 	"#30",
109 	"#31",
110 	"#32",
111 	"#33",
112 	"#34",
113 	"#35",
114 	"#36",
115 	"#37",
116 	"#38",
117 	"#39",
118 	"#40",
119 	"IP6",
120 	"#42",
121 	"routing",
122 	"fragment",
123 	"#45",
124 	"#46",
125 	"#47",
126 	"#48",
127 	"#49",
128 	"ESP",
129 	"AH",
130 	"#52",
131 	"#53",
132 	"#54",
133 	"#55",
134 	"#56",
135 	"#57",
136 	"ICMP6",
137 	"no next header",
138 	"destination option",
139 	"#61",
140 	"mobility",
141 	"#63",
142 	"#64",
143 	"#65",
144 	"#66",
145 	"#67",
146 	"#68",
147 	"#69",
148 	"#70",
149 	"#71",
150 	"#72",
151 	"#73",
152 	"#74",
153 	"#75",
154 	"#76",
155 	"#77",
156 	"#78",
157 	"#79",
158 	"ISOIP",
159 	"#81",
160 	"#82",
161 	"#83",
162 	"#84",
163 	"#85",
164 	"#86",
165 	"#87",
166 	"#88",
167 	"OSPF",
168 	"#80",
169 	"#91",
170 	"#92",
171 	"#93",
172 	"#94",
173 	"#95",
174 	"#96",
175 	"Ethernet",
176 	"#98",
177 	"#99",
178 	"#100",
179 	"#101",
180 	"#102",
181 	"PIM",
182 	"#104",
183 	"#105",
184 	"#106",
185 	"#107",
186 	"#108",
187 	"#109",
188 	"#110",
189 	"#111",
190 	"#112",
191 	"#113",
192 	"#114",
193 	"#115",
194 	"#116",
195 	"#117",
196 	"#118",
197 	"#119",
198 	"#120",
199 	"#121",
200 	"#122",
201 	"#123",
202 	"#124",
203 	"#125",
204 	"#126",
205 	"#127",
206 	"#128",
207 	"#129",
208 	"#130",
209 	"#131",
210 	"SCTP",
211 	"#133",
212 	"#134",
213 	"#135",
214 	"UDPLite",
215 	"#137",
216 	"#138",
217 	"#139",
218 	"#140",
219 	"#141",
220 	"#142",
221 	"#143",
222 	"#144",
223 	"#145",
224 	"#146",
225 	"#147",
226 	"#148",
227 	"#149",
228 	"#150",
229 	"#151",
230 	"#152",
231 	"#153",
232 	"#154",
233 	"#155",
234 	"#156",
235 	"#157",
236 	"#158",
237 	"#159",
238 	"#160",
239 	"#161",
240 	"#162",
241 	"#163",
242 	"#164",
243 	"#165",
244 	"#166",
245 	"#167",
246 	"#168",
247 	"#169",
248 	"#170",
249 	"#171",
250 	"#172",
251 	"#173",
252 	"#174",
253 	"#175",
254 	"#176",
255 	"#177",
256 	"#178",
257 	"#179",
258 	"#180",
259 	"#181",
260 	"#182",
261 	"#183",
262 	"#184",
263 	"#185",
264 	"#186",
265 	"#187",
266 	"#188",
267 	"#189",
268 	"#180",
269 	"#191",
270 	"#192",
271 	"#193",
272 	"#194",
273 	"#195",
274 	"#196",
275 	"#197",
276 	"#198",
277 	"#199",
278 	"#200",
279 	"#201",
280 	"#202",
281 	"#203",
282 	"#204",
283 	"#205",
284 	"#206",
285 	"#207",
286 	"#208",
287 	"#209",
288 	"#210",
289 	"#211",
290 	"#212",
291 	"#213",
292 	"#214",
293 	"#215",
294 	"#216",
295 	"#217",
296 	"#218",
297 	"#219",
298 	"#220",
299 	"#221",
300 	"#222",
301 	"#223",
302 	"#224",
303 	"#225",
304 	"#226",
305 	"#227",
306 	"#228",
307 	"#229",
308 	"#230",
309 	"#231",
310 	"#232",
311 	"#233",
312 	"#234",
313 	"#235",
314 	"#236",
315 	"#237",
316 	"#238",
317 	"#239",
318 	"#240",
319 	"#241",
320 	"#242",
321 	"#243",
322 	"#244",
323 	"#245",
324 	"#246",
325 	"#247",
326 	"#248",
327 	"#249",
328 	"#250",
329 	"#251",
330 	"#252",
331 	"#253",
332 	"#254",
333 	"#255",
334 };
335 
336 static const char *srcrule_str[] = {
337 	"first candidate",
338 	"same address",
339 	"appropriate scope",
340 	"deprecated address",
341 	"home address",
342 	"outgoing interface",
343 	"matching label",
344 	"public/temporary address",
345 	"alive interface",
346 	"better virtual status",
347 	"preferred source",
348 	"rule #11",
349 	"rule #12",
350 	"rule #13",
351 	"longest match",
352 	"rule #15",
353 };
354 
355 /*
356  * Dump IP6 statistics structure.
357  */
358 void
359 ip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
360 {
361 	struct ip6stat ip6stat;
362 	int first, i;
363 
364 	if (fetch_stats("net.inet6.ip6.stats", off, &ip6stat,
365 	    sizeof(ip6stat), kread_counters) != 0)
366 		return;
367 
368 	xo_open_container(name);
369 	xo_emit("{T:/%s}:\n", name);
370 
371 #define	p(f, m) if (ip6stat.f || sflag <= 1) \
372 	xo_emit(m, (uintmax_t)ip6stat.f, plural(ip6stat.f))
373 #define	p1a(f, m) if (ip6stat.f || sflag <= 1) \
374 	xo_emit(m, (uintmax_t)ip6stat.f)
375 
376 	p(ip6s_total, "\t{:received-packets/%ju} "
377 	    "{N:/total packet%s received}\n");
378 	p1a(ip6s_toosmall, "\t{:dropped-below-minimum-size/%ju} "
379 	    "{N:/with size smaller than minimum}\n");
380 	p1a(ip6s_tooshort, "\t{:dropped-short-packets/%ju} "
381 	    "{N:/with data size < data length}\n");
382 	p1a(ip6s_badoptions, "\t{:dropped-bad-options/%ju} "
383 	    "{N:/with bad options}\n");
384 	p1a(ip6s_badvers, "\t{:dropped-bad-version/%ju} "
385 	    "{N:/with incorrect version number}\n");
386 	p(ip6s_fragments, "\t{:received-fragments/%ju} "
387 	    "{N:/fragment%s received}\n");
388 	p(ip6s_fragdropped, "\t{:dropped-fragment/%ju} "
389 	    "{N:/fragment%s dropped (dup or out of space)}\n");
390 	p(ip6s_fragtimeout, "\t{:dropped-fragment-after-timeout/%ju} "
391 	    "{N:/fragment%s dropped after timeout}\n");
392 	p(ip6s_fragoverflow, "\t{:dropped-fragments-overflow/%ju} "
393 	    "{N:/fragment%s that exceeded limit}\n");
394 	p(ip6s_atomicfrags, "\t{:atomic-fragments/%ju} "
395 	    "{N:/atomic fragment%s}\n");
396 	p(ip6s_reassembled, "\t{:reassembled-packets/%ju} "
397 	    "{N:/packet%s reassembled ok}\n");
398 	p(ip6s_delivered, "\t{:received-local-packets/%ju} "
399 	    "{N:/packet%s for this host}\n");
400 	p(ip6s_forward, "\t{:forwarded-packets/%ju} "
401 	    "{N:/packet%s forwarded}\n");
402 	p(ip6s_cantforward, "\t{:packets-not-forwardable/%ju} "
403 	    "{N:/packet%s not forwardable}\n");
404 	p(ip6s_redirectsent, "\t{:sent-redirects/%ju} "
405 	    "{N:/redirect%s sent}\n");
406 	p(ip6s_localout, "\t{:sent-packets/%ju} "
407 	    "{N:/packet%s sent from this host}\n");
408 	p(ip6s_rawout, "\t{:send-packets-fabricated-header/%ju} "
409 	    "{N:/packet%s sent with fabricated ip header}\n");
410 	p(ip6s_odropped, "\t{:discard-no-mbufs/%ju} "
411 	    "{N:/output packet%s dropped due to no bufs, etc.}\n");
412 	p(ip6s_noroute, "\t{:discard-no-route/%ju} "
413 	    "{N:/output packet%s discarded due to no route}\n");
414 	p(ip6s_fragmented, "\t{:sent-fragments/%ju} "
415 	    "{N:/output datagram%s fragmented}\n");
416 	p(ip6s_ofragments, "\t{:fragments-created/%ju} "
417 	    "{N:/fragment%s created}\n");
418 	p(ip6s_cantfrag, "\t{:discard-cannot-fragment/%ju} "
419 	    "{N:/datagram%s that can't be fragmented}\n");
420 	p(ip6s_badscope, "\t{:discard-scope-violations/%ju} "
421 	    "{N:/packet%s that violated scope rules}\n");
422 	p(ip6s_notmember, "\t{:multicast-no-join-packets/%ju} "
423 	    "{N:/multicast packet%s which we don't join}\n");
424 	for (first = 1, i = 0; i < IP6S_HDRCNT; i++)
425 		if (ip6stat.ip6s_nxthist[i] != 0) {
426 			if (first) {
427 				xo_emit("\t{T:Input histogram}:\n");
428 				xo_open_list("input-histogram");
429 				first = 0;
430 			}
431 			xo_open_instance("input-histogram");
432 			xo_emit("\t\t{k:name/%s}: {:count/%ju}\n", ip6nh[i],
433 			    (uintmax_t)ip6stat.ip6s_nxthist[i]);
434 			xo_close_instance("input-histogram");
435 		}
436 	if (!first)
437 		xo_close_list("input-histogram");
438 
439 	xo_open_container("mbuf-statistics");
440 	xo_emit("\t{T:Mbuf statistics}:\n");
441 	xo_emit("\t\t{:one-mbuf/%ju} {N:/one mbuf}\n",
442 	    (uintmax_t)ip6stat.ip6s_m1);
443 	for (first = 1, i = 0; i < IP6S_M2MMAX; i++) {
444 		char ifbuf[IFNAMSIZ];
445 		if (ip6stat.ip6s_m2m[i] != 0) {
446 			if (first) {
447 				xo_emit("\t\t{N:two or more mbuf}:\n");
448 				xo_open_list("mbuf-data");
449 				first = 0;
450 			}
451 			xo_open_instance("mbuf-data");
452 			xo_emit("\t\t\t{k:name/%s}= {:count/%ju}\n",
453 			    if_indextoname(i, ifbuf),
454 			    (uintmax_t)ip6stat.ip6s_m2m[i]);
455 			xo_close_instance("mbuf-data");
456 		}
457 	}
458 	if (!first)
459 		xo_close_list("mbuf-data");
460 	xo_emit("\t\t{:one-extra-mbuf/%ju} {N:one ext mbuf}\n",
461 	    (uintmax_t)ip6stat.ip6s_mext1);
462 	xo_emit("\t\t{:two-or-more-extra-mbufs/%ju} "
463 	    "{N:/two or more ext mbuf}\n", (uintmax_t)ip6stat.ip6s_mext2m);
464 	xo_close_container("mbuf-statistics");
465 
466 	p(ip6s_exthdrtoolong, "\t{:dropped-header-too-long/%ju} "
467 	    "{N:/packet%s whose headers are not contiguous}\n");
468 	p(ip6s_nogif, "\t{:discard-tunnel-no-gif/%ju} "
469 	    "{N:/tunneling packet%s that can't find gif}\n");
470 	p(ip6s_toomanyhdr, "\t{:dropped-too-many-headers/%ju} "
471 	    "{N:/packet%s discarded because of too many headers}\n");
472 
473 	/* for debugging source address selection */
474 #define	PRINT_SCOPESTAT(s,i) do {\
475 		switch(i) { /* XXX hardcoding in each case */\
476 		case 1:\
477 			p(s, "\t\t{ke:name/interface-locals}{:count/%ju} " \
478 			  "{N:/interface-local%s}\n");	\
479 			break;\
480 		case 2:\
481 			p(s,"\t\t{ke:name/link-locals}{:count/%ju} " \
482 			"{N:/link-local%s}\n"); \
483 			break;\
484 		case 5:\
485 			p(s,"\t\t{ke:name/site-locals}{:count/%ju} " \
486 			  "{N:/site-local%s}\n");\
487 			break;\
488 		case 14:\
489 			p(s,"\t\t{ke:name/globals}{:count/%ju} " \
490 			  "{N:/global%s}\n");\
491 			break;\
492 		default:\
493 			xo_emit("\t\t{qke:name/%#x}{:count/%ju} " \
494 				"{N:/addresses scope=%#x}\n",\
495 				i, (uintmax_t)ip6stat.s, i);	   \
496 		}\
497 	} while (0);
498 
499 	xo_open_container("source-address-selection");
500 	p(ip6s_sources_none, "\t{:address-selection-failures/%ju} "
501 	    "{N:/failure%s of source address selection}\n");
502 
503 	for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) {
504 		if (ip6stat.ip6s_sources_sameif[i]) {
505 			if (first) {
506 				xo_open_list("outgoing-interface");
507 				xo_emit("\tsource addresses on an outgoing "
508 				    "I/F\n");
509 				first = 0;
510 			}
511 			xo_open_instance("outgoing-interface");
512 			PRINT_SCOPESTAT(ip6s_sources_sameif[i], i);
513 			xo_close_instance("outgoing-interface");
514 		}
515 	}
516 	if (!first)
517 		xo_close_list("outgoing-interface");
518 
519 	for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) {
520 		if (ip6stat.ip6s_sources_otherif[i]) {
521 			if (first) {
522 				xo_open_list("non-outgoing-interface");
523 				xo_emit("\tsource addresses on a non-outgoing "
524 				    "I/F\n");
525 				first = 0;
526 			}
527 			xo_open_instance("non-outgoing-interface");
528 			PRINT_SCOPESTAT(ip6s_sources_otherif[i], i);
529 			xo_close_instance("non-outgoing-interface");
530 		}
531 	}
532 	if (!first)
533 		xo_close_list("non-outgoing-interface");
534 
535 	for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) {
536 		if (ip6stat.ip6s_sources_samescope[i]) {
537 			if (first) {
538 				xo_open_list("same-source");
539 				xo_emit("\tsource addresses of same scope\n");
540 				first = 0;
541 			}
542 			xo_open_instance("same-source");
543 			PRINT_SCOPESTAT(ip6s_sources_samescope[i], i);
544 			xo_close_instance("same-source");
545 		}
546 	}
547 	if (!first)
548 		xo_close_list("same-source");
549 
550 	for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) {
551 		if (ip6stat.ip6s_sources_otherscope[i]) {
552 			if (first) {
553 				xo_open_list("different-scope");
554 				xo_emit("\tsource addresses of a different "
555 				    "scope\n");
556 				first = 0;
557 			}
558 			xo_open_instance("different-scope");
559 			PRINT_SCOPESTAT(ip6s_sources_otherscope[i], i);
560 			xo_close_instance("different-scope");
561 		}
562 	}
563 	if (!first)
564 		xo_close_list("different-scope");
565 
566 	for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) {
567 		if (ip6stat.ip6s_sources_deprecated[i]) {
568 			if (first) {
569 				xo_open_list("deprecated-source");
570 				xo_emit("\tdeprecated source addresses\n");
571 				first = 0;
572 			}
573 			xo_open_instance("deprecated-source");
574 			PRINT_SCOPESTAT(ip6s_sources_deprecated[i], i);
575 			xo_close_instance("deprecated-source");
576 		}
577 	}
578 	if (!first)
579 		xo_close_list("deprecated-source");
580 
581 	for (first = 1, i = 0; i < IP6S_RULESMAX; i++) {
582 		if (ip6stat.ip6s_sources_rule[i]) {
583 			if (first) {
584 				xo_open_list("rules-applied");
585 				xo_emit("\t{T:Source addresses selection "
586 				    "rule applied}:\n");
587 				first = 0;
588 			}
589 			xo_open_instance("rules-applied");
590 			xo_emit("\t\t{ke:name/%s}{:count/%ju} {d:name/%s}\n",
591 			    srcrule_str[i],
592 			    (uintmax_t)ip6stat.ip6s_sources_rule[i],
593 			    srcrule_str[i]);
594 			xo_close_instance("rules-applied");
595 		}
596 	}
597 	if (!first)
598 		xo_close_list("rules-applied");
599 
600 	xo_close_container("source-address-selection");
601 
602 #undef p
603 #undef p1a
604 	xo_close_container(name);
605 }
606 
607 /*
608  * Dump IPv6 per-interface statistics based on RFC 2465.
609  */
610 void
611 ip6_ifstats(char *ifname)
612 {
613 	struct in6_ifreq ifr;
614 	int s;
615 
616 #define	p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1)	\
617 	xo_emit(m, (uintmax_t)ifr.ifr_ifru.ifru_stat.f,		\
618 	    plural(ifr.ifr_ifru.ifru_stat.f))
619 
620 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
621 		xo_warn("Warning: socket(AF_INET6)");
622 		return;
623 	}
624 
625 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
626 #ifndef FSTACK
627 	if (ioctl(s, SIOCGIFSTAT_IN6, (char *)&ifr) < 0) {
628 #else
629 	if (ioctl_va(s, SIOCGIFSTAT_IN6, (char *)&ifr, 1, AF_INET6) < 0) {
630 #endif
631 		if (errno != EPFNOSUPPORT)
632 			xo_warn("Warning: ioctl(SIOCGIFSTAT_IN6)");
633 		goto end;
634 	}
635 
636 	xo_emit("{T:/ip6 on %s}:\n", ifr.ifr_name);
637 
638 	xo_open_instance("ip6-interface-statistics");
639 	xo_emit("{ke:name/%s}", ifr.ifr_name);
640 
641 	p(ifs6_in_receive, "\t{:received-packets/%ju} "
642 	    "{N:/total input datagram%s}\n");
643 	p(ifs6_in_hdrerr, "\t{:dropped-invalid-header/%ju} "
644 	    "{N:/datagram%s with invalid header received}\n");
645 	p(ifs6_in_toobig, "\t{:dropped-mtu-exceeded/%ju} "
646 	    "{N:/datagram%s exceeded MTU received}\n");
647 	p(ifs6_in_noroute, "\t{:dropped-no-route/%ju} "
648 	    "{N:/datagram%s with no route received}\n");
649 	p(ifs6_in_addrerr, "\t{:dropped-invalid-destination/%ju} "
650 	    "{N:/datagram%s with invalid dst received}\n");
651 	p(ifs6_in_protounknown, "\t{:dropped-unknown-protocol/%ju} "
652 	    "{N:/datagram%s with unknown proto received}\n");
653 	p(ifs6_in_truncated, "\t{:dropped-truncated/%ju} "
654 	    "{N:/truncated datagram%s received}\n");
655 	p(ifs6_in_discard, "\t{:dropped-discarded/%ju} "
656 	    "{N:/input datagram%s discarded}\n");
657  	p(ifs6_in_deliver, "\t{:received-valid-packets/%ju} "
658 	    "{N:/datagram%s delivered to an upper layer protocol}\n");
659 	p(ifs6_out_forward, "\t{:sent-forwarded/%ju} "
660 	    "{N:/datagram%s forwarded to this interface}\n");
661  	p(ifs6_out_request, "\t{:sent-packets/%ju} "
662 	    "{N:/datagram%s sent from an upper layer protocol}\n");
663 	p(ifs6_out_discard, "\t{:discard-packets/%ju} "
664 	    "{N:/total discarded output datagram%s}\n");
665 	p(ifs6_out_fragok, "\t{:discard-fragments/%ju} "
666 	    "{N:/output datagram%s fragmented}\n");
667 	p(ifs6_out_fragfail, "\t{:fragments-failed/%ju} "
668 	    "{N:/output datagram%s failed on fragment}\n");
669 	p(ifs6_out_fragcreat, "\t{:fragments-created/%ju} "
670 	    "{N:/output datagram%s succeeded on fragment}\n");
671 	p(ifs6_reass_reqd, "\t{:reassembly-required/%ju} "
672 	    "{N:/incoming datagram%s fragmented}\n");
673 	p(ifs6_reass_ok, "\t{:reassembled-packets/%ju} "
674 	    "{N:/datagram%s reassembled}\n");
675 	p(ifs6_reass_fail, "\t{:reassembly-failed/%ju} "
676 	    "{N:/datagram%s failed on reassembly}\n");
677 	p(ifs6_in_mcast, "\t{:received-multicast/%ju} "
678 	    "{N:/multicast datagram%s received}\n");
679 	p(ifs6_out_mcast, "\t{:sent-multicast/%ju} "
680 	    "{N:/multicast datagram%s sent}\n");
681 
682  end:
683 	xo_close_instance("ip6-interface-statistics");
684  	close(s);
685 
686 #undef p
687 }
688 
689 static	const char *icmp6names[] = {
690 	"#0",
691 	"unreach",
692 	"packet too big",
693 	"time exceed",
694 	"parameter problem",
695 	"#5",
696 	"#6",
697 	"#7",
698 	"#8",
699 	"#9",
700 	"#10",
701 	"#11",
702 	"#12",
703 	"#13",
704 	"#14",
705 	"#15",
706 	"#16",
707 	"#17",
708 	"#18",
709 	"#19",
710 	"#20",
711 	"#21",
712 	"#22",
713 	"#23",
714 	"#24",
715 	"#25",
716 	"#26",
717 	"#27",
718 	"#28",
719 	"#29",
720 	"#30",
721 	"#31",
722 	"#32",
723 	"#33",
724 	"#34",
725 	"#35",
726 	"#36",
727 	"#37",
728 	"#38",
729 	"#39",
730 	"#40",
731 	"#41",
732 	"#42",
733 	"#43",
734 	"#44",
735 	"#45",
736 	"#46",
737 	"#47",
738 	"#48",
739 	"#49",
740 	"#50",
741 	"#51",
742 	"#52",
743 	"#53",
744 	"#54",
745 	"#55",
746 	"#56",
747 	"#57",
748 	"#58",
749 	"#59",
750 	"#60",
751 	"#61",
752 	"#62",
753 	"#63",
754 	"#64",
755 	"#65",
756 	"#66",
757 	"#67",
758 	"#68",
759 	"#69",
760 	"#70",
761 	"#71",
762 	"#72",
763 	"#73",
764 	"#74",
765 	"#75",
766 	"#76",
767 	"#77",
768 	"#78",
769 	"#79",
770 	"#80",
771 	"#81",
772 	"#82",
773 	"#83",
774 	"#84",
775 	"#85",
776 	"#86",
777 	"#87",
778 	"#88",
779 	"#89",
780 	"#80",
781 	"#91",
782 	"#92",
783 	"#93",
784 	"#94",
785 	"#95",
786 	"#96",
787 	"#97",
788 	"#98",
789 	"#99",
790 	"#100",
791 	"#101",
792 	"#102",
793 	"#103",
794 	"#104",
795 	"#105",
796 	"#106",
797 	"#107",
798 	"#108",
799 	"#109",
800 	"#110",
801 	"#111",
802 	"#112",
803 	"#113",
804 	"#114",
805 	"#115",
806 	"#116",
807 	"#117",
808 	"#118",
809 	"#119",
810 	"#120",
811 	"#121",
812 	"#122",
813 	"#123",
814 	"#124",
815 	"#125",
816 	"#126",
817 	"#127",
818 	"echo",
819 	"echo reply",
820 	"multicast listener query",
821 	"MLDv1 listener report",
822 	"MLDv1 listener done",
823 	"router solicitation",
824 	"router advertisement",
825 	"neighbor solicitation",
826 	"neighbor advertisement",
827 	"redirect",
828 	"router renumbering",
829 	"node information request",
830 	"node information reply",
831 	"inverse neighbor solicitation",
832 	"inverse neighbor advertisement",
833 	"MLDv2 listener report",
834 	"#144",
835 	"#145",
836 	"#146",
837 	"#147",
838 	"#148",
839 	"#149",
840 	"#150",
841 	"#151",
842 	"#152",
843 	"#153",
844 	"#154",
845 	"#155",
846 	"#156",
847 	"#157",
848 	"#158",
849 	"#159",
850 	"#160",
851 	"#161",
852 	"#162",
853 	"#163",
854 	"#164",
855 	"#165",
856 	"#166",
857 	"#167",
858 	"#168",
859 	"#169",
860 	"#170",
861 	"#171",
862 	"#172",
863 	"#173",
864 	"#174",
865 	"#175",
866 	"#176",
867 	"#177",
868 	"#178",
869 	"#179",
870 	"#180",
871 	"#181",
872 	"#182",
873 	"#183",
874 	"#184",
875 	"#185",
876 	"#186",
877 	"#187",
878 	"#188",
879 	"#189",
880 	"#180",
881 	"#191",
882 	"#192",
883 	"#193",
884 	"#194",
885 	"#195",
886 	"#196",
887 	"#197",
888 	"#198",
889 	"#199",
890 	"#200",
891 	"#201",
892 	"#202",
893 	"#203",
894 	"#204",
895 	"#205",
896 	"#206",
897 	"#207",
898 	"#208",
899 	"#209",
900 	"#210",
901 	"#211",
902 	"#212",
903 	"#213",
904 	"#214",
905 	"#215",
906 	"#216",
907 	"#217",
908 	"#218",
909 	"#219",
910 	"#220",
911 	"#221",
912 	"#222",
913 	"#223",
914 	"#224",
915 	"#225",
916 	"#226",
917 	"#227",
918 	"#228",
919 	"#229",
920 	"#230",
921 	"#231",
922 	"#232",
923 	"#233",
924 	"#234",
925 	"#235",
926 	"#236",
927 	"#237",
928 	"#238",
929 	"#239",
930 	"#240",
931 	"#241",
932 	"#242",
933 	"#243",
934 	"#244",
935 	"#245",
936 	"#246",
937 	"#247",
938 	"#248",
939 	"#249",
940 	"#250",
941 	"#251",
942 	"#252",
943 	"#253",
944 	"#254",
945 	"#255",
946 };
947 
948 /*
949  * Dump ICMP6 statistics.
950  */
951 void
952 icmp6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
953 {
954 	struct icmp6stat icmp6stat;
955 	int i, first;
956 
957 	if (fetch_stats("net.inet6.icmp6.stats", off, &icmp6stat,
958 	    sizeof(icmp6stat), kread_counters) != 0)
959 		return;
960 
961 	xo_emit("{T:/%s}:\n", name);
962 	xo_open_container(name);
963 
964 #define	p(f, m) if (icmp6stat.f || sflag <= 1) \
965 	xo_emit(m, (uintmax_t)icmp6stat.f, plural(icmp6stat.f))
966 #define	p_5(f, m) if (icmp6stat.f || sflag <= 1) \
967 	xo_emit(m, (uintmax_t)icmp6stat.f)
968 
969 	p(icp6s_error, "\t{:icmp6-calls/%ju} "
970 	    "{N:/call%s to icmp6_error}\n");
971 	p(icp6s_canterror, "\t{:errors-not-generated-from-message/%ju} "
972 	    "{N:/error%s not generated in response to an icmp6 message}\n");
973 	p(icp6s_toofreq, "\t{:errors-discarded-by-rate-limitation/%ju} "
974 	    "{N:/error%s not generated because of rate limitation}\n");
975 #define	NELEM (int)(sizeof(icmp6stat.icp6s_outhist)/sizeof(icmp6stat.icp6s_outhist[0]))
976 	for (first = 1, i = 0; i < NELEM; i++)
977 		if (icmp6stat.icp6s_outhist[i] != 0) {
978 			if (first) {
979 				xo_open_list("output-histogram");
980 				xo_emit("\t{T:Output histogram}:\n");
981 				first = 0;
982 			}
983 			xo_open_instance("output-histogram");
984 			xo_emit("\t\t{k:name/%s}: {:count/%ju}\n",
985 			    icmp6names[i],
986 			    (uintmax_t)icmp6stat.icp6s_outhist[i]);
987 			xo_close_instance("output-histogram");
988 		}
989 	if (!first)
990 		xo_close_list("output-histogram");
991 #undef NELEM
992 
993 	p(icp6s_badcode, "\t{:dropped-bad-code/%ju} "
994 	    "{N:/message%s with bad code fields}\n");
995 	p(icp6s_tooshort, "\t{:dropped-too-short/%ju} "
996 	    "{N:/message%s < minimum length}\n");
997 	p(icp6s_checksum, "\t{:dropped-bad-checksum/%ju} "
998 	    "{N:/bad checksum%s}\n");
999 	p(icp6s_badlen, "\t{:dropped-bad-length/%ju} "
1000 	    "{N:/message%s with bad length}\n");
1001 #define	NELEM (int)(sizeof(icmp6stat.icp6s_inhist)/sizeof(icmp6stat.icp6s_inhist[0]))
1002 	for (first = 1, i = 0; i < NELEM; i++)
1003 		if (icmp6stat.icp6s_inhist[i] != 0) {
1004 			if (first) {
1005 				xo_open_list("input-histogram");
1006 				xo_emit("\t{T:Input histogram}:\n");
1007 				first = 0;
1008 			}
1009 			xo_open_instance("input-histogram");
1010 			xo_emit("\t\t{k:name/%s}: {:count/%ju}\n",
1011 			    icmp6names[i],
1012 			    (uintmax_t)icmp6stat.icp6s_inhist[i]);
1013 			xo_close_instance("input-histogram");
1014 		}
1015 	if (!first)
1016 		xo_close_list("input-histogram");
1017 #undef NELEM
1018 	xo_emit("\t{T:Histogram of error messages to be generated}:\n");
1019 	xo_open_container("errors");
1020 	p_5(icp6s_odst_unreach_noroute, "\t\t{:no-route/%ju} "
1021 	    "{N:/no route}\n");
1022 	p_5(icp6s_odst_unreach_admin, "\t\t{:admin-prohibited/%ju} "
1023 	    "{N:/administratively prohibited}\n");
1024 	p_5(icp6s_odst_unreach_beyondscope, "\t\t{:beyond-scope/%ju} "
1025 	    "{N:/beyond scope}\n");
1026 	p_5(icp6s_odst_unreach_addr, "\t\t{:address-unreachable/%ju} "
1027 	    "{N:/address unreachable}\n");
1028 	p_5(icp6s_odst_unreach_noport, "\t\t{:port-unreachable/%ju} "
1029 	    "{N:/port unreachable}\n");
1030 	p_5(icp6s_opacket_too_big, "\t\t{:packet-too-big/%ju} "
1031 	    "{N:/packet too big}\n");
1032 	p_5(icp6s_otime_exceed_transit, "\t\t{:time-exceed-transmit/%ju} "
1033 	    "{N:/time exceed transit}\n");
1034 	p_5(icp6s_otime_exceed_reassembly, "\t\t{:time-exceed-reassembly/%ju} "
1035 	    "{N:/time exceed reassembly}\n");
1036 	p_5(icp6s_oparamprob_header, "\t\t{:bad-header/%ju} "
1037 	    "{N:/erroneous header field}\n");
1038 	p_5(icp6s_oparamprob_nextheader, "\t\t{:bad-next-header/%ju} "
1039 	    "{N:/unrecognized next header}\n");
1040 	p_5(icp6s_oparamprob_option, "\t\t{:bad-option/%ju} "
1041 	    "{N:/unrecognized option}\n");
1042 	p_5(icp6s_oredirect, "\t\t{:redirects/%ju} "
1043 	    "{N:/redirect}\n");
1044 	p_5(icp6s_ounknown, "\t\t{:unknown/%ju} {N:unknown}\n");
1045 
1046 	p(icp6s_reflect, "\t{:reflect/%ju} "
1047 	    "{N:/message response%s generated}\n");
1048 	p(icp6s_nd_toomanyopt, "\t{:too-many-nd-options/%ju} "
1049 	    "{N:/message%s with too many ND options}\n");
1050 	p(icp6s_nd_badopt, "\t{:bad-nd-options/%ju} "
1051 	    "{N:/message%s with bad ND options}\n");
1052 	p(icp6s_badns, "\t{:bad-neighbor-solicitation/%ju} "
1053 	    "{N:/bad neighbor solicitation message%s}\n");
1054 	p(icp6s_badna, "\t{:bad-neighbor-advertisement/%ju} "
1055 	    "{N:/bad neighbor advertisement message%s}\n");
1056 	p(icp6s_badrs, "\t{:bad-router-solicitation/%ju} "
1057 	    "{N:/bad router solicitation message%s}\n");
1058 	p(icp6s_badra, "\t{:bad-router-advertisement/%ju} "
1059 	    "{N:/bad router advertisement message%s}\n");
1060 	p(icp6s_badredirect, "\t{:bad-redirect/%ju} "
1061 	    "{N:/bad redirect message%s}\n");
1062 	p(icp6s_overflowdefrtr, "\t{:default-routers-overflows/%ju} "
1063 	    "{N:/default routers overflow%s}\n");
1064 	p(icp6s_overflowprfx, "\t{:prefixes-overflows/%ju} "
1065 	    "{N:/prefix overflow%s}\n");
1066 	p(icp6s_overflownndp, "\t{:neighbour-entries-overflows/%ju} "
1067 	    "{N:/neighbour entries overflow%s}\n");
1068 	p(icp6s_overflowredirect, "\t{:redirect-overflows/%ju} "
1069 	    "{N:/redirect overflow%s}\n");
1070 	p(icp6s_invlhlim, "\t{:dropped-invalid-hop-limit/%ju} "
1071 	    "{N:/message%s with invalid hop limit}\n");
1072 	xo_close_container("errors");
1073 	p(icp6s_pmtuchg, "\t{:path-mtu-changes/%ju} {N:/path MTU change%s}\n");
1074 #undef p
1075 #undef p_5
1076 	xo_close_container(name);
1077 }
1078 
1079 /*
1080  * Dump ICMPv6 per-interface statistics based on RFC 2466.
1081  */
1082 void
1083 icmp6_ifstats(char *ifname)
1084 {
1085 	struct in6_ifreq ifr;
1086 	int s;
1087 
1088 #define	p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1)	\
1089 	xo_emit(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f,		\
1090 	    plural(ifr.ifr_ifru.ifru_icmp6stat.f))
1091 #define	p2(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1)	\
1092 	xo_emit(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f,		\
1093 	    pluralies(ifr.ifr_ifru.ifru_icmp6stat.f))
1094 
1095 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1096 		xo_warn("Warning: socket(AF_INET6)");
1097 		return;
1098 	}
1099 
1100 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1101 #ifndef FSTACK
1102 	if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) {
1103 #else
1104 	if (ioctl_va(s, SIOCGIFSTAT_ICMP6, (char *)&ifr, 1, AF_INET6) < 0) {
1105 #endif
1106 		if (errno != EPFNOSUPPORT)
1107 			xo_warn("Warning: ioctl(SIOCGIFSTAT_ICMP6)");
1108 		goto end;
1109 	}
1110 
1111 	xo_emit("{T:/icmp6 on %s}:\n", ifr.ifr_name);
1112 
1113 	xo_open_instance("icmp6-interface-statistics");
1114 	xo_emit("{ke:name/%s}", ifr.ifr_name);
1115 	p(ifs6_in_msg, "\t{:received-packets/%ju} "
1116 	    "{N:/total input message%s}\n");
1117 	p(ifs6_in_error, "\t{:received-errors/%ju} "
1118 	    "{N:/total input error message%s}\n");
1119 	p(ifs6_in_dstunreach, "\t{:received-destination-unreachable/%ju} "
1120 	    "{N:/input destination unreachable error%s}\n");
1121 	p(ifs6_in_adminprohib, "\t{:received-admin-prohibited/%ju} "
1122 	    "{N:/input administratively prohibited error%s}\n");
1123 	p(ifs6_in_timeexceed, "\t{:received-time-exceeded/%ju} "
1124 	    "{N:/input time exceeded error%s}\n");
1125 	p(ifs6_in_paramprob, "\t{:received-bad-parameter/%ju} "
1126 	    "{N:/input parameter problem error%s}\n");
1127 	p(ifs6_in_pkttoobig, "\t{:received-packet-too-big/%ju} "
1128 	    "{N:/input packet too big error%s}\n");
1129 	p(ifs6_in_echo, "\t{:received-echo-requests/%ju} "
1130 	    "{N:/input echo request%s}\n");
1131 	p2(ifs6_in_echoreply, "\t{:received-echo-replies/%ju} "
1132 	    "{N:/input echo repl%s}\n");
1133 	p(ifs6_in_routersolicit, "\t{:received-router-solicitation/%ju} "
1134 	    "{N:/input router solicitation%s}\n");
1135 	p(ifs6_in_routeradvert, "\t{:received-router-advertisement/%ju} "
1136 	    "{N:/input router advertisement%s}\n");
1137 	p(ifs6_in_neighborsolicit, "\t{:received-neighbor-solicitation/%ju} "
1138 	    "{N:/input neighbor solicitation%s}\n");
1139 	p(ifs6_in_neighboradvert, "\t{:received-neighbor-advertisement/%ju} "
1140 	    "{N:/input neighbor advertisement%s}\n");
1141 	p(ifs6_in_redirect, "\t{received-redirects/%ju} "
1142 	    "{N:/input redirect%s}\n");
1143 	p2(ifs6_in_mldquery, "\t{:received-mld-queries/%ju} "
1144 	    "{N:/input MLD quer%s}\n");
1145 	p(ifs6_in_mldreport, "\t{:received-mld-reports/%ju} "
1146 	    "{N:/input MLD report%s}\n");
1147 	p(ifs6_in_mlddone, "\t{:received-mld-done/%ju} "
1148 	    "{N:/input MLD done%s}\n");
1149 
1150 	p(ifs6_out_msg, "\t{:sent-packets/%ju} "
1151 	    "{N:/total output message%s}\n");
1152 	p(ifs6_out_error, "\t{:sent-errors/%ju} "
1153 	    "{N:/total output error message%s}\n");
1154 	p(ifs6_out_dstunreach, "\t{:sent-destination-unreachable/%ju} "
1155 	    "{N:/output destination unreachable error%s}\n");
1156 	p(ifs6_out_adminprohib, "\t{:sent-admin-prohibited/%ju} "
1157 	    "{N:/output administratively prohibited error%s}\n");
1158 	p(ifs6_out_timeexceed, "\t{:sent-time-exceeded/%ju} "
1159 	    "{N:/output time exceeded error%s}\n");
1160 	p(ifs6_out_paramprob, "\t{:sent-bad-parameter/%ju} "
1161 	    "{N:/output parameter problem error%s}\n");
1162 	p(ifs6_out_pkttoobig, "\t{:sent-packet-too-big/%ju} "
1163 	    "{N:/output packet too big error%s}\n");
1164 	p(ifs6_out_echo, "\t{:sent-echo-requests/%ju} "
1165 	    "{N:/output echo request%s}\n");
1166 	p2(ifs6_out_echoreply, "\t{:sent-echo-replies/%ju} "
1167 	    "{N:/output echo repl%s}\n");
1168 	p(ifs6_out_routersolicit, "\t{:sent-router-solicitation/%ju} "
1169 	    "{N:/output router solicitation%s}\n");
1170 	p(ifs6_out_routeradvert, "\t{:sent-router-advertisement/%ju} "
1171 	    "{N:/output router advertisement%s}\n");
1172 	p(ifs6_out_neighborsolicit, "\t{:sent-neighbor-solicitation/%ju} "
1173 	    "{N:/output neighbor solicitation%s}\n");
1174 	p(ifs6_out_neighboradvert, "\t{:sent-neighbor-advertisement/%ju} "
1175 	    "{N:/output neighbor advertisement%s}\n");
1176 	p(ifs6_out_redirect, "\t{:sent-redirects/%ju} "
1177 	    "{N:/output redirect%s}\n");
1178 	p2(ifs6_out_mldquery, "\t{:sent-mld-queries/%ju} "
1179 	    "{N:/output MLD quer%s}\n");
1180 	p(ifs6_out_mldreport, "\t{:sent-mld-reports/%ju} "
1181 	    "{N:/output MLD report%s}\n");
1182 	p(ifs6_out_mlddone, "\t{:sent-mld-dones/%ju} "
1183 	    "{N:/output MLD done%s}\n");
1184 
1185 end:
1186 	xo_close_instance("icmp6-interface-statistics");
1187 	close(s);
1188 #undef p
1189 }
1190 
1191 /*
1192  * Dump PIM statistics structure.
1193  */
1194 void
1195 pim6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
1196 {
1197 	struct pim6stat pim6stat;
1198 
1199 	if (fetch_stats("net.inet6.pim.stats", off, &pim6stat,
1200 	    sizeof(pim6stat), kread) != 0)
1201 		return;
1202 
1203 	xo_emit("{T:/%s}:\n", name);
1204 	xo_open_container(name);
1205 
1206 #define	p(f, m) if (pim6stat.f || sflag <= 1) \
1207 	xo_emit(m, (uintmax_t)pim6stat.f, plural(pim6stat.f))
1208 
1209 	p(pim6s_rcv_total, "\t{:received-packets/%ju} "
1210 	    "{N:/message%s received}\n");
1211 	p(pim6s_rcv_tooshort, "\t{:dropped-too-short/%ju} "
1212 	    "{N:/message%s received with too few bytes}\n");
1213 	p(pim6s_rcv_badsum, "\t{:dropped-bad-checksum/%ju} "
1214 	    "{N:/message%s received with bad checksum}\n");
1215 	p(pim6s_rcv_badversion, "\t{:dropped-bad-version/%ju} "
1216 	    "{N:/message%s received with bad version}\n");
1217 	p(pim6s_rcv_registers, "\t{:received-registers/%ju} "
1218 	    "{N:/register%s received}\n");
1219 	p(pim6s_rcv_badregisters, "\t{:received-bad-registers/%ju} "
1220 	    "{N:/bad register%s received}\n");
1221 	p(pim6s_snd_registers, "\t{:sent-registers/%ju} "
1222 	    "{N:/register%s sent}\n");
1223 #undef p
1224 	xo_close_container(name);
1225 }
1226 
1227 /*
1228  * Dump raw ip6 statistics structure.
1229  */
1230 void
1231 rip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
1232 {
1233 	struct rip6stat rip6stat;
1234 	u_quad_t delivered;
1235 
1236 	if (fetch_stats("net.inet6.ip6.rip6stats", off, &rip6stat,
1237 	    sizeof(rip6stat), kread_counters) != 0)
1238 		return;
1239 
1240 	xo_emit("{T:/%s}:\n", name);
1241 	xo_open_container(name);
1242 
1243 #define	p(f, m) if (rip6stat.f || sflag <= 1) \
1244 	xo_emit(m, (uintmax_t)rip6stat.f, plural(rip6stat.f))
1245 
1246 	p(rip6s_ipackets, "\t{:received-packets/%ju} "
1247 	    "{N:/message%s received}\n");
1248 	p(rip6s_isum, "\t{:input-checksum-computation/%ju} "
1249 	    "{N:/checksum calculation%s on inbound}\n");
1250 	p(rip6s_badsum, "\t{:received-bad-checksum/%ju} "
1251 	    "{N:/message%s with bad checksum}\n");
1252 	p(rip6s_nosock, "\t{:dropped-no-socket/%ju} "
1253 	    "{N:/message%s dropped due to no socket}\n");
1254 	p(rip6s_nosockmcast, "\t{:dropped-multicast-no-socket/%ju} "
1255 	    "{N:/multicast message%s dropped due to no socket}\n");
1256 	p(rip6s_fullsock, "\t{:dropped-full-socket-buffer/%ju} "
1257 	    "{N:/message%s dropped due to full socket buffers}\n");
1258 	delivered = rip6stat.rip6s_ipackets -
1259 		    rip6stat.rip6s_badsum -
1260 		    rip6stat.rip6s_nosock -
1261 		    rip6stat.rip6s_nosockmcast -
1262 		    rip6stat.rip6s_fullsock;
1263 	if (delivered || sflag <= 1)
1264 		xo_emit("\t{:delivered-packets/%ju} {N:/delivered}\n",
1265 		    (uintmax_t)delivered);
1266 	p(rip6s_opackets, "\t{:sent-packets/%ju} "
1267 	    "{N:/datagram%s output}\n");
1268 #undef p
1269 	xo_close_container(name);
1270 }
1271 
1272 /*
1273  * Pretty print an Internet address (net address + port).
1274  * Take numeric_addr and numeric_port into consideration.
1275  */
1276 #define	GETSERVBYPORT6(port, proto, ret)\
1277 {\
1278 	if (strcmp((proto), "tcp6") == 0)\
1279 		(ret) = getservbyport((int)(port), "tcp");\
1280 	else if (strcmp((proto), "udp6") == 0)\
1281 		(ret) = getservbyport((int)(port), "udp");\
1282 	else\
1283 		(ret) = getservbyport((int)(port), (proto));\
1284 };
1285 
1286 void
1287 inet6print(const char *container, struct in6_addr *in6, int port,
1288     const char *proto, int numeric)
1289 {
1290 	struct servent *sp = 0;
1291 	char line[80], *cp;
1292 	int width;
1293 	size_t alen, plen;
1294 
1295 	if (container)
1296 		xo_open_container(container);
1297 
1298 	snprintf(line, sizeof(line), "%.*s.",
1299 	    Wflag ? 39 : (Aflag && !numeric) ? 12 : 16,
1300 	    inet6name(in6));
1301 	alen = strlen(line);
1302 	cp = line + alen;
1303 	if (!numeric && port)
1304 		GETSERVBYPORT6(port, proto, sp);
1305 	if (sp || port == 0)
1306 		snprintf(cp, sizeof(line) - alen,
1307 		    "%.15s", sp ? sp->s_name : "*");
1308 	else
1309 		snprintf(cp, sizeof(line) - alen,
1310 		    "%d", ntohs((u_short)port));
1311 	width = Wflag ? 45 : Aflag ? 18 : 22;
1312 
1313 	xo_emit("{d:target/%-*.*s} ", width, width, line);
1314 
1315 	plen = strlen(cp);
1316 	alen--;
1317 	xo_emit("{e:address/%*.*s}{e:port/%*.*s}", alen, alen, line, plen,
1318 	    plen, cp);
1319 
1320 	if (container)
1321 		xo_close_container(container);
1322 }
1323 
1324 /*
1325  * Construct an Internet address representation.
1326  * If the numeric_addr has been supplied, give
1327  * numeric value, otherwise try for symbolic name.
1328  */
1329 
1330 char *
1331 inet6name(struct in6_addr *ia6)
1332 {
1333 	struct sockaddr_in6 sin6;
1334 	char hbuf[NI_MAXHOST], *cp;
1335 	static char line[NI_MAXHOST];
1336 	static char domain[MAXHOSTNAMELEN];
1337 	static int first = 1;
1338 	int flags, error;
1339 
1340 	if (IN6_IS_ADDR_UNSPECIFIED(ia6)) {
1341 		strcpy(line, "*");
1342 		return (line);
1343 	}
1344 
1345 #ifndef FSTACK
1346 	if (first && !numeric_addr) {
1347 		first = 0;
1348 		if (gethostname(domain, sizeof(domain)) == 0 &&
1349 		    (cp = strchr(domain, '.')))
1350 			strlcpy(domain, cp + 1, sizeof(domain));
1351 		else
1352 			domain[0] = 0;
1353 	}
1354 #endif
1355 
1356 	memset(&sin6, 0, sizeof(sin6));
1357 	memcpy(&sin6.sin6_addr, ia6, sizeof(*ia6));
1358 	sin6.sin6_family = AF_INET6;
1359 	/* XXX: ia6.s6_addr[2] can contain scopeid. */
1360 	in6_fillscopeid(&sin6);
1361 
1362 #ifndef FSTACK
1363 	flags = (numeric_addr) ? NI_NUMERICHOST : 0;
1364 	error = getnameinfo((struct sockaddr *)&sin6, sizeof(sin6), hbuf,
1365 	    sizeof(hbuf), NULL, 0, flags);
1366 	if (error == 0) {
1367 		if ((flags & NI_NUMERICHOST) == 0 &&
1368 		    (cp = strchr(hbuf, '.')) &&
1369 		    !strcmp(cp + 1, domain))
1370 			*cp = 0;
1371 		strlcpy(line, hbuf, sizeof(line));
1372 	} else {
1373 #else
1374 	{
1375 #endif
1376 		/* XXX: this should not happen. */
1377 		snprintf(line, sizeof(line), "%s",
1378 #ifndef FSTACK
1379 			inet_ntop(AF_INET6, (void *)&sin6.sin6_addr, ntop_buf,
1380 #else
1381 			inet_ntop(AF_INET6_LINUX, (void *)&sin6.sin6_addr, ntop_buf,
1382 #endif
1383 				sizeof(ntop_buf)));
1384 	}
1385 	return (line);
1386 }
1387 #endif /*INET6*/
1388