inet6.c revision 54263
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 * 3. All advertising materials mentioning features or use of this software
15 *    must display the following acknowledgement:
16 *	This product includes software developed by the University of
17 *	California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * $FreeBSD: head/usr.bin/netstat/inet6.c 54263 1999-12-07 17:39:16Z shin $
35 */
36
37#ifndef lint
38/*
39static char sccsid[] = "@(#)inet6.c	8.4 (Berkeley) 4/20/94";
40*/
41#endif /* not lint */
42
43#include <sys/param.h>
44#include <sys/socket.h>
45#include <sys/socketvar.h>
46#include <sys/ioctl.h>
47#include <sys/mbuf.h>
48#include <sys/protosw.h>
49
50#include <net/route.h>
51#include <net/if.h>
52#include <net/if_var.h>
53#include <netinet/in.h>
54#include <netinet/ip6.h>
55#include <netinet/icmp6.h>
56#include <netinet/in_systm.h>
57#include <netinet6/in6_pcb.h>
58#include <netinet6/in6_var.h>
59#include <netinet6/ip6_var.h>
60#include <netinet6/pim6_var.h>
61
62#include <arpa/inet.h>
63#include <netdb.h>
64
65#include <stdio.h>
66#include <string.h>
67#include <unistd.h>
68#include "netstat.h"
69
70struct	socket sockb;
71
72char	*inet6name __P((struct in6_addr *));
73void	inet6print __P((struct in6_addr *, int, char *, int));
74
75static char ntop_buf[INET6_ADDRSTRLEN];
76
77static	char *ip6nh[] = {
78	"hop by hop",
79	"ICMP",
80	"IGMP",
81	"#3",
82	"IP",
83	"#5",
84	"TCP",
85	"#7",
86	"#8",
87	"#9",
88	"#10",
89	"#11",
90	"#12",
91	"#13",
92	"#14",
93	"#15",
94	"#16",
95	"UDP",
96	"#18",
97	"#19",
98	"#20",
99	"#21",
100	"IDP",
101	"#23",
102	"#24",
103	"#25",
104	"#26",
105	"#27",
106	"#28",
107	"TP",
108	"#30",
109	"#31",
110	"#32",
111	"#33",
112	"#34",
113	"#35",
114	"#36",
115	"#37",
116	"#38",
117	"#39",
118	"#40",
119	"IP6",
120	"#42",
121	"routing",
122	"fragment",
123	"#45",
124	"#46",
125	"#47",
126	"#48",
127	"#49",
128	"ESP",
129	"AH",
130	"#52",
131	"#53",
132	"#54",
133	"#55",
134	"#56",
135	"#57",
136	"ICMP6",
137	"no next header",
138	"destination option",
139	"#61",
140	"#62",
141	"#63",
142	"#64",
143	"#65",
144	"#66",
145	"#67",
146	"#68",
147	"#69",
148	"#70",
149	"#71",
150	"#72",
151	"#73",
152	"#74",
153	"#75",
154	"#76",
155	"#77",
156	"#78",
157	"#79",
158	"ISOIP",
159	"#81",
160	"#82",
161	"#83",
162	"#84",
163	"#85",
164	"#86",
165	"#87",
166	"#88",
167	"#89",
168	"#80",
169	"#91",
170	"#92",
171	"#93",
172	"#94",
173	"#95",
174	"#96",
175	"Ethernet",
176	"#98",
177	"#99",
178	"#100",
179	"#101",
180	"#102",
181	"PIM",
182	"#104",
183	"#105",
184	"#106",
185	"#107",
186	"#108",
187	"#109",
188	"#110",
189	"#111",
190	"#112",
191	"#113",
192	"#114",
193	"#115",
194	"#116",
195	"#117",
196	"#118",
197	"#119",
198	"#120",
199	"#121",
200	"#122",
201	"#123",
202	"#124",
203	"#125",
204	"#126",
205	"#127",
206	"#128",
207	"#129",
208	"#130",
209	"#131",
210	"#132",
211	"#133",
212	"#134",
213	"#135",
214	"#136",
215	"#137",
216	"#138",
217	"#139",
218	"#140",
219	"#141",
220	"#142",
221	"#143",
222	"#144",
223	"#145",
224	"#146",
225	"#147",
226	"#148",
227	"#149",
228	"#150",
229	"#151",
230	"#152",
231	"#153",
232	"#154",
233	"#155",
234	"#156",
235	"#157",
236	"#158",
237	"#159",
238	"#160",
239	"#161",
240	"#162",
241	"#163",
242	"#164",
243	"#165",
244	"#166",
245	"#167",
246	"#168",
247	"#169",
248	"#170",
249	"#171",
250	"#172",
251	"#173",
252	"#174",
253	"#175",
254	"#176",
255	"#177",
256	"#178",
257	"#179",
258	"#180",
259	"#181",
260	"#182",
261	"#183",
262	"#184",
263	"#185",
264	"#186",
265	"#187",
266	"#188",
267	"#189",
268	"#180",
269	"#191",
270	"#192",
271	"#193",
272	"#194",
273	"#195",
274	"#196",
275	"#197",
276	"#198",
277	"#199",
278	"#200",
279	"#201",
280	"#202",
281	"#203",
282	"#204",
283	"#205",
284	"#206",
285	"#207",
286	"#208",
287	"#209",
288	"#210",
289	"#211",
290	"#212",
291	"#213",
292	"#214",
293	"#215",
294	"#216",
295	"#217",
296	"#218",
297	"#219",
298	"#220",
299	"#221",
300	"#222",
301	"#223",
302	"#224",
303	"#225",
304	"#226",
305	"#227",
306	"#228",
307	"#229",
308	"#230",
309	"#231",
310	"#232",
311	"#233",
312	"#234",
313	"#235",
314	"#236",
315	"#237",
316	"#238",
317	"#239",
318	"#240",
319	"#241",
320	"#242",
321	"#243",
322	"#244",
323	"#245",
324	"#246",
325	"#247",
326	"#248",
327	"#249",
328	"#250",
329	"#251",
330	"#252",
331	"#253",
332	"#254",
333	"#255",
334};
335
336/*
337 * Dump IP6 statistics structure.
338 */
339void
340ip6_stats(off, name)
341	u_long off;
342	char *name;
343{
344	struct ip6stat ip6stat;
345	int first, i;
346
347	if (off == 0)
348		return;
349
350	kread(off, (char *)&ip6stat, sizeof (ip6stat));
351	printf("%s:\n", name);
352
353#define	p(f, m) if (ip6stat.f || sflag <= 1) \
354    printf(m, ip6stat.f, plural(ip6stat.f))
355#define	p1a(f, m) if (ip6stat.f || sflag <= 1) \
356    printf(m, ip6stat.f)
357
358	p(ip6s_total, "\t%lu total packet%s received\n");
359	p1a(ip6s_toosmall, "\t%lu with size smaller than minimum\n");
360	p1a(ip6s_tooshort, "\t%lu with data size < data length\n");
361	p1a(ip6s_badoptions, "\t%lu with bad options\n");
362	p1a(ip6s_badvers, "\t%lu with incorrect version number\n");
363	p(ip6s_fragments, "\t%lu fragment%s received\n");
364	p(ip6s_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n");
365	p(ip6s_fragtimeout, "\t%lu fragment%s dropped after timeout\n");
366	p(ip6s_fragoverflow, "\t%lu fragment%s that exceeded limit\n");
367	p(ip6s_reassembled, "\t%lu packet%s reassembled ok\n");
368	p(ip6s_delivered, "\t%lu packet%s for this host\n");
369	p(ip6s_forward, "\t%lu packet%s forwarded\n");
370	p(ip6s_cantforward, "\t%lu packet%s not forwardable\n");
371	p(ip6s_redirectsent, "\t%lu redirect%s sent\n");
372	p(ip6s_localout, "\t%lu packet%s sent from this host\n");
373	p(ip6s_rawout, "\t%lu packet%s sent with fabricated ip header\n");
374	p(ip6s_odropped, "\t%lu output packet%s dropped due to no bufs, etc.\n");
375	p(ip6s_noroute, "\t%lu output packet%s discarded due to no route\n");
376	p(ip6s_fragmented, "\t%lu output datagram%s fragmented\n");
377	p(ip6s_ofragments, "\t%lu fragment%s created\n");
378	p(ip6s_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
379	p(ip6s_badscope, "\t%lu packet%s that violated scope rules\n");
380	p(ip6s_notmember, "\t%lu multicast packet%s which we don't join\n");
381	for (first = 1, i = 0; i < 256; i++)
382		if (ip6stat.ip6s_nxthist[i] != 0) {
383			if (first) {
384				printf("\tInput histogram:\n");
385				first = 0;
386			}
387			printf("\t\t%s: %lu\n", ip6nh[i],
388			       ip6stat.ip6s_nxthist[i]);
389		}
390	printf("\tMbuf statistics:\n");
391	printf("\t\t%lu one mbuf\n", ip6stat.ip6s_m1);
392	for (first = 1, i = 0; i < 32; i++) {
393		if (ip6stat.ip6s_m2m[i] != 0) {
394			if (first) {
395				printf("\t\ttwo or more mbuf:\n");
396				first = 0;
397			}
398			printf("\t\t\t"
399#ifdef notyet
400			       "%s"
401#else
402			       "if%d"
403#endif
404			       "= %ld\n",
405#ifdef notyet
406			       if_indextoname(i, ifbuf),
407#else
408			       i,
409#endif
410			       ip6stat.ip6s_m2m[i]);
411		}
412	}
413	printf("\t\t%lu one ext mbuf\n", ip6stat.ip6s_mext1);
414	printf("\t\t%lu two or more ext mbuf\n", ip6stat.ip6s_mext2m);
415	p(ip6s_exthdrtoolong, "\t%lu packet%s whose headers are not continuous\n");
416	p(ip6s_nogif, "\t%lu tunneling packet%s that can't find gif\n");
417	p(ip6s_toomanyhdr, "\t%lu packet%s discarded due to too may headers\n");
418#undef p
419}
420
421/*
422 * Dump IPv6 per-interface statistics based on RFC 2465.
423 */
424void
425ip6_ifstats(ifname)
426	char *ifname;
427{
428	struct in6_ifreq ifr;
429	int s;
430#define	p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
431    printf(m, ifr.ifr_ifru.ifru_stat.f, plural(ifr.ifr_ifru.ifru_stat.f))
432#define	p_5(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
433    printf(m, ip6stat.f)
434
435	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
436		perror("Warning: socket(AF_INET6)");
437		return;
438	}
439
440	strcpy(ifr.ifr_name, ifname);
441	printf("ip6 on %s:\n", ifr.ifr_name);
442
443	if (ioctl(s, SIOCGIFSTAT_IN6, (char *)&ifr) < 0) {
444		perror("Warning: ioctl(SIOCGIFSTAT_IN6)");
445		goto end;
446	}
447
448	p(ifs6_in_receive, "\t%qu total input datagram%s\n");
449	p(ifs6_in_hdrerr, "\t%qu datagram%s with invalid header received\n");
450	p(ifs6_in_toobig, "\t%qu datagram%s exceeded MTU received\n");
451	p(ifs6_in_noroute, "\t%qu datagram%s with no route received\n");
452	p(ifs6_in_addrerr, "\t%qu datagram%s with invalid dst received\n");
453	p(ifs6_in_protounknown, "\t%qu datagram%s with unknown proto received\n");
454	p(ifs6_in_truncated, "\t%qu truncated datagram%s received\n");
455	p(ifs6_in_discard, "\t%qu input datagram%s discarded\n");
456	p(ifs6_in_deliver,
457	  "\t%qu datagram%s delivered to an upper layer protocol\n");
458	p(ifs6_out_forward, "\t%qu datagram%s forwarded to this interface\n");
459	p(ifs6_out_request,
460	  "\t%qu datagram%s sent from an upper layer protocol\n");
461	p(ifs6_out_discard, "\t%qu total discarded output datagram%s\n");
462	p(ifs6_out_fragok, "\t%qu output datagram%s fragmented\n");
463	p(ifs6_out_fragfail, "\t%qu output datagram%s failed on fragment\n");
464	p(ifs6_out_fragcreat, "\t%qu output datagram%s succeeded on fragment\n");
465	p(ifs6_reass_reqd, "\t%qu incoming datagram%s fragmented\n");
466	p(ifs6_reass_ok, "\t%qu datagram%s reassembled\n");
467	p(ifs6_reass_fail, "\t%qu datagram%s failed on reassembling\n");
468	p(ifs6_in_mcast, "\t%qu multicast datagram%s received\n");
469	p(ifs6_out_mcast, "\t%qu multicast datagram%s sent\n");
470
471  end:
472	close(s);
473
474#undef p
475#undef p_5
476}
477
478static	char *icmp6names[] = {
479	"#0",
480	"unreach",
481	"packet too big",
482	"time exceed",
483	"parameter problem",
484	"#5",
485	"#6",
486	"#7",
487	"#8",
488	"#9",
489	"#10",
490	"#11",
491	"#12",
492	"#13",
493	"#14",
494	"#15",
495	"#16",
496	"#17",
497	"#18",
498	"#19",
499	"#20",
500	"#21",
501	"#22",
502	"#23",
503	"#24",
504	"#25",
505	"#26",
506	"#27",
507	"#28",
508	"#29",
509	"#30",
510	"#31",
511	"#32",
512	"#33",
513	"#34",
514	"#35",
515	"#36",
516	"#37",
517	"#38",
518	"#39",
519	"#40",
520	"#41",
521	"#42",
522	"#43",
523	"#44",
524	"#45",
525	"#46",
526	"#47",
527	"#48",
528	"#49",
529	"#50",
530	"#51",
531	"#52",
532	"#53",
533	"#54",
534	"#55",
535	"#56",
536	"#57",
537	"#58",
538	"#59",
539	"#60",
540	"#61",
541	"#62",
542	"#63",
543	"#64",
544	"#65",
545	"#66",
546	"#67",
547	"#68",
548	"#69",
549	"#70",
550	"#71",
551	"#72",
552	"#73",
553	"#74",
554	"#75",
555	"#76",
556	"#77",
557	"#78",
558	"#79",
559	"#80",
560	"#81",
561	"#82",
562	"#83",
563	"#84",
564	"#85",
565	"#86",
566	"#87",
567	"#88",
568	"#89",
569	"#80",
570	"#91",
571	"#92",
572	"#93",
573	"#94",
574	"#95",
575	"#96",
576	"#97",
577	"#98",
578	"#99",
579	"#100",
580	"#101",
581	"#102",
582	"#103",
583	"#104",
584	"#105",
585	"#106",
586	"#107",
587	"#108",
588	"#109",
589	"#110",
590	"#111",
591	"#112",
592	"#113",
593	"#114",
594	"#115",
595	"#116",
596	"#117",
597	"#118",
598	"#119",
599	"#120",
600	"#121",
601	"#122",
602	"#123",
603	"#124",
604	"#125",
605	"#126",
606	"#127",
607	"echo",
608	"echo reply",
609	"multicast listener query",
610	"multicast listener report",
611	"multicast listener done",
612	"router solicitation",
613	"router advertisment",
614	"neighbor solicitation",
615	"neighbor advertisment",
616	"redirect",
617	"router renumbering",
618	"node information request",
619	"node information reply",
620	"#141",
621	"#142",
622	"#143",
623	"#144",
624	"#145",
625	"#146",
626	"#147",
627	"#148",
628	"#149",
629	"#150",
630	"#151",
631	"#152",
632	"#153",
633	"#154",
634	"#155",
635	"#156",
636	"#157",
637	"#158",
638	"#159",
639	"#160",
640	"#161",
641	"#162",
642	"#163",
643	"#164",
644	"#165",
645	"#166",
646	"#167",
647	"#168",
648	"#169",
649	"#170",
650	"#171",
651	"#172",
652	"#173",
653	"#174",
654	"#175",
655	"#176",
656	"#177",
657	"#178",
658	"#179",
659	"#180",
660	"#181",
661	"#182",
662	"#183",
663	"#184",
664	"#185",
665	"#186",
666	"#187",
667	"#188",
668	"#189",
669	"#180",
670	"#191",
671	"#192",
672	"#193",
673	"#194",
674	"#195",
675	"#196",
676	"#197",
677	"#198",
678	"#199",
679	"#200",
680	"#201",
681	"#202",
682	"#203",
683	"#204",
684	"#205",
685	"#206",
686	"#207",
687	"#208",
688	"#209",
689	"#210",
690	"#211",
691	"#212",
692	"#213",
693	"#214",
694	"#215",
695	"#216",
696	"#217",
697	"#218",
698	"#219",
699	"#220",
700	"#221",
701	"#222",
702	"#223",
703	"#224",
704	"#225",
705	"#226",
706	"#227",
707	"#228",
708	"#229",
709	"#230",
710	"#231",
711	"#232",
712	"#233",
713	"#234",
714	"#235",
715	"#236",
716	"#237",
717	"#238",
718	"#239",
719	"#240",
720	"#241",
721	"#242",
722	"#243",
723	"#244",
724	"#245",
725	"#246",
726	"#247",
727	"#248",
728	"#249",
729	"#250",
730	"#251",
731	"#252",
732	"#253",
733	"#254",
734	"#255",
735};
736
737/*
738 * Dump ICMP6 statistics.
739 */
740void
741icmp6_stats(off, name)
742	u_long off;
743	char *name;
744{
745	struct icmp6stat icmp6stat;
746	register int i, first;
747
748	if (off == 0)
749		return;
750	kread(off, (char *)&icmp6stat, sizeof (icmp6stat));
751	printf("%s:\n", name);
752
753#define	p(f, m) if (icmp6stat.f || sflag <= 1) \
754    printf(m, icmp6stat.f, plural(icmp6stat.f))
755
756	p(icp6s_error, "\t%lu call%s to icmp_error\n");
757	p(icp6s_canterror,
758	    "\t%lu error%s not generated because old message was icmp error or so\n");
759	p(icp6s_toofreq,
760	  "\t%lu error%s not generated because rate limitation\n");
761	for (first = 1, i = 0; i < 256; i++)
762		if (icmp6stat.icp6s_outhist[i] != 0) {
763			if (first) {
764				printf("\tOutput histogram:\n");
765				first = 0;
766			}
767			printf("\t\t%s: %lu\n", icmp6names[i],
768				icmp6stat.icp6s_outhist[i]);
769		}
770	p(icp6s_badcode, "\t%lu message%s with bad code fields\n");
771	p(icp6s_tooshort, "\t%lu message%s < minimum length\n");
772	p(icp6s_checksum, "\t%lu bad checksum%s\n");
773	p(icp6s_badlen, "\t%lu message%s with bad length\n");
774	for (first = 1, i = 0; i < ICMP6_MAXTYPE; i++)
775		if (icmp6stat.icp6s_inhist[i] != 0) {
776			if (first) {
777				printf("\tInput histogram:\n");
778				first = 0;
779			}
780			printf("\t\t%s: %lu\n", icmp6names[i],
781				icmp6stat.icp6s_inhist[i]);
782		}
783	p(icp6s_reflect, "\t%lu message response%s generated\n");
784#undef p
785#undef p_5
786}
787
788/*
789 * Dump ICMPv6 per-interface statistics based on RFC 2466.
790 */
791void
792icmp6_ifstats(ifname)
793	char *ifname;
794{
795	struct in6_ifreq ifr;
796	int s;
797#define	p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \
798    printf(m, (u_quad_t)ifr.ifr_ifru.ifru_icmp6stat.f, plural(ifr.ifr_ifru.ifru_icmp6stat.f))
799
800	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
801		perror("Warning: socket(AF_INET6)");
802		return;
803	}
804
805	strcpy(ifr.ifr_name, ifname);
806	printf("icmp6 on %s:\n", ifr.ifr_name);
807
808	if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) {
809		perror("Warning: ioctl(SIOCGIFSTAT_ICMP6)");
810		goto end;
811	}
812
813	p(ifs6_in_msg, "\t%qu total input message%s\n");
814	p(ifs6_in_error, "\t%qu total input error message%s\n");
815	p(ifs6_in_dstunreach, "\t%qu input destination unreachable error%s\n");
816	p(ifs6_in_adminprohib, "\t%qu input administratively prohibited error%s\n");
817	p(ifs6_in_timeexceed, "\t%qu input time exceeded error%s\n");
818	p(ifs6_in_paramprob, "\t%qu input parameter problem error%s\n");
819	p(ifs6_in_pkttoobig, "\t%qu input packet too big error%s\n");
820	p(ifs6_in_echo, "\t%qu input echo request%s\n");
821	p(ifs6_in_echoreply, "\t%qu input echo reply%s\n");
822	p(ifs6_in_routersolicit, "\t%qu input router solicitation%s\n");
823	p(ifs6_in_routeradvert, "\t%qu input router advertisement%s\n");
824	p(ifs6_in_neighborsolicit, "\t%qu input neighbor solicitation%s\n");
825	p(ifs6_in_neighboradvert, "\t%qu input neighbor advertisement%s\n");
826	p(ifs6_in_redirect, "\t%qu input redirect%s\n");
827	p(ifs6_in_mldquery, "\t%qu input MLD query%s\n");
828	p(ifs6_in_mldreport, "\t%qu input MLD report%s\n");
829	p(ifs6_in_mlddone, "\t%qu input MLD done%s\n");
830
831	p(ifs6_out_msg, "\t%qu total output message%s\n");
832	p(ifs6_out_error, "\t%qu total output error message%s\n");
833	p(ifs6_out_dstunreach, "\t%qu output destination unreachable error%s\n");
834	p(ifs6_out_adminprohib, "\t%qu output administratively prohibited error%s\n");
835	p(ifs6_out_timeexceed, "\t%qu output time exceeded error%s\n");
836	p(ifs6_out_paramprob, "\t%qu output parameter problem error%s\n");
837	p(ifs6_out_pkttoobig, "\t%qu output packet too big error%s\n");
838	p(ifs6_out_echo, "\t%qu output echo request%s\n");
839	p(ifs6_out_echoreply, "\t%qu output echo reply%s\n");
840	p(ifs6_out_routersolicit, "\t%qu output router solicitation%s\n");
841	p(ifs6_out_routeradvert, "\t%qu output router advertisement%s\n");
842	p(ifs6_out_neighborsolicit, "\t%qu output neighbor solicitation%s\n");
843	p(ifs6_out_neighboradvert, "\t%qu output neighbor advertisement%s\n");
844	p(ifs6_out_redirect, "\t%qu output redirect%s\n");
845	p(ifs6_out_mldquery, "\t%qu output MLD query%s\n");
846	p(ifs6_out_mldreport, "\t%qu output MLD report%s\n");
847	p(ifs6_out_mlddone, "\t%qu output MLD done%s\n");
848
849  end:
850	close(s);
851#undef p
852}
853
854/*
855 * Dump PIM statistics structure.
856 */
857void
858pim6_stats(off, name)
859	u_long off;
860	char *name;
861{
862	struct pim6stat pim6stat;
863
864	if (off == 0)
865		return;
866	kread(off, (char *)&pim6stat, sizeof(pim6stat));
867	printf("%s:\n", name);
868
869#define	p(f, m) if (pim6stat.f || sflag <= 1) \
870    printf(m, pim6stat.f, plural(pim6stat.f))
871	p(pim6s_rcv_total, "\t%u message%s received\n");
872	p(pim6s_rcv_tooshort, "\t%u message%s received with too few bytes\n");
873	p(pim6s_rcv_badsum, "\t%u message%s received with bad checksum\n");
874	p(pim6s_rcv_badversion, "\t%u message%s received with bad version\n");
875	p(pim6s_rcv_registers, "\t%u register%s received\n");
876	p(pim6s_rcv_badregisters, "\t%u bad register%s received\n");
877	p(pim6s_snd_registers, "\t%u register%s sent\n");
878#undef p
879}
880
881/*
882 * Pretty print an Internet address (net address + port).
883 * If the nflag was specified, use numbers instead of names.
884 */
885#define GETSERVBYPORT6(port, proto, ret)\
886{\
887	if (strcmp((proto), "tcp6") == 0)\
888		(ret) = getservbyport((int)(port), "tcp");\
889	else if (strcmp((proto), "udp6") == 0)\
890		(ret) = getservbyport((int)(port), "udp");\
891	else\
892		(ret) = getservbyport((int)(port), (proto));\
893};
894
895void
896inet6print(in6, port, proto, numeric)
897	register struct in6_addr *in6;
898	int port;
899	char *proto;
900	int numeric;
901{
902	struct servent *sp = 0;
903	char line[80], *cp;
904	int width;
905
906	sprintf(line, "%.*s.", lflag ? 39 :
907		(Aflag && !numeric) ? 12 : 16, inet6name(in6));
908	cp = index(line, '\0');
909	if (!numeric && port)
910		GETSERVBYPORT6(port, proto, sp);
911	if (sp || port == 0)
912		sprintf(cp, "%.8s", sp ? sp->s_name : "*");
913	else
914		sprintf(cp, "%d", ntohs((u_short)port));
915	width = lflag ? 45 : Aflag ? 18 : 22;
916	printf(" %-*.*s", width, width, line);
917}
918
919/*
920 * Construct an Internet address representation.
921 * If the nflag has been supplied, give
922 * numeric value, otherwise try for symbolic name.
923 */
924
925char *
926inet6name(in6p)
927	struct in6_addr *in6p;
928{
929	register char *cp;
930	static char line[50];
931	struct hostent *hp;
932	static char domain[MAXHOSTNAMELEN + 1];
933	static int first = 1;
934
935	if (first && !nflag) {
936		first = 0;
937		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
938		    (cp = index(domain, '.')))
939			(void) strcpy(domain, cp + 1);
940		else
941			domain[0] = 0;
942	}
943	cp = 0;
944	if (!nflag && !IN6_IS_ADDR_UNSPECIFIED(in6p)) {
945		hp = gethostbyaddr((char *)in6p, sizeof(*in6p), AF_INET6);
946		if (hp) {
947			if ((cp = index(hp->h_name, '.')) &&
948			    !strcmp(cp + 1, domain))
949				*cp = 0;
950			cp = hp->h_name;
951		}
952	}
953	if (IN6_IS_ADDR_UNSPECIFIED(in6p))
954		strcpy(line, "*");
955	else if (cp)
956		strcpy(line, cp);
957	else
958		sprintf(line, "%s",
959			inet_ntop(AF_INET6, (void *)in6p, ntop_buf,
960				sizeof(ntop_buf)));
961	return (line);
962}
963