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