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