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