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