inet6.c revision 246988
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 * 4. Neither the name of the University nor the names of its contributors
15 *    may be used to endorse or promote products derived from this software
16 *    without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#if 0
32#ifndef lint
33static char sccsid[] = "@(#)inet6.c	8.4 (Berkeley) 4/20/94";
34#endif /* not lint */
35#endif
36
37#include <sys/cdefs.h>
38__FBSDID("$FreeBSD: head/usr.bin/netstat/inet6.c 246988 2013-02-19 13:17:16Z charnier $");
39
40#ifdef INET6
41#include <sys/param.h>
42#include <sys/socket.h>
43#include <sys/socketvar.h>
44#include <sys/ioctl.h>
45#include <sys/mbuf.h>
46#include <sys/protosw.h>
47#include <sys/sysctl.h>
48
49#include <net/route.h>
50#include <net/if.h>
51#include <net/if_var.h>
52#include <netinet/in.h>
53#include <netinet/ip6.h>
54#include <netinet/icmp6.h>
55#include <netinet/in_systm.h>
56#include <netinet6/in6_pcb.h>
57#include <netinet6/in6_var.h>
58#include <netinet6/ip6_var.h>
59#include <netinet6/pim6_var.h>
60#include <netinet6/raw_ip6.h>
61
62#include <arpa/inet.h>
63#include <netdb.h>
64
65#include <err.h>
66#include <stdint.h>
67#include <stdio.h>
68#include <errno.h>
69#include <string.h>
70#include <unistd.h>
71#include "netstat.h"
72
73struct	socket sockb;
74
75char	*inet6name(struct in6_addr *);
76
77static char ntop_buf[INET6_ADDRSTRLEN];
78
79static	const char *ip6nh[] = {
80	"hop by hop",
81	"ICMP",
82	"IGMP",
83	"#3",
84	"IP",
85	"#5",
86	"TCP",
87	"#7",
88	"#8",
89	"#9",
90	"#10",
91	"#11",
92	"#12",
93	"#13",
94	"#14",
95	"#15",
96	"#16",
97	"UDP",
98	"#18",
99	"#19",
100	"#20",
101	"#21",
102	"IDP",
103	"#23",
104	"#24",
105	"#25",
106	"#26",
107	"#27",
108	"#28",
109	"TP",
110	"#30",
111	"#31",
112	"#32",
113	"#33",
114	"#34",
115	"#35",
116	"#36",
117	"#37",
118	"#38",
119	"#39",
120	"#40",
121	"IP6",
122	"#42",
123	"routing",
124	"fragment",
125	"#45",
126	"#46",
127	"#47",
128	"#48",
129	"#49",
130	"ESP",
131	"AH",
132	"#52",
133	"#53",
134	"#54",
135	"#55",
136	"#56",
137	"#57",
138	"ICMP6",
139	"no next header",
140	"destination option",
141	"#61",
142	"mobility",
143	"#63",
144	"#64",
145	"#65",
146	"#66",
147	"#67",
148	"#68",
149	"#69",
150	"#70",
151	"#71",
152	"#72",
153	"#73",
154	"#74",
155	"#75",
156	"#76",
157	"#77",
158	"#78",
159	"#79",
160	"ISOIP",
161	"#81",
162	"#82",
163	"#83",
164	"#84",
165	"#85",
166	"#86",
167	"#87",
168	"#88",
169	"OSPF",
170	"#80",
171	"#91",
172	"#92",
173	"#93",
174	"#94",
175	"#95",
176	"#96",
177	"Ethernet",
178	"#98",
179	"#99",
180	"#100",
181	"#101",
182	"#102",
183	"PIM",
184	"#104",
185	"#105",
186	"#106",
187	"#107",
188	"#108",
189	"#109",
190	"#110",
191	"#111",
192	"#112",
193	"#113",
194	"#114",
195	"#115",
196	"#116",
197	"#117",
198	"#118",
199	"#119",
200	"#120",
201	"#121",
202	"#122",
203	"#123",
204	"#124",
205	"#125",
206	"#126",
207	"#127",
208	"#128",
209	"#129",
210	"#130",
211	"#131",
212	"#132",
213	"#133",
214	"#134",
215	"#135",
216	"#136",
217	"#137",
218	"#138",
219	"#139",
220	"#140",
221	"#141",
222	"#142",
223	"#143",
224	"#144",
225	"#145",
226	"#146",
227	"#147",
228	"#148",
229	"#149",
230	"#150",
231	"#151",
232	"#152",
233	"#153",
234	"#154",
235	"#155",
236	"#156",
237	"#157",
238	"#158",
239	"#159",
240	"#160",
241	"#161",
242	"#162",
243	"#163",
244	"#164",
245	"#165",
246	"#166",
247	"#167",
248	"#168",
249	"#169",
250	"#170",
251	"#171",
252	"#172",
253	"#173",
254	"#174",
255	"#175",
256	"#176",
257	"#177",
258	"#178",
259	"#179",
260	"#180",
261	"#181",
262	"#182",
263	"#183",
264	"#184",
265	"#185",
266	"#186",
267	"#187",
268	"#188",
269	"#189",
270	"#180",
271	"#191",
272	"#192",
273	"#193",
274	"#194",
275	"#195",
276	"#196",
277	"#197",
278	"#198",
279	"#199",
280	"#200",
281	"#201",
282	"#202",
283	"#203",
284	"#204",
285	"#205",
286	"#206",
287	"#207",
288	"#208",
289	"#209",
290	"#210",
291	"#211",
292	"#212",
293	"#213",
294	"#214",
295	"#215",
296	"#216",
297	"#217",
298	"#218",
299	"#219",
300	"#220",
301	"#221",
302	"#222",
303	"#223",
304	"#224",
305	"#225",
306	"#226",
307	"#227",
308	"#228",
309	"#229",
310	"#230",
311	"#231",
312	"#232",
313	"#233",
314	"#234",
315	"#235",
316	"#236",
317	"#237",
318	"#238",
319	"#239",
320	"#240",
321	"#241",
322	"#242",
323	"#243",
324	"#244",
325	"#245",
326	"#246",
327	"#247",
328	"#248",
329	"#249",
330	"#250",
331	"#251",
332	"#252",
333	"#253",
334	"#254",
335	"#255",
336};
337
338static const char *srcrule_str[] = {
339	"first candidate",
340	"same address",
341	"appropriate scope",
342	"deprecated address",
343	"home address",
344	"outgoing interface",
345	"matching label",
346	"public/temporary address",
347	"alive interface",
348	"preferred interface",
349	"rule #10",
350	"rule #11",
351	"rule #12",
352	"rule #13",
353	"longest match",
354	"rule #15",
355};
356
357/*
358 * Dump IP6 statistics structure.
359 */
360void
361ip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
362{
363	struct ip6stat ip6stat, zerostat;
364	int first, i;
365	size_t len;
366
367	len = sizeof ip6stat;
368	if (live) {
369		memset(&ip6stat, 0, len);
370		if (zflag)
371			memset(&zerostat, 0, len);
372		if (sysctlbyname("net.inet6.ip6.stats", &ip6stat, &len,
373		    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
374			if (errno != ENOENT)
375				warn("sysctl: net.inet6.ip6.stats");
376			return;
377		}
378	} else
379		kread(off, &ip6stat, len);
380
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 contiguous\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	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%ju %s\n",
517			       (uintmax_t)ip6stat.ip6s_sources_rule[i],
518			       srcrule_str[i]);
519	}
520#undef p
521#undef p1a
522}
523
524/*
525 * Dump IPv6 per-interface statistics based on RFC 2465.
526 */
527void
528ip6_ifstats(char *ifname)
529{
530	struct in6_ifreq ifr;
531	int s;
532#define	p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
533    printf(m, (uintmax_t)ifr.ifr_ifru.ifru_stat.f, plural(ifr.ifr_ifru.ifru_stat.f))
534#define	p_5(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
535    printf(m, (uintmax_t)ip6stat.f)
536
537	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
538		perror("Warning: socket(AF_INET6)");
539		return;
540	}
541
542	strcpy(ifr.ifr_name, ifname);
543	printf("ip6 on %s:\n", ifr.ifr_name);
544
545	if (ioctl(s, SIOCGIFSTAT_IN6, (char *)&ifr) < 0) {
546		perror("Warning: ioctl(SIOCGIFSTAT_IN6)");
547		goto end;
548	}
549
550	p(ifs6_in_receive, "\t%ju total input datagram%s\n");
551	p(ifs6_in_hdrerr, "\t%ju datagram%s with invalid header received\n");
552	p(ifs6_in_toobig, "\t%ju datagram%s exceeded MTU received\n");
553	p(ifs6_in_noroute, "\t%ju datagram%s with no route received\n");
554	p(ifs6_in_addrerr, "\t%ju datagram%s with invalid dst received\n");
555	p(ifs6_in_protounknown, "\t%ju datagram%s with unknown proto received\n");
556	p(ifs6_in_truncated, "\t%ju truncated datagram%s received\n");
557	p(ifs6_in_discard, "\t%ju input datagram%s discarded\n");
558	p(ifs6_in_deliver,
559	  "\t%ju datagram%s delivered to an upper layer protocol\n");
560	p(ifs6_out_forward, "\t%ju datagram%s forwarded to this interface\n");
561	p(ifs6_out_request,
562	  "\t%ju datagram%s sent from an upper layer protocol\n");
563	p(ifs6_out_discard, "\t%ju total discarded output datagram%s\n");
564	p(ifs6_out_fragok, "\t%ju output datagram%s fragmented\n");
565	p(ifs6_out_fragfail, "\t%ju output datagram%s failed on fragment\n");
566	p(ifs6_out_fragcreat, "\t%ju output datagram%s succeeded on fragment\n");
567	p(ifs6_reass_reqd, "\t%ju incoming datagram%s fragmented\n");
568	p(ifs6_reass_ok, "\t%ju datagram%s reassembled\n");
569	p(ifs6_reass_fail, "\t%ju datagram%s failed on reassembly\n");
570	p(ifs6_in_mcast, "\t%ju multicast datagram%s received\n");
571	p(ifs6_out_mcast, "\t%ju multicast datagram%s sent\n");
572
573  end:
574	close(s);
575
576#undef p
577#undef p_5
578}
579
580static	const char *icmp6names[] = {
581	"#0",
582	"unreach",
583	"packet too big",
584	"time exceed",
585	"parameter problem",
586	"#5",
587	"#6",
588	"#7",
589	"#8",
590	"#9",
591	"#10",
592	"#11",
593	"#12",
594	"#13",
595	"#14",
596	"#15",
597	"#16",
598	"#17",
599	"#18",
600	"#19",
601	"#20",
602	"#21",
603	"#22",
604	"#23",
605	"#24",
606	"#25",
607	"#26",
608	"#27",
609	"#28",
610	"#29",
611	"#30",
612	"#31",
613	"#32",
614	"#33",
615	"#34",
616	"#35",
617	"#36",
618	"#37",
619	"#38",
620	"#39",
621	"#40",
622	"#41",
623	"#42",
624	"#43",
625	"#44",
626	"#45",
627	"#46",
628	"#47",
629	"#48",
630	"#49",
631	"#50",
632	"#51",
633	"#52",
634	"#53",
635	"#54",
636	"#55",
637	"#56",
638	"#57",
639	"#58",
640	"#59",
641	"#60",
642	"#61",
643	"#62",
644	"#63",
645	"#64",
646	"#65",
647	"#66",
648	"#67",
649	"#68",
650	"#69",
651	"#70",
652	"#71",
653	"#72",
654	"#73",
655	"#74",
656	"#75",
657	"#76",
658	"#77",
659	"#78",
660	"#79",
661	"#80",
662	"#81",
663	"#82",
664	"#83",
665	"#84",
666	"#85",
667	"#86",
668	"#87",
669	"#88",
670	"#89",
671	"#80",
672	"#91",
673	"#92",
674	"#93",
675	"#94",
676	"#95",
677	"#96",
678	"#97",
679	"#98",
680	"#99",
681	"#100",
682	"#101",
683	"#102",
684	"#103",
685	"#104",
686	"#105",
687	"#106",
688	"#107",
689	"#108",
690	"#109",
691	"#110",
692	"#111",
693	"#112",
694	"#113",
695	"#114",
696	"#115",
697	"#116",
698	"#117",
699	"#118",
700	"#119",
701	"#120",
702	"#121",
703	"#122",
704	"#123",
705	"#124",
706	"#125",
707	"#126",
708	"#127",
709	"echo",
710	"echo reply",
711	"multicast listener query",
712	"MLDv1 listener report",
713	"MLDv1 listener done",
714	"router solicitation",
715	"router advertisement",
716	"neighbor solicitation",
717	"neighbor advertisement",
718	"redirect",
719	"router renumbering",
720	"node information request",
721	"node information reply",
722	"inverse neighbor solicitation",
723	"inverse neighbor advertisement",
724	"MLDv2 listener report",
725	"#144",
726	"#145",
727	"#146",
728	"#147",
729	"#148",
730	"#149",
731	"#150",
732	"#151",
733	"#152",
734	"#153",
735	"#154",
736	"#155",
737	"#156",
738	"#157",
739	"#158",
740	"#159",
741	"#160",
742	"#161",
743	"#162",
744	"#163",
745	"#164",
746	"#165",
747	"#166",
748	"#167",
749	"#168",
750	"#169",
751	"#170",
752	"#171",
753	"#172",
754	"#173",
755	"#174",
756	"#175",
757	"#176",
758	"#177",
759	"#178",
760	"#179",
761	"#180",
762	"#181",
763	"#182",
764	"#183",
765	"#184",
766	"#185",
767	"#186",
768	"#187",
769	"#188",
770	"#189",
771	"#180",
772	"#191",
773	"#192",
774	"#193",
775	"#194",
776	"#195",
777	"#196",
778	"#197",
779	"#198",
780	"#199",
781	"#200",
782	"#201",
783	"#202",
784	"#203",
785	"#204",
786	"#205",
787	"#206",
788	"#207",
789	"#208",
790	"#209",
791	"#210",
792	"#211",
793	"#212",
794	"#213",
795	"#214",
796	"#215",
797	"#216",
798	"#217",
799	"#218",
800	"#219",
801	"#220",
802	"#221",
803	"#222",
804	"#223",
805	"#224",
806	"#225",
807	"#226",
808	"#227",
809	"#228",
810	"#229",
811	"#230",
812	"#231",
813	"#232",
814	"#233",
815	"#234",
816	"#235",
817	"#236",
818	"#237",
819	"#238",
820	"#239",
821	"#240",
822	"#241",
823	"#242",
824	"#243",
825	"#244",
826	"#245",
827	"#246",
828	"#247",
829	"#248",
830	"#249",
831	"#250",
832	"#251",
833	"#252",
834	"#253",
835	"#254",
836	"#255",
837};
838
839/*
840 * Dump ICMP6 statistics.
841 */
842void
843icmp6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
844{
845	struct icmp6stat icmp6stat, zerostat;
846	int i, first;
847	size_t len;
848
849	len = sizeof icmp6stat;
850	if (live) {
851		memset(&icmp6stat, 0, len);
852		if (zflag)
853			memset(&zerostat, 0, len);
854		if (sysctlbyname("net.inet6.icmp6.stats", &icmp6stat, &len,
855		    zflag ? &zerostat : NULL, zflag ? len : 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, zerostat;
1041	u_quad_t delivered;
1042	size_t len;
1043
1044	len = sizeof(rip6stat);
1045	if (live) {
1046		if (zflag)
1047			memset(&zerostat, 0, len);
1048		if (sysctlbyname("net.inet6.ip6.rip6stats", &rip6stat, &len,
1049		    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
1050			if (errno != ENOENT)
1051				warn("sysctl: net.inet6.ip6.rip6stats");
1052			return;
1053		}
1054	} else
1055		kread(off, &rip6stat, len);
1056
1057	printf("%s:\n", name);
1058
1059#define	p(f, m) if (rip6stat.f || sflag <= 1) \
1060    printf(m, (uintmax_t)rip6stat.f, plural(rip6stat.f))
1061	p(rip6s_ipackets, "\t%ju message%s received\n");
1062	p(rip6s_isum, "\t%ju checksum calculation%s on inbound\n");
1063	p(rip6s_badsum, "\t%ju message%s with bad checksum\n");
1064	p(rip6s_nosock, "\t%ju message%s dropped due to no socket\n");
1065	p(rip6s_nosockmcast,
1066	    "\t%ju multicast message%s dropped due to no socket\n");
1067	p(rip6s_fullsock,
1068	    "\t%ju message%s dropped due to full socket buffers\n");
1069	delivered = rip6stat.rip6s_ipackets -
1070		    rip6stat.rip6s_badsum -
1071		    rip6stat.rip6s_nosock -
1072		    rip6stat.rip6s_nosockmcast -
1073		    rip6stat.rip6s_fullsock;
1074	if (delivered || sflag <= 1)
1075		printf("\t%ju delivered\n", (uintmax_t)delivered);
1076	p(rip6s_opackets, "\t%ju datagram%s output\n");
1077#undef p
1078}
1079
1080/*
1081 * Pretty print an Internet address (net address + port).
1082 * Take numeric_addr and numeric_port into consideration.
1083 */
1084#define	GETSERVBYPORT6(port, proto, ret)\
1085{\
1086	if (strcmp((proto), "tcp6") == 0)\
1087		(ret) = getservbyport((int)(port), "tcp");\
1088	else if (strcmp((proto), "udp6") == 0)\
1089		(ret) = getservbyport((int)(port), "udp");\
1090	else\
1091		(ret) = getservbyport((int)(port), (proto));\
1092};
1093
1094void
1095inet6print(struct in6_addr *in6, int port, const char *proto, int numeric)
1096{
1097	struct servent *sp = 0;
1098	char line[80], *cp;
1099	int width;
1100
1101	sprintf(line, "%.*s.", Wflag ? 39 :
1102		(Aflag && !numeric) ? 12 : 16, inet6name(in6));
1103	cp = strchr(line, '\0');
1104	if (!numeric && port)
1105		GETSERVBYPORT6(port, proto, sp);
1106	if (sp || port == 0)
1107		sprintf(cp, "%.15s", sp ? sp->s_name : "*");
1108	else
1109		sprintf(cp, "%d", ntohs((u_short)port));
1110	width = Wflag ? 45 : Aflag ? 18 : 22;
1111	printf("%-*.*s ", width, width, line);
1112}
1113
1114/*
1115 * Construct an Internet address representation.
1116 * If the numeric_addr has been supplied, give
1117 * numeric value, otherwise try for symbolic name.
1118 */
1119
1120char *
1121inet6name(struct in6_addr *in6p)
1122{
1123	char *cp;
1124	static char line[50];
1125	struct hostent *hp;
1126	static char domain[MAXHOSTNAMELEN];
1127	static int first = 1;
1128
1129	if (first && !numeric_addr) {
1130		first = 0;
1131		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
1132		    (cp = strchr(domain, '.')))
1133			(void) strcpy(domain, cp + 1);
1134		else
1135			domain[0] = 0;
1136	}
1137	cp = 0;
1138	if (!numeric_addr && !IN6_IS_ADDR_UNSPECIFIED(in6p)) {
1139		hp = gethostbyaddr((char *)in6p, sizeof(*in6p), AF_INET6);
1140		if (hp) {
1141			if ((cp = strchr(hp->h_name, '.')) &&
1142			    !strcmp(cp + 1, domain))
1143				*cp = 0;
1144			cp = hp->h_name;
1145		}
1146	}
1147	if (IN6_IS_ADDR_UNSPECIFIED(in6p))
1148		strcpy(line, "*");
1149	else if (cp)
1150		strcpy(line, cp);
1151	else
1152		sprintf(line, "%s",
1153			inet_ntop(AF_INET6, (void *)in6p, ntop_buf,
1154				sizeof(ntop_buf)));
1155	return (line);
1156}
1157#endif /*INET6*/
1158