inet6.c revision 187134
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 187134 2009-01-13 07:58:57Z maxim $");
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) if (icmp6stat.f || sflag <= 1) \
870    printf(m, (uintmax_t)icmp6stat.f)
871
872	p(icp6s_error, "\t%ju call%s to icmp6_error\n");
873	p(icp6s_canterror,
874	    "\t%ju error%s not generated in response to an icmp6 message\n");
875	p(icp6s_toofreq,
876	  "\t%ju error%s not generated because of rate limitation\n");
877#define	NELEM (int)(sizeof(icmp6stat.icp6s_outhist)/sizeof(icmp6stat.icp6s_outhist[0]))
878	for (first = 1, i = 0; i < NELEM; i++)
879		if (icmp6stat.icp6s_outhist[i] != 0) {
880			if (first) {
881				printf("\tOutput histogram:\n");
882				first = 0;
883			}
884			printf("\t\t%s: %ju\n", icmp6names[i],
885			    (uintmax_t)icmp6stat.icp6s_outhist[i]);
886		}
887#undef NELEM
888	p(icp6s_badcode, "\t%ju message%s with bad code fields\n");
889	p(icp6s_tooshort, "\t%ju message%s < minimum length\n");
890	p(icp6s_checksum, "\t%ju bad checksum%s\n");
891	p(icp6s_badlen, "\t%ju message%s with bad length\n");
892#define	NELEM (int)(sizeof(icmp6stat.icp6s_inhist)/sizeof(icmp6stat.icp6s_inhist[0]))
893	for (first = 1, i = 0; i < NELEM; i++)
894		if (icmp6stat.icp6s_inhist[i] != 0) {
895			if (first) {
896				printf("\tInput histogram:\n");
897				first = 0;
898			}
899			printf("\t\t%s: %ju\n", icmp6names[i],
900			    (uintmax_t)icmp6stat.icp6s_inhist[i]);
901		}
902#undef NELEM
903	printf("\tHistogram of error messages to be generated:\n");
904	p_5(icp6s_odst_unreach_noroute, "\t\t%ju no route\n");
905	p_5(icp6s_odst_unreach_admin, "\t\t%ju administratively prohibited\n");
906	p_5(icp6s_odst_unreach_beyondscope, "\t\t%ju beyond scope\n");
907	p_5(icp6s_odst_unreach_addr, "\t\t%ju address unreachable\n");
908	p_5(icp6s_odst_unreach_noport, "\t\t%ju port unreachable\n");
909	p_5(icp6s_opacket_too_big, "\t\t%ju packet too big\n");
910	p_5(icp6s_otime_exceed_transit, "\t\t%ju time exceed transit\n");
911	p_5(icp6s_otime_exceed_reassembly, "\t\t%ju time exceed reassembly\n");
912	p_5(icp6s_oparamprob_header, "\t\t%ju erroneous header field\n");
913	p_5(icp6s_oparamprob_nextheader, "\t\t%ju unrecognized next header\n");
914	p_5(icp6s_oparamprob_option, "\t\t%ju unrecognized option\n");
915	p_5(icp6s_oredirect, "\t\t%ju redirect\n");
916	p_5(icp6s_ounknown, "\t\t%ju unknown\n");
917
918	p(icp6s_reflect, "\t%ju message response%s generated\n");
919	p(icp6s_nd_toomanyopt, "\t%ju message%s with too many ND options\n");
920	p(icp6s_nd_badopt, "\t%ju message%s with bad ND options\n");
921	p(icp6s_badns, "\t%ju bad neighbor solicitation message%s\n");
922	p(icp6s_badna, "\t%ju bad neighbor advertisement message%s\n");
923	p(icp6s_badrs, "\t%ju bad router solicitation message%s\n");
924	p(icp6s_badra, "\t%ju bad router advertisement message%s\n");
925	p(icp6s_badredirect, "\t%ju bad redirect message%s\n");
926	p(icp6s_pmtuchg, "\t%ju path MTU change%s\n");
927#undef p
928#undef p_5
929}
930
931/*
932 * Dump ICMPv6 per-interface statistics based on RFC 2466.
933 */
934void
935icmp6_ifstats(char *ifname)
936{
937	struct in6_ifreq ifr;
938	int s;
939#define	p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \
940    printf(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f, plural(ifr.ifr_ifru.ifru_icmp6stat.f))
941#define	p2(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \
942    printf(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f, pluralies(ifr.ifr_ifru.ifru_icmp6stat.f))
943
944	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
945		perror("Warning: socket(AF_INET6)");
946		return;
947	}
948
949	strcpy(ifr.ifr_name, ifname);
950	printf("icmp6 on %s:\n", ifr.ifr_name);
951
952	if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) {
953		perror("Warning: ioctl(SIOCGIFSTAT_ICMP6)");
954		goto end;
955	}
956
957	p(ifs6_in_msg, "\t%ju total input message%s\n");
958	p(ifs6_in_error, "\t%ju total input error message%s\n");
959	p(ifs6_in_dstunreach, "\t%ju input destination unreachable error%s\n");
960	p(ifs6_in_adminprohib, "\t%ju input administratively prohibited error%s\n");
961	p(ifs6_in_timeexceed, "\t%ju input time exceeded error%s\n");
962	p(ifs6_in_paramprob, "\t%ju input parameter problem error%s\n");
963	p(ifs6_in_pkttoobig, "\t%ju input packet too big error%s\n");
964	p(ifs6_in_echo, "\t%ju input echo request%s\n");
965	p2(ifs6_in_echoreply, "\t%ju input echo repl%s\n");
966	p(ifs6_in_routersolicit, "\t%ju input router solicitation%s\n");
967	p(ifs6_in_routeradvert, "\t%ju input router advertisement%s\n");
968	p(ifs6_in_neighborsolicit, "\t%ju input neighbor solicitation%s\n");
969	p(ifs6_in_neighboradvert, "\t%ju input neighbor advertisement%s\n");
970	p(ifs6_in_redirect, "\t%ju input redirect%s\n");
971	p2(ifs6_in_mldquery, "\t%ju input MLD quer%s\n");
972	p(ifs6_in_mldreport, "\t%ju input MLD report%s\n");
973	p(ifs6_in_mlddone, "\t%ju input MLD done%s\n");
974
975	p(ifs6_out_msg, "\t%ju total output message%s\n");
976	p(ifs6_out_error, "\t%ju total output error message%s\n");
977	p(ifs6_out_dstunreach, "\t%ju output destination unreachable error%s\n");
978	p(ifs6_out_adminprohib, "\t%ju output administratively prohibited error%s\n");
979	p(ifs6_out_timeexceed, "\t%ju output time exceeded error%s\n");
980	p(ifs6_out_paramprob, "\t%ju output parameter problem error%s\n");
981	p(ifs6_out_pkttoobig, "\t%ju output packet too big error%s\n");
982	p(ifs6_out_echo, "\t%ju output echo request%s\n");
983	p2(ifs6_out_echoreply, "\t%ju output echo repl%s\n");
984	p(ifs6_out_routersolicit, "\t%ju output router solicitation%s\n");
985	p(ifs6_out_routeradvert, "\t%ju output router advertisement%s\n");
986	p(ifs6_out_neighborsolicit, "\t%ju output neighbor solicitation%s\n");
987	p(ifs6_out_neighboradvert, "\t%ju output neighbor advertisement%s\n");
988	p(ifs6_out_redirect, "\t%ju output redirect%s\n");
989	p2(ifs6_out_mldquery, "\t%ju output MLD quer%s\n");
990	p(ifs6_out_mldreport, "\t%ju output MLD report%s\n");
991	p(ifs6_out_mlddone, "\t%ju output MLD done%s\n");
992
993  end:
994	close(s);
995#undef p
996}
997
998/*
999 * Dump PIM statistics structure.
1000 */
1001void
1002pim6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
1003{
1004	struct pim6stat pim6stat, zerostat;
1005	size_t len = sizeof pim6stat;
1006
1007	if (live) {
1008		if (zflag)
1009			memset(&zerostat, 0, len);
1010		if (sysctlbyname("net.inet6.pim.stats", &pim6stat, &len,
1011		    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
1012			if (errno != ENOENT)
1013				warn("sysctl: net.inet6.pim.stats");
1014			return;
1015		}
1016	} else {
1017		if (off == 0)
1018			return;
1019		kread(off, &pim6stat, len);
1020	}
1021
1022	printf("%s:\n", name);
1023
1024#define	p(f, m) if (pim6stat.f || sflag <= 1) \
1025    printf(m, (uintmax_t)pim6stat.f, plural(pim6stat.f))
1026	p(pim6s_rcv_total, "\t%ju message%s received\n");
1027	p(pim6s_rcv_tooshort, "\t%ju message%s received with too few bytes\n");
1028	p(pim6s_rcv_badsum, "\t%ju message%s received with bad checksum\n");
1029	p(pim6s_rcv_badversion, "\t%ju message%s received with bad version\n");
1030	p(pim6s_rcv_registers, "\t%ju register%s received\n");
1031	p(pim6s_rcv_badregisters, "\t%ju bad register%s received\n");
1032	p(pim6s_snd_registers, "\t%ju register%s sent\n");
1033#undef p
1034}
1035
1036/*
1037 * Dump raw ip6 statistics structure.
1038 */
1039void
1040rip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
1041{
1042	struct rip6stat rip6stat;
1043	u_quad_t delivered;
1044	size_t len;
1045
1046	len = sizeof(rip6stat);
1047	if (live) {
1048		if (sysctlbyname("net.inet6.ip6.rip6stats", &rip6stat, &len,
1049		    NULL, 0) < 0) {
1050			if (errno != ENOENT)
1051				warn("sysctl: net.inet6.ip6.rip6stats");
1052			return;
1053		}
1054	} else
1055		kread(off, &rip6stat, len);
1056
1057	printf("%s:\n", name);
1058
1059#define	p(f, m) if (rip6stat.f || sflag <= 1) \
1060    printf(m, (uintmax_t)rip6stat.f, plural(rip6stat.f))
1061	p(rip6s_ipackets, "\t%ju message%s received\n");
1062	p(rip6s_isum, "\t%ju checksum calculation%s on inbound\n");
1063	p(rip6s_badsum, "\t%ju message%s with bad checksum\n");
1064	p(rip6s_nosock, "\t%ju message%s dropped due to no socket\n");
1065	p(rip6s_nosockmcast,
1066	    "\t%ju multicast message%s dropped due to no socket\n");
1067	p(rip6s_fullsock,
1068	    "\t%ju message%s dropped due to full socket buffers\n");
1069	delivered = rip6stat.rip6s_ipackets -
1070		    rip6stat.rip6s_badsum -
1071		    rip6stat.rip6s_nosock -
1072		    rip6stat.rip6s_nosockmcast -
1073		    rip6stat.rip6s_fullsock;
1074	if (delivered || sflag <= 1)
1075		printf("\t%ju delivered\n", (uintmax_t)delivered);
1076	p(rip6s_opackets, "\t%ju datagram%s output\n");
1077#undef p
1078}
1079
1080/*
1081 * Pretty print an Internet address (net address + port).
1082 * Take numeric_addr and numeric_port into consideration.
1083 */
1084#define	GETSERVBYPORT6(port, proto, ret)\
1085{\
1086	if (strcmp((proto), "tcp6") == 0)\
1087		(ret) = getservbyport((int)(port), "tcp");\
1088	else if (strcmp((proto), "udp6") == 0)\
1089		(ret) = getservbyport((int)(port), "udp");\
1090	else\
1091		(ret) = getservbyport((int)(port), (proto));\
1092};
1093
1094void
1095inet6print(struct in6_addr *in6, int port, const char *proto, int numeric)
1096{
1097	struct servent *sp = 0;
1098	char line[80], *cp;
1099	int width;
1100
1101	sprintf(line, "%.*s.", Wflag ? 39 :
1102		(Aflag && !numeric) ? 12 : 16, inet6name(in6));
1103	cp = index(line, '\0');
1104	if (!numeric && port)
1105		GETSERVBYPORT6(port, proto, sp);
1106	if (sp || port == 0)
1107		sprintf(cp, "%.15s", sp ? sp->s_name : "*");
1108	else
1109		sprintf(cp, "%d", ntohs((u_short)port));
1110	width = Wflag ? 45 : Aflag ? 18 : 22;
1111	printf("%-*.*s ", width, width, line);
1112}
1113
1114/*
1115 * Construct an Internet address representation.
1116 * If the numeric_addr has been supplied, give
1117 * numeric value, otherwise try for symbolic name.
1118 */
1119
1120char *
1121inet6name(struct in6_addr *in6p)
1122{
1123	char *cp;
1124	static char line[50];
1125	struct hostent *hp;
1126	static char domain[MAXHOSTNAMELEN];
1127	static int first = 1;
1128
1129	if (first && !numeric_addr) {
1130		first = 0;
1131		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
1132		    (cp = index(domain, '.')))
1133			(void) strcpy(domain, cp + 1);
1134		else
1135			domain[0] = 0;
1136	}
1137	cp = 0;
1138	if (!numeric_addr && !IN6_IS_ADDR_UNSPECIFIED(in6p)) {
1139		hp = gethostbyaddr((char *)in6p, sizeof(*in6p), AF_INET6);
1140		if (hp) {
1141			if ((cp = index(hp->h_name, '.')) &&
1142			    !strcmp(cp + 1, domain))
1143				*cp = 0;
1144			cp = hp->h_name;
1145		}
1146	}
1147	if (IN6_IS_ADDR_UNSPECIFIED(in6p))
1148		strcpy(line, "*");
1149	else if (cp)
1150		strcpy(line, cp);
1151	else
1152		sprintf(line, "%s",
1153			inet_ntop(AF_INET6, (void *)in6p, ntop_buf,
1154				sizeof(ntop_buf)));
1155	return (line);
1156}
1157#endif /*INET6*/
1158