inet6.c revision 279122
144743Smarkm/*	BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp	*/
244743Smarkm/*-
344743Smarkm * Copyright (c) 1983, 1988, 1993
444743Smarkm *	The Regents of the University of California.  All rights reserved.
544743Smarkm *
644743Smarkm * Redistribution and use in source and binary forms, with or without
744743Smarkm * modification, are permitted provided that the following conditions
844743Smarkm * are met:
944743Smarkm * 1. Redistributions of source code must retain the above copyright
1044743Smarkm *    notice, this list of conditions and the following disclaimer.
1144743Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1244743Smarkm *    notice, this list of conditions and the following disclaimer in the
1344743Smarkm *    documentation and/or other materials provided with the distribution.
1444743Smarkm * 4. Neither the name of the University nor the names of its contributors
1544743Smarkm *    may be used to endorse or promote products derived from this software
1644743Smarkm *    without specific prior written permission.
1744743Smarkm *
1844743Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1944743Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2044743Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2144743Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2244743Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2344743Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2444743Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2544743Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2644743Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2744743Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2844743Smarkm * SUCH DAMAGE.
2944743Smarkm */
3044743Smarkm
3144743Smarkm#if 0
3244743Smarkm#ifndef lint
3344743Smarkmstatic char sccsid[] = "@(#)inet6.c	8.4 (Berkeley) 4/20/94";
3444743Smarkm#endif /* not lint */
3544743Smarkm#endif
3644743Smarkm
3744743Smarkm#include <sys/cdefs.h>
3844743Smarkm__FBSDID("$FreeBSD: head/usr.bin/netstat/inet6.c 279122 2015-02-21 23:47:20Z marcel $");
3944743Smarkm
4044743Smarkm#ifdef INET6
4144743Smarkm#include <sys/param.h>
4244743Smarkm#include <sys/socket.h>
4344743Smarkm#include <sys/socketvar.h>
4444743Smarkm#include <sys/ioctl.h>
4544743Smarkm#include <sys/mbuf.h>
4644743Smarkm#include <sys/protosw.h>
4744743Smarkm#include <sys/sysctl.h>
4844743Smarkm
4944743Smarkm#include <net/route.h>
5044743Smarkm#include <net/if.h>
5144743Smarkm#include <net/if_var.h>
5244743Smarkm#include <netinet/in.h>
5344743Smarkm#include <netinet/ip6.h>
5444743Smarkm#include <netinet/icmp6.h>
5544743Smarkm#include <netinet/in_systm.h>
5644743Smarkm#include <netinet6/in6_pcb.h>
5744743Smarkm#include <netinet6/in6_var.h>
5844743Smarkm#include <netinet6/ip6_var.h>
5944743Smarkm#include <netinet6/pim6_var.h>
6044743Smarkm#include <netinet6/raw_ip6.h>
6144743Smarkm
6244743Smarkm#include <arpa/inet.h>
6344743Smarkm#include <netdb.h>
6444743Smarkm
6544743Smarkm#include <err.h>
6644743Smarkm#include <stdint.h>
6744743Smarkm#include <stdio.h>
6844743Smarkm#include <stdbool.h>
6944743Smarkm#include <errno.h>
7044743Smarkm#include <string.h>
7144743Smarkm#include <unistd.h>
7244743Smarkm#include <libxo/xo.h>
7344743Smarkm#include "netstat.h"
7444743Smarkm
7544743Smarkmstruct	socket sockb;
7644743Smarkm
7744743Smarkmchar	*inet6name(struct in6_addr *);
7844743Smarkm
7944743Smarkmstatic char ntop_buf[INET6_ADDRSTRLEN];
8044743Smarkm
8144743Smarkmstatic	const char *ip6nh[] = {
8244743Smarkm	"hop by hop",
8344743Smarkm	"ICMP",
8444743Smarkm	"IGMP",
8544743Smarkm	"#3",
8644743Smarkm	"IP",
8744743Smarkm	"#5",
8844743Smarkm	"TCP",
8944743Smarkm	"#7",
9044743Smarkm	"#8",
9144743Smarkm	"#9",
9244743Smarkm	"#10",
9344743Smarkm	"#11",
9444743Smarkm	"#12",
9544743Smarkm	"#13",
9644743Smarkm	"#14",
9744743Smarkm	"#15",
9844743Smarkm	"#16",
9944743Smarkm	"UDP",
10044743Smarkm	"#18",
10144743Smarkm	"#19",
10244743Smarkm	"#20",
10344743Smarkm	"#21",
10444743Smarkm	"IDP",
10544743Smarkm	"#23",
10644743Smarkm	"#24",
10744743Smarkm	"#25",
10844743Smarkm	"#26",
10944743Smarkm	"#27",
11044743Smarkm	"#28",
11144743Smarkm	"TP",
11244743Smarkm	"#30",
11344743Smarkm	"#31",
11444743Smarkm	"#32",
11544743Smarkm	"#33",
11644743Smarkm	"#34",
11744743Smarkm	"#35",
11844743Smarkm	"#36",
11944743Smarkm	"#37",
12044743Smarkm	"#38",
12144743Smarkm	"#39",
12244743Smarkm	"#40",
12344743Smarkm	"IP6",
12444743Smarkm	"#42",
12544743Smarkm	"routing",
12644743Smarkm	"fragment",
12744743Smarkm	"#45",
12844743Smarkm	"#46",
12944743Smarkm	"#47",
13044743Smarkm	"#48",
13144743Smarkm	"#49",
13244743Smarkm	"ESP",
13344743Smarkm	"AH",
13444743Smarkm	"#52",
13544743Smarkm	"#53",
13644743Smarkm	"#54",
13744743Smarkm	"#55",
13844743Smarkm	"#56",
13944743Smarkm	"#57",
14044743Smarkm	"ICMP6",
14144743Smarkm	"no next header",
14244743Smarkm	"destination option",
14344743Smarkm	"#61",
14444743Smarkm	"mobility",
14544743Smarkm	"#63",
14644743Smarkm	"#64",
14744743Smarkm	"#65",
14844743Smarkm	"#66",
14944743Smarkm	"#67",
15044743Smarkm	"#68",
15144743Smarkm	"#69",
15244743Smarkm	"#70",
15344743Smarkm	"#71",
15444743Smarkm	"#72",
15544743Smarkm	"#73",
15644743Smarkm	"#74",
15744743Smarkm	"#75",
15844743Smarkm	"#76",
15944743Smarkm	"#77",
16044743Smarkm	"#78",
16144743Smarkm	"#79",
16244743Smarkm	"ISOIP",
16344743Smarkm	"#81",
16444743Smarkm	"#82",
16544743Smarkm	"#83",
16644743Smarkm	"#84",
16744743Smarkm	"#85",
16844743Smarkm	"#86",
16944743Smarkm	"#87",
17044743Smarkm	"#88",
17144743Smarkm	"OSPF",
17244743Smarkm	"#80",
17344743Smarkm	"#91",
17444743Smarkm	"#92",
17544743Smarkm	"#93",
17644743Smarkm	"#94",
17744743Smarkm	"#95",
17844743Smarkm	"#96",
17944743Smarkm	"Ethernet",
18044743Smarkm	"#98",
18144743Smarkm	"#99",
18244743Smarkm	"#100",
18344743Smarkm	"#101",
18444743Smarkm	"#102",
18544743Smarkm	"PIM",
18644743Smarkm	"#104",
18744743Smarkm	"#105",
18844743Smarkm	"#106",
18944743Smarkm	"#107",
19044743Smarkm	"#108",
19144743Smarkm	"#109",
19244743Smarkm	"#110",
19344743Smarkm	"#111",
19444743Smarkm	"#112",
19544743Smarkm	"#113",
19644743Smarkm	"#114",
19744743Smarkm	"#115",
19844743Smarkm	"#116",
19944743Smarkm	"#117",
20044743Smarkm	"#118",
20144743Smarkm	"#119",
20244743Smarkm	"#120",
20344743Smarkm	"#121",
20444743Smarkm	"#122",
20544743Smarkm	"#123",
20644743Smarkm	"#124",
20744743Smarkm	"#125",
20844743Smarkm	"#126",
20944743Smarkm	"#127",
21044743Smarkm	"#128",
21144743Smarkm	"#129",
21244743Smarkm	"#130",
21344743Smarkm	"#131",
21444743Smarkm	"#132",
21544743Smarkm	"#133",
21644743Smarkm	"#134",
21744743Smarkm	"#135",
21844743Smarkm	"#136",
21944743Smarkm	"#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
340static 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 */
362void
363ip6_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 */
622void
623ip6_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
697static	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 */
959void
960icmp6_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 */
1091void
1092icmp6_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
1190end:
1191	xo_close_instance("icmp6-interface-statistics");
1192	close(s);
1193#undef p
1194}
1195
1196/*
1197 * Dump PIM statistics structure.
1198 */
1199void
1200pim6_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 */
1247void
1248rip6_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
1313void
1314inet6print(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
1351char *
1352inet6name(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