xref: /freebsd/usr.bin/netstat/inet6.c (revision 884a2a699669ec61e2366e3e358342dbc94be24a)
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
33 static 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$");
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 
73 struct	socket sockb;
74 
75 char	*inet6name(struct in6_addr *);
76 
77 static char ntop_buf[INET6_ADDRSTRLEN];
78 
79 static	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 
338 static 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  */
360 void
361 ip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
362 {
363 	struct ip6stat ip6stat;
364 	int first, i;
365 	size_t len;
366 
367 	len = sizeof ip6stat;
368 	if (live) {
369 		memset(&ip6stat, 0, len);
370 		if (sysctlbyname("net.inet6.ip6.stats", &ip6stat, &len, NULL,
371 		    0) < 0) {
372 			if (errno != ENOENT)
373 				warn("sysctl: net.inet6.ip6.stats");
374 			return;
375 		}
376 	} else
377 		kread(off, &ip6stat, len);
378 
379 	printf("%s:\n", name);
380 
381 #define	p(f, m) if (ip6stat.f || sflag <= 1) \
382     printf(m, (uintmax_t)ip6stat.f, plural(ip6stat.f))
383 #define	p1a(f, m) if (ip6stat.f || sflag <= 1) \
384     printf(m, (uintmax_t)ip6stat.f)
385 
386 	p(ip6s_total, "\t%ju total packet%s received\n");
387 	p1a(ip6s_toosmall, "\t%ju with size smaller than minimum\n");
388 	p1a(ip6s_tooshort, "\t%ju with data size < data length\n");
389 	p1a(ip6s_badoptions, "\t%ju with bad options\n");
390 	p1a(ip6s_badvers, "\t%ju with incorrect version number\n");
391 	p(ip6s_fragments, "\t%ju fragment%s received\n");
392 	p(ip6s_fragdropped, "\t%ju fragment%s dropped (dup or out of space)\n");
393 	p(ip6s_fragtimeout, "\t%ju fragment%s dropped after timeout\n");
394 	p(ip6s_fragoverflow, "\t%ju fragment%s that exceeded limit\n");
395 	p(ip6s_reassembled, "\t%ju packet%s reassembled ok\n");
396 	p(ip6s_delivered, "\t%ju packet%s for this host\n");
397 	p(ip6s_forward, "\t%ju packet%s forwarded\n");
398 	p(ip6s_cantforward, "\t%ju packet%s not forwardable\n");
399 	p(ip6s_redirectsent, "\t%ju redirect%s sent\n");
400 	p(ip6s_localout, "\t%ju packet%s sent from this host\n");
401 	p(ip6s_rawout, "\t%ju packet%s sent with fabricated ip header\n");
402 	p(ip6s_odropped, "\t%ju output packet%s dropped due to no bufs, etc.\n");
403 	p(ip6s_noroute, "\t%ju output packet%s discarded due to no route\n");
404 	p(ip6s_fragmented, "\t%ju output datagram%s fragmented\n");
405 	p(ip6s_ofragments, "\t%ju fragment%s created\n");
406 	p(ip6s_cantfrag, "\t%ju datagram%s that can't be fragmented\n");
407 	p(ip6s_badscope, "\t%ju packet%s that violated scope rules\n");
408 	p(ip6s_notmember, "\t%ju multicast packet%s which we don't join\n");
409 	for (first = 1, i = 0; i < 256; i++)
410 		if (ip6stat.ip6s_nxthist[i] != 0) {
411 			if (first) {
412 				printf("\tInput histogram:\n");
413 				first = 0;
414 			}
415 			printf("\t\t%s: %ju\n", ip6nh[i],
416 			    (uintmax_t)ip6stat.ip6s_nxthist[i]);
417 		}
418 	printf("\tMbuf statistics:\n");
419 	printf("\t\t%ju one mbuf\n", (uintmax_t)ip6stat.ip6s_m1);
420 	for (first = 1, i = 0; i < 32; i++) {
421 		char ifbuf[IFNAMSIZ];
422 		if (ip6stat.ip6s_m2m[i] != 0) {
423 			if (first) {
424 				printf("\t\ttwo or more mbuf:\n");
425 				first = 0;
426 			}
427 			printf("\t\t\t%s= %ju\n",
428 			    if_indextoname(i, ifbuf),
429 			    (uintmax_t)ip6stat.ip6s_m2m[i]);
430 		}
431 	}
432 	printf("\t\t%ju one ext mbuf\n",
433 	    (uintmax_t)ip6stat.ip6s_mext1);
434 	printf("\t\t%ju two or more ext mbuf\n",
435 	    (uintmax_t)ip6stat.ip6s_mext2m);
436 	p(ip6s_exthdrtoolong,
437 	    "\t%ju packet%s whose headers are not contiguous\n");
438 	p(ip6s_nogif, "\t%ju tunneling packet%s that can't find gif\n");
439 	p(ip6s_toomanyhdr,
440 	    "\t%ju packet%s discarded because of too many headers\n");
441 
442 	/* for debugging source address selection */
443 #define	PRINT_SCOPESTAT(s,i) do {\
444 		switch(i) { /* XXX hardcoding in each case */\
445 		case 1:\
446 			p(s, "\t\t%ju node-local%s\n");\
447 			break;\
448 		case 2:\
449 			p(s,"\t\t%ju link-local%s\n");\
450 			break;\
451 		case 5:\
452 			p(s,"\t\t%ju site-local%s\n");\
453 			break;\
454 		case 14:\
455 			p(s,"\t\t%ju global%s\n");\
456 			break;\
457 		default:\
458 			printf("\t\t%ju addresses scope=%x\n",\
459 			    (uintmax_t)ip6stat.s, i);\
460 		}\
461 	} while (0);
462 
463 	p(ip6s_sources_none,
464 	  "\t%ju failure%s of source address selection\n");
465 	for (first = 1, i = 0; i < 16; i++) {
466 		if (ip6stat.ip6s_sources_sameif[i]) {
467 			if (first) {
468 				printf("\tsource addresses on an outgoing I/F\n");
469 				first = 0;
470 			}
471 			PRINT_SCOPESTAT(ip6s_sources_sameif[i], i);
472 		}
473 	}
474 	for (first = 1, i = 0; i < 16; i++) {
475 		if (ip6stat.ip6s_sources_otherif[i]) {
476 			if (first) {
477 				printf("\tsource addresses on a non-outgoing I/F\n");
478 				first = 0;
479 			}
480 			PRINT_SCOPESTAT(ip6s_sources_otherif[i], i);
481 		}
482 	}
483 	for (first = 1, i = 0; i < 16; i++) {
484 		if (ip6stat.ip6s_sources_samescope[i]) {
485 			if (first) {
486 				printf("\tsource addresses of same scope\n");
487 				first = 0;
488 			}
489 			PRINT_SCOPESTAT(ip6s_sources_samescope[i], i);
490 		}
491 	}
492 	for (first = 1, i = 0; i < 16; i++) {
493 		if (ip6stat.ip6s_sources_otherscope[i]) {
494 			if (first) {
495 				printf("\tsource addresses of a different scope\n");
496 				first = 0;
497 			}
498 			PRINT_SCOPESTAT(ip6s_sources_otherscope[i], i);
499 		}
500 	}
501 	for (first = 1, i = 0; i < 16; i++) {
502 		if (ip6stat.ip6s_sources_deprecated[i]) {
503 			if (first) {
504 				printf("\tdeprecated source addresses\n");
505 				first = 0;
506 			}
507 			PRINT_SCOPESTAT(ip6s_sources_deprecated[i], i);
508 		}
509 	}
510 
511 	printf("\tSource addresses selection rule applied:\n");
512 	for (i = 0; i < 16; i++) {
513 		if (ip6stat.ip6s_sources_rule[i])
514 			printf("\t\t%ju %s\n",
515 			       (uintmax_t)ip6stat.ip6s_sources_rule[i],
516 			       srcrule_str[i]);
517 	}
518 #undef p
519 #undef p1a
520 }
521 
522 /*
523  * Dump IPv6 per-interface statistics based on RFC 2465.
524  */
525 void
526 ip6_ifstats(char *ifname)
527 {
528 	struct in6_ifreq ifr;
529 	int s;
530 #define	p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
531     printf(m, (uintmax_t)ifr.ifr_ifru.ifru_stat.f, plural(ifr.ifr_ifru.ifru_stat.f))
532 #define	p_5(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
533     printf(m, (uintmax_t)ip6stat.f)
534 
535 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
536 		perror("Warning: socket(AF_INET6)");
537 		return;
538 	}
539 
540 	strcpy(ifr.ifr_name, ifname);
541 	printf("ip6 on %s:\n", ifr.ifr_name);
542 
543 	if (ioctl(s, SIOCGIFSTAT_IN6, (char *)&ifr) < 0) {
544 		perror("Warning: ioctl(SIOCGIFSTAT_IN6)");
545 		goto end;
546 	}
547 
548 	p(ifs6_in_receive, "\t%ju total input datagram%s\n");
549 	p(ifs6_in_hdrerr, "\t%ju datagram%s with invalid header received\n");
550 	p(ifs6_in_toobig, "\t%ju datagram%s exceeded MTU received\n");
551 	p(ifs6_in_noroute, "\t%ju datagram%s with no route received\n");
552 	p(ifs6_in_addrerr, "\t%ju datagram%s with invalid dst received\n");
553 	p(ifs6_in_protounknown, "\t%ju datagram%s with unknown proto received\n");
554 	p(ifs6_in_truncated, "\t%ju truncated datagram%s received\n");
555 	p(ifs6_in_discard, "\t%ju input datagram%s discarded\n");
556 	p(ifs6_in_deliver,
557 	  "\t%ju datagram%s delivered to an upper layer protocol\n");
558 	p(ifs6_out_forward, "\t%ju datagram%s forwarded to this interface\n");
559 	p(ifs6_out_request,
560 	  "\t%ju datagram%s sent from an upper layer protocol\n");
561 	p(ifs6_out_discard, "\t%ju total discarded output datagram%s\n");
562 	p(ifs6_out_fragok, "\t%ju output datagram%s fragmented\n");
563 	p(ifs6_out_fragfail, "\t%ju output datagram%s failed on fragment\n");
564 	p(ifs6_out_fragcreat, "\t%ju output datagram%s succeeded on fragment\n");
565 	p(ifs6_reass_reqd, "\t%ju incoming datagram%s fragmented\n");
566 	p(ifs6_reass_ok, "\t%ju datagram%s reassembled\n");
567 	p(ifs6_reass_fail, "\t%ju datagram%s failed on reassembly\n");
568 	p(ifs6_in_mcast, "\t%ju multicast datagram%s received\n");
569 	p(ifs6_out_mcast, "\t%ju multicast datagram%s sent\n");
570 
571   end:
572 	close(s);
573 
574 #undef p
575 #undef p_5
576 }
577 
578 static	const char *icmp6names[] = {
579 	"#0",
580 	"unreach",
581 	"packet too big",
582 	"time exceed",
583 	"parameter problem",
584 	"#5",
585 	"#6",
586 	"#7",
587 	"#8",
588 	"#9",
589 	"#10",
590 	"#11",
591 	"#12",
592 	"#13",
593 	"#14",
594 	"#15",
595 	"#16",
596 	"#17",
597 	"#18",
598 	"#19",
599 	"#20",
600 	"#21",
601 	"#22",
602 	"#23",
603 	"#24",
604 	"#25",
605 	"#26",
606 	"#27",
607 	"#28",
608 	"#29",
609 	"#30",
610 	"#31",
611 	"#32",
612 	"#33",
613 	"#34",
614 	"#35",
615 	"#36",
616 	"#37",
617 	"#38",
618 	"#39",
619 	"#40",
620 	"#41",
621 	"#42",
622 	"#43",
623 	"#44",
624 	"#45",
625 	"#46",
626 	"#47",
627 	"#48",
628 	"#49",
629 	"#50",
630 	"#51",
631 	"#52",
632 	"#53",
633 	"#54",
634 	"#55",
635 	"#56",
636 	"#57",
637 	"#58",
638 	"#59",
639 	"#60",
640 	"#61",
641 	"#62",
642 	"#63",
643 	"#64",
644 	"#65",
645 	"#66",
646 	"#67",
647 	"#68",
648 	"#69",
649 	"#70",
650 	"#71",
651 	"#72",
652 	"#73",
653 	"#74",
654 	"#75",
655 	"#76",
656 	"#77",
657 	"#78",
658 	"#79",
659 	"#80",
660 	"#81",
661 	"#82",
662 	"#83",
663 	"#84",
664 	"#85",
665 	"#86",
666 	"#87",
667 	"#88",
668 	"#89",
669 	"#80",
670 	"#91",
671 	"#92",
672 	"#93",
673 	"#94",
674 	"#95",
675 	"#96",
676 	"#97",
677 	"#98",
678 	"#99",
679 	"#100",
680 	"#101",
681 	"#102",
682 	"#103",
683 	"#104",
684 	"#105",
685 	"#106",
686 	"#107",
687 	"#108",
688 	"#109",
689 	"#110",
690 	"#111",
691 	"#112",
692 	"#113",
693 	"#114",
694 	"#115",
695 	"#116",
696 	"#117",
697 	"#118",
698 	"#119",
699 	"#120",
700 	"#121",
701 	"#122",
702 	"#123",
703 	"#124",
704 	"#125",
705 	"#126",
706 	"#127",
707 	"echo",
708 	"echo reply",
709 	"multicast listener query",
710 	"MLDv1 listener report",
711 	"MLDv1 listener done",
712 	"router solicitation",
713 	"router advertisement",
714 	"neighbor solicitation",
715 	"neighbor advertisement",
716 	"redirect",
717 	"router renumbering",
718 	"node information request",
719 	"node information reply",
720 	"inverse neighbor solicitation",
721 	"inverse neighbor advertisement",
722 	"MLDv2 listener report",
723 	"#144",
724 	"#145",
725 	"#146",
726 	"#147",
727 	"#148",
728 	"#149",
729 	"#150",
730 	"#151",
731 	"#152",
732 	"#153",
733 	"#154",
734 	"#155",
735 	"#156",
736 	"#157",
737 	"#158",
738 	"#159",
739 	"#160",
740 	"#161",
741 	"#162",
742 	"#163",
743 	"#164",
744 	"#165",
745 	"#166",
746 	"#167",
747 	"#168",
748 	"#169",
749 	"#170",
750 	"#171",
751 	"#172",
752 	"#173",
753 	"#174",
754 	"#175",
755 	"#176",
756 	"#177",
757 	"#178",
758 	"#179",
759 	"#180",
760 	"#181",
761 	"#182",
762 	"#183",
763 	"#184",
764 	"#185",
765 	"#186",
766 	"#187",
767 	"#188",
768 	"#189",
769 	"#180",
770 	"#191",
771 	"#192",
772 	"#193",
773 	"#194",
774 	"#195",
775 	"#196",
776 	"#197",
777 	"#198",
778 	"#199",
779 	"#200",
780 	"#201",
781 	"#202",
782 	"#203",
783 	"#204",
784 	"#205",
785 	"#206",
786 	"#207",
787 	"#208",
788 	"#209",
789 	"#210",
790 	"#211",
791 	"#212",
792 	"#213",
793 	"#214",
794 	"#215",
795 	"#216",
796 	"#217",
797 	"#218",
798 	"#219",
799 	"#220",
800 	"#221",
801 	"#222",
802 	"#223",
803 	"#224",
804 	"#225",
805 	"#226",
806 	"#227",
807 	"#228",
808 	"#229",
809 	"#230",
810 	"#231",
811 	"#232",
812 	"#233",
813 	"#234",
814 	"#235",
815 	"#236",
816 	"#237",
817 	"#238",
818 	"#239",
819 	"#240",
820 	"#241",
821 	"#242",
822 	"#243",
823 	"#244",
824 	"#245",
825 	"#246",
826 	"#247",
827 	"#248",
828 	"#249",
829 	"#250",
830 	"#251",
831 	"#252",
832 	"#253",
833 	"#254",
834 	"#255",
835 };
836 
837 /*
838  * Dump ICMP6 statistics.
839  */
840 void
841 icmp6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
842 {
843 	struct icmp6stat icmp6stat;
844 	int i, first;
845 	size_t len;
846 
847 	len = sizeof icmp6stat;
848 	if (live) {
849 		memset(&icmp6stat, 0, len);
850 		if (sysctlbyname("net.inet6.icmp6.stats", &icmp6stat, &len,
851 		    NULL, 0) < 0) {
852 			if (errno != ENOENT)
853 				warn("sysctl: net.inet6.icmp6.stats");
854 			return;
855 		}
856 	} else
857 		kread(off, &icmp6stat, len);
858 
859 	printf("%s:\n", name);
860 
861 #define	p(f, m) if (icmp6stat.f || sflag <= 1) \
862     printf(m, (uintmax_t)icmp6stat.f, plural(icmp6stat.f))
863 #define	p_5(f, m) if (icmp6stat.f || sflag <= 1) \
864     printf(m, (uintmax_t)icmp6stat.f)
865 
866 	p(icp6s_error, "\t%ju call%s to icmp6_error\n");
867 	p(icp6s_canterror,
868 	    "\t%ju error%s not generated in response to an icmp6 message\n");
869 	p(icp6s_toofreq,
870 	  "\t%ju error%s not generated because of rate limitation\n");
871 #define	NELEM (int)(sizeof(icmp6stat.icp6s_outhist)/sizeof(icmp6stat.icp6s_outhist[0]))
872 	for (first = 1, i = 0; i < NELEM; i++)
873 		if (icmp6stat.icp6s_outhist[i] != 0) {
874 			if (first) {
875 				printf("\tOutput histogram:\n");
876 				first = 0;
877 			}
878 			printf("\t\t%s: %ju\n", icmp6names[i],
879 			    (uintmax_t)icmp6stat.icp6s_outhist[i]);
880 		}
881 #undef NELEM
882 	p(icp6s_badcode, "\t%ju message%s with bad code fields\n");
883 	p(icp6s_tooshort, "\t%ju message%s < minimum length\n");
884 	p(icp6s_checksum, "\t%ju bad checksum%s\n");
885 	p(icp6s_badlen, "\t%ju message%s with bad length\n");
886 #define	NELEM (int)(sizeof(icmp6stat.icp6s_inhist)/sizeof(icmp6stat.icp6s_inhist[0]))
887 	for (first = 1, i = 0; i < NELEM; i++)
888 		if (icmp6stat.icp6s_inhist[i] != 0) {
889 			if (first) {
890 				printf("\tInput histogram:\n");
891 				first = 0;
892 			}
893 			printf("\t\t%s: %ju\n", icmp6names[i],
894 			    (uintmax_t)icmp6stat.icp6s_inhist[i]);
895 		}
896 #undef NELEM
897 	printf("\tHistogram of error messages to be generated:\n");
898 	p_5(icp6s_odst_unreach_noroute, "\t\t%ju no route\n");
899 	p_5(icp6s_odst_unreach_admin, "\t\t%ju administratively prohibited\n");
900 	p_5(icp6s_odst_unreach_beyondscope, "\t\t%ju beyond scope\n");
901 	p_5(icp6s_odst_unreach_addr, "\t\t%ju address unreachable\n");
902 	p_5(icp6s_odst_unreach_noport, "\t\t%ju port unreachable\n");
903 	p_5(icp6s_opacket_too_big, "\t\t%ju packet too big\n");
904 	p_5(icp6s_otime_exceed_transit, "\t\t%ju time exceed transit\n");
905 	p_5(icp6s_otime_exceed_reassembly, "\t\t%ju time exceed reassembly\n");
906 	p_5(icp6s_oparamprob_header, "\t\t%ju erroneous header field\n");
907 	p_5(icp6s_oparamprob_nextheader, "\t\t%ju unrecognized next header\n");
908 	p_5(icp6s_oparamprob_option, "\t\t%ju unrecognized option\n");
909 	p_5(icp6s_oredirect, "\t\t%ju redirect\n");
910 	p_5(icp6s_ounknown, "\t\t%ju unknown\n");
911 
912 	p(icp6s_reflect, "\t%ju message response%s generated\n");
913 	p(icp6s_nd_toomanyopt, "\t%ju message%s with too many ND options\n");
914 	p(icp6s_nd_badopt, "\t%ju message%s with bad ND options\n");
915 	p(icp6s_badns, "\t%ju bad neighbor solicitation message%s\n");
916 	p(icp6s_badna, "\t%ju bad neighbor advertisement message%s\n");
917 	p(icp6s_badrs, "\t%ju bad router solicitation message%s\n");
918 	p(icp6s_badra, "\t%ju bad router advertisement message%s\n");
919 	p(icp6s_badredirect, "\t%ju bad redirect message%s\n");
920 	p(icp6s_pmtuchg, "\t%ju path MTU change%s\n");
921 #undef p
922 #undef p_5
923 }
924 
925 /*
926  * Dump ICMPv6 per-interface statistics based on RFC 2466.
927  */
928 void
929 icmp6_ifstats(char *ifname)
930 {
931 	struct in6_ifreq ifr;
932 	int s;
933 #define	p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \
934     printf(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f, plural(ifr.ifr_ifru.ifru_icmp6stat.f))
935 #define	p2(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \
936     printf(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f, pluralies(ifr.ifr_ifru.ifru_icmp6stat.f))
937 
938 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
939 		perror("Warning: socket(AF_INET6)");
940 		return;
941 	}
942 
943 	strcpy(ifr.ifr_name, ifname);
944 	printf("icmp6 on %s:\n", ifr.ifr_name);
945 
946 	if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) {
947 		perror("Warning: ioctl(SIOCGIFSTAT_ICMP6)");
948 		goto end;
949 	}
950 
951 	p(ifs6_in_msg, "\t%ju total input message%s\n");
952 	p(ifs6_in_error, "\t%ju total input error message%s\n");
953 	p(ifs6_in_dstunreach, "\t%ju input destination unreachable error%s\n");
954 	p(ifs6_in_adminprohib, "\t%ju input administratively prohibited error%s\n");
955 	p(ifs6_in_timeexceed, "\t%ju input time exceeded error%s\n");
956 	p(ifs6_in_paramprob, "\t%ju input parameter problem error%s\n");
957 	p(ifs6_in_pkttoobig, "\t%ju input packet too big error%s\n");
958 	p(ifs6_in_echo, "\t%ju input echo request%s\n");
959 	p2(ifs6_in_echoreply, "\t%ju input echo repl%s\n");
960 	p(ifs6_in_routersolicit, "\t%ju input router solicitation%s\n");
961 	p(ifs6_in_routeradvert, "\t%ju input router advertisement%s\n");
962 	p(ifs6_in_neighborsolicit, "\t%ju input neighbor solicitation%s\n");
963 	p(ifs6_in_neighboradvert, "\t%ju input neighbor advertisement%s\n");
964 	p(ifs6_in_redirect, "\t%ju input redirect%s\n");
965 	p2(ifs6_in_mldquery, "\t%ju input MLD quer%s\n");
966 	p(ifs6_in_mldreport, "\t%ju input MLD report%s\n");
967 	p(ifs6_in_mlddone, "\t%ju input MLD done%s\n");
968 
969 	p(ifs6_out_msg, "\t%ju total output message%s\n");
970 	p(ifs6_out_error, "\t%ju total output error message%s\n");
971 	p(ifs6_out_dstunreach, "\t%ju output destination unreachable error%s\n");
972 	p(ifs6_out_adminprohib, "\t%ju output administratively prohibited error%s\n");
973 	p(ifs6_out_timeexceed, "\t%ju output time exceeded error%s\n");
974 	p(ifs6_out_paramprob, "\t%ju output parameter problem error%s\n");
975 	p(ifs6_out_pkttoobig, "\t%ju output packet too big error%s\n");
976 	p(ifs6_out_echo, "\t%ju output echo request%s\n");
977 	p2(ifs6_out_echoreply, "\t%ju output echo repl%s\n");
978 	p(ifs6_out_routersolicit, "\t%ju output router solicitation%s\n");
979 	p(ifs6_out_routeradvert, "\t%ju output router advertisement%s\n");
980 	p(ifs6_out_neighborsolicit, "\t%ju output neighbor solicitation%s\n");
981 	p(ifs6_out_neighboradvert, "\t%ju output neighbor advertisement%s\n");
982 	p(ifs6_out_redirect, "\t%ju output redirect%s\n");
983 	p2(ifs6_out_mldquery, "\t%ju output MLD quer%s\n");
984 	p(ifs6_out_mldreport, "\t%ju output MLD report%s\n");
985 	p(ifs6_out_mlddone, "\t%ju output MLD done%s\n");
986 
987   end:
988 	close(s);
989 #undef p
990 }
991 
992 /*
993  * Dump PIM statistics structure.
994  */
995 void
996 pim6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
997 {
998 	struct pim6stat pim6stat, zerostat;
999 	size_t len = sizeof pim6stat;
1000 
1001 	if (live) {
1002 		if (zflag)
1003 			memset(&zerostat, 0, len);
1004 		if (sysctlbyname("net.inet6.pim.stats", &pim6stat, &len,
1005 		    zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
1006 			if (errno != ENOENT)
1007 				warn("sysctl: net.inet6.pim.stats");
1008 			return;
1009 		}
1010 	} else {
1011 		if (off == 0)
1012 			return;
1013 		kread(off, &pim6stat, len);
1014 	}
1015 
1016 	printf("%s:\n", name);
1017 
1018 #define	p(f, m) if (pim6stat.f || sflag <= 1) \
1019     printf(m, (uintmax_t)pim6stat.f, plural(pim6stat.f))
1020 	p(pim6s_rcv_total, "\t%ju message%s received\n");
1021 	p(pim6s_rcv_tooshort, "\t%ju message%s received with too few bytes\n");
1022 	p(pim6s_rcv_badsum, "\t%ju message%s received with bad checksum\n");
1023 	p(pim6s_rcv_badversion, "\t%ju message%s received with bad version\n");
1024 	p(pim6s_rcv_registers, "\t%ju register%s received\n");
1025 	p(pim6s_rcv_badregisters, "\t%ju bad register%s received\n");
1026 	p(pim6s_snd_registers, "\t%ju register%s sent\n");
1027 #undef p
1028 }
1029 
1030 /*
1031  * Dump raw ip6 statistics structure.
1032  */
1033 void
1034 rip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
1035 {
1036 	struct rip6stat rip6stat;
1037 	u_quad_t delivered;
1038 	size_t len;
1039 
1040 	len = sizeof(rip6stat);
1041 	if (live) {
1042 		if (sysctlbyname("net.inet6.ip6.rip6stats", &rip6stat, &len,
1043 		    NULL, 0) < 0) {
1044 			if (errno != ENOENT)
1045 				warn("sysctl: net.inet6.ip6.rip6stats");
1046 			return;
1047 		}
1048 	} else
1049 		kread(off, &rip6stat, len);
1050 
1051 	printf("%s:\n", name);
1052 
1053 #define	p(f, m) if (rip6stat.f || sflag <= 1) \
1054     printf(m, (uintmax_t)rip6stat.f, plural(rip6stat.f))
1055 	p(rip6s_ipackets, "\t%ju message%s received\n");
1056 	p(rip6s_isum, "\t%ju checksum calculation%s on inbound\n");
1057 	p(rip6s_badsum, "\t%ju message%s with bad checksum\n");
1058 	p(rip6s_nosock, "\t%ju message%s dropped due to no socket\n");
1059 	p(rip6s_nosockmcast,
1060 	    "\t%ju multicast message%s dropped due to no socket\n");
1061 	p(rip6s_fullsock,
1062 	    "\t%ju message%s dropped due to full socket buffers\n");
1063 	delivered = rip6stat.rip6s_ipackets -
1064 		    rip6stat.rip6s_badsum -
1065 		    rip6stat.rip6s_nosock -
1066 		    rip6stat.rip6s_nosockmcast -
1067 		    rip6stat.rip6s_fullsock;
1068 	if (delivered || sflag <= 1)
1069 		printf("\t%ju delivered\n", (uintmax_t)delivered);
1070 	p(rip6s_opackets, "\t%ju datagram%s output\n");
1071 #undef p
1072 }
1073 
1074 /*
1075  * Pretty print an Internet address (net address + port).
1076  * Take numeric_addr and numeric_port into consideration.
1077  */
1078 #define	GETSERVBYPORT6(port, proto, ret)\
1079 {\
1080 	if (strcmp((proto), "tcp6") == 0)\
1081 		(ret) = getservbyport((int)(port), "tcp");\
1082 	else if (strcmp((proto), "udp6") == 0)\
1083 		(ret) = getservbyport((int)(port), "udp");\
1084 	else\
1085 		(ret) = getservbyport((int)(port), (proto));\
1086 };
1087 
1088 void
1089 inet6print(struct in6_addr *in6, int port, const char *proto, int numeric)
1090 {
1091 	struct servent *sp = 0;
1092 	char line[80], *cp;
1093 	int width;
1094 
1095 	sprintf(line, "%.*s.", Wflag ? 39 :
1096 		(Aflag && !numeric) ? 12 : 16, inet6name(in6));
1097 	cp = index(line, '\0');
1098 	if (!numeric && port)
1099 		GETSERVBYPORT6(port, proto, sp);
1100 	if (sp || port == 0)
1101 		sprintf(cp, "%.15s", sp ? sp->s_name : "*");
1102 	else
1103 		sprintf(cp, "%d", ntohs((u_short)port));
1104 	width = Wflag ? 45 : Aflag ? 18 : 22;
1105 	printf("%-*.*s ", width, width, line);
1106 }
1107 
1108 /*
1109  * Construct an Internet address representation.
1110  * If the numeric_addr has been supplied, give
1111  * numeric value, otherwise try for symbolic name.
1112  */
1113 
1114 char *
1115 inet6name(struct in6_addr *in6p)
1116 {
1117 	char *cp;
1118 	static char line[50];
1119 	struct hostent *hp;
1120 	static char domain[MAXHOSTNAMELEN];
1121 	static int first = 1;
1122 
1123 	if (first && !numeric_addr) {
1124 		first = 0;
1125 		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
1126 		    (cp = index(domain, '.')))
1127 			(void) strcpy(domain, cp + 1);
1128 		else
1129 			domain[0] = 0;
1130 	}
1131 	cp = 0;
1132 	if (!numeric_addr && !IN6_IS_ADDR_UNSPECIFIED(in6p)) {
1133 		hp = gethostbyaddr((char *)in6p, sizeof(*in6p), AF_INET6);
1134 		if (hp) {
1135 			if ((cp = index(hp->h_name, '.')) &&
1136 			    !strcmp(cp + 1, domain))
1137 				*cp = 0;
1138 			cp = hp->h_name;
1139 		}
1140 	}
1141 	if (IN6_IS_ADDR_UNSPECIFIED(in6p))
1142 		strcpy(line, "*");
1143 	else if (cp)
1144 		strcpy(line, cp);
1145 	else
1146 		sprintf(line, "%s",
1147 			inet_ntop(AF_INET6, (void *)in6p, ntop_buf,
1148 				sizeof(ntop_buf)));
1149 	return (line);
1150 }
1151 #endif /*INET6*/
1152