inet6.c revision 1.30
1/*	$OpenBSD: inet6.c,v 1.30 2003/11/06 06:18:20 itojun Exp $	*/
2/*	BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp	*/
3/*
4 * Copyright (c) 1983, 1988, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33#ifndef lint
34#if 0
35static char sccsid[] = "@(#)inet.c	8.4 (Berkeley) 4/20/94";
36#else
37/*__RCSID("$OpenBSD: inet6.c,v 1.30 2003/11/06 06:18:20 itojun Exp $");*/
38/*__RCSID("KAME Id: inet6.c,v 1.10 2000/02/09 10:49:31 itojun Exp");*/
39#endif
40#endif /* not lint */
41
42#include <sys/param.h>
43#include <sys/socket.h>
44#include <sys/socketvar.h>
45#include <sys/ioctl.h>
46#include <sys/mbuf.h>
47#include <sys/protosw.h>
48
49#include <net/route.h>
50#include <net/if.h>
51#include <netinet/in.h>
52#include <netinet/ip6.h>
53#include <netinet/icmp6.h>
54#include <netinet/in_systm.h>
55#ifndef TCP6
56#include <netinet/ip.h>
57#include <netinet/ip_var.h>
58#endif
59#include <netinet6/ip6_var.h>
60#include <netinet6/in6_var.h>
61#include <netinet6/pim6_var.h>
62#include <netinet6/raw_ip6.h>
63
64#include <arpa/inet.h>
65#if 0
66#include "gethostbyname2.h"
67#endif
68#include <netdb.h>
69
70#include <stdio.h>
71#include <string.h>
72#include <unistd.h>
73#include "netstat.h"
74
75#ifdef INET6
76
77struct	socket sockb;
78
79char	*inet6name(struct in6_addr *);
80void	inet6print(struct in6_addr *, int, char *);
81
82static	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	"#62",
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
341/*
342 * Dump IP6 statistics structure.
343 */
344void
345ip6_stats(u_long off, char *name)
346{
347	struct ip6stat ip6stat;
348	int first, i;
349	struct protoent *ep;
350	const char *n;
351
352	if (off == 0)
353		return;
354
355	kread(off, (char *)&ip6stat, sizeof (ip6stat));
356	printf("%s:\n", name);
357
358#define	p(f, m) if (ip6stat.f || sflag <= 1) \
359	printf(m, (unsigned long long)ip6stat.f, plural(ip6stat.f))
360#define	p1(f, m) if (ip6stat.f || sflag <= 1) \
361	printf(m, (unsigned long long)ip6stat.f)
362
363	p(ip6s_total, "\t%llu total packet%s received\n");
364	p1(ip6s_toosmall, "\t%llu with size smaller than minimum\n");
365	p1(ip6s_tooshort, "\t%llu with data size < data length\n");
366	p1(ip6s_badoptions, "\t%llu with bad options\n");
367	p1(ip6s_badvers, "\t%llu with incorrect version number\n");
368	p(ip6s_fragments, "\t%llu fragment%s received\n");
369	p(ip6s_fragdropped,
370	    "\t%llu fragment%s dropped (duplicates or out of space)\n");
371	p(ip6s_fragtimeout, "\t%llu fragment%s dropped after timeout\n");
372	p(ip6s_fragoverflow, "\t%llu fragment%s that exceeded limit\n");
373	p(ip6s_reassembled, "\t%llu packet%s reassembled ok\n");
374	p(ip6s_delivered, "\t%llu packet%s for this host\n");
375	p(ip6s_forward, "\t%llu packet%s forwarded\n");
376	p(ip6s_cantforward, "\t%llu packet%s not forwardable\n");
377	p(ip6s_redirectsent, "\t%llu redirect%s sent\n");
378	p(ip6s_localout, "\t%llu packet%s sent from this host\n");
379	p(ip6s_rawout, "\t%llu packet%s sent with fabricated ip header\n");
380	p(ip6s_odropped,
381	    "\t%llu output packet%s dropped due to no bufs, etc.\n");
382	p(ip6s_noroute, "\t%llu output packet%s discarded due to no route\n");
383	p(ip6s_fragmented, "\t%llu output datagram%s fragmented\n");
384	p(ip6s_ofragments, "\t%llu fragment%s created\n");
385	p(ip6s_cantfrag, "\t%llu datagram%s that can't be fragmented\n");
386	p(ip6s_badscope, "\t%llu packet%s that violated scope rules\n");
387	p(ip6s_notmember, "\t%llu multicast packet%s which we don't join\n");
388	for (first = 1, i = 0; i < 256; i++)
389		if (ip6stat.ip6s_nxthist[i] != 0) {
390			if (first) {
391				printf("\tInput packet histogram:\n");
392				first = 0;
393			}
394			n = NULL;
395			if (ip6nh[i])
396				n = ip6nh[i];
397			else if ((ep = getprotobynumber(i)) != NULL)
398				n = ep->p_name;
399			if (n)
400				printf("\t\t%s: %llu\n", n,
401				    (unsigned long long)ip6stat.ip6s_nxthist[i]);
402			else
403				printf("\t\t#%d: %llu\n", i,
404				    (unsigned long long)ip6stat.ip6s_nxthist[i]);
405		}
406	printf("\tMbuf statistics:\n");
407	p(ip6s_m1, "\t\t%llu one mbuf%s\n");
408	for (first = 1, i = 0; i < 32; i++) {
409		char ifbuf[IFNAMSIZ];
410		if (ip6stat.ip6s_m2m[i] != 0) {
411			if (first) {
412				printf("\t\ttwo or more mbuf:\n");
413				first = 0;
414			}
415			printf("\t\t\t%s = %llu\n",
416			    if_indextoname(i, ifbuf),
417			    (unsigned long long)ip6stat.ip6s_m2m[i]);
418		}
419	}
420	p(ip6s_mext1, "\t\t%llu one ext mbuf%s\n");
421	p(ip6s_mext2m, "\t\t%llu two or more ext mbuf%s\n");
422	p(ip6s_exthdrtoolong,
423	    "\t%llu packet%s whose headers are not continuous\n");
424	p(ip6s_nogif, "\t%llu tunneling packet%s that can't find gif\n");
425	p(ip6s_toomanyhdr,
426	    "\t%llu packet%s discarded due to too many headers\n");
427
428	/* for debugging source address selection */
429#define PRINT_SCOPESTAT(s,i) do {\
430		switch(i) { /* XXX hardcoding in each case */\
431		case 1:\
432			p(s, "\t\t%llu node-local%s\n");\
433			break;\
434		case 2:\
435			p(s, "\t\t%llu link-local%s\n");\
436			break;\
437		case 5:\
438			p(s, "\t\t%llu site-local%s\n");\
439			break;\
440		case 14:\
441			p(s, "\t\t%llu global%s\n");\
442			break;\
443		default:\
444			printf("\t\t%llu addresses scope=%x\n",\
445			    (unsigned long long)ip6stat.s, i);\
446		}\
447	} while(0);
448
449	p(ip6s_sources_none,
450	    "\t%llu failure%s of source address selection\n");
451	for (first = 1, i = 0; i < 16; i++) {
452		if (ip6stat.ip6s_sources_sameif[i]) {
453			if (first) {
454				printf("\tsource addresses on an outgoing I/F\n");
455				first = 0;
456			}
457			PRINT_SCOPESTAT(ip6s_sources_sameif[i], i);
458		}
459	}
460	for (first = 1, i = 0; i < 16; i++) {
461		if (ip6stat.ip6s_sources_otherif[i]) {
462			if (first) {
463				printf("\tsource addresses on a non-outgoing I/F\n");
464				first = 0;
465			}
466			PRINT_SCOPESTAT(ip6s_sources_otherif[i], i);
467		}
468	}
469	for (first = 1, i = 0; i < 16; i++) {
470		if (ip6stat.ip6s_sources_samescope[i]) {
471			if (first) {
472				printf("\tsource addresses of same scope\n");
473				first = 0;
474			}
475			PRINT_SCOPESTAT(ip6s_sources_samescope[i], i);
476		}
477	}
478	for (first = 1, i = 0; i < 16; i++) {
479		if (ip6stat.ip6s_sources_otherscope[i]) {
480			if (first) {
481				printf("\tsource addresses of a different scope\n");
482				first = 0;
483			}
484			PRINT_SCOPESTAT(ip6s_sources_otherscope[i], i);
485		}
486	}
487	for (first = 1, i = 0; i < 16; i++) {
488		if (ip6stat.ip6s_sources_deprecated[i]) {
489			if (first) {
490				printf("\tdeprecated source addresses\n");
491				first = 0;
492			}
493			PRINT_SCOPESTAT(ip6s_sources_deprecated[i], i);
494		}
495	}
496
497	p1(ip6s_forward_cachehit, "\t%llu forward cache hit\n");
498	p1(ip6s_forward_cachemiss, "\t%llu forward cache miss\n");
499#undef p
500#undef p1
501}
502
503/*
504 * Dump IPv6 per-interface statistics based on RFC 2465.
505 */
506void
507ip6_ifstats(char *ifname)
508{
509	struct in6_ifreq ifr;
510	int s;
511
512#define	p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
513	printf(m, (unsigned long long)ifr.ifr_ifru.ifru_stat.f, \
514	    plural(ifr.ifr_ifru.ifru_stat.f))
515#define	p_5(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
516	printf(m, (unsigned long long)ip6stat.f)
517
518	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
519		perror("Warning: socket(AF_INET6)");
520		return;
521	}
522
523	strlcpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name);
524	printf("ip6 on %s:\n", ifr.ifr_name);
525
526	if (ioctl(s, SIOCGIFSTAT_IN6, (char *)&ifr) < 0) {
527		perror("Warning: ioctl(SIOCGIFSTAT_IN6)");
528		goto end;
529	}
530
531	p(ifs6_in_receive, "\t%llu total input datagram%s\n");
532	p(ifs6_in_hdrerr, "\t%llu datagram%s with invalid header received\n");
533	p(ifs6_in_toobig, "\t%llu datagram%s exceeded MTU received\n");
534	p(ifs6_in_noroute, "\t%llu datagram%s with no route received\n");
535	p(ifs6_in_addrerr, "\t%llu datagram%s with invalid dst received\n");
536	p(ifs6_in_truncated, "\t%llu truncated datagram%s received\n");
537	p(ifs6_in_protounknown, "\t%llu datagram%s with unknown proto received\n");
538	p(ifs6_in_discard, "\t%llu input datagram%s discarded\n");
539	p(ifs6_in_deliver,
540	    "\t%llu datagram%s delivered to an upper layer protocol\n");
541	p(ifs6_out_forward, "\t%llu datagram%s forwarded to this interface\n");
542	p(ifs6_out_request,
543	    "\t%llu datagram%s sent from an upper layer protocol\n");
544	p(ifs6_out_discard, "\t%llu total discarded output datagram%s\n");
545	p(ifs6_out_fragok, "\t%llu output datagram%s fragmented\n");
546	p(ifs6_out_fragfail, "\t%llu output datagram%s failed on fragment\n");
547	p(ifs6_out_fragcreat, "\t%llu output datagram%s succeeded on fragment\n");
548	p(ifs6_reass_reqd, "\t%llu incoming datagram%s fragmented\n");
549	p(ifs6_reass_ok, "\t%llu datagram%s reassembled\n");
550	p(ifs6_reass_fail, "\t%llu datagram%s failed on reassembling\n");
551	p(ifs6_in_mcast, "\t%llu multicast datagram%s received\n");
552	p(ifs6_out_mcast, "\t%llu multicast datagram%s sent\n");
553
554  end:
555	close(s);
556
557#undef p
558#undef p_5
559}
560
561static	char *icmp6names[] = {
562	"#0",
563	"unreach",
564	"packet too big",
565	"time exceed",
566	"parameter problem",
567	"#5",
568	"#6",
569	"#7",
570	"#8",
571	"#9",
572	"#10",
573	"#11",
574	"#12",
575	"#13",
576	"#14",
577	"#15",
578	"#16",
579	"#17",
580	"#18",
581	"#19",
582	"#20",
583	"#21",
584	"#22",
585	"#23",
586	"#24",
587	"#25",
588	"#26",
589	"#27",
590	"#28",
591	"#29",
592	"#30",
593	"#31",
594	"#32",
595	"#33",
596	"#34",
597	"#35",
598	"#36",
599	"#37",
600	"#38",
601	"#39",
602	"#40",
603	"#41",
604	"#42",
605	"#43",
606	"#44",
607	"#45",
608	"#46",
609	"#47",
610	"#48",
611	"#49",
612	"#50",
613	"#51",
614	"#52",
615	"#53",
616	"#54",
617	"#55",
618	"#56",
619	"#57",
620	"#58",
621	"#59",
622	"#60",
623	"#61",
624	"#62",
625	"#63",
626	"#64",
627	"#65",
628	"#66",
629	"#67",
630	"#68",
631	"#69",
632	"#70",
633	"#71",
634	"#72",
635	"#73",
636	"#74",
637	"#75",
638	"#76",
639	"#77",
640	"#78",
641	"#79",
642	"#80",
643	"#81",
644	"#82",
645	"#83",
646	"#84",
647	"#85",
648	"#86",
649	"#87",
650	"#88",
651	"#89",
652	"#80",
653	"#91",
654	"#92",
655	"#93",
656	"#94",
657	"#95",
658	"#96",
659	"#97",
660	"#98",
661	"#99",
662	"#100",
663	"#101",
664	"#102",
665	"#103",
666	"#104",
667	"#105",
668	"#106",
669	"#107",
670	"#108",
671	"#109",
672	"#110",
673	"#111",
674	"#112",
675	"#113",
676	"#114",
677	"#115",
678	"#116",
679	"#117",
680	"#118",
681	"#119",
682	"#120",
683	"#121",
684	"#122",
685	"#123",
686	"#124",
687	"#125",
688	"#126",
689	"#127",
690	"echo",
691	"echo reply",
692	"multicast listener query",
693	"multicast listener report",
694	"multicast listener done",
695	"router solicitation",
696	"router advertisement",
697	"neighbor solicitation",
698	"neighbor advertisement",
699	"redirect",
700	"router renumbering",
701	"node information request",
702	"node information reply",
703	"#141",
704	"#142",
705	"#143",
706	"#144",
707	"#145",
708	"#146",
709	"#147",
710	"#148",
711	"#149",
712	"#150",
713	"#151",
714	"#152",
715	"#153",
716	"#154",
717	"#155",
718	"#156",
719	"#157",
720	"#158",
721	"#159",
722	"#160",
723	"#161",
724	"#162",
725	"#163",
726	"#164",
727	"#165",
728	"#166",
729	"#167",
730	"#168",
731	"#169",
732	"#170",
733	"#171",
734	"#172",
735	"#173",
736	"#174",
737	"#175",
738	"#176",
739	"#177",
740	"#178",
741	"#179",
742	"#180",
743	"#181",
744	"#182",
745	"#183",
746	"#184",
747	"#185",
748	"#186",
749	"#187",
750	"#188",
751	"#189",
752	"#180",
753	"#191",
754	"#192",
755	"#193",
756	"#194",
757	"#195",
758	"#196",
759	"#197",
760	"#198",
761	"#199",
762	"#200",
763	"#201",
764	"#202",
765	"#203",
766	"#204",
767	"#205",
768	"#206",
769	"#207",
770	"#208",
771	"#209",
772	"#210",
773	"#211",
774	"#212",
775	"#213",
776	"#214",
777	"#215",
778	"#216",
779	"#217",
780	"#218",
781	"#219",
782	"#220",
783	"#221",
784	"#222",
785	"#223",
786	"#224",
787	"#225",
788	"#226",
789	"#227",
790	"#228",
791	"#229",
792	"#230",
793	"#231",
794	"#232",
795	"#233",
796	"#234",
797	"#235",
798	"#236",
799	"#237",
800	"#238",
801	"#239",
802	"#240",
803	"#241",
804	"#242",
805	"#243",
806	"#244",
807	"#245",
808	"#246",
809	"#247",
810	"#248",
811	"#249",
812	"#250",
813	"#251",
814	"#252",
815	"#253",
816	"#254",
817	"#255",
818};
819
820/*
821 * Dump ICMPv6 statistics.
822 */
823void
824icmp6_stats(u_long off, char *name)
825{
826	struct icmp6stat icmp6stat;
827	int i, first;
828
829	if (off == 0)
830		return;
831	kread(off, (char *)&icmp6stat, sizeof (icmp6stat));
832	printf("%s:\n", name);
833
834#define	p(f, m) if (icmp6stat.f || sflag <= 1) \
835	printf(m, (unsigned long long)icmp6stat.f, plural(icmp6stat.f))
836#define p_5(f, m) if (icmp6stat.f || sflag <= 1) \
837	printf(m, (unsigned long long)icmp6stat.f)
838
839	p(icp6s_error, "\t%llu call%s to icmp6_error\n");
840	p(icp6s_canterror,
841	    "\t%llu error%s not generated because old message was icmp6 or so\n");
842	p(icp6s_toofreq,
843	    "\t%llu error%s not generated because of rate limitation\n");
844	for (first = 1, i = 0; i < 256; i++)
845		if (icmp6stat.icp6s_outhist[i] != 0) {
846			if (first) {
847				printf("\tOutput packet histogram:\n");
848				first = 0;
849			}
850			printf("\t\t%s: %llu\n", icmp6names[i],
851			    (unsigned long long)icmp6stat.icp6s_outhist[i]);
852		}
853	p(icp6s_badcode, "\t%llu message%s with bad code fields\n");
854	p(icp6s_tooshort, "\t%llu message%s < minimum length\n");
855	p(icp6s_checksum, "\t%llu bad checksum%s\n");
856	p(icp6s_badlen, "\t%llu message%s with bad length\n");
857	for (first = 1, i = 0; i < ICMP6_MAXTYPE; i++)
858		if (icmp6stat.icp6s_inhist[i] != 0) {
859			if (first) {
860				printf("\tInput packet histogram:\n");
861				first = 0;
862			}
863			printf("\t\t%s: %llu\n", icmp6names[i],
864			    (unsigned long long)icmp6stat.icp6s_inhist[i]);
865		}
866	printf("\tHistogram of error messages to be generated:\n");
867	p_5(icp6s_odst_unreach_noroute, "\t\t%llu no route\n");
868	p_5(icp6s_odst_unreach_admin, "\t\t%llu administratively prohibited\n");
869	p_5(icp6s_odst_unreach_beyondscope, "\t\t%llu beyond scope\n");
870	p_5(icp6s_odst_unreach_addr, "\t\t%llu address unreachable\n");
871	p_5(icp6s_odst_unreach_noport, "\t\t%llu port unreachable\n");
872	p_5(icp6s_opacket_too_big, "\t\t%llu packet too big\n");
873	p_5(icp6s_otime_exceed_transit, "\t\t%llu time exceed transit\n");
874	p_5(icp6s_otime_exceed_reassembly, "\t\t%llu time exceed reassembly\n");
875	p_5(icp6s_oparamprob_header, "\t\t%llu erroneous header field\n");
876	p_5(icp6s_oparamprob_nextheader, "\t\t%llu unrecognized next header\n");
877	p_5(icp6s_oparamprob_option, "\t\t%llu unrecognized option\n");
878	p_5(icp6s_oredirect, "\t\t%llu redirect\n");
879	p_5(icp6s_ounknown, "\t\t%llu unknown\n");
880
881	p(icp6s_reflect, "\t%llu message response%s generated\n");
882	p(icp6s_nd_toomanyopt, "\t%llu message%s with too many ND options\n");
883	p(icp6s_nd_badopt, "\t%llu message%s with bad ND options\n");
884	p(icp6s_badns, "\t%llu bad neighbor solicitation message%s\n");
885	p(icp6s_badna, "\t%llu bad neighbor advertisement message%s\n");
886	p(icp6s_badrs, "\t%llu bad router solicitation message%s\n");
887	p(icp6s_badra, "\t%llu bad router advertisement message%s\n");
888	p(icp6s_badredirect, "\t%llu bad redirect message%s\n");
889	p(icp6s_pmtuchg, "\t%llu path MTU change%s\n");
890#undef p
891#undef p_5
892}
893
894/*
895 * Dump ICMPv6 per-interface statistics based on RFC 2466.
896 */
897void
898icmp6_ifstats(char *ifname)
899{
900	struct in6_ifreq ifr;
901	int s;
902
903#define	p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \
904	printf(m, (unsigned long long)ifr.ifr_ifru.ifru_icmp6stat.f, \
905	    plural(ifr.ifr_ifru.ifru_icmp6stat.f))
906
907	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
908		perror("Warning: socket(AF_INET6)");
909		return;
910	}
911
912	strlcpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name);
913	printf("icmp6 on %s:\n", ifr.ifr_name);
914
915	if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) {
916		perror("Warning: ioctl(SIOCGIFSTAT_ICMP6)");
917		goto end;
918	}
919
920	p(ifs6_in_msg, "\t%llu total input message%s\n");
921	p(ifs6_in_error, "\t%llu total input error message%s\n");
922	p(ifs6_in_dstunreach, "\t%llu input destination unreachable error%s\n");
923	p(ifs6_in_adminprohib, "\t%llu input administratively prohibited error%s\n");
924	p(ifs6_in_timeexceed, "\t%llu input time exceeded error%s\n");
925	p(ifs6_in_paramprob, "\t%llu input parameter problem error%s\n");
926	p(ifs6_in_pkttoobig, "\t%llu input packet too big error%s\n");
927	p(ifs6_in_echo, "\t%llu input echo request%s\n");
928	p(ifs6_in_echoreply, "\t%llu input echo reply%s\n");
929	p(ifs6_in_routersolicit, "\t%llu input router solicitation%s\n");
930	p(ifs6_in_routeradvert, "\t%llu input router advertisement%s\n");
931	p(ifs6_in_neighborsolicit, "\t%llu input neighbor solicitation%s\n");
932	p(ifs6_in_neighboradvert, "\t%llu input neighbor advertisement%s\n");
933	p(ifs6_in_redirect, "\t%llu input redirect%s\n");
934	p(ifs6_in_mldquery, "\t%llu input MLD query%s\n");
935	p(ifs6_in_mldreport, "\t%llu input MLD report%s\n");
936	p(ifs6_in_mlddone, "\t%llu input MLD done%s\n");
937
938	p(ifs6_out_msg, "\t%llu total output message%s\n");
939	p(ifs6_out_error, "\t%llu total output error message%s\n");
940	p(ifs6_out_dstunreach, "\t%llu output destination unreachable error%s\n");
941	p(ifs6_out_adminprohib, "\t%llu output administratively prohibited error%s\n");
942	p(ifs6_out_timeexceed, "\t%llu output time exceeded error%s\n");
943	p(ifs6_out_paramprob, "\t%llu output parameter problem error%s\n");
944	p(ifs6_out_pkttoobig, "\t%llu output packet too big error%s\n");
945	p(ifs6_out_echo, "\t%llu output echo request%s\n");
946	p(ifs6_out_echoreply, "\t%llu output echo reply%s\n");
947	p(ifs6_out_routersolicit, "\t%llu output router solicitation%s\n");
948	p(ifs6_out_routeradvert, "\t%llu output router advertisement%s\n");
949	p(ifs6_out_neighborsolicit, "\t%llu output neighbor solicitation%s\n");
950	p(ifs6_out_neighboradvert, "\t%llu output neighbor advertisement%s\n");
951	p(ifs6_out_redirect, "\t%llu output redirect%s\n");
952	p(ifs6_out_mldquery, "\t%llu output MLD query%s\n");
953	p(ifs6_out_mldreport, "\t%llu output MLD report%s\n");
954	p(ifs6_out_mlddone, "\t%llu output MLD done%s\n");
955
956  end:
957	close(s);
958#undef p
959}
960
961/*
962 * Dump PIM statistics structure.
963 */
964void
965pim6_stats(u_long off, char *name)
966{
967	struct pim6stat pim6stat;
968
969	if (off == 0)
970		return;
971	kread(off, (char *)&pim6stat, sizeof(pim6stat));
972	printf("%s:\n", name);
973
974#define	p(f, m) if (pim6stat.f || sflag <= 1) \
975	printf(m, (unsigned long long)pim6stat.f, plural(pim6stat.f))
976
977	p(pim6s_rcv_total, "\t%llu message%s received\n");
978	p(pim6s_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
979	p(pim6s_rcv_badsum, "\t%llu message%s received with bad checksum\n");
980	p(pim6s_rcv_badversion, "\t%llu message%s received with bad version\n");
981	p(pim6s_rcv_registers, "\t%llu register%s received\n");
982	p(pim6s_rcv_badregisters, "\t%llu bad register%s received\n");
983	p(pim6s_snd_registers, "\t%llu register%s sent\n");
984#undef p
985}
986
987/*
988 * Dump raw ip6 statistics structure.
989 */
990void
991rip6_stats(u_long off, char *name)
992{
993	struct rip6stat rip6stat;
994	u_quad_t delivered;
995
996	if (off == 0)
997		return;
998	kread(off, (char *)&rip6stat, sizeof(rip6stat));
999	printf("%s:\n", name);
1000
1001#define	p(f, m) if (rip6stat.f || sflag <= 1) \
1002    printf(m, (unsigned long long)rip6stat.f, plural(rip6stat.f))
1003	p(rip6s_ipackets, "\t%llu message%s received\n");
1004	p(rip6s_isum, "\t%llu checksum calculation%s on inbound\n");
1005	p(rip6s_badsum, "\t%llu message%s with bad checksum\n");
1006	p(rip6s_nosock, "\t%llu message%s dropped due to no socket\n");
1007	p(rip6s_nosockmcast,
1008	    "\t%llu multicast message%s dropped due to no socket\n");
1009	p(rip6s_fullsock,
1010	    "\t%llu message%s dropped due to full socket buffers\n");
1011	delivered = rip6stat.rip6s_ipackets -
1012		    rip6stat.rip6s_badsum -
1013		    rip6stat.rip6s_nosock -
1014		    rip6stat.rip6s_nosockmcast -
1015		    rip6stat.rip6s_fullsock;
1016	if (delivered || sflag <= 1)
1017		printf("\t%llu delivered\n", (unsigned long long)delivered);
1018	p(rip6s_opackets, "\t%llu datagram%s output\n");
1019#undef p
1020}
1021
1022/*
1023 * Pretty print an Internet address (net address + port).
1024 * If the nflag was specified, use numbers instead of names.
1025 */
1026
1027void
1028inet6print(struct in6_addr *in6, int port, char *proto)
1029{
1030
1031#define GETSERVBYPORT6(port, proto, ret) do { \
1032	if (strcmp((proto), "tcp6") == 0) \
1033		(ret) = getservbyport((int)(port), "tcp"); \
1034	else if (strcmp((proto), "udp6") == 0) \
1035		(ret) = getservbyport((int)(port), "udp"); \
1036	else \
1037		(ret) = getservbyport((int)(port), (proto)); \
1038	} while (0)
1039
1040	struct servent *sp = 0;
1041	char line[80], *cp;
1042	int width;
1043	int len = sizeof line;
1044
1045	width = Aflag ? 12 : 16;
1046	if (vflag && width < strlen(inet6name(in6)))
1047		width = strlen(inet6name(in6));
1048	snprintf(line, len, "%.*s.", width, inet6name(in6));
1049	len -= strlen(line);
1050	if (len <= 0)
1051		goto bail;
1052
1053	cp = strchr(line, '\0');
1054	if (!nflag && port)
1055		GETSERVBYPORT6(port, proto, sp);
1056	if (sp || port == 0)
1057		snprintf(cp, len, "%.8s", sp ? sp->s_name : "*");
1058	else
1059		snprintf(cp, len, "%d", ntohs((u_short)port));
1060	width = Aflag ? 18 : 22;
1061	if (vflag && width < strlen(line))
1062		width = strlen(line);
1063bail:
1064	printf(" %-*.*s", width, width, line);
1065}
1066
1067/*
1068 * Construct an Internet address representation.
1069 * If the nflag has been supplied, give
1070 * numeric value, otherwise try for symbolic name.
1071 */
1072
1073char *
1074inet6name(struct in6_addr *in6p)
1075{
1076	char *cp;
1077	static char line[NI_MAXHOST];
1078	struct hostent *hp;
1079	static char domain[MAXHOSTNAMELEN];
1080	static int first = 1;
1081	char hbuf[NI_MAXHOST];
1082	struct sockaddr_in6 sin6;
1083#ifdef NI_WITHSCOPEID
1084	const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID;
1085#else
1086	const int niflag = NI_NUMERICHOST;
1087#endif
1088
1089	if (first && !nflag) {
1090		first = 0;
1091		if (gethostname(domain, sizeof(domain)) == 0 &&
1092		    (cp = strchr(domain, '.')))
1093			(void) strlcpy(domain, cp + 1, sizeof domain);
1094		else
1095			domain[0] = '\0';
1096	}
1097	cp = 0;
1098	if (!nflag && !IN6_IS_ADDR_UNSPECIFIED(in6p)) {
1099		hp = gethostbyaddr((char *)in6p, sizeof(*in6p), AF_INET6);
1100		if (hp) {
1101			if ((cp = strchr(hp->h_name, '.')) &&
1102			    !strcmp(cp + 1, domain))
1103				*cp = 0;
1104			cp = hp->h_name;
1105		}
1106	}
1107	if (IN6_IS_ADDR_UNSPECIFIED(in6p))
1108		strlcpy(line, "*", sizeof(line));
1109	else if (cp)
1110		strlcpy(line, cp, sizeof(line));
1111	else {
1112		memset(&sin6, 0, sizeof(sin6));
1113		sin6.sin6_len = sizeof(sin6);
1114		sin6.sin6_family = AF_INET6;
1115		sin6.sin6_addr = *in6p;
1116#ifdef __KAME__
1117		if (IN6_IS_ADDR_LINKLOCAL(in6p) ||
1118		    IN6_IS_ADDR_MC_LINKLOCAL(in6p)) {
1119			sin6.sin6_scope_id =
1120			    ntohs(*(u_int16_t *)&in6p->s6_addr[2]);
1121			sin6.sin6_addr.s6_addr[2] = 0;
1122			sin6.sin6_addr.s6_addr[3] = 0;
1123		}
1124#endif
1125		if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
1126		    hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
1127			strlcpy(hbuf, "?", sizeof hbuf);
1128		strlcpy(line, hbuf, sizeof(line));
1129	}
1130	return (line);
1131}
1132
1133#ifdef TCP6
1134/*
1135 * Dump the contents of a TCP6 PCB.
1136 */
1137void
1138tcp6_dump(u_long pcbaddr)
1139{
1140	struct tcp6cb tcp6cb;
1141	int i;
1142
1143	kread(pcbaddr, (char *)&tcp6cb, sizeof(tcp6cb));
1144
1145	printf("TCP Protocol Control Block at 0x%08lx:\n\n", pcbaddr);
1146
1147	printf("Timers:\n");
1148	for (i = 0; i < TCP6T_NTIMERS; i++)
1149		printf("\t%s: %u", tcp6timers[i], tcp6cb.t_timer[i]);
1150	printf("\n\n");
1151
1152	if (tcp6cb.t_state < 0 || tcp6cb.t_state >= TCP6_NSTATES)
1153		printf("State: %d", tcp6cb.t_state);
1154	else
1155		printf("State: %s", tcp6states[tcp6cb.t_state]);
1156	printf(", flags 0x%x, in6pcb 0x%lx\n\n", tcp6cb.t_flags,
1157	    (u_long)tcp6cb.t_in6pcb);
1158
1159	printf("rxtshift %d, rxtcur %d, dupacks %d\n", tcp6cb.t_rxtshift,
1160	    tcp6cb.t_rxtcur, tcp6cb.t_dupacks);
1161	printf("peermaxseg %u, maxseg %u, force %d\n\n", tcp6cb.t_peermaxseg,
1162	    tcp6cb.t_maxseg, tcp6cb.t_force);
1163
1164	printf("snd_una %u, snd_nxt %u, snd_up %u\n",
1165	    tcp6cb.snd_una, tcp6cb.snd_nxt, tcp6cb.snd_up);
1166	printf("snd_wl1 %u, snd_wl2 %u, iss %u, snd_wnd %lu\n\n",
1167	    tcp6cb.snd_wl1, tcp6cb.snd_wl2, tcp6cb.iss, tcp6cb.snd_wnd);
1168
1169	printf("rcv_wnd %lu, rcv_nxt %u, rcv_up %u, irs %u\n\n",
1170	    tcp6cb.rcv_wnd, tcp6cb.rcv_nxt, tcp6cb.rcv_up, tcp6cb.irs);
1171
1172	printf("rcv_adv %u, snd_max %u, snd_cwnd %lu, snd_ssthresh %lu\n",
1173	    tcp6cb.rcv_adv, tcp6cb.snd_max, tcp6cb.snd_cwnd, tcp6cb.snd_ssthresh);
1174
1175	printf("idle %d, rtt %d, rtseq %u, srtt %d, rttvar %d, rttmin %d, "
1176	    "max_sndwnd %lu\n\n", tcp6cb.t_idle, tcp6cb.t_rtt, tcp6cb.t_rtseq,
1177	    tcp6cb.t_srtt, tcp6cb.t_rttvar, tcp6cb.t_rttmin, tcp6cb.max_sndwnd);
1178
1179	printf("oobflags %d, iobc %d, softerror %d\n\n", tcp6cb.t_oobflags,
1180	    tcp6cb.t_iobc, tcp6cb.t_softerror);
1181
1182	printf("snd_scale %d, rcv_scale %d, req_r_scale %d, req_s_scale %d\n",
1183	    tcp6cb.snd_scale, tcp6cb.rcv_scale, tcp6cb.request_r_scale,
1184	    tcp6cb.requested_s_scale);
1185	printf("ts_recent %u, ts_regent_age %d, last_ack_sent %u\n",
1186	    tcp6cb.ts_recent, tcp6cb.ts_recent_age, tcp6cb.last_ack_sent);
1187}
1188#endif
1189
1190#endif /*INET6*/
1191