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