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