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