inet6.c revision 187989
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 187989 2009-02-01 21:11:08Z bz $");
43
44#ifdef INET6
45#include <sys/param.h>
46#include <sys/socket.h>
47#include <sys/socketvar.h>
48#include <sys/ioctl.h>
49#include <sys/mbuf.h>
50#include <sys/protosw.h>
51#include <sys/sysctl.h>
52
53#include <net/route.h>
54#include <net/if.h>
55#include <net/if_var.h>
56#include <netinet/in.h>
57#include <netinet/ip6.h>
58#include <netinet/icmp6.h>
59#include <netinet/in_systm.h>
60#include <netinet6/in6_pcb.h>
61#include <netinet6/in6_var.h>
62#include <netinet6/ip6_var.h>
63#include <netinet6/pim6_var.h>
64#include <netinet6/raw_ip6.h>
65
66#include <arpa/inet.h>
67#include <netdb.h>
68
69#include <err.h>
70#include <stdint.h>
71#include <stdio.h>
72#include <errno.h>
73#include <string.h>
74#include <unistd.h>
75#include "netstat.h"
76
77struct	socket sockb;
78
79char	*inet6name(struct in6_addr *);
80
81static char ntop_buf[INET6_ADDRSTRLEN];
82
83static	const char *ip6nh[] = {
84	"hop by hop",
85	"ICMP",
86	"IGMP",
87	"#3",
88	"IP",
89	"#5",
90	"TCP",
91	"#7",
92	"#8",
93	"#9",
94	"#10",
95	"#11",
96	"#12",
97	"#13",
98	"#14",
99	"#15",
100	"#16",
101	"UDP",
102	"#18",
103	"#19",
104	"#20",
105	"#21",
106	"IDP",
107	"#23",
108	"#24",
109	"#25",
110	"#26",
111	"#27",
112	"#28",
113	"TP",
114	"#30",
115	"#31",
116	"#32",
117	"#33",
118	"#34",
119	"#35",
120	"#36",
121	"#37",
122	"#38",
123	"#39",
124	"#40",
125	"IP6",
126	"#42",
127	"routing",
128	"fragment",
129	"#45",
130	"#46",
131	"#47",
132	"#48",
133	"#49",
134	"ESP",
135	"AH",
136	"#52",
137	"#53",
138	"#54",
139	"#55",
140	"#56",
141	"#57",
142	"ICMP6",
143	"no next header",
144	"destination option",
145	"#61",
146	"mobility",
147	"#63",
148	"#64",
149	"#65",
150	"#66",
151	"#67",
152	"#68",
153	"#69",
154	"#70",
155	"#71",
156	"#72",
157	"#73",
158	"#74",
159	"#75",
160	"#76",
161	"#77",
162	"#78",
163	"#79",
164	"ISOIP",
165	"#81",
166	"#82",
167	"#83",
168	"#84",
169	"#85",
170	"#86",
171	"#87",
172	"#88",
173	"OSPF",
174	"#80",
175	"#91",
176	"#92",
177	"#93",
178	"#94",
179	"#95",
180	"#96",
181	"Ethernet",
182	"#98",
183	"#99",
184	"#100",
185	"#101",
186	"#102",
187	"PIM",
188	"#104",
189	"#105",
190	"#106",
191	"#107",
192	"#108",
193	"#109",
194	"#110",
195	"#111",
196	"#112",
197	"#113",
198	"#114",
199	"#115",
200	"#116",
201	"#117",
202	"#118",
203	"#119",
204	"#120",
205	"#121",
206	"#122",
207	"#123",
208	"#124",
209	"#125",
210	"#126",
211	"#127",
212	"#128",
213	"#129",
214	"#130",
215	"#131",
216	"#132",
217	"#133",
218	"#134",
219	"#135",
220	"#136",
221	"#137",
222	"#138",
223	"#139",
224	"#140",
225	"#141",
226	"#142",
227	"#143",
228	"#144",
229	"#145",
230	"#146",
231	"#147",
232	"#148",
233	"#149",
234	"#150",
235	"#151",
236	"#152",
237	"#153",
238	"#154",
239	"#155",
240	"#156",
241	"#157",
242	"#158",
243	"#159",
244	"#160",
245	"#161",
246	"#162",
247	"#163",
248	"#164",
249	"#165",
250	"#166",
251	"#167",
252	"#168",
253	"#169",
254	"#170",
255	"#171",
256	"#172",
257	"#173",
258	"#174",
259	"#175",
260	"#176",
261	"#177",
262	"#178",
263	"#179",
264	"#180",
265	"#181",
266	"#182",
267	"#183",
268	"#184",
269	"#185",
270	"#186",
271	"#187",
272	"#188",
273	"#189",
274	"#180",
275	"#191",
276	"#192",
277	"#193",
278	"#194",
279	"#195",
280	"#196",
281	"#197",
282	"#198",
283	"#199",
284	"#200",
285	"#201",
286	"#202",
287	"#203",
288	"#204",
289	"#205",
290	"#206",
291	"#207",
292	"#208",
293	"#209",
294	"#210",
295	"#211",
296	"#212",
297	"#213",
298	"#214",
299	"#215",
300	"#216",
301	"#217",
302	"#218",
303	"#219",
304	"#220",
305	"#221",
306	"#222",
307	"#223",
308	"#224",
309	"#225",
310	"#226",
311	"#227",
312	"#228",
313	"#229",
314	"#230",
315	"#231",
316	"#232",
317	"#233",
318	"#234",
319	"#235",
320	"#236",
321	"#237",
322	"#238",
323	"#239",
324	"#240",
325	"#241",
326	"#242",
327	"#243",
328	"#244",
329	"#245",
330	"#246",
331	"#247",
332	"#248",
333	"#249",
334	"#250",
335	"#251",
336	"#252",
337	"#253",
338	"#254",
339	"#255",
340};
341
342static char *srcrule_str[] = {
343	"first candidate",
344	"same address",
345	"appropriate scope",
346	"deprecated address",
347	"home address",
348	"outgoing interface",
349	"matching label",
350	"public/temporary address",
351	"alive interface",
352	"preferred interface",
353	"rule #10",
354	"rule #11",
355	"rule #12",
356	"rule #13",
357	"longest match",
358	"rule #15",
359};
360
361/*
362 * Dump IP6 statistics structure.
363 */
364void
365ip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
366{
367	struct ip6stat ip6stat;
368	int first, i;
369	size_t len;
370
371	len = sizeof ip6stat;
372	if (live) {
373		memset(&ip6stat, 0, len);
374		if (sysctlbyname("net.inet6.ip6.stats", &ip6stat, &len, NULL,
375		    0) < 0) {
376			if (errno != ENOENT)
377				warn("sysctl: net.inet6.ip6.stats");
378			return;
379		}
380	} else
381		kread(off, &ip6stat, len);
382
383	printf("%s:\n", name);
384
385#define	p(f, m) if (ip6stat.f || sflag <= 1) \
386    printf(m, (uintmax_t)ip6stat.f, plural(ip6stat.f))
387#define	p1a(f, m) if (ip6stat.f || sflag <= 1) \
388    printf(m, (uintmax_t)ip6stat.f)
389
390	p(ip6s_total, "\t%ju total packet%s received\n");
391	p1a(ip6s_toosmall, "\t%ju with size smaller than minimum\n");
392	p1a(ip6s_tooshort, "\t%ju with data size < data length\n");
393	p1a(ip6s_badoptions, "\t%ju with bad options\n");
394	p1a(ip6s_badvers, "\t%ju with incorrect version number\n");
395	p(ip6s_fragments, "\t%ju fragment%s received\n");
396	p(ip6s_fragdropped, "\t%ju fragment%s dropped (dup or out of space)\n");
397	p(ip6s_fragtimeout, "\t%ju fragment%s dropped after timeout\n");
398	p(ip6s_fragoverflow, "\t%ju fragment%s that exceeded limit\n");
399	p(ip6s_reassembled, "\t%ju packet%s reassembled ok\n");
400	p(ip6s_delivered, "\t%ju packet%s for this host\n");
401	p(ip6s_forward, "\t%ju packet%s forwarded\n");
402	p(ip6s_cantforward, "\t%ju packet%s not forwardable\n");
403	p(ip6s_redirectsent, "\t%ju redirect%s sent\n");
404	p(ip6s_localout, "\t%ju packet%s sent from this host\n");
405	p(ip6s_rawout, "\t%ju packet%s sent with fabricated ip header\n");
406	p(ip6s_odropped, "\t%ju output packet%s dropped due to no bufs, etc.\n");
407	p(ip6s_noroute, "\t%ju output packet%s discarded due to no route\n");
408	p(ip6s_fragmented, "\t%ju output datagram%s fragmented\n");
409	p(ip6s_ofragments, "\t%ju fragment%s created\n");
410	p(ip6s_cantfrag, "\t%ju datagram%s that can't be fragmented\n");
411	p(ip6s_badscope, "\t%ju packet%s that violated scope rules\n");
412	p(ip6s_notmember, "\t%ju multicast packet%s which we don't join\n");
413	for (first = 1, i = 0; i < 256; i++)
414		if (ip6stat.ip6s_nxthist[i] != 0) {
415			if (first) {
416				printf("\tInput histogram:\n");
417				first = 0;
418			}
419			printf("\t\t%s: %ju\n", ip6nh[i],
420			    (uintmax_t)ip6stat.ip6s_nxthist[i]);
421		}
422	printf("\tMbuf statistics:\n");
423	printf("\t\t%ju one mbuf\n", (uintmax_t)ip6stat.ip6s_m1);
424	for (first = 1, i = 0; i < 32; i++) {
425		char ifbuf[IFNAMSIZ];
426		if (ip6stat.ip6s_m2m[i] != 0) {
427			if (first) {
428				printf("\t\ttwo or more mbuf:\n");
429				first = 0;
430			}
431			printf("\t\t\t%s= %ju\n",
432			    if_indextoname(i, ifbuf),
433			    (uintmax_t)ip6stat.ip6s_m2m[i]);
434		}
435	}
436	printf("\t\t%ju one ext mbuf\n",
437	    (uintmax_t)ip6stat.ip6s_mext1);
438	printf("\t\t%ju two or more ext mbuf\n",
439	    (uintmax_t)ip6stat.ip6s_mext2m);
440	p(ip6s_exthdrtoolong,
441	    "\t%ju packet%s whose headers are not continuous\n");
442	p(ip6s_nogif, "\t%ju tunneling packet%s that can't find gif\n");
443	p(ip6s_toomanyhdr,
444	    "\t%ju packet%s discarded because of too many headers\n");
445
446	/* for debugging source address selection */
447#define	PRINT_SCOPESTAT(s,i) do {\
448		switch(i) { /* XXX hardcoding in each case */\
449		case 1:\
450			p(s, "\t\t%ju node-local%s\n");\
451			break;\
452		case 2:\
453			p(s,"\t\t%ju link-local%s\n");\
454			break;\
455		case 5:\
456			p(s,"\t\t%ju site-local%s\n");\
457			break;\
458		case 14:\
459			p(s,"\t\t%ju global%s\n");\
460			break;\
461		default:\
462			printf("\t\t%ju addresses scope=%x\n",\
463			    (uintmax_t)ip6stat.s, i);\
464		}\
465	} while (0);
466
467	p(ip6s_sources_none,
468	  "\t%ju failure%s of source address selection\n");
469	for (first = 1, i = 0; i < 16; i++) {
470		if (ip6stat.ip6s_sources_sameif[i]) {
471			if (first) {
472				printf("\tsource addresses on an outgoing I/F\n");
473				first = 0;
474			}
475			PRINT_SCOPESTAT(ip6s_sources_sameif[i], i);
476		}
477	}
478	for (first = 1, i = 0; i < 16; i++) {
479		if (ip6stat.ip6s_sources_otherif[i]) {
480			if (first) {
481				printf("\tsource addresses on a non-outgoing I/F\n");
482				first = 0;
483			}
484			PRINT_SCOPESTAT(ip6s_sources_otherif[i], i);
485		}
486	}
487	for (first = 1, i = 0; i < 16; i++) {
488		if (ip6stat.ip6s_sources_samescope[i]) {
489			if (first) {
490				printf("\tsource addresses of same scope\n");
491				first = 0;
492			}
493			PRINT_SCOPESTAT(ip6s_sources_samescope[i], i);
494		}
495	}
496	for (first = 1, i = 0; i < 16; i++) {
497		if (ip6stat.ip6s_sources_otherscope[i]) {
498			if (first) {
499				printf("\tsource addresses of a different scope\n");
500				first = 0;
501			}
502			PRINT_SCOPESTAT(ip6s_sources_otherscope[i], i);
503		}
504	}
505	for (first = 1, i = 0; i < 16; i++) {
506		if (ip6stat.ip6s_sources_deprecated[i]) {
507			if (first) {
508				printf("\tdeprecated source addresses\n");
509				first = 0;
510			}
511			PRINT_SCOPESTAT(ip6s_sources_deprecated[i], i);
512		}
513	}
514
515	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, const char *name, int af1 __unused, int proto __unused)
846{
847	struct icmp6stat icmp6stat;
848	int i, first;
849	size_t len;
850
851	len = sizeof icmp6stat;
852	if (live) {
853		memset(&icmp6stat, 0, len);
854		if (sysctlbyname("net.inet6.icmp6.stats", &icmp6stat, &len,
855		    NULL, 0) < 0) {
856			if (errno != ENOENT)
857				warn("sysctl: net.inet6.icmp6.stats");
858			return;
859		}
860	} else
861		kread(off, &icmp6stat, len);
862
863	printf("%s:\n", name);
864
865#define	p(f, m) if (icmp6stat.f || sflag <= 1) \
866    printf(m, (uintmax_t)icmp6stat.f, plural(icmp6stat.f))
867#define	p_5(f, m) if (icmp6stat.f || sflag <= 1) \
868    printf(m, (uintmax_t)icmp6stat.f)
869
870	p(icp6s_error, "\t%ju call%s to icmp6_error\n");
871	p(icp6s_canterror,
872	    "\t%ju error%s not generated in response to an icmp6 message\n");
873	p(icp6s_toofreq,
874	  "\t%ju error%s not generated because of rate limitation\n");
875#define	NELEM (int)(sizeof(icmp6stat.icp6s_outhist)/sizeof(icmp6stat.icp6s_outhist[0]))
876	for (first = 1, i = 0; i < NELEM; i++)
877		if (icmp6stat.icp6s_outhist[i] != 0) {
878			if (first) {
879				printf("\tOutput histogram:\n");
880				first = 0;
881			}
882			printf("\t\t%s: %ju\n", icmp6names[i],
883			    (uintmax_t)icmp6stat.icp6s_outhist[i]);
884		}
885#undef NELEM
886	p(icp6s_badcode, "\t%ju message%s with bad code fields\n");
887	p(icp6s_tooshort, "\t%ju message%s < minimum length\n");
888	p(icp6s_checksum, "\t%ju bad checksum%s\n");
889	p(icp6s_badlen, "\t%ju message%s with bad length\n");
890#define	NELEM (int)(sizeof(icmp6stat.icp6s_inhist)/sizeof(icmp6stat.icp6s_inhist[0]))
891	for (first = 1, i = 0; i < NELEM; i++)
892		if (icmp6stat.icp6s_inhist[i] != 0) {
893			if (first) {
894				printf("\tInput histogram:\n");
895				first = 0;
896			}
897			printf("\t\t%s: %ju\n", icmp6names[i],
898			    (uintmax_t)icmp6stat.icp6s_inhist[i]);
899		}
900#undef NELEM
901	printf("\tHistogram of error messages to be generated:\n");
902	p_5(icp6s_odst_unreach_noroute, "\t\t%ju no route\n");
903	p_5(icp6s_odst_unreach_admin, "\t\t%ju administratively prohibited\n");
904	p_5(icp6s_odst_unreach_beyondscope, "\t\t%ju beyond scope\n");
905	p_5(icp6s_odst_unreach_addr, "\t\t%ju address unreachable\n");
906	p_5(icp6s_odst_unreach_noport, "\t\t%ju port unreachable\n");
907	p_5(icp6s_opacket_too_big, "\t\t%ju packet too big\n");
908	p_5(icp6s_otime_exceed_transit, "\t\t%ju time exceed transit\n");
909	p_5(icp6s_otime_exceed_reassembly, "\t\t%ju time exceed reassembly\n");
910	p_5(icp6s_oparamprob_header, "\t\t%ju erroneous header field\n");
911	p_5(icp6s_oparamprob_nextheader, "\t\t%ju unrecognized next header\n");
912	p_5(icp6s_oparamprob_option, "\t\t%ju unrecognized option\n");
913	p_5(icp6s_oredirect, "\t\t%ju redirect\n");
914	p_5(icp6s_ounknown, "\t\t%ju unknown\n");
915
916	p(icp6s_reflect, "\t%ju message response%s generated\n");
917	p(icp6s_nd_toomanyopt, "\t%ju message%s with too many ND options\n");
918	p(icp6s_nd_badopt, "\t%ju message%s with bad ND options\n");
919	p(icp6s_badns, "\t%ju bad neighbor solicitation message%s\n");
920	p(icp6s_badna, "\t%ju bad neighbor advertisement message%s\n");
921	p(icp6s_badrs, "\t%ju bad router solicitation message%s\n");
922	p(icp6s_badra, "\t%ju bad router advertisement message%s\n");
923	p(icp6s_badredirect, "\t%ju bad redirect message%s\n");
924	p(icp6s_pmtuchg, "\t%ju path MTU change%s\n");
925#undef p
926#undef p_5
927}
928
929/*
930 * Dump ICMPv6 per-interface statistics based on RFC 2466.
931 */
932void
933icmp6_ifstats(char *ifname)
934{
935	struct in6_ifreq ifr;
936	int s;
937#define	p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \
938    printf(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f, plural(ifr.ifr_ifru.ifru_icmp6stat.f))
939#define	p2(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \
940    printf(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f, pluralies(ifr.ifr_ifru.ifru_icmp6stat.f))
941
942	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
943		perror("Warning: socket(AF_INET6)");
944		return;
945	}
946
947	strcpy(ifr.ifr_name, ifname);
948	printf("icmp6 on %s:\n", ifr.ifr_name);
949
950	if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) {
951		perror("Warning: ioctl(SIOCGIFSTAT_ICMP6)");
952		goto end;
953	}
954
955	p(ifs6_in_msg, "\t%ju total input message%s\n");
956	p(ifs6_in_error, "\t%ju total input error message%s\n");
957	p(ifs6_in_dstunreach, "\t%ju input destination unreachable error%s\n");
958	p(ifs6_in_adminprohib, "\t%ju input administratively prohibited error%s\n");
959	p(ifs6_in_timeexceed, "\t%ju input time exceeded error%s\n");
960	p(ifs6_in_paramprob, "\t%ju input parameter problem error%s\n");
961	p(ifs6_in_pkttoobig, "\t%ju input packet too big error%s\n");
962	p(ifs6_in_echo, "\t%ju input echo request%s\n");
963	p2(ifs6_in_echoreply, "\t%ju input echo repl%s\n");
964	p(ifs6_in_routersolicit, "\t%ju input router solicitation%s\n");
965	p(ifs6_in_routeradvert, "\t%ju input router advertisement%s\n");
966	p(ifs6_in_neighborsolicit, "\t%ju input neighbor solicitation%s\n");
967	p(ifs6_in_neighboradvert, "\t%ju input neighbor advertisement%s\n");
968	p(ifs6_in_redirect, "\t%ju input redirect%s\n");
969	p2(ifs6_in_mldquery, "\t%ju input MLD quer%s\n");
970	p(ifs6_in_mldreport, "\t%ju input MLD report%s\n");
971	p(ifs6_in_mlddone, "\t%ju input MLD done%s\n");
972
973	p(ifs6_out_msg, "\t%ju total output message%s\n");
974	p(ifs6_out_error, "\t%ju total output error message%s\n");
975	p(ifs6_out_dstunreach, "\t%ju output destination unreachable error%s\n");
976	p(ifs6_out_adminprohib, "\t%ju output administratively prohibited error%s\n");
977	p(ifs6_out_timeexceed, "\t%ju output time exceeded error%s\n");
978	p(ifs6_out_paramprob, "\t%ju output parameter problem error%s\n");
979	p(ifs6_out_pkttoobig, "\t%ju output packet too big error%s\n");
980	p(ifs6_out_echo, "\t%ju output echo request%s\n");
981	p2(ifs6_out_echoreply, "\t%ju output echo repl%s\n");
982	p(ifs6_out_routersolicit, "\t%ju output router solicitation%s\n");
983	p(ifs6_out_routeradvert, "\t%ju output router advertisement%s\n");
984	p(ifs6_out_neighborsolicit, "\t%ju output neighbor solicitation%s\n");
985	p(ifs6_out_neighboradvert, "\t%ju output neighbor advertisement%s\n");
986	p(ifs6_out_redirect, "\t%ju output redirect%s\n");
987	p2(ifs6_out_mldquery, "\t%ju output MLD quer%s\n");
988	p(ifs6_out_mldreport, "\t%ju output MLD report%s\n");
989	p(ifs6_out_mlddone, "\t%ju output MLD done%s\n");
990
991  end:
992	close(s);
993#undef p
994}
995
996/*
997 * Dump PIM statistics structure.
998 */
999void
1000pim6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
1001{
1002	struct pim6stat pim6stat, zerostat;
1003	size_t len = sizeof pim6stat;
1004
1005	if (live) {
1006		if (zflag)
1007			memset(&zerostat, 0, len);
1008		if (sysctlbyname("net.inet6.pim.stats", &pim6stat, &len,
1009		    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
1010			if (errno != ENOENT)
1011				warn("sysctl: net.inet6.pim.stats");
1012			return;
1013		}
1014	} else {
1015		if (off == 0)
1016			return;
1017		kread(off, &pim6stat, len);
1018	}
1019
1020	printf("%s:\n", name);
1021
1022#define	p(f, m) if (pim6stat.f || sflag <= 1) \
1023    printf(m, (uintmax_t)pim6stat.f, plural(pim6stat.f))
1024	p(pim6s_rcv_total, "\t%ju message%s received\n");
1025	p(pim6s_rcv_tooshort, "\t%ju message%s received with too few bytes\n");
1026	p(pim6s_rcv_badsum, "\t%ju message%s received with bad checksum\n");
1027	p(pim6s_rcv_badversion, "\t%ju message%s received with bad version\n");
1028	p(pim6s_rcv_registers, "\t%ju register%s received\n");
1029	p(pim6s_rcv_badregisters, "\t%ju bad register%s received\n");
1030	p(pim6s_snd_registers, "\t%ju register%s sent\n");
1031#undef p
1032}
1033
1034/*
1035 * Dump raw ip6 statistics structure.
1036 */
1037void
1038rip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
1039{
1040	struct rip6stat rip6stat;
1041	u_quad_t delivered;
1042	size_t len;
1043
1044	len = sizeof(rip6stat);
1045	if (live) {
1046		if (sysctlbyname("net.inet6.ip6.rip6stats", &rip6stat, &len,
1047		    NULL, 0) < 0) {
1048			if (errno != ENOENT)
1049				warn("sysctl: net.inet6.ip6.rip6stats");
1050			return;
1051		}
1052	} else
1053		kread(off, &rip6stat, len);
1054
1055	printf("%s:\n", name);
1056
1057#define	p(f, m) if (rip6stat.f || sflag <= 1) \
1058    printf(m, (uintmax_t)rip6stat.f, plural(rip6stat.f))
1059	p(rip6s_ipackets, "\t%ju message%s received\n");
1060	p(rip6s_isum, "\t%ju checksum calculation%s on inbound\n");
1061	p(rip6s_badsum, "\t%ju message%s with bad checksum\n");
1062	p(rip6s_nosock, "\t%ju message%s dropped due to no socket\n");
1063	p(rip6s_nosockmcast,
1064	    "\t%ju multicast message%s dropped due to no socket\n");
1065	p(rip6s_fullsock,
1066	    "\t%ju message%s dropped due to full socket buffers\n");
1067	delivered = rip6stat.rip6s_ipackets -
1068		    rip6stat.rip6s_badsum -
1069		    rip6stat.rip6s_nosock -
1070		    rip6stat.rip6s_nosockmcast -
1071		    rip6stat.rip6s_fullsock;
1072	if (delivered || sflag <= 1)
1073		printf("\t%ju delivered\n", (uintmax_t)delivered);
1074	p(rip6s_opackets, "\t%ju datagram%s output\n");
1075#undef p
1076}
1077
1078/*
1079 * Pretty print an Internet address (net address + port).
1080 * Take numeric_addr and numeric_port into consideration.
1081 */
1082#define	GETSERVBYPORT6(port, proto, ret)\
1083{\
1084	if (strcmp((proto), "tcp6") == 0)\
1085		(ret) = getservbyport((int)(port), "tcp");\
1086	else if (strcmp((proto), "udp6") == 0)\
1087		(ret) = getservbyport((int)(port), "udp");\
1088	else\
1089		(ret) = getservbyport((int)(port), (proto));\
1090};
1091
1092void
1093inet6print(struct in6_addr *in6, int port, const char *proto, int numeric)
1094{
1095	struct servent *sp = 0;
1096	char line[80], *cp;
1097	int width;
1098
1099	sprintf(line, "%.*s.", Wflag ? 39 :
1100		(Aflag && !numeric) ? 12 : 16, inet6name(in6));
1101	cp = index(line, '\0');
1102	if (!numeric && port)
1103		GETSERVBYPORT6(port, proto, sp);
1104	if (sp || port == 0)
1105		sprintf(cp, "%.15s", sp ? sp->s_name : "*");
1106	else
1107		sprintf(cp, "%d", ntohs((u_short)port));
1108	width = Wflag ? 45 : Aflag ? 18 : 22;
1109	printf("%-*.*s ", width, width, line);
1110}
1111
1112/*
1113 * Construct an Internet address representation.
1114 * If the numeric_addr has been supplied, give
1115 * numeric value, otherwise try for symbolic name.
1116 */
1117
1118char *
1119inet6name(struct in6_addr *in6p)
1120{
1121	char *cp;
1122	static char line[50];
1123	struct hostent *hp;
1124	static char domain[MAXHOSTNAMELEN];
1125	static int first = 1;
1126
1127	if (first && !numeric_addr) {
1128		first = 0;
1129		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
1130		    (cp = index(domain, '.')))
1131			(void) strcpy(domain, cp + 1);
1132		else
1133			domain[0] = 0;
1134	}
1135	cp = 0;
1136	if (!numeric_addr && !IN6_IS_ADDR_UNSPECIFIED(in6p)) {
1137		hp = gethostbyaddr((char *)in6p, sizeof(*in6p), AF_INET6);
1138		if (hp) {
1139			if ((cp = index(hp->h_name, '.')) &&
1140			    !strcmp(cp + 1, domain))
1141				*cp = 0;
1142			cp = hp->h_name;
1143		}
1144	}
1145	if (IN6_IS_ADDR_UNSPECIFIED(in6p))
1146		strcpy(line, "*");
1147	else if (cp)
1148		strcpy(line, cp);
1149	else
1150		sprintf(line, "%s",
1151			inet_ntop(AF_INET6, (void *)in6p, ntop_buf,
1152				sizeof(ntop_buf)));
1153	return (line);
1154}
1155#endif /*INET6*/
1156