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