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