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