ifmcstat.c revision 167706
1167706Sbms/*	$KAME: ifmcstat.c,v 1.48 2006/11/15 05:13:59 itojun Exp $	*/
2167706Sbms
355163Sshin/*
455163Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
555163Sshin * All rights reserved.
662785Sume *
755163Sshin * Redistribution and use in source and binary forms, with or without
855163Sshin * modification, are permitted provided that the following conditions
955163Sshin * are met:
1055163Sshin * 1. Redistributions of source code must retain the above copyright
1155163Sshin *    notice, this list of conditions and the following disclaimer.
1255163Sshin * 2. Redistributions in binary form must reproduce the above copyright
1355163Sshin *    notice, this list of conditions and the following disclaimer in the
1455163Sshin *    documentation and/or other materials provided with the distribution.
1555163Sshin * 3. Neither the name of the project nor the names of its contributors
1655163Sshin *    may be used to endorse or promote products derived from this software
1755163Sshin *    without specific prior written permission.
1862785Sume *
1955163Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2055163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2155163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2255163Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2355163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2455163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2555163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2655163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2755163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2855163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2955163Sshin * SUCH DAMAGE.
3055163Sshin */
3155163Sshin
32167706Sbms#ifdef __FreeBSD__
33167706Sbms#include <sys/cdefs.h>
34167706Sbms__FBSDID("$FreeBSD: head/usr.sbin/ifmcstat/ifmcstat.c 167706 2007-03-19 16:45:06Z bms $");
35167706Sbms#endif
36167706Sbms
3755163Sshin#include <stdio.h>
3855163Sshin#include <stdlib.h>
3955163Sshin#include <fcntl.h>
4055163Sshin#include <kvm.h>
4155163Sshin#include <nlist.h>
4255163Sshin#include <string.h>
4355163Sshin#include <limits.h>
44167706Sbms#include <unistd.h>
4555163Sshin
4655163Sshin#include <sys/types.h>
47167706Sbms#include <sys/param.h>
4855163Sshin#include <sys/socket.h>
4978064Sume#include <sys/queue.h>
5078064Sume
5155163Sshin#include <net/if.h>
52167706Sbms#ifdef __FreeBSD__
53167706Sbms# include <net/if_var.h>
54167706Sbms#endif
5555163Sshin#include <net/if_types.h>
5655163Sshin#include <net/if_dl.h>
57167706Sbms#include <net/route.h>
5855163Sshin#include <netinet/in.h>
59167706Sbms#include <netinet/in_systm.h>
60167706Sbms#include <netinet/ip.h>
61167706Sbms#include <netinet/igmp.h>
62167706Sbms#ifdef HAVE_IGMPV3
63167706Sbms#include <netinet/in_msf.h>
64167706Sbms#endif
65167706Sbms#ifdef HAVE_MLDV2
66167706Sbms#include <net/route.h>
67167706Sbms#include <netinet6/in6_msf.h>
68167706Sbms#endif
69167706Sbms#ifndef __NetBSD__
70167706Sbms# ifdef	__FreeBSD__
71167706Sbms#  define	KERNEL
72167706Sbms# endif
73167706Sbms# include <netinet/if_ether.h>
74167706Sbms# ifdef	__FreeBSD__
75167706Sbms#  undef	KERNEL
76167706Sbms# endif
77167706Sbms#else
78167706Sbms# include <net/if_ether.h>
79167706Sbms#endif
8055163Sshin#include <netinet/in_var.h>
81167706Sbms#include <netinet/icmp6.h>
82167706Sbms#define _KERNEL
83167706Sbms/* defined _KERNEL only to define IGMP_v?_ROUTER and MLD_V?_ROUTER */
84167706Sbms#ifdef __FreeBSD__
85167706Sbms#include <sys/sysctl.h>
86167706Sbms#endif
87167706Sbms#include <netinet/igmp_var.h>
88167706Sbms#include <netinet6/mld6_var.h>
89167706Sbms#ifdef __FreeBSD__
90167706Sbms#define IGMP_v1_ROUTER IGMP_V1_ROUTER
91167706Sbms#define IGMP_v2_ROUTER IGMP_V2_ROUTER
92167706Sbms#define IGMP_v3_ROUTER IGMP_V3_ROUTER
93167706Sbms#endif
94167706Sbms#undef _KERNEL
9555163Sshin#include <arpa/inet.h>
9655163Sshin
9762785Sume#include <netdb.h>
9862785Sume
9955163Sshinkvm_t	*kvmd;
100167706Sbmsint ifindex = 0;
101167706Sbmsint af = AF_UNSPEC;
10255163Sshin
10355163Sshinstruct	nlist nl[] = {
10455163Sshin#define	N_IFNET	0
10555163Sshin	{ "_ifnet" },
106167706Sbms#ifndef __FreeBSD__
107167706Sbms#define N_IN6_MK 1
108167706Sbms	{ "_in6_mk" },
109167706Sbms#endif
11055163Sshin	{ "" },
11155163Sshin};
11255163Sshin
11355163Sshinconst char *inet6_n2a __P((struct in6_addr *));
114167706Sbmsint main __P((int, char **));
11555163Sshinchar *ifname __P((struct ifnet *));
11655163Sshinvoid kread __P((u_long, void *, int));
117167706Sbms#ifndef __FreeBSD__
118167706Sbmsvoid acmc __P((struct ether_multi *));
119167706Sbms#endif
12055163Sshinvoid if6_addrlist __P((struct ifaddr *));
12155163Sshinvoid in6_multilist __P((struct in6_multi *));
12262785Sumestruct in6_multi * in6_multientry __P((struct in6_multi *));
123167706Sbmsvoid if_addrlist(struct ifaddr *);
124167706Sbmsvoid in_multilist(struct in_multi *);
125167706Sbmsstruct in_multi * in_multientry(struct in_multi *);
126167706Sbms#ifdef HAVE_IGMPV3
127167706Sbmsvoid in_addr_slistentry(struct in_addr_slist *ias, char *heading);
128167706Sbms#endif
129167706Sbms#ifdef HAVE_MLDV2
130167706Sbmsvoid in6_addr_slistentry(struct in6_addr_slist *ias, char *heading);
131167706Sbms#endif
13255163Sshin
13355163Sshin#define	KREAD(addr, buf, type) \
13455163Sshin	kread((u_long)addr, (void *)buf, sizeof(type))
13555163Sshin
13662785Sume#ifdef N_IN6_MK
13762785Sumestruct multi6_kludge {
13862785Sume	LIST_ENTRY(multi6_kludge) mk_entry;
13962785Sume	struct ifnet *mk_ifp;
14062785Sume	struct in6_multihead mk_head;
14162785Sume};
14262785Sume#endif
14362785Sume
14455163Sshinconst char *inet6_n2a(p)
14555163Sshin	struct in6_addr *p;
14655163Sshin{
14762785Sume	static char buf[NI_MAXHOST];
14862785Sume	struct sockaddr_in6 sin6;
14962785Sume	u_int32_t scopeid;
15062785Sume	const int niflags = NI_NUMERICHOST;
15155163Sshin
15262785Sume	memset(&sin6, 0, sizeof(sin6));
15362785Sume	sin6.sin6_family = AF_INET6;
15462785Sume	sin6.sin6_len = sizeof(struct sockaddr_in6);
15562785Sume	sin6.sin6_addr = *p;
156167706Sbms	if (IN6_IS_ADDR_LINKLOCAL(p) || IN6_IS_ADDR_MC_LINKLOCAL(p) ||
157167706Sbms	    IN6_IS_ADDR_MC_NODELOCAL(p)) {
15862785Sume		scopeid = ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
15962785Sume		if (scopeid) {
16062785Sume			sin6.sin6_scope_id = scopeid;
16162785Sume			sin6.sin6_addr.s6_addr[2] = 0;
16262785Sume			sin6.sin6_addr.s6_addr[3] = 0;
16362785Sume		}
16462785Sume	}
16562785Sume	if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
16662785Sume			buf, sizeof(buf), NULL, 0, niflags) == 0)
16762785Sume		return buf;
16862785Sume	else
16962785Sume		return "(invalid)";
17055163Sshin}
17155163Sshin
172167706Sbmsint main(argc, argv)
173167706Sbms	int argc;
174167706Sbms	char **argv;
17555163Sshin{
17655163Sshin	char	buf[_POSIX2_LINE_MAX], ifname[IFNAMSIZ];
177167706Sbms	int c;
17855163Sshin	struct	ifnet	*ifp, *nifp, ifnet;
179167706Sbms#ifndef __FreeBSD__
180167706Sbms#ifndef __NetBSD__
181167706Sbms	struct	arpcom	arpcom;
182167706Sbms#else
183167706Sbms	struct ethercom ec;
184167706Sbms	struct sockaddr_dl sdl;
185167706Sbms#endif
186167706Sbms#endif
187167706Sbms	const char *kernel = NULL;
18855163Sshin
189167706Sbms	/* "ifmcstat [kernel]" format is supported for backward compatiblity */
190167706Sbms	if (argc == 2)
191167706Sbms		kernel = argv[1];
192167706Sbms
193167706Sbms	while ((c = getopt(argc, argv, "i:f:k:")) != -1) {
194167706Sbms		switch (c) {
195167706Sbms		case 'i':
196167706Sbms			if ((ifindex = if_nametoindex(optarg)) == 0) {
197167706Sbms				fprintf(stderr, "%s: unknown interface\n", optarg);
198167706Sbms				exit(1);
199167706Sbms			}
200167706Sbms			break;
201167706Sbms		case 'f':
202167706Sbms			if (strcmp(optarg, "inet") == 0) {
203167706Sbms				af = AF_INET;
204167706Sbms				break;
205167706Sbms			}
206167706Sbms			if (strcmp(optarg, "inet6") == 0) {
207167706Sbms				af = AF_INET6;
208167706Sbms				break;
209167706Sbms			}
210167706Sbms			fprintf(stderr, "%s: unknown address family\n", optarg);
211167706Sbms			exit(1);
212167706Sbms			/*NOTREACHED*/
213167706Sbms		case 'k':
214167706Sbms			kernel = strdup(optarg);
215167706Sbms			break;
216167706Sbms		default:
217167706Sbms			fprintf(stderr, "usage: ifmcstat [-i interface] [-f address family] [-k kernel]\n");
218167706Sbms			exit(1);
219167706Sbms			/*NOTREACHED*/
220167706Sbms		}
221167706Sbms	}
222167706Sbms
223167706Sbms	if ((kvmd = kvm_openfiles(kernel, NULL, NULL, O_RDONLY, buf)) == NULL) {
22455163Sshin		perror("kvm_openfiles");
22555163Sshin		exit(1);
22655163Sshin	}
22755163Sshin	if (kvm_nlist(kvmd, nl) < 0) {
22855163Sshin		perror("kvm_nlist");
22955163Sshin		exit(1);
23055163Sshin	}
23155163Sshin	if (nl[N_IFNET].n_value == 0) {
23255163Sshin		printf("symbol %s not found\n", nl[N_IFNET].n_name);
23355163Sshin		exit(1);
23455163Sshin	}
23555163Sshin	KREAD(nl[N_IFNET].n_value, &ifp, struct ifnet *);
23655163Sshin	while (ifp) {
23755163Sshin		KREAD(ifp, &ifnet, struct ifnet);
238167706Sbms#if defined(__NetBSD__) || defined(__OpenBSD__)
239167706Sbms		nifp = ifnet.if_list.tqe_next;
240167706Sbms#else
241167706Sbms		nifp = ifnet.if_link.tqe_next;
242167706Sbms#endif
243167706Sbms		if (ifindex && ifindex != ifnet.if_index)
244167706Sbms			goto next;
245167706Sbms
24655163Sshin		printf("%s:\n", if_indextoname(ifnet.if_index, ifname));
247167706Sbms#if defined(__NetBSD__) || defined(__OpenBSD__)
248167706Sbms		if_addrlist(ifnet.if_addrlist.tqh_first);
249167706Sbms		if6_addrlist(ifnet.if_addrlist.tqh_first);
250167706Sbms#else
251167706Sbms		if_addrlist(TAILQ_FIRST(&ifnet.if_addrhead));
25255163Sshin		if6_addrlist(TAILQ_FIRST(&ifnet.if_addrhead));
253167706Sbms#endif
25462785Sume
255167706Sbms#ifdef __NetBSD__
256167706Sbms		KREAD(ifnet.if_sadl, &sdl, struct sockaddr_dl);
257167706Sbms		if (sdl.sdl_type == IFT_ETHER) {
258167706Sbms			printf("\tenaddr %s",
259167706Sbms			       ether_ntoa((struct ether_addr *)LLADDR(&sdl)));
260167706Sbms			KREAD(ifp, &ec, struct ethercom);
261167706Sbms			printf(" multicnt %d", ec.ec_multicnt);
262167706Sbms			acmc(ec.ec_multiaddrs.lh_first);
263167706Sbms			printf("\n");
264167706Sbms		}
265167706Sbms#elif defined(__FreeBSD__)
26662785Sume		/* not supported */
267167706Sbms#else /* __OpenBSD__ */
268167706Sbms		if (ifnet.if_type == IFT_ETHER) {
269167706Sbms			KREAD(ifp, &arpcom, struct arpcom);
270167706Sbms			printf("\tenaddr %s",
271167706Sbms			    ether_ntoa((struct ether_addr *)arpcom.ac_enaddr));
272167706Sbms			KREAD(ifp, &arpcom, struct arpcom);
273167706Sbms			printf(" multicnt %d", arpcom.ac_multicnt);
274167706Sbms			acmc(arpcom.ac_multiaddrs.lh_first);
275167706Sbms			printf("\n");
276167706Sbms		}
277167706Sbms#endif
27862785Sume
279167706Sbmsnext:
28062785Sume		ifp = nifp;
28155163Sshin	}
28255163Sshin
28355163Sshin	exit(0);
28455163Sshin	/*NOTREACHED*/
28555163Sshin}
28655163Sshin
28755163Sshinchar *ifname(ifp)
28855163Sshin	struct ifnet *ifp;
28955163Sshin{
29055163Sshin	static char buf[BUFSIZ];
29162785Sume	struct ifnet ifnet;
29255163Sshin
29362785Sume	KREAD(ifp, &ifnet, struct ifnet);
294121816Sbrooks	strlcpy(buf, ifnet.if_xname, sizeof(buf));
29555163Sshin	return buf;
29655163Sshin}
29755163Sshin
29855163Sshinvoid kread(addr, buf, len)
29955163Sshin	u_long addr;
30055163Sshin	void *buf;
30155163Sshin	int len;
30255163Sshin{
30355163Sshin	if (kvm_read(kvmd, addr, buf, len) != len) {
30455163Sshin		perror("kvm_read");
30555163Sshin		exit(1);
30655163Sshin	}
30755163Sshin}
30855163Sshin
309167706Sbms#ifndef __FreeBSD__
310167706Sbmsvoid acmc(am)
311167706Sbms	struct ether_multi *am;
312167706Sbms{
313167706Sbms	struct ether_multi em;
314167706Sbms
315167706Sbms	while (am) {
316167706Sbms		KREAD(am, &em, struct ether_multi);
317167706Sbms
318167706Sbms		printf("\n\t\t");
319167706Sbms		printf("%s -- ", ether_ntoa((struct ether_addr *)em.enm_addrlo));
320167706Sbms		printf("%s ", ether_ntoa((struct ether_addr *)&em.enm_addrhi));
321167706Sbms		printf("%d", em.enm_refcount);
322167706Sbms#if !defined(__NetBSD__) && !defined(__OpenBSD__)
323167706Sbms		am = em.enm_next;
324167706Sbms#else
325167706Sbms		am = em.enm_list.le_next;
326167706Sbms#endif
327167706Sbms	}
328167706Sbms}
329167706Sbms#endif
330167706Sbms
33155163Sshinvoid
33255163Sshinif6_addrlist(ifap)
33355163Sshin	struct ifaddr *ifap;
33455163Sshin{
33555163Sshin	struct ifaddr ifa;
33662785Sume	struct sockaddr sa;
33762785Sume	struct in6_ifaddr if6a;
338167706Sbms#ifndef __FreeBSD__
339167706Sbms	struct in6_multi *mc = 0;
340167706Sbms#endif
34155543Sshin	struct ifaddr *ifap0;
34255163Sshin
343167706Sbms	if (af && af != AF_INET6)
344167706Sbms		return;
34555163Sshin	ifap0 = ifap;
34662785Sume	while (ifap) {
34755163Sshin		KREAD(ifap, &ifa, struct ifaddr);
34855163Sshin		if (ifa.ifa_addr == NULL)
34962785Sume			goto nextifap;
35055163Sshin		KREAD(ifa.ifa_addr, &sa, struct sockaddr);
35155163Sshin		if (sa.sa_family != PF_INET6)
35262785Sume			goto nextifap;
35355163Sshin		KREAD(ifap, &if6a, struct in6_ifaddr);
35462785Sume		printf("\tinet6 %s\n", inet6_n2a(&if6a.ia_addr.sin6_addr));
355167706Sbms#ifndef __FreeBSD__
356167706Sbms		mc = mc ? mc : if6a.ia6_multiaddrs.lh_first;
357167706Sbms#endif
35862785Sume	nextifap:
359167706Sbms#if defined(__NetBSD__) || defined(__OpenBSD__)
360167706Sbms		ifap = ifa.ifa_list.tqe_next;
361167706Sbms#else
362167706Sbms		ifap = ifa.ifa_link.tqe_next;
363167706Sbms#endif
36462785Sume	}
365167706Sbms#ifdef __FreeBSD__
36662785Sume	if (ifap0) {
36762785Sume		struct ifnet ifnet;
36862785Sume		struct ifmultiaddr ifm, *ifmp = 0;
36962785Sume		struct sockaddr_dl sdl;
37055163Sshin
37162785Sume		KREAD(ifap0, &ifa, struct ifaddr);
37262785Sume		KREAD(ifa.ifa_ifp, &ifnet, struct ifnet);
37372084Sphk		if (TAILQ_FIRST(&ifnet.if_multiaddrs))
37472084Sphk			ifmp = TAILQ_FIRST(&ifnet.if_multiaddrs);
37562785Sume		while (ifmp) {
37662785Sume			KREAD(ifmp, &ifm, struct ifmultiaddr);
37762785Sume			if (ifm.ifma_addr == NULL)
37862785Sume				goto nextmulti;
37962785Sume			KREAD(ifm.ifma_addr, &sa, struct sockaddr);
38062785Sume			if (sa.sa_family != AF_INET6)
38162785Sume				goto nextmulti;
38262785Sume			(void)in6_multientry((struct in6_multi *)
38362785Sume					     ifm.ifma_protospec);
38462785Sume			if (ifm.ifma_lladdr == 0)
38562785Sume				goto nextmulti;
38662785Sume			KREAD(ifm.ifma_lladdr, &sdl, struct sockaddr_dl);
38762785Sume			printf("\t\t\tmcast-macaddr %s multicnt %d\n",
38862785Sume			       ether_ntoa((struct ether_addr *)LLADDR(&sdl)),
38962785Sume			       ifm.ifma_refcount);
39062785Sume		    nextmulti:
39172084Sphk			ifmp = TAILQ_NEXT(&ifm, ifma_link);
39262785Sume		}
39362785Sume	}
394167706Sbms#else
395167706Sbms	if (mc)
396167706Sbms		in6_multilist(mc);
397167706Sbms#endif
39862785Sume#ifdef N_IN6_MK
39962785Sume	if (nl[N_IN6_MK].n_value != 0) {
40062785Sume		LIST_HEAD(in6_mktype, multi6_kludge) in6_mk;
40162785Sume		struct multi6_kludge *mkp, mk;
40262785Sume		char *nam;
40362785Sume
40462785Sume		KREAD(nl[N_IN6_MK].n_value, &in6_mk, struct in6_mktype);
40562785Sume		KREAD(ifap0, &ifa, struct ifaddr);
40662785Sume
40762785Sume		nam = strdup(ifname(ifa.ifa_ifp));
40878064Sume		if (!nam) {
40978064Sume			fprintf(stderr, "ifmcstat: not enough core\n");
41078064Sume			exit(1);
41178064Sume		}
41262785Sume
413167706Sbms		for (mkp = in6_mk.lh_first; mkp; mkp = mk.mk_entry.le_next) {
41462785Sume			KREAD(mkp, &mk, struct multi6_kludge);
41562785Sume			if (strcmp(nam, ifname(mk.mk_ifp)) == 0 &&
416167706Sbms			    mk.mk_head.lh_first) {
41762785Sume				printf("\t(on kludge entry for %s)\n", nam);
418167706Sbms				in6_multilist(mk.mk_head.lh_first);
41962785Sume			}
42062785Sume		}
42162785Sume
42262785Sume		free(nam);
42362785Sume	}
42462785Sume#endif
42555163Sshin}
42655163Sshin
42762785Sumestruct in6_multi *
42855163Sshinin6_multientry(mc)
42955163Sshin	struct in6_multi *mc;
43055163Sshin{
43155163Sshin	struct in6_multi multi;
432167706Sbms#ifdef HAVE_MLDV2
433167706Sbms	struct in6_multi_source src;
434167706Sbms	struct router6_info rt6i;
435167706Sbms#endif
43655163Sshin
43755163Sshin	KREAD(mc, &multi, struct in6_multi);
43862785Sume	printf("\t\tgroup %s", inet6_n2a(&multi.in6m_addr));
43962785Sume	printf(" refcnt %u\n", multi.in6m_refcount);
440167706Sbms
441167706Sbms#ifdef HAVE_MLDV2
442167706Sbms	if (multi.in6m_rti != NULL) {
443167706Sbms		KREAD(multi.in6m_rti, &rt6i, struct router_info);
444167706Sbms		printf("\t\t\t");
445167706Sbms		switch (rt6i.rt6i_type) {
446167706Sbms		case MLD_V1_ROUTER:
447167706Sbms			printf("mldv1");
448167706Sbms			break;
449167706Sbms		case MLD_V2_ROUTER:
450167706Sbms			printf("mldv2");
451167706Sbms			break;
452167706Sbms		default:
453167706Sbms			printf("mldv?(%d)", rt6i.rt6i_type);
454167706Sbms			break;
455167706Sbms		}
456167706Sbms
457167706Sbms		if (multi.in6m_source == NULL) {
458167706Sbms			printf("\n");
459167706Sbms			return(multi.in6m_entry.le_next);
460167706Sbms		}
461167706Sbms
462167706Sbms		KREAD(multi.in6m_source, &src, struct in6_multi_source);
463167706Sbms		printf(" mode=%s grpjoin=%d\n",
464167706Sbms		    src.i6ms_mode == MCAST_INCLUDE ? "include" :
465167706Sbms		    src.i6ms_mode == MCAST_EXCLUDE ? "exclude" :
466167706Sbms		    "???",
467167706Sbms		    src.i6ms_grpjoin);
468167706Sbms		in6_addr_slistentry(src.i6ms_cur, "current");
469167706Sbms		in6_addr_slistentry(src.i6ms_rec, "recorded");
470167706Sbms		in6_addr_slistentry(src.i6ms_in, "included");
471167706Sbms		in6_addr_slistentry(src.i6ms_ex, "excluded");
472167706Sbms		in6_addr_slistentry(src.i6ms_alw, "allowed");
473167706Sbms		in6_addr_slistentry(src.i6ms_blk, "blocked");
474167706Sbms		in6_addr_slistentry(src.i6ms_toin, "to-include");
475167706Sbms		in6_addr_slistentry(src.i6ms_ex, "to-exclude");
476167706Sbms	}
477167706Sbms#endif
478167706Sbms	return(multi.in6m_entry.le_next);
47955163Sshin}
48062785Sume
481167706Sbms#ifdef HAVE_MLDV2
48262785Sumevoid
483167706Sbmsin6_addr_slistentry(struct in6_addr_slist *ias, char *heading)
484167706Sbms{
485167706Sbms	struct in6_addr_slist slist;
486167706Sbms	struct i6as_head head;
487167706Sbms	struct in6_addr_source src;
488167706Sbms
489167706Sbms	if (ias == NULL) {
490167706Sbms		printf("\t\t\t\t%s (none)\n", heading);
491167706Sbms		return;
492167706Sbms	}
493167706Sbms	memset(&slist, 0, sizeof(slist));
494167706Sbms	KREAD(ias, &slist, struct in6_addr_source);
495167706Sbms	printf("\t\t\t\t%s (entry num=%d)\n", heading, slist.numsrc);
496167706Sbms	if (slist.numsrc == 0) {
497167706Sbms		return;
498167706Sbms	}
499167706Sbms	KREAD(slist.head, &head, struct i6as_head);
500167706Sbms
501167706Sbms	KREAD(head.lh_first, &src, struct in6_addr_source);
502167706Sbms	while (1) {
503167706Sbms		printf("\t\t\t\t\tsource %s (ref=%d)\n",
504167706Sbms			inet6_n2a(&src.i6as_addr.sin6_addr),
505167706Sbms			src.i6as_refcount);
506167706Sbms		if (src.i6as_list.le_next == NULL)
507167706Sbms			break;
508167706Sbms		KREAD(src.i6as_list.le_next, &src, struct in6_addr_source);
509167706Sbms	}
510167706Sbms	return;
511167706Sbms}
512167706Sbms#endif
513167706Sbms
514167706Sbmsvoid
51562785Sumein6_multilist(mc)
51662785Sume	struct in6_multi *mc;
51762785Sume{
51862785Sume	while (mc)
51962785Sume		mc = in6_multientry(mc);
52062785Sume}
521167706Sbms
522167706Sbmsvoid
523167706Sbmsif_addrlist(ifap)
524167706Sbms	struct ifaddr *ifap;
525167706Sbms{
526167706Sbms	struct ifaddr ifa;
527167706Sbms	struct sockaddr sa;
528167706Sbms	struct in_ifaddr ia;
529167706Sbms#ifndef __FreeBSD__
530167706Sbms	struct in_multi *mc = 0;
531167706Sbms#endif
532167706Sbms	struct ifaddr *ifap0;
533167706Sbms
534167706Sbms	if (af && af != AF_INET)
535167706Sbms		return;
536167706Sbms	ifap0 = ifap;
537167706Sbms	while (ifap) {
538167706Sbms		KREAD(ifap, &ifa, struct ifaddr);
539167706Sbms		if (ifa.ifa_addr == NULL)
540167706Sbms			goto nextifap;
541167706Sbms		KREAD(ifa.ifa_addr, &sa, struct sockaddr);
542167706Sbms		if (sa.sa_family != PF_INET)
543167706Sbms			goto nextifap;
544167706Sbms		KREAD(ifap, &ia, struct in_ifaddr);
545167706Sbms		printf("\tinet %s\n", inet_ntoa(ia.ia_addr.sin_addr));
546167706Sbms#ifndef __FreeBSD__
547167706Sbms		mc = mc ? mc : ia.ia_multiaddrs.lh_first;
548167706Sbms#endif
549167706Sbms	nextifap:
550167706Sbms#if defined(__NetBSD__) || defined(__OpenBSD__)
551167706Sbms		ifap = ifa.ifa_list.tqe_next;
552167706Sbms#else
553167706Sbms		ifap = ifa.ifa_link.tqe_next;
554167706Sbms#endif
555167706Sbms	}
556167706Sbms#ifdef __FreeBSD__
557167706Sbms	if (ifap0) {
558167706Sbms		struct ifnet ifnet;
559167706Sbms		struct ifmultiaddr ifm, *ifmp = 0;
560167706Sbms		struct sockaddr_dl sdl;
561167706Sbms
562167706Sbms		KREAD(ifap0, &ifa, struct ifaddr);
563167706Sbms		KREAD(ifa.ifa_ifp, &ifnet, struct ifnet);
564167706Sbms		if (TAILQ_FIRST(&ifnet.if_multiaddrs))
565167706Sbms			ifmp = TAILQ_FIRST(&ifnet.if_multiaddrs);
566167706Sbms		while (ifmp) {
567167706Sbms			KREAD(ifmp, &ifm, struct ifmultiaddr);
568167706Sbms			if (ifm.ifma_addr == NULL)
569167706Sbms				goto nextmulti;
570167706Sbms			KREAD(ifm.ifma_addr, &sa, struct sockaddr);
571167706Sbms			if (sa.sa_family != AF_INET)
572167706Sbms				goto nextmulti;
573167706Sbms			(void)in_multientry((struct in_multi *)
574167706Sbms					    ifm.ifma_protospec);
575167706Sbms			if (ifm.ifma_lladdr == 0)
576167706Sbms				goto nextmulti;
577167706Sbms			KREAD(ifm.ifma_lladdr, &sdl, struct sockaddr_dl);
578167706Sbms			printf("\t\t\tmcast-macaddr %s multicnt %d\n",
579167706Sbms			       ether_ntoa((struct ether_addr *)LLADDR(&sdl)),
580167706Sbms			       ifm.ifma_refcount);
581167706Sbms		    nextmulti:
582167706Sbms			ifmp = TAILQ_NEXT(&ifm, ifma_link);
583167706Sbms		}
584167706Sbms	}
585167706Sbms#else /* !FreeBSD */
586167706Sbms	if (mc)
587167706Sbms		in_multilist(mc);
588167706Sbms#endif
589167706Sbms}
590167706Sbms
591167706Sbmsvoid
592167706Sbmsin_multilist(mc)
593167706Sbms	struct in_multi *mc;
594167706Sbms{
595167706Sbms	while (mc)
596167706Sbms		mc = in_multientry(mc);
597167706Sbms}
598167706Sbms
599167706Sbmsstruct in_multi *
600167706Sbmsin_multientry(mc)
601167706Sbms	struct in_multi *mc;
602167706Sbms{
603167706Sbms	struct in_multi multi;
604167706Sbms	struct router_info rti;
605167706Sbms#ifdef HAVE_IGMPV3
606167706Sbms	struct in_multi_source src;
607167706Sbms#endif
608167706Sbms
609167706Sbms	KREAD(mc, &multi, struct in_multi);
610167706Sbms	printf("\t\tgroup %s\n", inet_ntoa(multi.inm_addr));
611167706Sbms
612167706Sbms	if (multi.inm_rti != NULL) {
613167706Sbms		KREAD(multi.inm_rti, &rti, struct router_info);
614167706Sbms		printf("\t\t\t");
615167706Sbms		switch (rti.rti_type) {
616167706Sbms		case IGMP_v1_ROUTER:
617167706Sbms			printf("igmpv1");
618167706Sbms			break;
619167706Sbms		case IGMP_v2_ROUTER:
620167706Sbms			printf("igmpv2");
621167706Sbms			break;
622167706Sbms#ifdef HAVE_IGMPV3
623167706Sbms		case IGMP_v3_ROUTER:
624167706Sbms			printf("igmpv3");
625167706Sbms			break;
626167706Sbms#endif
627167706Sbms		default:
628167706Sbms			printf("igmpv?(%d)", rti.rti_type);
629167706Sbms			break;
630167706Sbms		}
631167706Sbms
632167706Sbms#ifdef HAVE_IGMPV3
633167706Sbms		if (multi.inm_source == NULL) {
634167706Sbms			printf("\n");
635167706Sbms			return (multi.inm_list.le_next);
636167706Sbms		}
637167706Sbms
638167706Sbms		KREAD(multi.inm_source, &src, struct in_multi_source);
639167706Sbms		printf(" mode=%s grpjoin=%d\n",
640167706Sbms		    src.ims_mode == MCAST_INCLUDE ? "include" :
641167706Sbms		    src.ims_mode == MCAST_EXCLUDE ? "exclude" :
642167706Sbms		    "???",
643167706Sbms		    src.ims_grpjoin);
644167706Sbms		in_addr_slistentry(src.ims_cur, "current");
645167706Sbms		in_addr_slistentry(src.ims_rec, "recorded");
646167706Sbms		in_addr_slistentry(src.ims_in, "included");
647167706Sbms		in_addr_slistentry(src.ims_ex, "excluded");
648167706Sbms		in_addr_slistentry(src.ims_alw, "allowed");
649167706Sbms		in_addr_slistentry(src.ims_blk, "blocked");
650167706Sbms		in_addr_slistentry(src.ims_toin, "to-include");
651167706Sbms		in_addr_slistentry(src.ims_ex, "to-exclude");
652167706Sbms#else
653167706Sbms		printf("\n");
654167706Sbms#endif
655167706Sbms	}
656167706Sbms
657167706Sbms#ifdef __FreeBSD__
658167706Sbms	return (NULL);
659167706Sbms#else
660167706Sbms	return (multi.inm_list.le_next);
661167706Sbms#endif
662167706Sbms}
663167706Sbms
664167706Sbms#ifdef HAVE_IGMPV3
665167706Sbmsvoid
666167706Sbmsin_addr_slistentry(struct in_addr_slist *ias, char *heading)
667167706Sbms{
668167706Sbms	struct in_addr_slist slist;
669167706Sbms	struct ias_head head;
670167706Sbms	struct in_addr_source src;
671167706Sbms
672167706Sbms	if (ias == NULL) {
673167706Sbms		printf("\t\t\t\t%s (none)\n", heading);
674167706Sbms		return;
675167706Sbms	}
676167706Sbms	memset(&slist, 0, sizeof(slist));
677167706Sbms	KREAD(ias, &slist, struct in_addr_source);
678167706Sbms	printf("\t\t\t\t%s (entry num=%d)\n", heading, slist.numsrc);
679167706Sbms	if (slist.numsrc == 0) {
680167706Sbms		return;
681167706Sbms	}
682167706Sbms	KREAD(slist.head, &head, struct ias_head);
683167706Sbms
684167706Sbms	KREAD(head.lh_first, &src, struct in_addr_source);
685167706Sbms	while (1) {
686167706Sbms		printf("\t\t\t\t\tsource %s (ref=%d)\n",
687167706Sbms			inet_ntoa(src.ias_addr.sin_addr), src.ias_refcount);
688167706Sbms		if (src.ias_list.le_next == NULL)
689167706Sbms			break;
690167706Sbms		KREAD(src.ias_list.le_next, &src, struct in_addr_source);
691167706Sbms	}
692167706Sbms	return;
693167706Sbms}
694167706Sbms#endif
695