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