ifmcstat.c revision 55163
155163Sshin/*
255163Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
355163Sshin * All rights reserved.
455163Sshin *
555163Sshin * Redistribution and use in source and binary forms, with or without
655163Sshin * modification, are permitted provided that the following conditions
755163Sshin * are met:
855163Sshin * 1. Redistributions of source code must retain the above copyright
955163Sshin *    notice, this list of conditions and the following disclaimer.
1055163Sshin * 2. Redistributions in binary form must reproduce the above copyright
1155163Sshin *    notice, this list of conditions and the following disclaimer in the
1255163Sshin *    documentation and/or other materials provided with the distribution.
1355163Sshin * 3. Neither the name of the project nor the names of its contributors
1455163Sshin *    may be used to endorse or promote products derived from this software
1555163Sshin *    without specific prior written permission.
1655163Sshin *
1755163Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1855163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1955163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2055163Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2155163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2255163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2355163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2455163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2555163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2655163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2755163Sshin * SUCH DAMAGE.
2855163Sshin *
2955163Sshin * $FreeBSD: head/usr.sbin/ifmcstat/ifmcstat.c 55163 1999-12-28 02:37:14Z shin $
3055163Sshin */
3155163Sshin
3255163Sshin#include <stdio.h>
3355163Sshin#include <stdlib.h>
3455163Sshin#include <fcntl.h>
3555163Sshin#include <kvm.h>
3655163Sshin#include <nlist.h>
3755163Sshin#include <string.h>
3855163Sshin#include <limits.h>
3955163Sshin
4055163Sshin#include <sys/types.h>
4155163Sshin#include <sys/socket.h>
4255163Sshin#include <net/if.h>
4355163Sshin#if defined(__FreeBSD__) && __FreeBSD__ >= 3
4455163Sshin# include <net/if_var.h>
4555163Sshin#endif
4655163Sshin#include <net/if_types.h>
4755163Sshin#include <net/if_dl.h>
4855163Sshin#include <netinet/in.h>
4955163Sshin#ifndef __NetBSD__
5055163Sshin# ifdef	__FreeBSD__
5155163Sshin#  define	KERNEL
5255163Sshin# endif
5355163Sshin# include <netinet/if_ether.h>
5455163Sshin# ifdef	__FreeBSD__
5555163Sshin#  undef	KERNEL
5655163Sshin# endif
5755163Sshin#else
5855163Sshin# include <net/if_ether.h>
5955163Sshin#endif
6055163Sshin#include <netinet/in_var.h>
6155163Sshin#include <arpa/inet.h>
6255163Sshin
6355163Sshinkvm_t	*kvmd;
6455163Sshin
6555163Sshinstruct	nlist nl[] = {
6655163Sshin#define	N_IFNET	0
6755163Sshin	{ "_ifnet" },
6855163Sshin	{ "" },
6955163Sshin};
7055163Sshin
7155163Sshinconst char *inet6_n2a __P((struct in6_addr *));
7255163Sshinint main __P((void));
7355163Sshinchar *ifname __P((struct ifnet *));
7455163Sshinvoid kread __P((u_long, void *, int));
7555163Sshin#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
7655163Sshinvoid acmc __P((struct ether_multi *));
7755163Sshin#endif
7855163Sshinvoid if6_addrlist __P((struct ifaddr *));
7955163Sshinvoid in6_multilist __P((struct in6_multi *));
8055163Sshinstruct in6_multi * in6_multientry __P((struct in6_multi *));
8155163Sshin
8255163Sshin#if !defined(__NetBSD__) && !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__OpenBSD__)
8355163Sshin#ifdef __bsdi__
8455163Sshinstruct ether_addr {
8555163Sshin	u_int8_t ether_addr_octet[6];
8655163Sshin};
8755163Sshin#endif
8855163Sshinstatic char *ether_ntoa __P((struct ether_addr *));
8955163Sshin#endif
9055163Sshin
9155163Sshin#define	KREAD(addr, buf, type) \
9255163Sshin	kread((u_long)addr, (void *)buf, sizeof(type))
9355163Sshin
9455163Sshinconst char *inet6_n2a(p)
9555163Sshin	struct in6_addr *p;
9655163Sshin{
9755163Sshin	static char buf[BUFSIZ];
9855163Sshin
9955163Sshin	if (IN6_IS_ADDR_UNSPECIFIED(p))
10055163Sshin		return "*";
10155163Sshin	return inet_ntop(AF_INET6, (void *)p, buf, sizeof(buf));
10255163Sshin}
10355163Sshin
10455163Sshinint main()
10555163Sshin{
10655163Sshin	char	buf[_POSIX2_LINE_MAX], ifname[IFNAMSIZ];
10755163Sshin	struct	ifnet	*ifp, *nifp, ifnet;
10855163Sshin#ifndef __NetBSD__
10955163Sshin	struct	arpcom	arpcom;
11055163Sshin#else
11155163Sshin	struct ethercom ec;
11255163Sshin	struct sockaddr_dl sdl;
11355163Sshin#endif
11455163Sshin
11555163Sshin	if ((kvmd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, buf)) == NULL) {
11655163Sshin		perror("kvm_openfiles");
11755163Sshin		exit(1);
11855163Sshin	}
11955163Sshin	if (kvm_nlist(kvmd, nl) < 0) {
12055163Sshin		perror("kvm_nlist");
12155163Sshin		exit(1);
12255163Sshin	}
12355163Sshin	if (nl[N_IFNET].n_value == 0) {
12455163Sshin		printf("symbol %s not found\n", nl[N_IFNET].n_name);
12555163Sshin		exit(1);
12655163Sshin	}
12755163Sshin	KREAD(nl[N_IFNET].n_value, &ifp, struct ifnet *);
12855163Sshin	while (ifp) {
12955163Sshin		KREAD(ifp, &ifnet, struct ifnet);
13055163Sshin		printf("%s:\n", if_indextoname(ifnet.if_index, ifname));
13155163Sshin
13255163Sshin#if defined(__NetBSD__) || defined(__OpenBSD__)
13355163Sshin		if6_addrlist(ifnet.if_addrlist.tqh_first);
13455163Sshin		nifp = ifnet.if_list.tqe_next;
13555163Sshin#elif defined(__FreeBSD__) && __FreeBSD__ >= 3
13655163Sshin		if6_addrlist(TAILQ_FIRST(&ifnet.if_addrhead));
13755163Sshin		nifp = ifnet.if_link.tqe_next;
13855163Sshin#else
13955163Sshin		if6_addrlist(ifnet.if_addrlist);
14055163Sshin		nifp = ifnet.if_next;
14155163Sshin#endif
14255163Sshin
14355163Sshin#ifdef __NetBSD__
14455163Sshin		KREAD(ifnet.if_sadl, &sdl, struct sockaddr_dl);
14555163Sshin		if (sdl.sdl_type == IFT_ETHER) {
14655163Sshin			printf("\tenaddr %s",
14755163Sshin			       ether_ntoa((struct ether_addr *)LLADDR(&sdl)));
14855163Sshin			KREAD(ifp, &ec, struct ethercom);
14955163Sshin			printf(" multicnt %d", ec.ec_multicnt);
15055163Sshin			acmc(ec.ec_multiaddrs.lh_first);
15155163Sshin			printf("\n");
15255163Sshin		}
15355163Sshin#elif defined(__FreeBSD__) && __FreeBSD__ >= 3
15455163Sshin		/* not supported */
15555163Sshin#else
15655163Sshin		if (ifnet.if_type == IFT_ETHER) {
15755163Sshin			KREAD(ifp, &arpcom, struct arpcom);
15855163Sshin			printf("\tenaddr %s",
15955163Sshin			    ether_ntoa((struct ether_addr *)arpcom.ac_enaddr));
16055163Sshin			KREAD(ifp, &arpcom, struct arpcom);
16155163Sshin			printf(" multicnt %d", arpcom.ac_multicnt);
16255163Sshin#ifdef __OpenBSD__
16355163Sshin			acmc(arpcom.ac_multiaddrs.lh_first);
16455163Sshin#else
16555163Sshin			acmc(arpcom.ac_multiaddrs);
16655163Sshin#endif
16755163Sshin			printf("\n");
16855163Sshin		}
16955163Sshin#endif
17055163Sshin
17155163Sshin		ifp = nifp;
17255163Sshin	}
17355163Sshin
17455163Sshin	exit(0);
17555163Sshin	/*NOTREACHED*/
17655163Sshin}
17755163Sshin
17855163Sshinchar *ifname(ifp)
17955163Sshin	struct ifnet *ifp;
18055163Sshin{
18155163Sshin	static char buf[BUFSIZ];
18255163Sshin
18355163Sshin#if defined(__NetBSD__) || defined(__OpenBSD__)
18455163Sshin	KREAD(ifp->if_xname, buf, IFNAMSIZ);
18555163Sshin#else
18655163Sshin	KREAD(ifp->if_name, buf, IFNAMSIZ);
18755163Sshin#endif
18855163Sshin	return buf;
18955163Sshin}
19055163Sshin
19155163Sshinvoid kread(addr, buf, len)
19255163Sshin	u_long addr;
19355163Sshin	void *buf;
19455163Sshin	int len;
19555163Sshin{
19655163Sshin	if (kvm_read(kvmd, addr, buf, len) != len) {
19755163Sshin		perror("kvm_read");
19855163Sshin		exit(1);
19955163Sshin	}
20055163Sshin}
20155163Sshin
20255163Sshin#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
20355163Sshinvoid acmc(am)
20455163Sshin	struct ether_multi *am;
20555163Sshin{
20655163Sshin	struct ether_multi em;
20755163Sshin
20855163Sshin	while (am) {
20955163Sshin		KREAD(am, &em, struct ether_multi);
21055163Sshin
21155163Sshin		printf("\n\t\t");
21255163Sshin		printf("%s -- ", ether_ntoa((struct ether_addr *)em.enm_addrlo));
21355163Sshin		printf("%s ", ether_ntoa((struct ether_addr *)&em.enm_addrhi));
21455163Sshin		printf("%d", em.enm_refcount);
21555163Sshin#if !defined(__NetBSD__) && !defined(__OpenBSD__)
21655163Sshin		am = em.enm_next;
21755163Sshin#else
21855163Sshin		am = em.enm_list.le_next;
21955163Sshin#endif
22055163Sshin	}
22155163Sshin}
22255163Sshin#endif
22355163Sshin
22455163Sshinvoid
22555163Sshinif6_addrlist(ifap)
22655163Sshin	struct ifaddr *ifap;
22755163Sshin{
22855163Sshin	static char in6buf[BUFSIZ];
22955163Sshin	struct ifaddr ifa;
23055163Sshin	struct sockaddr sa;
23155163Sshin	struct in6_ifaddr if6a;
23255163Sshin	struct in6_multi *mc = 0;
23355163Sshin#if defined(__FreeBSD__) && __FreeBSD__ >= 3
23455163Sshin	struct ifaddr *ifap0;
23555163Sshin#endif /* __FreeBSD__ >= 3 */
23655163Sshin
23755163Sshin#if defined(__FreeBSD__) && __FreeBSD__ >= 3
23855163Sshin	ifap0 = ifap;
23955163Sshin#endif /* __FreeBSD__ >= 3 */
24055163Sshin	while (ifap) {
24155163Sshin		KREAD(ifap, &ifa, struct ifaddr);
24255163Sshin		if (ifa.ifa_addr == NULL)
24355163Sshin			goto nextifap;
24455163Sshin		KREAD(ifa.ifa_addr, &sa, struct sockaddr);
24555163Sshin		if (sa.sa_family != PF_INET6)
24655163Sshin			goto nextifap;
24755163Sshin		KREAD(ifap, &if6a, struct in6_ifaddr);
24855163Sshin		printf("\tinet6 %s\n",
24955163Sshin		       inet_ntop(AF_INET6,
25055163Sshin				 (const void *)&if6a.ia_addr.sin6_addr,
25155163Sshin				 in6buf, sizeof(in6buf)));
25255163Sshin#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
25355163Sshin		mc = mc ? mc : if6a.ia6_multiaddrs.lh_first;
25455163Sshin#endif
25555163Sshin	nextifap:
25655163Sshin#if defined(__NetBSD__) || defined(__OpenBSD__)
25755163Sshin		ifap = ifa.ifa_list.tqe_next;
25855163Sshin#elif defined(__FreeBSD__) && __FreeBSD__ >= 3
25955163Sshin		ifap = ifa.ifa_link.tqe_next;
26055163Sshin#else
26155163Sshin		ifap = ifa.ifa_next;
26255163Sshin#endif /* __FreeBSD__ >= 3 */
26355163Sshin	}
26455163Sshin#if defined(__FreeBSD__) && __FreeBSD__ >= 3
26555163Sshin	if (ifap0) {
26655163Sshin		struct ifnet ifnet;
26755163Sshin		struct ifmultiaddr ifm, *ifmp = 0;
26855163Sshin		struct sockaddr_in6 sin6;
26955163Sshin		struct in6_multi in6m;
27055163Sshin		struct sockaddr_dl sdl;
27155163Sshin		int in6_multilist_done = 0;
27255163Sshin
27355163Sshin		KREAD(ifap0, &ifa, struct ifaddr);
27455163Sshin		KREAD(ifa.ifa_ifp, &ifnet, struct ifnet);
27555163Sshin		if (ifnet.if_multiaddrs.lh_first)
27655163Sshin			ifmp = ifnet.if_multiaddrs.lh_first;
27755163Sshin		while (ifmp) {
27855163Sshin			KREAD(ifmp, &ifm, struct ifmultiaddr);
27955163Sshin			if (ifm.ifma_addr == NULL)
28055163Sshin				goto nextmulti;
28155163Sshin			KREAD(ifm.ifma_addr, &sa, struct sockaddr);
28255163Sshin			if (sa.sa_family != AF_INET6)
28355163Sshin				goto nextmulti;
28455163Sshin			(void)in6_multientry((struct in6_multi *)
28555163Sshin					     ifm.ifma_protospec);
28655163Sshin			if (ifm.ifma_lladdr == 0)
28755163Sshin				goto nextmulti;
28855163Sshin			KREAD(ifm.ifma_lladdr, &sdl, struct sockaddr_dl);
28955163Sshin			printf("\t\t\tmcast-macaddr %s multicnt %d\n",
29055163Sshin			       ether_ntoa((struct ether_addr *)LLADDR(&sdl)),
29155163Sshin			       ifm.ifma_refcount);
29255163Sshin		    nextmulti:
29355163Sshin			ifmp = ifm.ifma_link.le_next;
29455163Sshin		}
29555163Sshin	}
29655163Sshin#else
29755163Sshin	if (mc)
29855163Sshin		in6_multilist(mc);
29955163Sshin#endif
30055163Sshin}
30155163Sshin
30255163Sshinstruct in6_multi *
30355163Sshinin6_multientry(mc)
30455163Sshin	struct in6_multi *mc;
30555163Sshin{
30655163Sshin	static char mcbuf[BUFSIZ];
30755163Sshin	struct in6_multi multi;
30855163Sshin
30955163Sshin	KREAD(mc, &multi, struct in6_multi);
31055163Sshin	printf("\t\tgroup %s\n", inet_ntop(AF_INET6,
31155163Sshin					   (const void *)&multi.in6m_addr,
31255163Sshin					   mcbuf, sizeof(mcbuf)));
31355163Sshin	return(multi.in6m_entry.le_next);
31455163Sshin}
31555163Sshin
31655163Sshinvoid
31755163Sshinin6_multilist(mc)
31855163Sshin	struct in6_multi *mc;
31955163Sshin{
32055163Sshin	while (mc)
32155163Sshin		mc = in6_multientry(mc);
32255163Sshin}
32355163Sshin
32455163Sshin#if !defined(__NetBSD__) && !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__OpenBSD__)
32555163Sshinstatic char *
32655163Sshinether_ntoa(e)
32755163Sshin	struct ether_addr *e;
32855163Sshin{
32955163Sshin	static char buf[20];
33055163Sshin	u_char *p;
33155163Sshin
33255163Sshin	p = (u_char *)e;
33355163Sshin
33455163Sshin	snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
33555163Sshin		p[0], p[1], p[2], p[3], p[4], p[5]);
33655163Sshin	return buf;
33755163Sshin}
33855163Sshin#endif
339