xref: /freebsd/usr.bin/netstat/inet6.c (revision c74c7b73a005e689b922dfcfe5b94804669b595b)
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
37 static 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$");
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 
77 struct	socket sockb;
78 
79 char	*inet6name(struct in6_addr *);
80 
81 static char ntop_buf[INET6_ADDRSTRLEN];
82 
83 static	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 
342 static 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  */
364 void
365 ip6_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 	p1a(ip6s_forward_cachehit, "\t%ju forward cache hit\n");
516 	p1a(ip6s_forward_cachemiss, "\t%ju forward cache miss\n");
517 	printf("\tSource addresses selection rule applied:\n");
518 	for (i = 0; i < 16; i++) {
519 		if (ip6stat.ip6s_sources_rule[i])
520 			printf("\t\t%ju %s\n",
521 			       (uintmax_t)ip6stat.ip6s_sources_rule[i],
522 			       srcrule_str[i]);
523 	}
524 #undef p
525 #undef p1a
526 }
527 
528 /*
529  * Dump IPv6 per-interface statistics based on RFC 2465.
530  */
531 void
532 ip6_ifstats(char *ifname)
533 {
534 	struct in6_ifreq ifr;
535 	int s;
536 #define	p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
537     printf(m, (uintmax_t)ifr.ifr_ifru.ifru_stat.f, plural(ifr.ifr_ifru.ifru_stat.f))
538 #define	p_5(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
539     printf(m, (uintmax_t)ip6stat.f)
540 
541 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
542 		perror("Warning: socket(AF_INET6)");
543 		return;
544 	}
545 
546 	strcpy(ifr.ifr_name, ifname);
547 	printf("ip6 on %s:\n", ifr.ifr_name);
548 
549 	if (ioctl(s, SIOCGIFSTAT_IN6, (char *)&ifr) < 0) {
550 		perror("Warning: ioctl(SIOCGIFSTAT_IN6)");
551 		goto end;
552 	}
553 
554 	p(ifs6_in_receive, "\t%ju total input datagram%s\n");
555 	p(ifs6_in_hdrerr, "\t%ju datagram%s with invalid header received\n");
556 	p(ifs6_in_toobig, "\t%ju datagram%s exceeded MTU received\n");
557 	p(ifs6_in_noroute, "\t%ju datagram%s with no route received\n");
558 	p(ifs6_in_addrerr, "\t%ju datagram%s with invalid dst received\n");
559 	p(ifs6_in_protounknown, "\t%ju datagram%s with unknown proto received\n");
560 	p(ifs6_in_truncated, "\t%ju truncated datagram%s received\n");
561 	p(ifs6_in_discard, "\t%ju input datagram%s discarded\n");
562 	p(ifs6_in_deliver,
563 	  "\t%ju datagram%s delivered to an upper layer protocol\n");
564 	p(ifs6_out_forward, "\t%ju datagram%s forwarded to this interface\n");
565 	p(ifs6_out_request,
566 	  "\t%ju datagram%s sent from an upper layer protocol\n");
567 	p(ifs6_out_discard, "\t%ju total discarded output datagram%s\n");
568 	p(ifs6_out_fragok, "\t%ju output datagram%s fragmented\n");
569 	p(ifs6_out_fragfail, "\t%ju output datagram%s failed on fragment\n");
570 	p(ifs6_out_fragcreat, "\t%ju output datagram%s succeeded on fragment\n");
571 	p(ifs6_reass_reqd, "\t%ju incoming datagram%s fragmented\n");
572 	p(ifs6_reass_ok, "\t%ju datagram%s reassembled\n");
573 	p(ifs6_reass_fail, "\t%ju datagram%s failed on reassembly\n");
574 	p(ifs6_in_mcast, "\t%ju multicast datagram%s received\n");
575 	p(ifs6_out_mcast, "\t%ju multicast datagram%s sent\n");
576 
577   end:
578 	close(s);
579 
580 #undef p
581 #undef p_5
582 }
583 
584 static	const char *icmp6names[] = {
585 	"#0",
586 	"unreach",
587 	"packet too big",
588 	"time exceed",
589 	"parameter problem",
590 	"#5",
591 	"#6",
592 	"#7",
593 	"#8",
594 	"#9",
595 	"#10",
596 	"#11",
597 	"#12",
598 	"#13",
599 	"#14",
600 	"#15",
601 	"#16",
602 	"#17",
603 	"#18",
604 	"#19",
605 	"#20",
606 	"#21",
607 	"#22",
608 	"#23",
609 	"#24",
610 	"#25",
611 	"#26",
612 	"#27",
613 	"#28",
614 	"#29",
615 	"#30",
616 	"#31",
617 	"#32",
618 	"#33",
619 	"#34",
620 	"#35",
621 	"#36",
622 	"#37",
623 	"#38",
624 	"#39",
625 	"#40",
626 	"#41",
627 	"#42",
628 	"#43",
629 	"#44",
630 	"#45",
631 	"#46",
632 	"#47",
633 	"#48",
634 	"#49",
635 	"#50",
636 	"#51",
637 	"#52",
638 	"#53",
639 	"#54",
640 	"#55",
641 	"#56",
642 	"#57",
643 	"#58",
644 	"#59",
645 	"#60",
646 	"#61",
647 	"#62",
648 	"#63",
649 	"#64",
650 	"#65",
651 	"#66",
652 	"#67",
653 	"#68",
654 	"#69",
655 	"#70",
656 	"#71",
657 	"#72",
658 	"#73",
659 	"#74",
660 	"#75",
661 	"#76",
662 	"#77",
663 	"#78",
664 	"#79",
665 	"#80",
666 	"#81",
667 	"#82",
668 	"#83",
669 	"#84",
670 	"#85",
671 	"#86",
672 	"#87",
673 	"#88",
674 	"#89",
675 	"#80",
676 	"#91",
677 	"#92",
678 	"#93",
679 	"#94",
680 	"#95",
681 	"#96",
682 	"#97",
683 	"#98",
684 	"#99",
685 	"#100",
686 	"#101",
687 	"#102",
688 	"#103",
689 	"#104",
690 	"#105",
691 	"#106",
692 	"#107",
693 	"#108",
694 	"#109",
695 	"#110",
696 	"#111",
697 	"#112",
698 	"#113",
699 	"#114",
700 	"#115",
701 	"#116",
702 	"#117",
703 	"#118",
704 	"#119",
705 	"#120",
706 	"#121",
707 	"#122",
708 	"#123",
709 	"#124",
710 	"#125",
711 	"#126",
712 	"#127",
713 	"echo",
714 	"echo reply",
715 	"multicast listener query",
716 	"multicast listener report",
717 	"multicast listener done",
718 	"router solicitation",
719 	"router advertisement",
720 	"neighbor solicitation",
721 	"neighbor advertisement",
722 	"redirect",
723 	"router renumbering",
724 	"node information request",
725 	"node information reply",
726 	"inverse neighbor solicitation",
727 	"inverse neighbor advertisement",
728 	"#143",
729 	"#144",
730 	"#145",
731 	"#146",
732 	"#147",
733 	"#148",
734 	"#149",
735 	"#150",
736 	"#151",
737 	"#152",
738 	"#153",
739 	"#154",
740 	"#155",
741 	"#156",
742 	"#157",
743 	"#158",
744 	"#159",
745 	"#160",
746 	"#161",
747 	"#162",
748 	"#163",
749 	"#164",
750 	"#165",
751 	"#166",
752 	"#167",
753 	"#168",
754 	"#169",
755 	"#170",
756 	"#171",
757 	"#172",
758 	"#173",
759 	"#174",
760 	"#175",
761 	"#176",
762 	"#177",
763 	"#178",
764 	"#179",
765 	"#180",
766 	"#181",
767 	"#182",
768 	"#183",
769 	"#184",
770 	"#185",
771 	"#186",
772 	"#187",
773 	"#188",
774 	"#189",
775 	"#180",
776 	"#191",
777 	"#192",
778 	"#193",
779 	"#194",
780 	"#195",
781 	"#196",
782 	"#197",
783 	"#198",
784 	"#199",
785 	"#200",
786 	"#201",
787 	"#202",
788 	"#203",
789 	"#204",
790 	"#205",
791 	"#206",
792 	"#207",
793 	"#208",
794 	"#209",
795 	"#210",
796 	"#211",
797 	"#212",
798 	"#213",
799 	"#214",
800 	"#215",
801 	"#216",
802 	"#217",
803 	"#218",
804 	"#219",
805 	"#220",
806 	"#221",
807 	"#222",
808 	"#223",
809 	"#224",
810 	"#225",
811 	"#226",
812 	"#227",
813 	"#228",
814 	"#229",
815 	"#230",
816 	"#231",
817 	"#232",
818 	"#233",
819 	"#234",
820 	"#235",
821 	"#236",
822 	"#237",
823 	"#238",
824 	"#239",
825 	"#240",
826 	"#241",
827 	"#242",
828 	"#243",
829 	"#244",
830 	"#245",
831 	"#246",
832 	"#247",
833 	"#248",
834 	"#249",
835 	"#250",
836 	"#251",
837 	"#252",
838 	"#253",
839 	"#254",
840 	"#255",
841 };
842 
843 /*
844  * Dump ICMP6 statistics.
845  */
846 void
847 icmp6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
848 {
849 	struct icmp6stat icmp6stat;
850 	int i, first;
851 	size_t len;
852 
853 	len = sizeof icmp6stat;
854 	if (live) {
855 		memset(&icmp6stat, 0, len);
856 		if (sysctlbyname("net.inet6.icmp6.stats", &icmp6stat, &len,
857 		    NULL, 0) < 0) {
858 			if (errno != ENOENT)
859 				warn("sysctl: net.inet6.icmp6.stats");
860 			return;
861 		}
862 	} else
863 		kread(off, &icmp6stat, len);
864 
865 	printf("%s:\n", name);
866 
867 #define	p(f, m) if (icmp6stat.f || sflag <= 1) \
868     printf(m, (uintmax_t)icmp6stat.f, plural(icmp6stat.f))
869 #define	p_5(f, m) if (icmp6stat.f || sflag <= 1) \
870     printf(m, (uintmax_t)icmp6stat.f)
871 
872 	p(icp6s_error, "\t%ju call%s to icmp6_error\n");
873 	p(icp6s_canterror,
874 	    "\t%ju error%s not generated in response to an icmp6 message\n");
875 	p(icp6s_toofreq,
876 	  "\t%ju error%s not generated because of rate limitation\n");
877 #define	NELEM (int)(sizeof(icmp6stat.icp6s_outhist)/sizeof(icmp6stat.icp6s_outhist[0]))
878 	for (first = 1, i = 0; i < NELEM; i++)
879 		if (icmp6stat.icp6s_outhist[i] != 0) {
880 			if (first) {
881 				printf("\tOutput histogram:\n");
882 				first = 0;
883 			}
884 			printf("\t\t%s: %ju\n", icmp6names[i],
885 			    (uintmax_t)icmp6stat.icp6s_outhist[i]);
886 		}
887 #undef NELEM
888 	p(icp6s_badcode, "\t%ju message%s with bad code fields\n");
889 	p(icp6s_tooshort, "\t%ju message%s < minimum length\n");
890 	p(icp6s_checksum, "\t%ju bad checksum%s\n");
891 	p(icp6s_badlen, "\t%ju message%s with bad length\n");
892 #define	NELEM (int)(sizeof(icmp6stat.icp6s_inhist)/sizeof(icmp6stat.icp6s_inhist[0]))
893 	for (first = 1, i = 0; i < NELEM; i++)
894 		if (icmp6stat.icp6s_inhist[i] != 0) {
895 			if (first) {
896 				printf("\tInput histogram:\n");
897 				first = 0;
898 			}
899 			printf("\t\t%s: %ju\n", icmp6names[i],
900 			    (uintmax_t)icmp6stat.icp6s_inhist[i]);
901 		}
902 #undef NELEM
903 	printf("\tHistogram of error messages to be generated:\n");
904 	p_5(icp6s_odst_unreach_noroute, "\t\t%ju no route\n");
905 	p_5(icp6s_odst_unreach_admin, "\t\t%ju administratively prohibited\n");
906 	p_5(icp6s_odst_unreach_beyondscope, "\t\t%ju beyond scope\n");
907 	p_5(icp6s_odst_unreach_addr, "\t\t%ju address unreachable\n");
908 	p_5(icp6s_odst_unreach_noport, "\t\t%ju port unreachable\n");
909 	p_5(icp6s_opacket_too_big, "\t\t%ju packet too big\n");
910 	p_5(icp6s_otime_exceed_transit, "\t\t%ju time exceed transit\n");
911 	p_5(icp6s_otime_exceed_reassembly, "\t\t%ju time exceed reassembly\n");
912 	p_5(icp6s_oparamprob_header, "\t\t%ju erroneous header field\n");
913 	p_5(icp6s_oparamprob_nextheader, "\t\t%ju unrecognized next header\n");
914 	p_5(icp6s_oparamprob_option, "\t\t%ju unrecognized option\n");
915 	p_5(icp6s_oredirect, "\t\t%ju redirect\n");
916 	p_5(icp6s_ounknown, "\t\t%ju unknown\n");
917 
918 	p(icp6s_reflect, "\t%ju message response%s generated\n");
919 	p(icp6s_nd_toomanyopt, "\t%ju message%s with too many ND options\n");
920 	p(icp6s_nd_badopt, "\t%ju message%s with bad ND options\n");
921 	p(icp6s_badns, "\t%ju bad neighbor solicitation message%s\n");
922 	p(icp6s_badna, "\t%ju bad neighbor advertisement message%s\n");
923 	p(icp6s_badrs, "\t%ju bad router solicitation message%s\n");
924 	p(icp6s_badra, "\t%ju bad router advertisement message%s\n");
925 	p(icp6s_badredirect, "\t%ju bad redirect message%s\n");
926 	p(icp6s_pmtuchg, "\t%ju path MTU change%s\n");
927 #undef p
928 #undef p_5
929 }
930 
931 /*
932  * Dump ICMPv6 per-interface statistics based on RFC 2466.
933  */
934 void
935 icmp6_ifstats(char *ifname)
936 {
937 	struct in6_ifreq ifr;
938 	int s;
939 #define	p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \
940     printf(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f, plural(ifr.ifr_ifru.ifru_icmp6stat.f))
941 #define	p2(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \
942     printf(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f, pluralies(ifr.ifr_ifru.ifru_icmp6stat.f))
943 
944 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
945 		perror("Warning: socket(AF_INET6)");
946 		return;
947 	}
948 
949 	strcpy(ifr.ifr_name, ifname);
950 	printf("icmp6 on %s:\n", ifr.ifr_name);
951 
952 	if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) {
953 		perror("Warning: ioctl(SIOCGIFSTAT_ICMP6)");
954 		goto end;
955 	}
956 
957 	p(ifs6_in_msg, "\t%ju total input message%s\n");
958 	p(ifs6_in_error, "\t%ju total input error message%s\n");
959 	p(ifs6_in_dstunreach, "\t%ju input destination unreachable error%s\n");
960 	p(ifs6_in_adminprohib, "\t%ju input administratively prohibited error%s\n");
961 	p(ifs6_in_timeexceed, "\t%ju input time exceeded error%s\n");
962 	p(ifs6_in_paramprob, "\t%ju input parameter problem error%s\n");
963 	p(ifs6_in_pkttoobig, "\t%ju input packet too big error%s\n");
964 	p(ifs6_in_echo, "\t%ju input echo request%s\n");
965 	p2(ifs6_in_echoreply, "\t%ju input echo repl%s\n");
966 	p(ifs6_in_routersolicit, "\t%ju input router solicitation%s\n");
967 	p(ifs6_in_routeradvert, "\t%ju input router advertisement%s\n");
968 	p(ifs6_in_neighborsolicit, "\t%ju input neighbor solicitation%s\n");
969 	p(ifs6_in_neighboradvert, "\t%ju input neighbor advertisement%s\n");
970 	p(ifs6_in_redirect, "\t%ju input redirect%s\n");
971 	p2(ifs6_in_mldquery, "\t%ju input MLD quer%s\n");
972 	p(ifs6_in_mldreport, "\t%ju input MLD report%s\n");
973 	p(ifs6_in_mlddone, "\t%ju input MLD done%s\n");
974 
975 	p(ifs6_out_msg, "\t%ju total output message%s\n");
976 	p(ifs6_out_error, "\t%ju total output error message%s\n");
977 	p(ifs6_out_dstunreach, "\t%ju output destination unreachable error%s\n");
978 	p(ifs6_out_adminprohib, "\t%ju output administratively prohibited error%s\n");
979 	p(ifs6_out_timeexceed, "\t%ju output time exceeded error%s\n");
980 	p(ifs6_out_paramprob, "\t%ju output parameter problem error%s\n");
981 	p(ifs6_out_pkttoobig, "\t%ju output packet too big error%s\n");
982 	p(ifs6_out_echo, "\t%ju output echo request%s\n");
983 	p2(ifs6_out_echoreply, "\t%ju output echo repl%s\n");
984 	p(ifs6_out_routersolicit, "\t%ju output router solicitation%s\n");
985 	p(ifs6_out_routeradvert, "\t%ju output router advertisement%s\n");
986 	p(ifs6_out_neighborsolicit, "\t%ju output neighbor solicitation%s\n");
987 	p(ifs6_out_neighboradvert, "\t%ju output neighbor advertisement%s\n");
988 	p(ifs6_out_redirect, "\t%ju output redirect%s\n");
989 	p2(ifs6_out_mldquery, "\t%ju output MLD quer%s\n");
990 	p(ifs6_out_mldreport, "\t%ju output MLD report%s\n");
991 	p(ifs6_out_mlddone, "\t%ju output MLD done%s\n");
992 
993   end:
994 	close(s);
995 #undef p
996 }
997 
998 /*
999  * Dump PIM statistics structure.
1000  */
1001 void
1002 pim6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
1003 {
1004 	struct pim6stat pim6stat, zerostat;
1005 	size_t len = sizeof pim6stat;
1006 
1007 	if (live) {
1008 		if (zflag)
1009 			memset(&zerostat, 0, len);
1010 		if (sysctlbyname("net.inet6.pim.stats", &pim6stat, &len,
1011 		    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
1012 			if (errno != ENOENT)
1013 				warn("sysctl: net.inet6.pim.stats");
1014 			return;
1015 		}
1016 	} else {
1017 		if (off == 0)
1018 			return;
1019 		kread(off, &pim6stat, len);
1020 	}
1021 
1022 	printf("%s:\n", name);
1023 
1024 #define	p(f, m) if (pim6stat.f || sflag <= 1) \
1025     printf(m, (uintmax_t)pim6stat.f, plural(pim6stat.f))
1026 	p(pim6s_rcv_total, "\t%ju message%s received\n");
1027 	p(pim6s_rcv_tooshort, "\t%ju message%s received with too few bytes\n");
1028 	p(pim6s_rcv_badsum, "\t%ju message%s received with bad checksum\n");
1029 	p(pim6s_rcv_badversion, "\t%ju message%s received with bad version\n");
1030 	p(pim6s_rcv_registers, "\t%ju register%s received\n");
1031 	p(pim6s_rcv_badregisters, "\t%ju bad register%s received\n");
1032 	p(pim6s_snd_registers, "\t%ju register%s sent\n");
1033 #undef p
1034 }
1035 
1036 /*
1037  * Dump raw ip6 statistics structure.
1038  */
1039 void
1040 rip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
1041 {
1042 	struct rip6stat rip6stat;
1043 	u_quad_t delivered;
1044 	size_t len;
1045 
1046 	len = sizeof(rip6stat);
1047 	if (live) {
1048 		if (sysctlbyname("net.inet6.ip6.rip6stats", &rip6stat, &len,
1049 		    NULL, 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 
1094 void
1095 inet6print(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 = index(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 
1120 char *
1121 inet6name(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 = index(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 = index(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