inet6.c revision 55533
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 55533 2000-01-07 05:17:09Z 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		char ifbuf[IFNAMSIZ];
394		if (ip6stat.ip6s_m2m[i] != 0) {
395			if (first) {
396				printf("\t\ttwo or more mbuf:\n");
397				first = 0;
398			}
399			printf("\t\t\t%s= %ld\n",
400			       if_indextoname(i, ifbuf),
401			       ip6stat.ip6s_m2m[i]);
402		}
403	}
404	printf("\t\t%lu one ext mbuf\n", ip6stat.ip6s_mext1);
405	printf("\t\t%lu two or more ext mbuf\n", ip6stat.ip6s_mext2m);
406	p(ip6s_exthdrtoolong, "\t%lu packet%s whose headers are not continuous\n");
407	p(ip6s_nogif, "\t%lu tunneling packet%s that can't find gif\n");
408	p(ip6s_toomanyhdr, "\t%lu packet%s discarded due to too may headers\n");
409#undef p
410}
411
412/*
413 * Dump IPv6 per-interface statistics based on RFC 2465.
414 */
415void
416ip6_ifstats(ifname)
417	char *ifname;
418{
419	struct in6_ifreq ifr;
420	int s;
421#define	p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
422    printf(m, ifr.ifr_ifru.ifru_stat.f, plural(ifr.ifr_ifru.ifru_stat.f))
423#define	p_5(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
424    printf(m, ip6stat.f)
425
426	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
427		perror("Warning: socket(AF_INET6)");
428		return;
429	}
430
431	strcpy(ifr.ifr_name, ifname);
432	printf("ip6 on %s:\n", ifr.ifr_name);
433
434	if (ioctl(s, SIOCGIFSTAT_IN6, (char *)&ifr) < 0) {
435		perror("Warning: ioctl(SIOCGIFSTAT_IN6)");
436		goto end;
437	}
438
439	p(ifs6_in_receive, "\t%qu total input datagram%s\n");
440	p(ifs6_in_hdrerr, "\t%qu datagram%s with invalid header received\n");
441	p(ifs6_in_toobig, "\t%qu datagram%s exceeded MTU received\n");
442	p(ifs6_in_noroute, "\t%qu datagram%s with no route received\n");
443	p(ifs6_in_addrerr, "\t%qu datagram%s with invalid dst received\n");
444	p(ifs6_in_protounknown, "\t%qu datagram%s with unknown proto received\n");
445	p(ifs6_in_truncated, "\t%qu truncated datagram%s received\n");
446	p(ifs6_in_discard, "\t%qu input datagram%s discarded\n");
447	p(ifs6_in_deliver,
448	  "\t%qu datagram%s delivered to an upper layer protocol\n");
449	p(ifs6_out_forward, "\t%qu datagram%s forwarded to this interface\n");
450	p(ifs6_out_request,
451	  "\t%qu datagram%s sent from an upper layer protocol\n");
452	p(ifs6_out_discard, "\t%qu total discarded output datagram%s\n");
453	p(ifs6_out_fragok, "\t%qu output datagram%s fragmented\n");
454	p(ifs6_out_fragfail, "\t%qu output datagram%s failed on fragment\n");
455	p(ifs6_out_fragcreat, "\t%qu output datagram%s succeeded on fragment\n");
456	p(ifs6_reass_reqd, "\t%qu incoming datagram%s fragmented\n");
457	p(ifs6_reass_ok, "\t%qu datagram%s reassembled\n");
458	p(ifs6_reass_fail, "\t%qu datagram%s failed on reassembling\n");
459	p(ifs6_in_mcast, "\t%qu multicast datagram%s received\n");
460	p(ifs6_out_mcast, "\t%qu multicast datagram%s sent\n");
461
462  end:
463	close(s);
464
465#undef p
466#undef p_5
467}
468
469static	char *icmp6names[] = {
470	"#0",
471	"unreach",
472	"packet too big",
473	"time exceed",
474	"parameter problem",
475	"#5",
476	"#6",
477	"#7",
478	"#8",
479	"#9",
480	"#10",
481	"#11",
482	"#12",
483	"#13",
484	"#14",
485	"#15",
486	"#16",
487	"#17",
488	"#18",
489	"#19",
490	"#20",
491	"#21",
492	"#22",
493	"#23",
494	"#24",
495	"#25",
496	"#26",
497	"#27",
498	"#28",
499	"#29",
500	"#30",
501	"#31",
502	"#32",
503	"#33",
504	"#34",
505	"#35",
506	"#36",
507	"#37",
508	"#38",
509	"#39",
510	"#40",
511	"#41",
512	"#42",
513	"#43",
514	"#44",
515	"#45",
516	"#46",
517	"#47",
518	"#48",
519	"#49",
520	"#50",
521	"#51",
522	"#52",
523	"#53",
524	"#54",
525	"#55",
526	"#56",
527	"#57",
528	"#58",
529	"#59",
530	"#60",
531	"#61",
532	"#62",
533	"#63",
534	"#64",
535	"#65",
536	"#66",
537	"#67",
538	"#68",
539	"#69",
540	"#70",
541	"#71",
542	"#72",
543	"#73",
544	"#74",
545	"#75",
546	"#76",
547	"#77",
548	"#78",
549	"#79",
550	"#80",
551	"#81",
552	"#82",
553	"#83",
554	"#84",
555	"#85",
556	"#86",
557	"#87",
558	"#88",
559	"#89",
560	"#80",
561	"#91",
562	"#92",
563	"#93",
564	"#94",
565	"#95",
566	"#96",
567	"#97",
568	"#98",
569	"#99",
570	"#100",
571	"#101",
572	"#102",
573	"#103",
574	"#104",
575	"#105",
576	"#106",
577	"#107",
578	"#108",
579	"#109",
580	"#110",
581	"#111",
582	"#112",
583	"#113",
584	"#114",
585	"#115",
586	"#116",
587	"#117",
588	"#118",
589	"#119",
590	"#120",
591	"#121",
592	"#122",
593	"#123",
594	"#124",
595	"#125",
596	"#126",
597	"#127",
598	"echo",
599	"echo reply",
600	"multicast listener query",
601	"multicast listener report",
602	"multicast listener done",
603	"router solicitation",
604	"router advertisment",
605	"neighbor solicitation",
606	"neighbor advertisment",
607	"redirect",
608	"router renumbering",
609	"node information request",
610	"node information reply",
611	"#141",
612	"#142",
613	"#143",
614	"#144",
615	"#145",
616	"#146",
617	"#147",
618	"#148",
619	"#149",
620	"#150",
621	"#151",
622	"#152",
623	"#153",
624	"#154",
625	"#155",
626	"#156",
627	"#157",
628	"#158",
629	"#159",
630	"#160",
631	"#161",
632	"#162",
633	"#163",
634	"#164",
635	"#165",
636	"#166",
637	"#167",
638	"#168",
639	"#169",
640	"#170",
641	"#171",
642	"#172",
643	"#173",
644	"#174",
645	"#175",
646	"#176",
647	"#177",
648	"#178",
649	"#179",
650	"#180",
651	"#181",
652	"#182",
653	"#183",
654	"#184",
655	"#185",
656	"#186",
657	"#187",
658	"#188",
659	"#189",
660	"#180",
661	"#191",
662	"#192",
663	"#193",
664	"#194",
665	"#195",
666	"#196",
667	"#197",
668	"#198",
669	"#199",
670	"#200",
671	"#201",
672	"#202",
673	"#203",
674	"#204",
675	"#205",
676	"#206",
677	"#207",
678	"#208",
679	"#209",
680	"#210",
681	"#211",
682	"#212",
683	"#213",
684	"#214",
685	"#215",
686	"#216",
687	"#217",
688	"#218",
689	"#219",
690	"#220",
691	"#221",
692	"#222",
693	"#223",
694	"#224",
695	"#225",
696	"#226",
697	"#227",
698	"#228",
699	"#229",
700	"#230",
701	"#231",
702	"#232",
703	"#233",
704	"#234",
705	"#235",
706	"#236",
707	"#237",
708	"#238",
709	"#239",
710	"#240",
711	"#241",
712	"#242",
713	"#243",
714	"#244",
715	"#245",
716	"#246",
717	"#247",
718	"#248",
719	"#249",
720	"#250",
721	"#251",
722	"#252",
723	"#253",
724	"#254",
725	"#255",
726};
727
728/*
729 * Dump ICMP6 statistics.
730 */
731void
732icmp6_stats(off, name)
733	u_long off;
734	char *name;
735{
736	struct icmp6stat icmp6stat;
737	register int i, first;
738
739	if (off == 0)
740		return;
741	kread(off, (char *)&icmp6stat, sizeof (icmp6stat));
742	printf("%s:\n", name);
743
744#define	p(f, m) if (icmp6stat.f || sflag <= 1) \
745    printf(m, icmp6stat.f, plural(icmp6stat.f))
746
747	p(icp6s_error, "\t%lu call%s to icmp_error\n");
748	p(icp6s_canterror,
749	    "\t%lu error%s not generated because old message was icmp error or so\n");
750	p(icp6s_toofreq,
751	  "\t%lu error%s not generated because rate limitation\n");
752	for (first = 1, i = 0; i < 256; i++)
753		if (icmp6stat.icp6s_outhist[i] != 0) {
754			if (first) {
755				printf("\tOutput histogram:\n");
756				first = 0;
757			}
758			printf("\t\t%s: %lu\n", icmp6names[i],
759				icmp6stat.icp6s_outhist[i]);
760		}
761	p(icp6s_badcode, "\t%lu message%s with bad code fields\n");
762	p(icp6s_tooshort, "\t%lu message%s < minimum length\n");
763	p(icp6s_checksum, "\t%lu bad checksum%s\n");
764	p(icp6s_badlen, "\t%lu message%s with bad length\n");
765	for (first = 1, i = 0; i < ICMP6_MAXTYPE; i++)
766		if (icmp6stat.icp6s_inhist[i] != 0) {
767			if (first) {
768				printf("\tInput histogram:\n");
769				first = 0;
770			}
771			printf("\t\t%s: %lu\n", icmp6names[i],
772				icmp6stat.icp6s_inhist[i]);
773		}
774	p(icp6s_reflect, "\t%lu message response%s generated\n");
775#undef p
776#undef p_5
777}
778
779/*
780 * Dump ICMPv6 per-interface statistics based on RFC 2466.
781 */
782void
783icmp6_ifstats(ifname)
784	char *ifname;
785{
786	struct in6_ifreq ifr;
787	int s;
788#define	p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \
789    printf(m, (u_quad_t)ifr.ifr_ifru.ifru_icmp6stat.f, plural(ifr.ifr_ifru.ifru_icmp6stat.f))
790
791	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
792		perror("Warning: socket(AF_INET6)");
793		return;
794	}
795
796	strcpy(ifr.ifr_name, ifname);
797	printf("icmp6 on %s:\n", ifr.ifr_name);
798
799	if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) {
800		perror("Warning: ioctl(SIOCGIFSTAT_ICMP6)");
801		goto end;
802	}
803
804	p(ifs6_in_msg, "\t%qu total input message%s\n");
805	p(ifs6_in_error, "\t%qu total input error message%s\n");
806	p(ifs6_in_dstunreach, "\t%qu input destination unreachable error%s\n");
807	p(ifs6_in_adminprohib, "\t%qu input administratively prohibited error%s\n");
808	p(ifs6_in_timeexceed, "\t%qu input time exceeded error%s\n");
809	p(ifs6_in_paramprob, "\t%qu input parameter problem error%s\n");
810	p(ifs6_in_pkttoobig, "\t%qu input packet too big error%s\n");
811	p(ifs6_in_echo, "\t%qu input echo request%s\n");
812	p(ifs6_in_echoreply, "\t%qu input echo reply%s\n");
813	p(ifs6_in_routersolicit, "\t%qu input router solicitation%s\n");
814	p(ifs6_in_routeradvert, "\t%qu input router advertisement%s\n");
815	p(ifs6_in_neighborsolicit, "\t%qu input neighbor solicitation%s\n");
816	p(ifs6_in_neighboradvert, "\t%qu input neighbor advertisement%s\n");
817	p(ifs6_in_redirect, "\t%qu input redirect%s\n");
818	p(ifs6_in_mldquery, "\t%qu input MLD query%s\n");
819	p(ifs6_in_mldreport, "\t%qu input MLD report%s\n");
820	p(ifs6_in_mlddone, "\t%qu input MLD done%s\n");
821
822	p(ifs6_out_msg, "\t%qu total output message%s\n");
823	p(ifs6_out_error, "\t%qu total output error message%s\n");
824	p(ifs6_out_dstunreach, "\t%qu output destination unreachable error%s\n");
825	p(ifs6_out_adminprohib, "\t%qu output administratively prohibited error%s\n");
826	p(ifs6_out_timeexceed, "\t%qu output time exceeded error%s\n");
827	p(ifs6_out_paramprob, "\t%qu output parameter problem error%s\n");
828	p(ifs6_out_pkttoobig, "\t%qu output packet too big error%s\n");
829	p(ifs6_out_echo, "\t%qu output echo request%s\n");
830	p(ifs6_out_echoreply, "\t%qu output echo reply%s\n");
831	p(ifs6_out_routersolicit, "\t%qu output router solicitation%s\n");
832	p(ifs6_out_routeradvert, "\t%qu output router advertisement%s\n");
833	p(ifs6_out_neighborsolicit, "\t%qu output neighbor solicitation%s\n");
834	p(ifs6_out_neighboradvert, "\t%qu output neighbor advertisement%s\n");
835	p(ifs6_out_redirect, "\t%qu output redirect%s\n");
836	p(ifs6_out_mldquery, "\t%qu output MLD query%s\n");
837	p(ifs6_out_mldreport, "\t%qu output MLD report%s\n");
838	p(ifs6_out_mlddone, "\t%qu output MLD done%s\n");
839
840  end:
841	close(s);
842#undef p
843}
844
845/*
846 * Dump PIM statistics structure.
847 */
848void
849pim6_stats(off, name)
850	u_long off;
851	char *name;
852{
853	struct pim6stat pim6stat;
854
855	if (off == 0)
856		return;
857	kread(off, (char *)&pim6stat, sizeof(pim6stat));
858	printf("%s:\n", name);
859
860#define	p(f, m) if (pim6stat.f || sflag <= 1) \
861    printf(m, pim6stat.f, plural(pim6stat.f))
862	p(pim6s_rcv_total, "\t%u message%s received\n");
863	p(pim6s_rcv_tooshort, "\t%u message%s received with too few bytes\n");
864	p(pim6s_rcv_badsum, "\t%u message%s received with bad checksum\n");
865	p(pim6s_rcv_badversion, "\t%u message%s received with bad version\n");
866	p(pim6s_rcv_registers, "\t%u register%s received\n");
867	p(pim6s_rcv_badregisters, "\t%u bad register%s received\n");
868	p(pim6s_snd_registers, "\t%u register%s sent\n");
869#undef p
870}
871
872/*
873 * Pretty print an Internet address (net address + port).
874 * If the nflag was specified, use numbers instead of names.
875 */
876#define GETSERVBYPORT6(port, proto, ret)\
877{\
878	if (strcmp((proto), "tcp6") == 0)\
879		(ret) = getservbyport((int)(port), "tcp");\
880	else if (strcmp((proto), "udp6") == 0)\
881		(ret) = getservbyport((int)(port), "udp");\
882	else\
883		(ret) = getservbyport((int)(port), (proto));\
884};
885
886void
887inet6print(in6, port, proto, numeric)
888	register struct in6_addr *in6;
889	int port;
890	char *proto;
891	int numeric;
892{
893	struct servent *sp = 0;
894	char line[80], *cp;
895	int width;
896
897	sprintf(line, "%.*s.", lflag ? 39 :
898		(Aflag && !numeric) ? 12 : 16, inet6name(in6));
899	cp = index(line, '\0');
900	if (!numeric && port)
901		GETSERVBYPORT6(port, proto, sp);
902	if (sp || port == 0)
903		sprintf(cp, "%.8s", sp ? sp->s_name : "*");
904	else
905		sprintf(cp, "%d", ntohs((u_short)port));
906	width = lflag ? 45 : Aflag ? 18 : 22;
907	printf("%-*.*s ", width, width, line);
908}
909
910/*
911 * Construct an Internet address representation.
912 * If the nflag has been supplied, give
913 * numeric value, otherwise try for symbolic name.
914 */
915
916char *
917inet6name(in6p)
918	struct in6_addr *in6p;
919{
920	register char *cp;
921	static char line[50];
922	struct hostent *hp;
923	static char domain[MAXHOSTNAMELEN + 1];
924	static int first = 1;
925
926	if (first && !nflag) {
927		first = 0;
928		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
929		    (cp = index(domain, '.')))
930			(void) strcpy(domain, cp + 1);
931		else
932			domain[0] = 0;
933	}
934	cp = 0;
935	if (!nflag && !IN6_IS_ADDR_UNSPECIFIED(in6p)) {
936		hp = gethostbyaddr((char *)in6p, sizeof(*in6p), AF_INET6);
937		if (hp) {
938			if ((cp = index(hp->h_name, '.')) &&
939			    !strcmp(cp + 1, domain))
940				*cp = 0;
941			cp = hp->h_name;
942		}
943	}
944	if (IN6_IS_ADDR_UNSPECIFIED(in6p))
945		strcpy(line, "*");
946	else if (cp)
947		strcpy(line, cp);
948	else
949		sprintf(line, "%s",
950			inet_ntop(AF_INET6, (void *)in6p, ntop_buf,
951				sizeof(ntop_buf)));
952	return (line);
953}
954