xref: /freebsd-src/usr.sbin/ifmcstat/ifmcstat.c (revision 4d65a7c6951cea0333f1a0c1b32c38489cdfa6c5)
11048e675SBruce M Simpson /*	$KAME: ifmcstat.c,v 1.48 2006/11/15 05:13:59 itojun Exp $	*/
21048e675SBruce M Simpson 
3*8a16b7a1SPedro F. Giffuni /*-
4*8a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
5*8a16b7a1SPedro F. Giffuni  *
6d508ff40SBruce M Simpson  * Copyright (c) 2007-2009 Bruce Simpson.
77d56d374SYoshinobu Inoue  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
87d56d374SYoshinobu Inoue  * All rights reserved.
97d56d374SYoshinobu Inoue  *
107d56d374SYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
117d56d374SYoshinobu Inoue  * modification, are permitted provided that the following conditions
127d56d374SYoshinobu Inoue  * are met:
137d56d374SYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
147d56d374SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
157d56d374SYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
167d56d374SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
177d56d374SYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
187d56d374SYoshinobu Inoue  * 3. Neither the name of the project nor the names of its contributors
197d56d374SYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
207d56d374SYoshinobu Inoue  *    without specific prior written permission.
217d56d374SYoshinobu Inoue  *
227d56d374SYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
237d56d374SYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
247d56d374SYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
257d56d374SYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
267d56d374SYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
277d56d374SYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
287d56d374SYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
297d56d374SYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
307d56d374SYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
317d56d374SYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
327d56d374SYoshinobu Inoue  * SUCH DAMAGE.
337d56d374SYoshinobu Inoue  */
347d56d374SYoshinobu Inoue 
35cb48db9cSBruce M Simpson #include <sys/types.h>
36cb48db9cSBruce M Simpson #include <sys/param.h>
37d10910e6SBruce M Simpson #include <sys/sysctl.h>
38cb48db9cSBruce M Simpson #include <sys/socket.h>
39cb48db9cSBruce M Simpson #include <sys/queue.h>
40d10910e6SBruce M Simpson #include <sys/tree.h>
41cb48db9cSBruce M Simpson 
42cb48db9cSBruce M Simpson #include <net/if.h>
43cb48db9cSBruce M Simpson #include <net/if_types.h>
44cb48db9cSBruce M Simpson #include <net/if_dl.h>
45cb48db9cSBruce M Simpson #include <net/route.h>
46cb48db9cSBruce M Simpson 
47cb48db9cSBruce M Simpson #include <netinet/in.h>
48cb48db9cSBruce M Simpson #include <netinet/in_var.h>
49cb48db9cSBruce M Simpson #include <netinet/in_systm.h>
50cb48db9cSBruce M Simpson #include <netinet/ip.h>
51cb48db9cSBruce M Simpson #include <netinet/igmp.h>
52cb48db9cSBruce M Simpson #include <netinet/if_ether.h>
53cb48db9cSBruce M Simpson #include <netinet/igmp_var.h>
54cb48db9cSBruce M Simpson 
55cb48db9cSBruce M Simpson #ifdef INET6
56cb48db9cSBruce M Simpson #include <netinet/icmp6.h>
57cb48db9cSBruce M Simpson #include <netinet6/mld6_var.h>
58cb48db9cSBruce M Simpson #endif /* INET6 */
591048e675SBruce M Simpson 
607d56d374SYoshinobu Inoue #include <arpa/inet.h>
619bdd4811SHajimu UMEMOTO #include <netdb.h>
629bdd4811SHajimu UMEMOTO 
6360dd8da7SBruce M Simpson #include <stddef.h>
6460dd8da7SBruce M Simpson #include <stdarg.h>
6560dd8da7SBruce M Simpson #include <stdint.h>
6660dd8da7SBruce M Simpson #include <stdio.h>
6760dd8da7SBruce M Simpson #include <stdlib.h>
6860dd8da7SBruce M Simpson #include <string.h>
6960dd8da7SBruce M Simpson 
7060dd8da7SBruce M Simpson #include <ctype.h>
7160dd8da7SBruce M Simpson #include <err.h>
72d10910e6SBruce M Simpson #include <errno.h>
7360dd8da7SBruce M Simpson #include <fcntl.h>
7460dd8da7SBruce M Simpson #include <limits.h>
7560dd8da7SBruce M Simpson #include <ifaddrs.h>
7660dd8da7SBruce M Simpson #include <sysexits.h>
7760dd8da7SBruce M Simpson #include <unistd.h>
7860dd8da7SBruce M Simpson 
79b1499febSGleb Smirnoff #ifdef KVM
80b1499febSGleb Smirnoff /*
81b1499febSGleb Smirnoff  * Currently the KVM build is broken. To be fixed it requires uncovering
82b1499febSGleb Smirnoff  * large amount of _KERNEL code in include files, and it is also very
83b1499febSGleb Smirnoff  * tentative to internal kernel ABI changes. If anyone wishes to restore
84b1499febSGleb Smirnoff  * it, please move it out of src/usr.sbin to src/tools/tools.
85b1499febSGleb Smirnoff  */
86b1499febSGleb Smirnoff #include <kvm.h>
87b1499febSGleb Smirnoff #include <nlist.h>
88b1499febSGleb Smirnoff #endif
89b1499febSGleb Smirnoff 
90b1499febSGleb Smirnoff /* XXX: This file currently assumes INET support in the base system. */
9160dd8da7SBruce M Simpson #ifndef INET
9260dd8da7SBruce M Simpson #define INET
9360dd8da7SBruce M Simpson #endif
9460dd8da7SBruce M Simpson 
95d10910e6SBruce M Simpson extern void	printb(const char *, unsigned int, const char *);
96d10910e6SBruce M Simpson 
9760dd8da7SBruce M Simpson union sockunion {
9860dd8da7SBruce M Simpson 	struct sockaddr_storage	ss;
9960dd8da7SBruce M Simpson 	struct sockaddr		sa;
10060dd8da7SBruce M Simpson 	struct sockaddr_dl	sdl;
10160dd8da7SBruce M Simpson #ifdef INET
10260dd8da7SBruce M Simpson 	struct sockaddr_in	sin;
10360dd8da7SBruce M Simpson #endif
10460dd8da7SBruce M Simpson #ifdef INET6
10560dd8da7SBruce M Simpson 	struct sockaddr_in6	sin6;
10660dd8da7SBruce M Simpson #endif
10760dd8da7SBruce M Simpson };
10860dd8da7SBruce M Simpson typedef union sockunion sockunion_t;
10960dd8da7SBruce M Simpson 
11060dd8da7SBruce M Simpson uint32_t	ifindex = 0;
1111048e675SBruce M Simpson int		af = AF_UNSPEC;
112d10910e6SBruce M Simpson #ifdef WITH_KVM
113d10910e6SBruce M Simpson int		Kflag = 0;
114d10910e6SBruce M Simpson #endif
115d508ff40SBruce M Simpson int		vflag = 0;
1167d56d374SYoshinobu Inoue 
11760dd8da7SBruce M Simpson #define	sa_dl_equal(a1, a2)	\
11860dd8da7SBruce M Simpson 	((((struct sockaddr_dl *)(a1))->sdl_len ==			\
11960dd8da7SBruce M Simpson 	 ((struct sockaddr_dl *)(a2))->sdl_len) &&			\
12060dd8da7SBruce M Simpson 	 (bcmp(LLADDR((struct sockaddr_dl *)(a1)),			\
12160dd8da7SBruce M Simpson 	       LLADDR((struct sockaddr_dl *)(a2)),			\
12260dd8da7SBruce M Simpson 	       ((struct sockaddr_dl *)(a1))->sdl_alen) == 0))
12360dd8da7SBruce M Simpson 
12460dd8da7SBruce M Simpson /*
12560dd8da7SBruce M Simpson  * Most of the code in this utility is to support the use of KVM for
12660dd8da7SBruce M Simpson  * post-mortem debugging of the multicast code.
12760dd8da7SBruce M Simpson  */
12860dd8da7SBruce M Simpson #ifdef WITH_KVM
12960dd8da7SBruce M Simpson 
13060dd8da7SBruce M Simpson #ifdef INET
13160dd8da7SBruce M Simpson static void		if_addrlist(struct ifaddr *);
13260dd8da7SBruce M Simpson static struct in_multi *
13360dd8da7SBruce M Simpson 			in_multientry(struct in_multi *);
13460dd8da7SBruce M Simpson #endif /* INET */
13560dd8da7SBruce M Simpson 
13660dd8da7SBruce M Simpson #ifdef INET6
13760dd8da7SBruce M Simpson static void		if6_addrlist(struct ifaddr *);
13860dd8da7SBruce M Simpson static struct in6_multi *
13960dd8da7SBruce M Simpson 			in6_multientry(struct in6_multi *);
14060dd8da7SBruce M Simpson #endif /* INET6 */
14160dd8da7SBruce M Simpson 
14260dd8da7SBruce M Simpson static void		kread(u_long, void *, int);
143d508ff40SBruce M Simpson static void		ll_addrlist(struct ifaddr *);
144d508ff40SBruce M Simpson 
14560dd8da7SBruce M Simpson static int		ifmcstat_kvm(const char *kernel, const char *core);
1467d56d374SYoshinobu Inoue 
1477d56d374SYoshinobu Inoue #define	KREAD(addr, buf, type) \
1487d56d374SYoshinobu Inoue 	kread((u_long)addr, (void *)buf, sizeof(type))
1497d56d374SYoshinobu Inoue 
15060dd8da7SBruce M Simpson kvm_t	*kvmd;
15160dd8da7SBruce M Simpson struct	nlist nl[] = {
15260dd8da7SBruce M Simpson 	{ "_ifnet", 0, 0, 0, 0, },
15360dd8da7SBruce M Simpson 	{ "", 0, 0, 0, 0, },
15460dd8da7SBruce M Simpson };
15560dd8da7SBruce M Simpson #define	N_IFNET	0
15660dd8da7SBruce M Simpson 
15760dd8da7SBruce M Simpson #endif /* WITH_KVM */
15860dd8da7SBruce M Simpson 
15960dd8da7SBruce M Simpson static int		ifmcstat_getifmaddrs(void);
160d10910e6SBruce M Simpson #ifdef INET
161d10910e6SBruce M Simpson static void		in_ifinfo(struct igmp_ifinfo *);
162d10910e6SBruce M Simpson static const char *	inm_mode(u_int mode);
163d10910e6SBruce M Simpson #endif
164d508ff40SBruce M Simpson #ifdef INET6
16533cde130SBruce M Simpson static void		in6_ifinfo(struct mld_ifinfo *);
166a038519eSHiroki Sato static const char *	inet6_n2a(struct in6_addr *, uint32_t);
167d508ff40SBruce M Simpson #endif
16860dd8da7SBruce M Simpson int			main(int, char **);
16960dd8da7SBruce M Simpson 
170d508ff40SBruce M Simpson static void
usage()171d508ff40SBruce M Simpson usage()
172d508ff40SBruce M Simpson {
173d508ff40SBruce M Simpson 
174d508ff40SBruce M Simpson 	fprintf(stderr,
175d508ff40SBruce M Simpson 	    "usage: ifmcstat [-i interface] [-f address family]"
176d508ff40SBruce M Simpson 	    " [-v]"
177d508ff40SBruce M Simpson #ifdef WITH_KVM
178d10910e6SBruce M Simpson 	    " [-K] [-M core] [-N system]"
179d508ff40SBruce M Simpson #endif
180d508ff40SBruce M Simpson 	    "\n");
181d508ff40SBruce M Simpson 	exit(EX_USAGE);
182d508ff40SBruce M Simpson }
183d508ff40SBruce M Simpson 
184d10910e6SBruce M Simpson static const char *options = "i:f:vM:N:"
185d10910e6SBruce M Simpson #ifdef WITH_KVM
186d10910e6SBruce M Simpson 	"K"
187d10910e6SBruce M Simpson #endif
188d10910e6SBruce M Simpson 	;
189d10910e6SBruce M Simpson 
19060dd8da7SBruce M Simpson int
main(int argc,char ** argv)19160dd8da7SBruce M Simpson main(int argc, char **argv)
19260dd8da7SBruce M Simpson {
19360dd8da7SBruce M Simpson 	int c, error;
19460dd8da7SBruce M Simpson #ifdef WITH_KVM
19560dd8da7SBruce M Simpson 	const char *kernel = NULL;
19660dd8da7SBruce M Simpson 	const char *core = NULL;
19760dd8da7SBruce M Simpson #endif
19860dd8da7SBruce M Simpson 
199d10910e6SBruce M Simpson 	while ((c = getopt(argc, argv, options)) != -1) {
20060dd8da7SBruce M Simpson 		switch (c) {
20160dd8da7SBruce M Simpson 		case 'i':
20260dd8da7SBruce M Simpson 			if ((ifindex = if_nametoindex(optarg)) == 0) {
20360dd8da7SBruce M Simpson 				fprintf(stderr, "%s: unknown interface\n",
20460dd8da7SBruce M Simpson 				    optarg);
2053f3d246fSBruce M Simpson 				exit(EX_NOHOST);
20660dd8da7SBruce M Simpson 			}
20760dd8da7SBruce M Simpson 			break;
20860dd8da7SBruce M Simpson 
20960dd8da7SBruce M Simpson 		case 'f':
21060dd8da7SBruce M Simpson #ifdef INET
21160dd8da7SBruce M Simpson 			if (strcmp(optarg, "inet") == 0) {
21260dd8da7SBruce M Simpson 				af = AF_INET;
21360dd8da7SBruce M Simpson 				break;
21460dd8da7SBruce M Simpson 			}
21560dd8da7SBruce M Simpson #endif
21660dd8da7SBruce M Simpson #ifdef INET6
21760dd8da7SBruce M Simpson 			if (strcmp(optarg, "inet6") == 0) {
21860dd8da7SBruce M Simpson 				af = AF_INET6;
21960dd8da7SBruce M Simpson 				break;
22060dd8da7SBruce M Simpson 			}
22160dd8da7SBruce M Simpson #endif
222d508ff40SBruce M Simpson 			if (strcmp(optarg, "link") == 0) {
223d508ff40SBruce M Simpson 				af = AF_LINK;
224d508ff40SBruce M Simpson 				break;
225d508ff40SBruce M Simpson 			}
22660dd8da7SBruce M Simpson 			fprintf(stderr, "%s: unknown address family\n", optarg);
2273f3d246fSBruce M Simpson 			exit(EX_USAGE);
22860dd8da7SBruce M Simpson 			/*NOTREACHED*/
22960dd8da7SBruce M Simpson 			break;
23060dd8da7SBruce M Simpson 
231d10910e6SBruce M Simpson #ifdef WITH_KVM
232d10910e6SBruce M Simpson 		case 'K':
233d10910e6SBruce M Simpson 			++Kflag;
234d10910e6SBruce M Simpson 			break;
235d10910e6SBruce M Simpson #endif
236d10910e6SBruce M Simpson 
237d508ff40SBruce M Simpson 		case 'v':
238d10910e6SBruce M Simpson 			++vflag;
239d508ff40SBruce M Simpson 			break;
240d508ff40SBruce M Simpson 
24160dd8da7SBruce M Simpson #ifdef WITH_KVM
24260dd8da7SBruce M Simpson 		case 'M':
24360dd8da7SBruce M Simpson 			core = strdup(optarg);
24460dd8da7SBruce M Simpson 			break;
24560dd8da7SBruce M Simpson 
24660dd8da7SBruce M Simpson 		case 'N':
24760dd8da7SBruce M Simpson 			kernel = strdup(optarg);
24860dd8da7SBruce M Simpson 			break;
24960dd8da7SBruce M Simpson #endif
25060dd8da7SBruce M Simpson 
25160dd8da7SBruce M Simpson 		default:
252d508ff40SBruce M Simpson 			usage();
25360dd8da7SBruce M Simpson 			break;
25460dd8da7SBruce M Simpson 			/*NOTREACHED*/
25560dd8da7SBruce M Simpson 		}
25660dd8da7SBruce M Simpson 	}
25760dd8da7SBruce M Simpson 
258d508ff40SBruce M Simpson 	if (af == AF_LINK && vflag)
259d508ff40SBruce M Simpson 		usage();
260d508ff40SBruce M Simpson 
26160dd8da7SBruce M Simpson #ifdef WITH_KVM
26229dc7bc6SBruce M Simpson 	if (Kflag)
26360dd8da7SBruce M Simpson 		error = ifmcstat_kvm(kernel, core);
26460dd8da7SBruce M Simpson 	/*
26560dd8da7SBruce M Simpson 	 * If KVM failed, and user did not explicitly specify a core file,
266d10910e6SBruce M Simpson 	 * or force KVM backend to be disabled, try the sysctl backend.
26760dd8da7SBruce M Simpson 	 */
26829dc7bc6SBruce M Simpson 	if (!Kflag || (error != 0 && (core == NULL && kernel == NULL)))
26960dd8da7SBruce M Simpson #endif
27060dd8da7SBruce M Simpson 	error = ifmcstat_getifmaddrs();
27160dd8da7SBruce M Simpson 	if (error != 0)
2723f3d246fSBruce M Simpson 		exit(EX_OSERR);
27360dd8da7SBruce M Simpson 
2743f3d246fSBruce M Simpson 	exit(EX_OK);
27560dd8da7SBruce M Simpson 	/*NOTREACHED*/
27660dd8da7SBruce M Simpson }
27760dd8da7SBruce M Simpson 
278d10910e6SBruce M Simpson #ifdef INET
279d10910e6SBruce M Simpson 
280d10910e6SBruce M Simpson static void
in_ifinfo(struct igmp_ifinfo * igi)281d10910e6SBruce M Simpson in_ifinfo(struct igmp_ifinfo *igi)
282d10910e6SBruce M Simpson {
283d10910e6SBruce M Simpson 
284d10910e6SBruce M Simpson 	printf("\t");
285d10910e6SBruce M Simpson 	switch (igi->igi_version) {
286d10910e6SBruce M Simpson 	case IGMP_VERSION_1:
287d10910e6SBruce M Simpson 	case IGMP_VERSION_2:
288d10910e6SBruce M Simpson 	case IGMP_VERSION_3:
289d10910e6SBruce M Simpson 		printf("igmpv%d", igi->igi_version);
290d10910e6SBruce M Simpson 		break;
291d10910e6SBruce M Simpson 	default:
292d10910e6SBruce M Simpson 		printf("igmpv?(%d)", igi->igi_version);
293d10910e6SBruce M Simpson 		break;
294d10910e6SBruce M Simpson 	}
295e0418c03SHiroki Sato 	if (igi->igi_flags)
296d10910e6SBruce M Simpson 		printb(" flags", igi->igi_flags, "\020\1SILENT\2LOOPBACK");
297d10910e6SBruce M Simpson 	if (igi->igi_version == IGMP_VERSION_3) {
298d10910e6SBruce M Simpson 		printf(" rv %u qi %u qri %u uri %u",
299d10910e6SBruce M Simpson 		    igi->igi_rv, igi->igi_qi, igi->igi_qri, igi->igi_uri);
300d10910e6SBruce M Simpson 	}
301d10910e6SBruce M Simpson 	if (vflag >= 2) {
302d10910e6SBruce M Simpson 		printf(" v1timer %u v2timer %u v3timer %u",
303d10910e6SBruce M Simpson 		    igi->igi_v1_timer, igi->igi_v2_timer, igi->igi_v3_timer);
304d10910e6SBruce M Simpson 	}
305d10910e6SBruce M Simpson 	printf("\n");
306d10910e6SBruce M Simpson }
307d10910e6SBruce M Simpson 
308d10910e6SBruce M Simpson static const char *inm_modes[] = {
309d10910e6SBruce M Simpson 	"undefined",
310d10910e6SBruce M Simpson 	"include",
311d10910e6SBruce M Simpson 	"exclude",
312d10910e6SBruce M Simpson };
313d10910e6SBruce M Simpson 
314d10910e6SBruce M Simpson static const char *
inm_mode(u_int mode)315d10910e6SBruce M Simpson inm_mode(u_int mode)
316d10910e6SBruce M Simpson {
317d10910e6SBruce M Simpson 
318d10910e6SBruce M Simpson 	if (mode >= MCAST_UNDEFINED && mode <= MCAST_EXCLUDE)
319d10910e6SBruce M Simpson 		return (inm_modes[mode]);
320d10910e6SBruce M Simpson 	return (NULL);
321d10910e6SBruce M Simpson }
322d10910e6SBruce M Simpson 
323d10910e6SBruce M Simpson #endif /* INET */
324d10910e6SBruce M Simpson 
32560dd8da7SBruce M Simpson #ifdef WITH_KVM
32660dd8da7SBruce M Simpson 
32760dd8da7SBruce M Simpson static int
ifmcstat_kvm(const char * kernel,const char * core)32860dd8da7SBruce M Simpson ifmcstat_kvm(const char *kernel, const char *core)
32960dd8da7SBruce M Simpson {
33060dd8da7SBruce M Simpson 	char	buf[_POSIX2_LINE_MAX], ifname[IFNAMSIZ];
33160dd8da7SBruce M Simpson 	struct	ifnet	*ifp, *nifp, ifnet;
33260dd8da7SBruce M Simpson 
33360dd8da7SBruce M Simpson 	if ((kvmd = kvm_openfiles(kernel, core, NULL, O_RDONLY, buf)) ==
33460dd8da7SBruce M Simpson 	    NULL) {
33560dd8da7SBruce M Simpson 		perror("kvm_openfiles");
33660dd8da7SBruce M Simpson 		return (-1);
33760dd8da7SBruce M Simpson 	}
33860dd8da7SBruce M Simpson 	if (kvm_nlist(kvmd, nl) < 0) {
33960dd8da7SBruce M Simpson 		perror("kvm_nlist");
34060dd8da7SBruce M Simpson 		return (-1);
34160dd8da7SBruce M Simpson 	}
34260dd8da7SBruce M Simpson 	if (nl[N_IFNET].n_value == 0) {
34360dd8da7SBruce M Simpson 		printf("symbol %s not found\n", nl[N_IFNET].n_name);
34460dd8da7SBruce M Simpson 		return (-1);
34560dd8da7SBruce M Simpson 	}
34660dd8da7SBruce M Simpson 	KREAD(nl[N_IFNET].n_value, &ifp, struct ifnet *);
34760dd8da7SBruce M Simpson 	while (ifp) {
34860dd8da7SBruce M Simpson 		KREAD(ifp, &ifnet, struct ifnet);
34960dd8da7SBruce M Simpson 		nifp = ifnet.if_link.tqe_next;
35060dd8da7SBruce M Simpson 		if (ifindex && ifindex != ifnet.if_index)
35160dd8da7SBruce M Simpson 			goto next;
35260dd8da7SBruce M Simpson 
35360dd8da7SBruce M Simpson 		printf("%s:\n", if_indextoname(ifnet.if_index, ifname));
35460dd8da7SBruce M Simpson #ifdef INET
35560dd8da7SBruce M Simpson 		if_addrlist(TAILQ_FIRST(&ifnet.if_addrhead));
35660dd8da7SBruce M Simpson #endif
35760dd8da7SBruce M Simpson #ifdef INET6
35860dd8da7SBruce M Simpson 		if6_addrlist(TAILQ_FIRST(&ifnet.if_addrhead));
35960dd8da7SBruce M Simpson #endif
360d508ff40SBruce M Simpson 		if (vflag)
361d508ff40SBruce M Simpson 			ll_addrlist(TAILQ_FIRST(&ifnet.if_addrhead));
36260dd8da7SBruce M Simpson 	next:
36360dd8da7SBruce M Simpson 		ifp = nifp;
36460dd8da7SBruce M Simpson 	}
36560dd8da7SBruce M Simpson 
36660dd8da7SBruce M Simpson 	return (0);
36760dd8da7SBruce M Simpson }
36860dd8da7SBruce M Simpson 
36960dd8da7SBruce M Simpson static void
kread(u_long addr,void * buf,int len)37060dd8da7SBruce M Simpson kread(u_long addr, void *buf, int len)
37160dd8da7SBruce M Simpson {
37260dd8da7SBruce M Simpson 
37360dd8da7SBruce M Simpson 	if (kvm_read(kvmd, addr, buf, len) != len) {
37460dd8da7SBruce M Simpson 		perror("kvm_read");
3753f3d246fSBruce M Simpson 		exit(EX_OSERR);
37660dd8da7SBruce M Simpson 	}
37760dd8da7SBruce M Simpson }
37860dd8da7SBruce M Simpson 
379d508ff40SBruce M Simpson static void
ll_addrlist(struct ifaddr * ifap)380d508ff40SBruce M Simpson ll_addrlist(struct ifaddr *ifap)
3817d56d374SYoshinobu Inoue {
382d508ff40SBruce M Simpson 	char addrbuf[NI_MAXHOST];
383d508ff40SBruce M Simpson 	struct ifaddr ifa;
384d508ff40SBruce M Simpson 	struct sockaddr sa;
385d508ff40SBruce M Simpson 	struct sockaddr_dl sdl;
386d508ff40SBruce M Simpson 	struct ifaddr *ifap0;
3877d56d374SYoshinobu Inoue 
388d508ff40SBruce M Simpson 	if (af && af != AF_LINK)
389d508ff40SBruce M Simpson 		return;
390d508ff40SBruce M Simpson 
391d508ff40SBruce M Simpson 	ifap0 = ifap;
392d508ff40SBruce M Simpson 	while (ifap) {
393d508ff40SBruce M Simpson 		KREAD(ifap, &ifa, struct ifaddr);
394d508ff40SBruce M Simpson 		if (ifa.ifa_addr == NULL)
395d508ff40SBruce M Simpson 			goto nextifap;
396d508ff40SBruce M Simpson 		KREAD(ifa.ifa_addr, &sa, struct sockaddr);
397d508ff40SBruce M Simpson 		if (sa.sa_family != PF_LINK)
398d508ff40SBruce M Simpson 			goto nextifap;
399d508ff40SBruce M Simpson 		KREAD(ifa.ifa_addr, &sdl, struct sockaddr_dl);
400d508ff40SBruce M Simpson 		if (sdl.sdl_alen == 0)
401d508ff40SBruce M Simpson 			goto nextifap;
402d508ff40SBruce M Simpson 		addrbuf[0] = '\0';
4034ab8581bSEitan Adler 		getnameinfo((struct sockaddr *)&sdl, sdl.sdl_len,
404d508ff40SBruce M Simpson 		    addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST);
405d508ff40SBruce M Simpson 		printf("\tlink %s\n", addrbuf);
406d508ff40SBruce M Simpson 	nextifap:
407d508ff40SBruce M Simpson 		ifap = ifa.ifa_link.tqe_next;
408d508ff40SBruce M Simpson 	}
409d508ff40SBruce M Simpson 	if (ifap0) {
410d508ff40SBruce M Simpson 		struct ifnet ifnet;
411d508ff40SBruce M Simpson 		struct ifmultiaddr ifm, *ifmp = 0;
412d508ff40SBruce M Simpson 
413d508ff40SBruce M Simpson 		KREAD(ifap0, &ifa, struct ifaddr);
414d508ff40SBruce M Simpson 		KREAD(ifa.ifa_ifp, &ifnet, struct ifnet);
415d508ff40SBruce M Simpson 		if (TAILQ_FIRST(&ifnet.if_multiaddrs))
416d508ff40SBruce M Simpson 			ifmp = TAILQ_FIRST(&ifnet.if_multiaddrs);
417d508ff40SBruce M Simpson 		while (ifmp) {
418d508ff40SBruce M Simpson 			KREAD(ifmp, &ifm, struct ifmultiaddr);
419d508ff40SBruce M Simpson 			if (ifm.ifma_addr == NULL)
420d508ff40SBruce M Simpson 				goto nextmulti;
421d508ff40SBruce M Simpson 			KREAD(ifm.ifma_addr, &sa, struct sockaddr);
422d508ff40SBruce M Simpson 			if (sa.sa_family != AF_LINK)
423d508ff40SBruce M Simpson 				goto nextmulti;
424d508ff40SBruce M Simpson 			KREAD(ifm.ifma_addr, &sdl, struct sockaddr_dl);
425d508ff40SBruce M Simpson 			addrbuf[0] = '\0';
4264ab8581bSEitan Adler 			getnameinfo((struct sockaddr *)&sdl,
427d508ff40SBruce M Simpson 			    sdl.sdl_len, addrbuf, sizeof(addrbuf),
428d508ff40SBruce M Simpson 			    NULL, 0, NI_NUMERICHOST);
429d508ff40SBruce M Simpson 			printf("\t\tgroup %s refcnt %d\n",
430d508ff40SBruce M Simpson 			    addrbuf, ifm.ifma_refcount);
431d508ff40SBruce M Simpson 		nextmulti:
432d508ff40SBruce M Simpson 			ifmp = TAILQ_NEXT(&ifm, ifma_link);
4339bdd4811SHajimu UMEMOTO 		}
4349bdd4811SHajimu UMEMOTO 	}
4357d56d374SYoshinobu Inoue }
4367d56d374SYoshinobu Inoue 
437d508ff40SBruce M Simpson #ifdef INET6
438d508ff40SBruce M Simpson 
43960dd8da7SBruce M Simpson static void
if6_addrlist(struct ifaddr * ifap)44060dd8da7SBruce M Simpson if6_addrlist(struct ifaddr *ifap)
4417d56d374SYoshinobu Inoue {
44233cde130SBruce M Simpson 	struct ifnet ifnet;
4437d56d374SYoshinobu Inoue 	struct ifaddr ifa;
44404e87720SYoshinobu Inoue 	struct sockaddr sa;
4459bdd4811SHajimu UMEMOTO 	struct in6_ifaddr if6a;
4469bdd4811SHajimu UMEMOTO 	struct ifaddr *ifap0;
4477d56d374SYoshinobu Inoue 
4481048e675SBruce M Simpson 	if (af && af != AF_INET6)
4491048e675SBruce M Simpson 		return;
4507d56d374SYoshinobu Inoue 	ifap0 = ifap;
4519bdd4811SHajimu UMEMOTO 	while (ifap) {
4527d56d374SYoshinobu Inoue 		KREAD(ifap, &ifa, struct ifaddr);
4537d56d374SYoshinobu Inoue 		if (ifa.ifa_addr == NULL)
4549bdd4811SHajimu UMEMOTO 			goto nextifap;
4557d56d374SYoshinobu Inoue 		KREAD(ifa.ifa_addr, &sa, struct sockaddr);
4567d56d374SYoshinobu Inoue 		if (sa.sa_family != PF_INET6)
4579bdd4811SHajimu UMEMOTO 			goto nextifap;
4587d56d374SYoshinobu Inoue 		KREAD(ifap, &if6a, struct in6_ifaddr);
459a038519eSHiroki Sato 		printf("\tinet6 %s\n", inet6_n2a(&if6a.ia_addr.sin6_addr,
460a038519eSHiroki Sato 		    if6a.ia_addr.sin6_scope_id));
46133cde130SBruce M Simpson 		/*
46233cde130SBruce M Simpson 		 * Print per-link MLD information, if available.
46333cde130SBruce M Simpson 		 */
46433cde130SBruce M Simpson 		if (ifa.ifa_ifp != NULL) {
46533cde130SBruce M Simpson 			struct in6_ifextra ie;
46633cde130SBruce M Simpson 			struct mld_ifinfo mli;
46733cde130SBruce M Simpson 
46833cde130SBruce M Simpson 			KREAD(ifa.ifa_ifp, &ifnet, struct ifnet);
46933cde130SBruce M Simpson 			KREAD(ifnet.if_afdata[AF_INET6], &ie,
47033cde130SBruce M Simpson 			    struct in6_ifextra);
47133cde130SBruce M Simpson 			if (ie.mld_ifinfo != NULL) {
47233cde130SBruce M Simpson 				KREAD(ie.mld_ifinfo, &mli, struct mld_ifinfo);
47333cde130SBruce M Simpson 				in6_ifinfo(&mli);
47433cde130SBruce M Simpson 			}
47533cde130SBruce M Simpson 		}
4769bdd4811SHajimu UMEMOTO 	nextifap:
4771048e675SBruce M Simpson 		ifap = ifa.ifa_link.tqe_next;
4789bdd4811SHajimu UMEMOTO 	}
4799bdd4811SHajimu UMEMOTO 	if (ifap0) {
4809bdd4811SHajimu UMEMOTO 		struct ifnet ifnet;
4819bdd4811SHajimu UMEMOTO 		struct ifmultiaddr ifm, *ifmp = 0;
4829bdd4811SHajimu UMEMOTO 		struct sockaddr_dl sdl;
4837d56d374SYoshinobu Inoue 
4847d56d374SYoshinobu Inoue 		KREAD(ifap0, &ifa, struct ifaddr);
4857d56d374SYoshinobu Inoue 		KREAD(ifa.ifa_ifp, &ifnet, struct ifnet);
4866817526dSPoul-Henning Kamp 		if (TAILQ_FIRST(&ifnet.if_multiaddrs))
4876817526dSPoul-Henning Kamp 			ifmp = TAILQ_FIRST(&ifnet.if_multiaddrs);
4889bdd4811SHajimu UMEMOTO 		while (ifmp) {
4897d56d374SYoshinobu Inoue 			KREAD(ifmp, &ifm, struct ifmultiaddr);
4907d56d374SYoshinobu Inoue 			if (ifm.ifma_addr == NULL)
4919bdd4811SHajimu UMEMOTO 				goto nextmulti;
4927d56d374SYoshinobu Inoue 			KREAD(ifm.ifma_addr, &sa, struct sockaddr);
4937d56d374SYoshinobu Inoue 			if (sa.sa_family != AF_INET6)
4949bdd4811SHajimu UMEMOTO 				goto nextmulti;
4959bdd4811SHajimu UMEMOTO 			(void)in6_multientry((struct in6_multi *)
4969bdd4811SHajimu UMEMOTO 					     ifm.ifma_protospec);
4977d56d374SYoshinobu Inoue 			if (ifm.ifma_lladdr == 0)
4989bdd4811SHajimu UMEMOTO 				goto nextmulti;
4997d56d374SYoshinobu Inoue 			KREAD(ifm.ifma_lladdr, &sdl, struct sockaddr_dl);
50060dd8da7SBruce M Simpson 			printf("\t\t\tmcast-macaddr %s refcnt %d\n",
5017d56d374SYoshinobu Inoue 			       ether_ntoa((struct ether_addr *)LLADDR(&sdl)),
5027d56d374SYoshinobu Inoue 			       ifm.ifma_refcount);
5039bdd4811SHajimu UMEMOTO 		    nextmulti:
5046817526dSPoul-Henning Kamp 			ifmp = TAILQ_NEXT(&ifm, ifma_link);
5059bdd4811SHajimu UMEMOTO 		}
5069bdd4811SHajimu UMEMOTO 	}
5079bdd4811SHajimu UMEMOTO }
5089bdd4811SHajimu UMEMOTO 
50960dd8da7SBruce M Simpson static struct in6_multi *
in6_multientry(struct in6_multi * mc)51060dd8da7SBruce M Simpson in6_multientry(struct in6_multi *mc)
5117d56d374SYoshinobu Inoue {
5127d56d374SYoshinobu Inoue 	struct in6_multi multi;
5137d56d374SYoshinobu Inoue 
5147d56d374SYoshinobu Inoue 	KREAD(mc, &multi, struct in6_multi);
515a038519eSHiroki Sato 	printf("\t\tgroup %s", inet6_n2a(&multi.in6m_addr, 0));
5169bdd4811SHajimu UMEMOTO 	printf(" refcnt %u\n", multi.in6m_refcount);
5171048e675SBruce M Simpson 
5181048e675SBruce M Simpson 	return (multi.in6m_entry.le_next);
5191048e675SBruce M Simpson }
5201048e675SBruce M Simpson 
521cb48db9cSBruce M Simpson #endif /* INET6 */
522cb48db9cSBruce M Simpson 
52360dd8da7SBruce M Simpson #ifdef INET
52460dd8da7SBruce M Simpson 
52560dd8da7SBruce M Simpson static void
if_addrlist(struct ifaddr * ifap)52660dd8da7SBruce M Simpson if_addrlist(struct ifaddr *ifap)
5271048e675SBruce M Simpson {
5281048e675SBruce M Simpson 	struct ifaddr ifa;
529d10910e6SBruce M Simpson 	struct ifnet ifnet;
5301048e675SBruce M Simpson 	struct sockaddr sa;
5311048e675SBruce M Simpson 	struct in_ifaddr ia;
5321048e675SBruce M Simpson 	struct ifaddr *ifap0;
5331048e675SBruce M Simpson 
5341048e675SBruce M Simpson 	if (af && af != AF_INET)
5351048e675SBruce M Simpson 		return;
5361048e675SBruce M Simpson 	ifap0 = ifap;
5371048e675SBruce M Simpson 	while (ifap) {
5381048e675SBruce M Simpson 		KREAD(ifap, &ifa, struct ifaddr);
5391048e675SBruce M Simpson 		if (ifa.ifa_addr == NULL)
5401048e675SBruce M Simpson 			goto nextifap;
5411048e675SBruce M Simpson 		KREAD(ifa.ifa_addr, &sa, struct sockaddr);
5421048e675SBruce M Simpson 		if (sa.sa_family != PF_INET)
5431048e675SBruce M Simpson 			goto nextifap;
5441048e675SBruce M Simpson 		KREAD(ifap, &ia, struct in_ifaddr);
5451048e675SBruce M Simpson 		printf("\tinet %s\n", inet_ntoa(ia.ia_addr.sin_addr));
546d10910e6SBruce M Simpson 		/*
547d10910e6SBruce M Simpson 		 * Print per-link IGMP information, if available.
548d10910e6SBruce M Simpson 		 */
549d10910e6SBruce M Simpson 		if (ifa.ifa_ifp != NULL) {
550d10910e6SBruce M Simpson 			struct in_ifinfo ii;
551d10910e6SBruce M Simpson 			struct igmp_ifinfo igi;
552d10910e6SBruce M Simpson 
553d10910e6SBruce M Simpson 			KREAD(ifa.ifa_ifp, &ifnet, struct ifnet);
554d10910e6SBruce M Simpson 			KREAD(ifnet.if_afdata[AF_INET], &ii, struct in_ifinfo);
555d10910e6SBruce M Simpson 			if (ii.ii_igmp != NULL) {
556d10910e6SBruce M Simpson 				KREAD(ii.ii_igmp, &igi, struct igmp_ifinfo);
557d10910e6SBruce M Simpson 				in_ifinfo(&igi);
558d10910e6SBruce M Simpson 			}
559d10910e6SBruce M Simpson 		}
5601048e675SBruce M Simpson 	nextifap:
5611048e675SBruce M Simpson 		ifap = ifa.ifa_link.tqe_next;
5621048e675SBruce M Simpson 	}
5631048e675SBruce M Simpson 	if (ifap0) {
5641048e675SBruce M Simpson 		struct ifmultiaddr ifm, *ifmp = 0;
5651048e675SBruce M Simpson 		struct sockaddr_dl sdl;
5661048e675SBruce M Simpson 
5671048e675SBruce M Simpson 		KREAD(ifap0, &ifa, struct ifaddr);
5681048e675SBruce M Simpson 		KREAD(ifa.ifa_ifp, &ifnet, struct ifnet);
5691048e675SBruce M Simpson 		if (TAILQ_FIRST(&ifnet.if_multiaddrs))
5701048e675SBruce M Simpson 			ifmp = TAILQ_FIRST(&ifnet.if_multiaddrs);
5711048e675SBruce M Simpson 		while (ifmp) {
5721048e675SBruce M Simpson 			KREAD(ifmp, &ifm, struct ifmultiaddr);
5731048e675SBruce M Simpson 			if (ifm.ifma_addr == NULL)
5741048e675SBruce M Simpson 				goto nextmulti;
5751048e675SBruce M Simpson 			KREAD(ifm.ifma_addr, &sa, struct sockaddr);
5761048e675SBruce M Simpson 			if (sa.sa_family != AF_INET)
5771048e675SBruce M Simpson 				goto nextmulti;
5781048e675SBruce M Simpson 			(void)in_multientry((struct in_multi *)
5791048e675SBruce M Simpson 					    ifm.ifma_protospec);
5801048e675SBruce M Simpson 			if (ifm.ifma_lladdr == 0)
5811048e675SBruce M Simpson 				goto nextmulti;
5821048e675SBruce M Simpson 			KREAD(ifm.ifma_lladdr, &sdl, struct sockaddr_dl);
58360dd8da7SBruce M Simpson 			printf("\t\t\tmcast-macaddr %s refcnt %d\n",
5841048e675SBruce M Simpson 			       ether_ntoa((struct ether_addr *)LLADDR(&sdl)),
5851048e675SBruce M Simpson 			       ifm.ifma_refcount);
5861048e675SBruce M Simpson 		    nextmulti:
5871048e675SBruce M Simpson 			ifmp = TAILQ_NEXT(&ifm, ifma_link);
5881048e675SBruce M Simpson 		}
5891048e675SBruce M Simpson 	}
5901048e675SBruce M Simpson }
5911048e675SBruce M Simpson 
592d10910e6SBruce M Simpson static const char *inm_states[] = {
593d10910e6SBruce M Simpson 	"not-member",
594d10910e6SBruce M Simpson 	"silent",
595d10910e6SBruce M Simpson 	"idle",
596d10910e6SBruce M Simpson 	"lazy",
597d10910e6SBruce M Simpson 	"sleeping",
598d10910e6SBruce M Simpson 	"awakening",
599d10910e6SBruce M Simpson 	"query-pending",
600d10910e6SBruce M Simpson 	"sg-query-pending",
601d10910e6SBruce M Simpson 	"leaving"
602d10910e6SBruce M Simpson };
603d10910e6SBruce M Simpson 
604d10910e6SBruce M Simpson static const char *
inm_state(u_int state)605d10910e6SBruce M Simpson inm_state(u_int state)
6061048e675SBruce M Simpson {
6071048e675SBruce M Simpson 
608d10910e6SBruce M Simpson 	if (state >= IGMP_NOT_MEMBER && state <= IGMP_LEAVING_MEMBER)
609d10910e6SBruce M Simpson 		return (inm_states[state]);
6101048e675SBruce M Simpson 	return (NULL);
6111048e675SBruce M Simpson }
6121048e675SBruce M Simpson 
613d10910e6SBruce M Simpson #if 0
614d10910e6SBruce M Simpson static struct ip_msource *
615d10910e6SBruce M Simpson ims_min_kvm(struct in_multi *pinm)
6161048e675SBruce M Simpson {
617d10910e6SBruce M Simpson 	struct ip_msource ims0;
618d10910e6SBruce M Simpson 	struct ip_msource *tmp, *parent;
6191048e675SBruce M Simpson 
620d10910e6SBruce M Simpson 	parent = NULL;
621d10910e6SBruce M Simpson 	tmp = RB_ROOT(&pinm->inm_srcs);
622d10910e6SBruce M Simpson 	while (tmp) {
623d10910e6SBruce M Simpson 		parent = tmp;
624d10910e6SBruce M Simpson 		KREAD(tmp, &ims0, struct ip_msource);
625d10910e6SBruce M Simpson 		tmp = RB_LEFT(&ims0, ims_link);
6261048e675SBruce M Simpson 	}
627d10910e6SBruce M Simpson 	return (parent); /* kva */
6281048e675SBruce M Simpson }
6291048e675SBruce M Simpson 
630d10910e6SBruce M Simpson /* XXX This routine is buggy. See RB_NEXT in sys/tree.h. */
631d10910e6SBruce M Simpson static struct ip_msource *
632d10910e6SBruce M Simpson ims_next_kvm(struct ip_msource *ims)
633d10910e6SBruce M Simpson {
634d10910e6SBruce M Simpson 	struct ip_msource ims0, ims1;
635d10910e6SBruce M Simpson 	struct ip_msource *tmp;
636d10910e6SBruce M Simpson 
637d10910e6SBruce M Simpson 	KREAD(ims, &ims0, struct ip_msource);
638d10910e6SBruce M Simpson 	if (RB_RIGHT(&ims0, ims_link)) {
639d10910e6SBruce M Simpson 		ims = RB_RIGHT(&ims0, ims_link);
640d10910e6SBruce M Simpson 		KREAD(ims, &ims1, struct ip_msource);
641d10910e6SBruce M Simpson 		while ((tmp = RB_LEFT(&ims1, ims_link))) {
642d10910e6SBruce M Simpson 			KREAD(tmp, &ims0, struct ip_msource);
643d10910e6SBruce M Simpson 			ims = RB_LEFT(&ims0, ims_link);
644d10910e6SBruce M Simpson 		}
645d10910e6SBruce M Simpson 	} else {
646d10910e6SBruce M Simpson 		tmp = RB_PARENT(&ims0, ims_link);
647d10910e6SBruce M Simpson 		if (tmp) {
648d10910e6SBruce M Simpson 			KREAD(tmp, &ims1, struct ip_msource);
649d10910e6SBruce M Simpson 			if (ims == RB_LEFT(&ims1, ims_link))
650d10910e6SBruce M Simpson 				ims = tmp;
651d10910e6SBruce M Simpson 		} else {
652d10910e6SBruce M Simpson 			while ((tmp = RB_PARENT(&ims0, ims_link))) {
653d10910e6SBruce M Simpson 				KREAD(tmp, &ims1, struct ip_msource);
654d10910e6SBruce M Simpson 				if (ims == RB_RIGHT(&ims1, ims_link)) {
655d10910e6SBruce M Simpson 					ims = tmp;
656d10910e6SBruce M Simpson 					KREAD(ims, &ims0, struct ip_msource);
657d10910e6SBruce M Simpson 				} else
6581048e675SBruce M Simpson 					break;
659d10910e6SBruce M Simpson 			}
660d10910e6SBruce M Simpson 			ims = RB_PARENT(&ims0, ims_link);
6611048e675SBruce M Simpson 		}
6621048e675SBruce M Simpson 	}
663d10910e6SBruce M Simpson 	return (ims); /* kva */
664d10910e6SBruce M Simpson }
665d10910e6SBruce M Simpson 
666d10910e6SBruce M Simpson static void
667d10910e6SBruce M Simpson inm_print_sources_kvm(struct in_multi *pinm)
668d10910e6SBruce M Simpson {
669d10910e6SBruce M Simpson 	struct ip_msource ims0;
670d10910e6SBruce M Simpson 	struct ip_msource *ims;
671d10910e6SBruce M Simpson 	struct in_addr src;
672d10910e6SBruce M Simpson 	int cnt;
673d10910e6SBruce M Simpson 	uint8_t fmode;
674d10910e6SBruce M Simpson 
675d10910e6SBruce M Simpson 	cnt = 0;
676d10910e6SBruce M Simpson 	fmode = pinm->inm_st[1].iss_fmode;
677d10910e6SBruce M Simpson 	if (fmode == MCAST_UNDEFINED)
678d10910e6SBruce M Simpson 		return;
679d10910e6SBruce M Simpson 	for (ims = ims_min_kvm(pinm); ims != NULL; ims = ims_next_kvm(ims)) {
680d10910e6SBruce M Simpson 		if (cnt == 0)
681d10910e6SBruce M Simpson 			printf(" srcs ");
682d10910e6SBruce M Simpson 		KREAD(ims, &ims0, struct ip_msource);
683d10910e6SBruce M Simpson 		/* Only print sources in-mode at t1. */
684d10910e6SBruce M Simpson 		if (fmode != ims_get_mode(pinm, ims, 1))
685d10910e6SBruce M Simpson 			continue;
686d10910e6SBruce M Simpson 		src.s_addr = htonl(ims0.ims_haddr);
687d10910e6SBruce M Simpson 		printf("%s%s", (cnt++ == 0 ? "" : ","), inet_ntoa(src));
688d10910e6SBruce M Simpson 	}
689d10910e6SBruce M Simpson }
690d10910e6SBruce M Simpson #endif
691d10910e6SBruce M Simpson 
692d10910e6SBruce M Simpson static struct in_multi *
in_multientry(struct in_multi * pinm)693d10910e6SBruce M Simpson in_multientry(struct in_multi *pinm)
694d10910e6SBruce M Simpson {
695d10910e6SBruce M Simpson 	struct in_multi inm;
696d10910e6SBruce M Simpson 	const char *state, *mode;
697d10910e6SBruce M Simpson 
698d10910e6SBruce M Simpson 	KREAD(pinm, &inm, struct in_multi);
699d10910e6SBruce M Simpson 	printf("\t\tgroup %s", inet_ntoa(inm.inm_addr));
700d10910e6SBruce M Simpson 	printf(" refcnt %u", inm.inm_refcount);
701d10910e6SBruce M Simpson 
702d10910e6SBruce M Simpson 	state = inm_state(inm.inm_state);
703d10910e6SBruce M Simpson 	if (state)
704d10910e6SBruce M Simpson 		printf(" state %s", state);
705d10910e6SBruce M Simpson 	else
706d10910e6SBruce M Simpson 		printf(" state (%d)", inm.inm_state);
707d10910e6SBruce M Simpson 
708d10910e6SBruce M Simpson 	mode = inm_mode(inm.inm_st[1].iss_fmode);
709d10910e6SBruce M Simpson 	if (mode)
710d10910e6SBruce M Simpson 		printf(" mode %s", mode);
711d10910e6SBruce M Simpson 	else
712d10910e6SBruce M Simpson 		printf(" mode (%d)", inm.inm_st[1].iss_fmode);
713d10910e6SBruce M Simpson 
714d10910e6SBruce M Simpson 	if (vflag >= 2) {
715d10910e6SBruce M Simpson 		printf(" asm %u ex %u in %u rec %u",
716d10910e6SBruce M Simpson 		    (u_int)inm.inm_st[1].iss_asm,
717d10910e6SBruce M Simpson 		    (u_int)inm.inm_st[1].iss_ex,
718d10910e6SBruce M Simpson 		    (u_int)inm.inm_st[1].iss_in,
719d10910e6SBruce M Simpson 		    (u_int)inm.inm_st[1].iss_rec);
720d10910e6SBruce M Simpson 	}
721d10910e6SBruce M Simpson 
722d10910e6SBruce M Simpson #if 0
723d10910e6SBruce M Simpson 	/* Buggy. */
724d10910e6SBruce M Simpson 	if (vflag)
725d10910e6SBruce M Simpson 		inm_print_sources_kvm(&inm);
726d10910e6SBruce M Simpson #endif
727d10910e6SBruce M Simpson 
728d10910e6SBruce M Simpson 	printf("\n");
729d10910e6SBruce M Simpson 	return (NULL);
730d10910e6SBruce M Simpson }
73160dd8da7SBruce M Simpson 
73260dd8da7SBruce M Simpson #endif /* INET */
73360dd8da7SBruce M Simpson 
73460dd8da7SBruce M Simpson #endif /* WITH_KVM */
73560dd8da7SBruce M Simpson 
736d508ff40SBruce M Simpson #ifdef INET6
73710fa36f0SMaxim Konovalov 
73810fa36f0SMaxim Konovalov static void
in6_ifinfo(struct mld_ifinfo * mli)73910fa36f0SMaxim Konovalov in6_ifinfo(struct mld_ifinfo *mli)
74010fa36f0SMaxim Konovalov {
74110fa36f0SMaxim Konovalov 
74210fa36f0SMaxim Konovalov 	printf("\t");
74310fa36f0SMaxim Konovalov 	switch (mli->mli_version) {
74410fa36f0SMaxim Konovalov 	case MLD_VERSION_1:
74510fa36f0SMaxim Konovalov 	case MLD_VERSION_2:
74610fa36f0SMaxim Konovalov 		printf("mldv%d", mli->mli_version);
74710fa36f0SMaxim Konovalov 		break;
74810fa36f0SMaxim Konovalov 	default:
74910fa36f0SMaxim Konovalov 		printf("mldv?(%d)", mli->mli_version);
75010fa36f0SMaxim Konovalov 		break;
75110fa36f0SMaxim Konovalov 	}
752e0418c03SHiroki Sato 	if (mli->mli_flags)
753a038519eSHiroki Sato 		printb(" flags", mli->mli_flags, "\020\1SILENT\2USEALLOW");
75410fa36f0SMaxim Konovalov 	if (mli->mli_version == MLD_VERSION_2) {
75510fa36f0SMaxim Konovalov 		printf(" rv %u qi %u qri %u uri %u",
75610fa36f0SMaxim Konovalov 		    mli->mli_rv, mli->mli_qi, mli->mli_qri, mli->mli_uri);
75710fa36f0SMaxim Konovalov 	}
75810fa36f0SMaxim Konovalov 	if (vflag >= 2) {
75910fa36f0SMaxim Konovalov 		printf(" v1timer %u v2timer %u", mli->mli_v1_timer,
76010fa36f0SMaxim Konovalov 		   mli->mli_v2_timer);
76110fa36f0SMaxim Konovalov 	}
76210fa36f0SMaxim Konovalov 	printf("\n");
76310fa36f0SMaxim Konovalov }
76410fa36f0SMaxim Konovalov 
765d508ff40SBruce M Simpson static const char *
inet6_n2a(struct in6_addr * p,uint32_t scope_id)766a038519eSHiroki Sato inet6_n2a(struct in6_addr *p, uint32_t scope_id)
767d508ff40SBruce M Simpson {
768d508ff40SBruce M Simpson 	static char buf[NI_MAXHOST];
769d508ff40SBruce M Simpson 	struct sockaddr_in6 sin6;
770d508ff40SBruce M Simpson 	const int niflags = NI_NUMERICHOST;
771d508ff40SBruce M Simpson 
772d508ff40SBruce M Simpson 	memset(&sin6, 0, sizeof(sin6));
773d508ff40SBruce M Simpson 	sin6.sin6_family = AF_INET6;
774d508ff40SBruce M Simpson 	sin6.sin6_len = sizeof(struct sockaddr_in6);
775d508ff40SBruce M Simpson 	sin6.sin6_addr = *p;
776a038519eSHiroki Sato 	sin6.sin6_scope_id = scope_id;
777d508ff40SBruce M Simpson 	if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
7783f3d246fSBruce M Simpson 	    buf, sizeof(buf), NULL, 0, niflags) == 0) {
7793f3d246fSBruce M Simpson 		return (buf);
7803f3d246fSBruce M Simpson 	} else {
7813f3d246fSBruce M Simpson 		return ("(invalid)");
7823f3d246fSBruce M Simpson 	}
783d508ff40SBruce M Simpson }
784d508ff40SBruce M Simpson #endif /* INET6 */
785d508ff40SBruce M Simpson 
786d10910e6SBruce M Simpson #ifdef INET
787d10910e6SBruce M Simpson /*
788d10910e6SBruce M Simpson  * Retrieve per-group source filter mode and lists via sysctl.
789d10910e6SBruce M Simpson  */
790d10910e6SBruce M Simpson static void
inm_print_sources_sysctl(uint32_t ifindex,struct in_addr gina)791d10910e6SBruce M Simpson inm_print_sources_sysctl(uint32_t ifindex, struct in_addr gina)
792d10910e6SBruce M Simpson {
793d10910e6SBruce M Simpson #define	MAX_SYSCTL_TRY	5
794d10910e6SBruce M Simpson 	int mib[7];
795d10910e6SBruce M Simpson 	int ntry = 0;
796d10910e6SBruce M Simpson 	size_t mibsize;
797d10910e6SBruce M Simpson 	size_t len;
798d10910e6SBruce M Simpson 	size_t needed;
799d10910e6SBruce M Simpson 	size_t cnt;
800d10910e6SBruce M Simpson 	int i;
801d10910e6SBruce M Simpson 	char *buf;
802d10910e6SBruce M Simpson 	struct in_addr *pina;
803d10910e6SBruce M Simpson 	uint32_t *p;
804d10910e6SBruce M Simpson 	uint32_t fmode;
805d10910e6SBruce M Simpson 	const char *modestr;
806d10910e6SBruce M Simpson 
807bd4862e5SMarcelo Araujo 	mibsize = nitems(mib);
808d10910e6SBruce M Simpson 	if (sysctlnametomib("net.inet.ip.mcast.filters", mib, &mibsize) == -1) {
809d10910e6SBruce M Simpson 		perror("sysctlnametomib");
810d10910e6SBruce M Simpson 		return;
811d10910e6SBruce M Simpson 	}
812d10910e6SBruce M Simpson 
813d10910e6SBruce M Simpson 	needed = 0;
814d10910e6SBruce M Simpson 	mib[5] = ifindex;
815d10910e6SBruce M Simpson 	mib[6] = gina.s_addr;	/* 32 bits wide */
816bd4862e5SMarcelo Araujo 	mibsize = nitems(mib);
817d10910e6SBruce M Simpson 	do {
818d10910e6SBruce M Simpson 		if (sysctl(mib, mibsize, NULL, &needed, NULL, 0) == -1) {
819d10910e6SBruce M Simpson 			perror("sysctl net.inet.ip.mcast.filters");
820d10910e6SBruce M Simpson 			return;
821d10910e6SBruce M Simpson 		}
822d10910e6SBruce M Simpson 		if ((buf = malloc(needed)) == NULL) {
823d10910e6SBruce M Simpson 			perror("malloc");
824d10910e6SBruce M Simpson 			return;
825d10910e6SBruce M Simpson 		}
826d10910e6SBruce M Simpson 		if (sysctl(mib, mibsize, buf, &needed, NULL, 0) == -1) {
827d10910e6SBruce M Simpson 			if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
828d10910e6SBruce M Simpson 				perror("sysctl");
829d10910e6SBruce M Simpson 				goto out_free;
830d10910e6SBruce M Simpson 			}
831d10910e6SBruce M Simpson 			free(buf);
832d10910e6SBruce M Simpson 			buf = NULL;
833d10910e6SBruce M Simpson 		}
834d10910e6SBruce M Simpson 	} while (buf == NULL);
835d10910e6SBruce M Simpson 
836d10910e6SBruce M Simpson 	len = needed;
837d10910e6SBruce M Simpson 	if (len < sizeof(uint32_t)) {
838d10910e6SBruce M Simpson 		perror("sysctl");
839d10910e6SBruce M Simpson 		goto out_free;
840d10910e6SBruce M Simpson 	}
841d10910e6SBruce M Simpson 
842d10910e6SBruce M Simpson 	p = (uint32_t *)buf;
843d10910e6SBruce M Simpson 	fmode = *p++;
844d10910e6SBruce M Simpson 	len -= sizeof(uint32_t);
845d10910e6SBruce M Simpson 
846d10910e6SBruce M Simpson 	modestr = inm_mode(fmode);
847d10910e6SBruce M Simpson 	if (modestr)
848d10910e6SBruce M Simpson 		printf(" mode %s", modestr);
849d10910e6SBruce M Simpson 	else
850d10910e6SBruce M Simpson 		printf(" mode (%u)", fmode);
851d10910e6SBruce M Simpson 
852d10910e6SBruce M Simpson 	if (vflag == 0)
853d10910e6SBruce M Simpson 		goto out_free;
854d10910e6SBruce M Simpson 
855d10910e6SBruce M Simpson 	cnt = len / sizeof(struct in_addr);
856d10910e6SBruce M Simpson 	pina = (struct in_addr *)p;
857d10910e6SBruce M Simpson 
858d10910e6SBruce M Simpson 	for (i = 0; i < cnt; i++) {
859d10910e6SBruce M Simpson 		if (i == 0)
860d10910e6SBruce M Simpson 			printf(" srcs ");
861d10910e6SBruce M Simpson 		fprintf(stdout, "%s%s", (i == 0 ? "" : ","),
862d10910e6SBruce M Simpson 		    inet_ntoa(*pina++));
863d10910e6SBruce M Simpson 		len -= sizeof(struct in_addr);
864d10910e6SBruce M Simpson 	}
865d10910e6SBruce M Simpson 	if (len > 0) {
866d10910e6SBruce M Simpson 		fprintf(stderr, "warning: %u trailing bytes from %s\n",
867d10910e6SBruce M Simpson 		    (unsigned int)len, "net.inet.ip.mcast.filters");
868d10910e6SBruce M Simpson 	}
869d10910e6SBruce M Simpson 
870d10910e6SBruce M Simpson out_free:
871d10910e6SBruce M Simpson 	free(buf);
872d10910e6SBruce M Simpson #undef	MAX_SYSCTL_TRY
873d10910e6SBruce M Simpson }
874d10910e6SBruce M Simpson 
875d10910e6SBruce M Simpson #endif /* INET */
876d10910e6SBruce M Simpson 
87733cde130SBruce M Simpson #ifdef INET6
87833cde130SBruce M Simpson /*
87933cde130SBruce M Simpson  * Retrieve MLD per-group source filter mode and lists via sysctl.
88033cde130SBruce M Simpson  *
8813df5ecacSUlrich Spörlein  * Note: The 128-bit IPv6 group address needs to be segmented into
88233cde130SBruce M Simpson  * 32-bit pieces for marshaling to sysctl. So the MIB name ends
88333cde130SBruce M Simpson  * up looking like this:
88433cde130SBruce M Simpson  *  a.b.c.d.e.ifindex.g[0].g[1].g[2].g[3]
88533cde130SBruce M Simpson  * Assumes that pgroup originated from the kernel, so its components
88633cde130SBruce M Simpson  * are already in network-byte order.
88733cde130SBruce M Simpson  */
88833cde130SBruce M Simpson static void
in6m_print_sources_sysctl(uint32_t ifindex,struct in6_addr * pgroup)88933cde130SBruce M Simpson in6m_print_sources_sysctl(uint32_t ifindex, struct in6_addr *pgroup)
89033cde130SBruce M Simpson {
89133cde130SBruce M Simpson #define	MAX_SYSCTL_TRY	5
89233cde130SBruce M Simpson 	char addrbuf[INET6_ADDRSTRLEN];
89333cde130SBruce M Simpson 	int mib[10];
89433cde130SBruce M Simpson 	int ntry = 0;
89533cde130SBruce M Simpson 	int *pi;
89633cde130SBruce M Simpson 	size_t mibsize;
89733cde130SBruce M Simpson 	size_t len;
89833cde130SBruce M Simpson 	size_t needed;
89933cde130SBruce M Simpson 	size_t cnt;
90033cde130SBruce M Simpson 	int i;
90133cde130SBruce M Simpson 	char *buf;
90233cde130SBruce M Simpson 	struct in6_addr *pina;
90333cde130SBruce M Simpson 	uint32_t *p;
90433cde130SBruce M Simpson 	uint32_t fmode;
90533cde130SBruce M Simpson 	const char *modestr;
90633cde130SBruce M Simpson 
907bd4862e5SMarcelo Araujo 	mibsize = nitems(mib);
90833cde130SBruce M Simpson 	if (sysctlnametomib("net.inet6.ip6.mcast.filters", mib,
90933cde130SBruce M Simpson 	    &mibsize) == -1) {
91033cde130SBruce M Simpson 		perror("sysctlnametomib");
91133cde130SBruce M Simpson 		return;
91233cde130SBruce M Simpson 	}
91333cde130SBruce M Simpson 
91433cde130SBruce M Simpson 	needed = 0;
91533cde130SBruce M Simpson 	mib[5] = ifindex;
91633cde130SBruce M Simpson 	pi = (int *)pgroup;
91733cde130SBruce M Simpson 	for (i = 0; i < 4; i++)
91833cde130SBruce M Simpson 		mib[6 + i] = *pi++;
91933cde130SBruce M Simpson 
920bd4862e5SMarcelo Araujo 	mibsize = nitems(mib);
92133cde130SBruce M Simpson 	do {
92233cde130SBruce M Simpson 		if (sysctl(mib, mibsize, NULL, &needed, NULL, 0) == -1) {
92333cde130SBruce M Simpson 			perror("sysctl net.inet6.ip6.mcast.filters");
92433cde130SBruce M Simpson 			return;
92533cde130SBruce M Simpson 		}
92633cde130SBruce M Simpson 		if ((buf = malloc(needed)) == NULL) {
92733cde130SBruce M Simpson 			perror("malloc");
92833cde130SBruce M Simpson 			return;
92933cde130SBruce M Simpson 		}
93033cde130SBruce M Simpson 		if (sysctl(mib, mibsize, buf, &needed, NULL, 0) == -1) {
93133cde130SBruce M Simpson 			if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
93233cde130SBruce M Simpson 				perror("sysctl");
93333cde130SBruce M Simpson 				goto out_free;
93433cde130SBruce M Simpson 			}
93533cde130SBruce M Simpson 			free(buf);
93633cde130SBruce M Simpson 			buf = NULL;
93733cde130SBruce M Simpson 		}
93833cde130SBruce M Simpson 	} while (buf == NULL);
93933cde130SBruce M Simpson 
94033cde130SBruce M Simpson 	len = needed;
94133cde130SBruce M Simpson 	if (len < sizeof(uint32_t)) {
94233cde130SBruce M Simpson 		perror("sysctl");
94333cde130SBruce M Simpson 		goto out_free;
94433cde130SBruce M Simpson 	}
94533cde130SBruce M Simpson 
94633cde130SBruce M Simpson 	p = (uint32_t *)buf;
94733cde130SBruce M Simpson 	fmode = *p++;
94833cde130SBruce M Simpson 	len -= sizeof(uint32_t);
94933cde130SBruce M Simpson 
95033cde130SBruce M Simpson 	modestr = inm_mode(fmode);
95133cde130SBruce M Simpson 	if (modestr)
95233cde130SBruce M Simpson 		printf(" mode %s", modestr);
95333cde130SBruce M Simpson 	else
95433cde130SBruce M Simpson 		printf(" mode (%u)", fmode);
95533cde130SBruce M Simpson 
95633cde130SBruce M Simpson 	if (vflag == 0)
95733cde130SBruce M Simpson 		goto out_free;
95833cde130SBruce M Simpson 
95933cde130SBruce M Simpson 	cnt = len / sizeof(struct in6_addr);
96033cde130SBruce M Simpson 	pina = (struct in6_addr *)p;
96133cde130SBruce M Simpson 
96233cde130SBruce M Simpson 	for (i = 0; i < cnt; i++) {
96333cde130SBruce M Simpson 		if (i == 0)
96433cde130SBruce M Simpson 			printf(" srcs ");
96533cde130SBruce M Simpson 		inet_ntop(AF_INET6, (const char *)pina++, addrbuf,
96633cde130SBruce M Simpson 		    INET6_ADDRSTRLEN);
96733cde130SBruce M Simpson 		fprintf(stdout, "%s%s", (i == 0 ? "" : ","), addrbuf);
96833cde130SBruce M Simpson 		len -= sizeof(struct in6_addr);
96933cde130SBruce M Simpson 	}
97033cde130SBruce M Simpson 	if (len > 0) {
97133cde130SBruce M Simpson 		fprintf(stderr, "warning: %u trailing bytes from %s\n",
97233cde130SBruce M Simpson 		    (unsigned int)len, "net.inet6.ip6.mcast.filters");
97333cde130SBruce M Simpson 	}
97433cde130SBruce M Simpson 
97533cde130SBruce M Simpson out_free:
97633cde130SBruce M Simpson 	free(buf);
97733cde130SBruce M Simpson #undef	MAX_SYSCTL_TRY
97833cde130SBruce M Simpson }
97933cde130SBruce M Simpson #endif /* INET6 */
98033cde130SBruce M Simpson 
98160dd8da7SBruce M Simpson static int
ifmcstat_getifmaddrs(void)98260dd8da7SBruce M Simpson ifmcstat_getifmaddrs(void)
98360dd8da7SBruce M Simpson {
98460dd8da7SBruce M Simpson 	char			 thisifname[IFNAMSIZ];
985d508ff40SBruce M Simpson 	char			 addrbuf[NI_MAXHOST];
98660dd8da7SBruce M Simpson 	struct ifaddrs		*ifap, *ifa;
98760dd8da7SBruce M Simpson 	struct ifmaddrs		*ifmap, *ifma;
98860dd8da7SBruce M Simpson 	sockunion_t		 lastifasa;
98960dd8da7SBruce M Simpson 	sockunion_t		*psa, *pgsa, *pllsa, *pifasa;
99060dd8da7SBruce M Simpson 	char			*pcolon;
99160dd8da7SBruce M Simpson 	char			*pafname;
99260dd8da7SBruce M Simpson 	uint32_t		 lastifindex, thisifindex;
99360dd8da7SBruce M Simpson 	int			 error;
99460dd8da7SBruce M Simpson 
99560dd8da7SBruce M Simpson 	error = 0;
99660dd8da7SBruce M Simpson 	ifap = NULL;
99760dd8da7SBruce M Simpson 	ifmap = NULL;
99860dd8da7SBruce M Simpson 	lastifindex = 0;
99960dd8da7SBruce M Simpson 	thisifindex = 0;
100060dd8da7SBruce M Simpson 	lastifasa.ss.ss_family = AF_UNSPEC;
100160dd8da7SBruce M Simpson 
100260dd8da7SBruce M Simpson 	if (getifaddrs(&ifap) != 0) {
100360dd8da7SBruce M Simpson 		warn("getifmaddrs");
100460dd8da7SBruce M Simpson 		return (-1);
100560dd8da7SBruce M Simpson 	}
100660dd8da7SBruce M Simpson 
100760dd8da7SBruce M Simpson 	if (getifmaddrs(&ifmap) != 0) {
100860dd8da7SBruce M Simpson 		warn("getifmaddrs");
100960dd8da7SBruce M Simpson 		error = -1;
101060dd8da7SBruce M Simpson 		goto out;
101160dd8da7SBruce M Simpson 	}
101260dd8da7SBruce M Simpson 
101360dd8da7SBruce M Simpson 	for (ifma = ifmap; ifma; ifma = ifma->ifma_next) {
101460dd8da7SBruce M Simpson 		error = 0;
101560dd8da7SBruce M Simpson 		if (ifma->ifma_name == NULL || ifma->ifma_addr == NULL)
101660dd8da7SBruce M Simpson 			continue;
101760dd8da7SBruce M Simpson 
101860dd8da7SBruce M Simpson 		psa = (sockunion_t *)ifma->ifma_name;
101960dd8da7SBruce M Simpson 		if (psa->sa.sa_family != AF_LINK) {
102060dd8da7SBruce M Simpson 			fprintf(stderr,
102160dd8da7SBruce M Simpson 			    "WARNING: Kernel returned invalid data.\n");
102260dd8da7SBruce M Simpson 			error = -1;
102360dd8da7SBruce M Simpson 			break;
102460dd8da7SBruce M Simpson 		}
102560dd8da7SBruce M Simpson 
102660dd8da7SBruce M Simpson 		/* Filter on interface name. */
102760dd8da7SBruce M Simpson 		thisifindex = psa->sdl.sdl_index;
102860dd8da7SBruce M Simpson 		if (ifindex != 0 && thisifindex != ifindex)
102960dd8da7SBruce M Simpson 			continue;
103060dd8da7SBruce M Simpson 
103160dd8da7SBruce M Simpson 		/* Filter on address family. */
103260dd8da7SBruce M Simpson 		pgsa = (sockunion_t *)ifma->ifma_addr;
103360dd8da7SBruce M Simpson 		if (af != 0 && pgsa->sa.sa_family != af)
103460dd8da7SBruce M Simpson 			continue;
103560dd8da7SBruce M Simpson 
103660dd8da7SBruce M Simpson 		strlcpy(thisifname, link_ntoa(&psa->sdl), IFNAMSIZ);
103760dd8da7SBruce M Simpson 		pcolon = strchr(thisifname, ':');
103860dd8da7SBruce M Simpson 		if (pcolon)
103960dd8da7SBruce M Simpson 			*pcolon = '\0';
104060dd8da7SBruce M Simpson 
104160dd8da7SBruce M Simpson 		/* Only print the banner for the first ifmaddrs entry. */
104260dd8da7SBruce M Simpson 		if (lastifindex == 0 || lastifindex != thisifindex) {
104360dd8da7SBruce M Simpson 			lastifindex = thisifindex;
104460dd8da7SBruce M Simpson 			fprintf(stdout, "%s:\n", thisifname);
104560dd8da7SBruce M Simpson 		}
104660dd8da7SBruce M Simpson 
104760dd8da7SBruce M Simpson 		/*
104860dd8da7SBruce M Simpson 		 * Currently, multicast joins only take place on the
104960dd8da7SBruce M Simpson 		 * primary IPv4 address, and only on the link-local IPv6
105060dd8da7SBruce M Simpson 		 * address, as per IGMPv2/3 and MLDv1/2 semantics.
105160dd8da7SBruce M Simpson 		 * Therefore, we only look up the primary address on
105260dd8da7SBruce M Simpson 		 * the first pass.
105360dd8da7SBruce M Simpson 		 */
105460dd8da7SBruce M Simpson 		pifasa = NULL;
105560dd8da7SBruce M Simpson 		for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
105660dd8da7SBruce M Simpson 			if ((strcmp(ifa->ifa_name, thisifname) != 0) ||
105760dd8da7SBruce M Simpson 			    (ifa->ifa_addr == NULL) ||
105860dd8da7SBruce M Simpson 			    (ifa->ifa_addr->sa_family != pgsa->sa.sa_family))
105960dd8da7SBruce M Simpson 				continue;
106060dd8da7SBruce M Simpson 			/*
106160dd8da7SBruce M Simpson 			 * For AF_INET6 only the link-local address should
1062d508ff40SBruce M Simpson 			 * be returned. If built without IPv6 support,
1063d508ff40SBruce M Simpson 			 * skip this address entirely.
106460dd8da7SBruce M Simpson 			 */
106560dd8da7SBruce M Simpson 			pifasa = (sockunion_t *)ifa->ifa_addr;
1066d508ff40SBruce M Simpson 			if (pifasa->sa.sa_family == AF_INET6
1067d508ff40SBruce M Simpson #ifdef INET6
1068d508ff40SBruce M Simpson 			    && !IN6_IS_ADDR_LINKLOCAL(&pifasa->sin6.sin6_addr)
1069d508ff40SBruce M Simpson #endif
1070d508ff40SBruce M Simpson 			) {
107160dd8da7SBruce M Simpson 				pifasa = NULL;
107260dd8da7SBruce M Simpson 				continue;
107360dd8da7SBruce M Simpson 			}
107460dd8da7SBruce M Simpson 			break;
107560dd8da7SBruce M Simpson 		}
107660dd8da7SBruce M Simpson 		if (pifasa == NULL)
107760dd8da7SBruce M Simpson 			continue;	/* primary address not found */
107860dd8da7SBruce M Simpson 
1079d508ff40SBruce M Simpson 		if (!vflag && pifasa->sa.sa_family == AF_LINK)
1080d508ff40SBruce M Simpson 			continue;
1081d508ff40SBruce M Simpson 
108260dd8da7SBruce M Simpson 		/* Parse and print primary address, if not already printed. */
108360dd8da7SBruce M Simpson 		if (lastifasa.ss.ss_family == AF_UNSPEC ||
108460dd8da7SBruce M Simpson 		    ((lastifasa.ss.ss_family == AF_LINK &&
108560dd8da7SBruce M Simpson 		      !sa_dl_equal(&lastifasa.sa, &pifasa->sa)) ||
108660dd8da7SBruce M Simpson 		     !sa_equal(&lastifasa.sa, &pifasa->sa))) {
108760dd8da7SBruce M Simpson 
108860dd8da7SBruce M Simpson 			switch (pifasa->sa.sa_family) {
108960dd8da7SBruce M Simpson 			case AF_INET:
109060dd8da7SBruce M Simpson 				pafname = "inet";
109160dd8da7SBruce M Simpson 				break;
109260dd8da7SBruce M Simpson 			case AF_INET6:
109360dd8da7SBruce M Simpson 				pafname = "inet6";
109460dd8da7SBruce M Simpson 				break;
109560dd8da7SBruce M Simpson 			case AF_LINK:
109660dd8da7SBruce M Simpson 				pafname = "link";
109760dd8da7SBruce M Simpson 				break;
109860dd8da7SBruce M Simpson 			default:
109960dd8da7SBruce M Simpson 				pafname = "unknown";
110060dd8da7SBruce M Simpson 				break;
110160dd8da7SBruce M Simpson 			}
110260dd8da7SBruce M Simpson 
110360dd8da7SBruce M Simpson 			switch (pifasa->sa.sa_family) {
110460dd8da7SBruce M Simpson 			case AF_INET6:
1105d508ff40SBruce M Simpson #ifdef INET6
1106d508ff40SBruce M Simpson 			{
1107d508ff40SBruce M Simpson 				const char *p =
1108a038519eSHiroki Sato 				    inet6_n2a(&pifasa->sin6.sin6_addr,
1109a038519eSHiroki Sato 					pifasa->sin6.sin6_scope_id);
1110d508ff40SBruce M Simpson 				strlcpy(addrbuf, p, sizeof(addrbuf));
1111d508ff40SBruce M Simpson 				break;
1112d508ff40SBruce M Simpson 			}
1113d508ff40SBruce M Simpson #else
1114d508ff40SBruce M Simpson 			/* FALLTHROUGH */
1115d508ff40SBruce M Simpson #endif
1116d508ff40SBruce M Simpson 			case AF_INET:
111760dd8da7SBruce M Simpson 			case AF_LINK:
111860dd8da7SBruce M Simpson 				error = getnameinfo(&pifasa->sa,
111960dd8da7SBruce M Simpson 				    pifasa->sa.sa_len,
112060dd8da7SBruce M Simpson 				    addrbuf, sizeof(addrbuf), NULL, 0,
112160dd8da7SBruce M Simpson 				    NI_NUMERICHOST);
112260dd8da7SBruce M Simpson 				if (error)
112360dd8da7SBruce M Simpson 					perror("getnameinfo");
112460dd8da7SBruce M Simpson 				break;
112560dd8da7SBruce M Simpson 			default:
112660dd8da7SBruce M Simpson 				addrbuf[0] = '\0';
112760dd8da7SBruce M Simpson 				break;
112860dd8da7SBruce M Simpson 			}
112960dd8da7SBruce M Simpson 
1130e0418c03SHiroki Sato 			fprintf(stdout, "\t%s %s", pafname, addrbuf);
1131e0418c03SHiroki Sato #ifdef INET6
1132e0418c03SHiroki Sato 			if (pifasa->sa.sa_family == AF_INET6 &&
1133e0418c03SHiroki Sato 			    pifasa->sin6.sin6_scope_id)
1134e0418c03SHiroki Sato 				fprintf(stdout, " scopeid 0x%x",
1135e0418c03SHiroki Sato 				    pifasa->sin6.sin6_scope_id);
1136e0418c03SHiroki Sato #endif
1137e0418c03SHiroki Sato 			fprintf(stdout, "\n");
1138d10910e6SBruce M Simpson #ifdef INET
1139d10910e6SBruce M Simpson 			/*
1140d10910e6SBruce M Simpson 			 * Print per-link IGMP information, if available.
1141d10910e6SBruce M Simpson 			 */
1142d10910e6SBruce M Simpson 			if (pifasa->sa.sa_family == AF_INET) {
1143d10910e6SBruce M Simpson 				struct igmp_ifinfo igi;
1144d10910e6SBruce M Simpson 				size_t mibsize, len;
1145d10910e6SBruce M Simpson 				int mib[5];
1146d10910e6SBruce M Simpson 
1147bd4862e5SMarcelo Araujo 				mibsize = nitems(mib);
1148d10910e6SBruce M Simpson 				if (sysctlnametomib("net.inet.igmp.ifinfo",
1149d10910e6SBruce M Simpson 				    mib, &mibsize) == -1) {
1150d10910e6SBruce M Simpson 					perror("sysctlnametomib");
1151d10910e6SBruce M Simpson 					goto next_ifnet;
1152d10910e6SBruce M Simpson 				}
1153d10910e6SBruce M Simpson 				mib[mibsize] = thisifindex;
1154d10910e6SBruce M Simpson 				len = sizeof(struct igmp_ifinfo);
1155d10910e6SBruce M Simpson 				if (sysctl(mib, mibsize + 1, &igi, &len, NULL,
1156d10910e6SBruce M Simpson 				    0) == -1) {
1157d10910e6SBruce M Simpson 					perror("sysctl net.inet.igmp.ifinfo");
1158d10910e6SBruce M Simpson 					goto next_ifnet;
1159d10910e6SBruce M Simpson 				}
1160d10910e6SBruce M Simpson 				in_ifinfo(&igi);
1161d10910e6SBruce M Simpson 			}
116233cde130SBruce M Simpson #endif /* INET */
116333cde130SBruce M Simpson #ifdef INET6
116433cde130SBruce M Simpson 			/*
116533cde130SBruce M Simpson 			 * Print per-link MLD information, if available.
116633cde130SBruce M Simpson 			 */
116733cde130SBruce M Simpson 			if (pifasa->sa.sa_family == AF_INET6) {
116833cde130SBruce M Simpson 				struct mld_ifinfo mli;
116933cde130SBruce M Simpson 				size_t mibsize, len;
117033cde130SBruce M Simpson 				int mib[5];
117133cde130SBruce M Simpson 
1172bd4862e5SMarcelo Araujo 				mibsize = nitems(mib);
117333cde130SBruce M Simpson 				if (sysctlnametomib("net.inet6.mld.ifinfo",
117433cde130SBruce M Simpson 				    mib, &mibsize) == -1) {
117533cde130SBruce M Simpson 					perror("sysctlnametomib");
117633cde130SBruce M Simpson 					goto next_ifnet;
117733cde130SBruce M Simpson 				}
117833cde130SBruce M Simpson 				mib[mibsize] = thisifindex;
117933cde130SBruce M Simpson 				len = sizeof(struct mld_ifinfo);
118033cde130SBruce M Simpson 				if (sysctl(mib, mibsize + 1, &mli, &len, NULL,
118133cde130SBruce M Simpson 				    0) == -1) {
118233cde130SBruce M Simpson 					perror("sysctl net.inet6.mld.ifinfo");
118333cde130SBruce M Simpson 					goto next_ifnet;
118433cde130SBruce M Simpson 				}
118533cde130SBruce M Simpson 				in6_ifinfo(&mli);
118633cde130SBruce M Simpson 			}
118733cde130SBruce M Simpson #endif /* INET6 */
118833cde130SBruce M Simpson #if defined(INET) || defined(INET6)
1189d10910e6SBruce M Simpson next_ifnet:
1190d10910e6SBruce M Simpson #endif
119160dd8da7SBruce M Simpson 			lastifasa = *pifasa;
119260dd8da7SBruce M Simpson 		}
119360dd8da7SBruce M Simpson 
119460dd8da7SBruce M Simpson 		/* Print this group address. */
1195d508ff40SBruce M Simpson #ifdef INET6
1196d508ff40SBruce M Simpson 		if (pgsa->sa.sa_family == AF_INET6) {
1197a038519eSHiroki Sato 			const char *p = inet6_n2a(&pgsa->sin6.sin6_addr,
1198a038519eSHiroki Sato 			    pgsa->sin6.sin6_scope_id);
1199d508ff40SBruce M Simpson 			strlcpy(addrbuf, p, sizeof(addrbuf));
1200d508ff40SBruce M Simpson 		} else
1201d508ff40SBruce M Simpson #endif
1202d508ff40SBruce M Simpson 		{
1203d508ff40SBruce M Simpson 			error = getnameinfo(&pgsa->sa, pgsa->sa.sa_len,
1204d508ff40SBruce M Simpson 			    addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST);
120560dd8da7SBruce M Simpson 			if (error)
120660dd8da7SBruce M Simpson 				perror("getnameinfo");
1207d508ff40SBruce M Simpson 		}
1208d508ff40SBruce M Simpson 
1209d10910e6SBruce M Simpson 		fprintf(stdout, "\t\tgroup %s", addrbuf);
1210e0418c03SHiroki Sato #ifdef INET6
1211e0418c03SHiroki Sato 		if (pgsa->sa.sa_family == AF_INET6 &&
1212e0418c03SHiroki Sato 		    pgsa->sin6.sin6_scope_id)
1213e0418c03SHiroki Sato 			fprintf(stdout, " scopeid 0x%x",
1214e0418c03SHiroki Sato 			    pgsa->sin6.sin6_scope_id);
1215e0418c03SHiroki Sato #endif
1216d10910e6SBruce M Simpson #ifdef INET
1217d10910e6SBruce M Simpson 		if (pgsa->sa.sa_family == AF_INET) {
1218d10910e6SBruce M Simpson 			inm_print_sources_sysctl(thisifindex,
1219d10910e6SBruce M Simpson 			    pgsa->sin.sin_addr);
1220d10910e6SBruce M Simpson 		}
1221d10910e6SBruce M Simpson #endif
122233cde130SBruce M Simpson #ifdef INET6
122333cde130SBruce M Simpson 		if (pgsa->sa.sa_family == AF_INET6) {
122433cde130SBruce M Simpson 			in6m_print_sources_sysctl(thisifindex,
122533cde130SBruce M Simpson 			    &pgsa->sin6.sin6_addr);
122633cde130SBruce M Simpson 		}
122733cde130SBruce M Simpson #endif
1228d10910e6SBruce M Simpson 		fprintf(stdout, "\n");
122960dd8da7SBruce M Simpson 
123060dd8da7SBruce M Simpson 		/* Link-layer mapping, if present. */
123160dd8da7SBruce M Simpson 		pllsa = (sockunion_t *)ifma->ifma_lladdr;
123260dd8da7SBruce M Simpson 		if (pllsa != NULL) {
123315c83493SBruce M Simpson 			error = getnameinfo(&pllsa->sa, pllsa->sa.sa_len,
123460dd8da7SBruce M Simpson 			    addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST);
123560dd8da7SBruce M Simpson 			fprintf(stdout, "\t\t\tmcast-macaddr %s\n", addrbuf);
123660dd8da7SBruce M Simpson 		}
123760dd8da7SBruce M Simpson 	}
123860dd8da7SBruce M Simpson out:
123960dd8da7SBruce M Simpson 	if (ifmap != NULL)
124060dd8da7SBruce M Simpson 		freeifmaddrs(ifmap);
124160dd8da7SBruce M Simpson 	if (ifap != NULL)
124260dd8da7SBruce M Simpson 		freeifaddrs(ifap);
124360dd8da7SBruce M Simpson 
124460dd8da7SBruce M Simpson 	return (error);
124560dd8da7SBruce M Simpson }
1246