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