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