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