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