ifmcstat.c revision 55163
1/*
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD: head/usr.sbin/ifmcstat/ifmcstat.c 55163 1999-12-28 02:37:14Z shin $
30 */
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <fcntl.h>
35#include <kvm.h>
36#include <nlist.h>
37#include <string.h>
38#include <limits.h>
39
40#include <sys/types.h>
41#include <sys/socket.h>
42#include <net/if.h>
43#if defined(__FreeBSD__) && __FreeBSD__ >= 3
44# include <net/if_var.h>
45#endif
46#include <net/if_types.h>
47#include <net/if_dl.h>
48#include <netinet/in.h>
49#ifndef __NetBSD__
50# ifdef	__FreeBSD__
51#  define	KERNEL
52# endif
53# include <netinet/if_ether.h>
54# ifdef	__FreeBSD__
55#  undef	KERNEL
56# endif
57#else
58# include <net/if_ether.h>
59#endif
60#include <netinet/in_var.h>
61#include <arpa/inet.h>
62
63kvm_t	*kvmd;
64
65struct	nlist nl[] = {
66#define	N_IFNET	0
67	{ "_ifnet" },
68	{ "" },
69};
70
71const char *inet6_n2a __P((struct in6_addr *));
72int main __P((void));
73char *ifname __P((struct ifnet *));
74void kread __P((u_long, void *, int));
75#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
76void acmc __P((struct ether_multi *));
77#endif
78void if6_addrlist __P((struct ifaddr *));
79void in6_multilist __P((struct in6_multi *));
80struct in6_multi * in6_multientry __P((struct in6_multi *));
81
82#if !defined(__NetBSD__) && !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__OpenBSD__)
83#ifdef __bsdi__
84struct ether_addr {
85	u_int8_t ether_addr_octet[6];
86};
87#endif
88static char *ether_ntoa __P((struct ether_addr *));
89#endif
90
91#define	KREAD(addr, buf, type) \
92	kread((u_long)addr, (void *)buf, sizeof(type))
93
94const char *inet6_n2a(p)
95	struct in6_addr *p;
96{
97	static char buf[BUFSIZ];
98
99	if (IN6_IS_ADDR_UNSPECIFIED(p))
100		return "*";
101	return inet_ntop(AF_INET6, (void *)p, buf, sizeof(buf));
102}
103
104int main()
105{
106	char	buf[_POSIX2_LINE_MAX], ifname[IFNAMSIZ];
107	struct	ifnet	*ifp, *nifp, ifnet;
108#ifndef __NetBSD__
109	struct	arpcom	arpcom;
110#else
111	struct ethercom ec;
112	struct sockaddr_dl sdl;
113#endif
114
115	if ((kvmd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, buf)) == NULL) {
116		perror("kvm_openfiles");
117		exit(1);
118	}
119	if (kvm_nlist(kvmd, nl) < 0) {
120		perror("kvm_nlist");
121		exit(1);
122	}
123	if (nl[N_IFNET].n_value == 0) {
124		printf("symbol %s not found\n", nl[N_IFNET].n_name);
125		exit(1);
126	}
127	KREAD(nl[N_IFNET].n_value, &ifp, struct ifnet *);
128	while (ifp) {
129		KREAD(ifp, &ifnet, struct ifnet);
130		printf("%s:\n", if_indextoname(ifnet.if_index, ifname));
131
132#if defined(__NetBSD__) || defined(__OpenBSD__)
133		if6_addrlist(ifnet.if_addrlist.tqh_first);
134		nifp = ifnet.if_list.tqe_next;
135#elif defined(__FreeBSD__) && __FreeBSD__ >= 3
136		if6_addrlist(TAILQ_FIRST(&ifnet.if_addrhead));
137		nifp = ifnet.if_link.tqe_next;
138#else
139		if6_addrlist(ifnet.if_addrlist);
140		nifp = ifnet.if_next;
141#endif
142
143#ifdef __NetBSD__
144		KREAD(ifnet.if_sadl, &sdl, struct sockaddr_dl);
145		if (sdl.sdl_type == IFT_ETHER) {
146			printf("\tenaddr %s",
147			       ether_ntoa((struct ether_addr *)LLADDR(&sdl)));
148			KREAD(ifp, &ec, struct ethercom);
149			printf(" multicnt %d", ec.ec_multicnt);
150			acmc(ec.ec_multiaddrs.lh_first);
151			printf("\n");
152		}
153#elif defined(__FreeBSD__) && __FreeBSD__ >= 3
154		/* not supported */
155#else
156		if (ifnet.if_type == IFT_ETHER) {
157			KREAD(ifp, &arpcom, struct arpcom);
158			printf("\tenaddr %s",
159			    ether_ntoa((struct ether_addr *)arpcom.ac_enaddr));
160			KREAD(ifp, &arpcom, struct arpcom);
161			printf(" multicnt %d", arpcom.ac_multicnt);
162#ifdef __OpenBSD__
163			acmc(arpcom.ac_multiaddrs.lh_first);
164#else
165			acmc(arpcom.ac_multiaddrs);
166#endif
167			printf("\n");
168		}
169#endif
170
171		ifp = nifp;
172	}
173
174	exit(0);
175	/*NOTREACHED*/
176}
177
178char *ifname(ifp)
179	struct ifnet *ifp;
180{
181	static char buf[BUFSIZ];
182
183#if defined(__NetBSD__) || defined(__OpenBSD__)
184	KREAD(ifp->if_xname, buf, IFNAMSIZ);
185#else
186	KREAD(ifp->if_name, buf, IFNAMSIZ);
187#endif
188	return buf;
189}
190
191void kread(addr, buf, len)
192	u_long addr;
193	void *buf;
194	int len;
195{
196	if (kvm_read(kvmd, addr, buf, len) != len) {
197		perror("kvm_read");
198		exit(1);
199	}
200}
201
202#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
203void acmc(am)
204	struct ether_multi *am;
205{
206	struct ether_multi em;
207
208	while (am) {
209		KREAD(am, &em, struct ether_multi);
210
211		printf("\n\t\t");
212		printf("%s -- ", ether_ntoa((struct ether_addr *)em.enm_addrlo));
213		printf("%s ", ether_ntoa((struct ether_addr *)&em.enm_addrhi));
214		printf("%d", em.enm_refcount);
215#if !defined(__NetBSD__) && !defined(__OpenBSD__)
216		am = em.enm_next;
217#else
218		am = em.enm_list.le_next;
219#endif
220	}
221}
222#endif
223
224void
225if6_addrlist(ifap)
226	struct ifaddr *ifap;
227{
228	static char in6buf[BUFSIZ];
229	struct ifaddr ifa;
230	struct sockaddr sa;
231	struct in6_ifaddr if6a;
232	struct in6_multi *mc = 0;
233#if defined(__FreeBSD__) && __FreeBSD__ >= 3
234	struct ifaddr *ifap0;
235#endif /* __FreeBSD__ >= 3 */
236
237#if defined(__FreeBSD__) && __FreeBSD__ >= 3
238	ifap0 = ifap;
239#endif /* __FreeBSD__ >= 3 */
240	while (ifap) {
241		KREAD(ifap, &ifa, struct ifaddr);
242		if (ifa.ifa_addr == NULL)
243			goto nextifap;
244		KREAD(ifa.ifa_addr, &sa, struct sockaddr);
245		if (sa.sa_family != PF_INET6)
246			goto nextifap;
247		KREAD(ifap, &if6a, struct in6_ifaddr);
248		printf("\tinet6 %s\n",
249		       inet_ntop(AF_INET6,
250				 (const void *)&if6a.ia_addr.sin6_addr,
251				 in6buf, sizeof(in6buf)));
252#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
253		mc = mc ? mc : if6a.ia6_multiaddrs.lh_first;
254#endif
255	nextifap:
256#if defined(__NetBSD__) || defined(__OpenBSD__)
257		ifap = ifa.ifa_list.tqe_next;
258#elif defined(__FreeBSD__) && __FreeBSD__ >= 3
259		ifap = ifa.ifa_link.tqe_next;
260#else
261		ifap = ifa.ifa_next;
262#endif /* __FreeBSD__ >= 3 */
263	}
264#if defined(__FreeBSD__) && __FreeBSD__ >= 3
265	if (ifap0) {
266		struct ifnet ifnet;
267		struct ifmultiaddr ifm, *ifmp = 0;
268		struct sockaddr_in6 sin6;
269		struct in6_multi in6m;
270		struct sockaddr_dl sdl;
271		int in6_multilist_done = 0;
272
273		KREAD(ifap0, &ifa, struct ifaddr);
274		KREAD(ifa.ifa_ifp, &ifnet, struct ifnet);
275		if (ifnet.if_multiaddrs.lh_first)
276			ifmp = ifnet.if_multiaddrs.lh_first;
277		while (ifmp) {
278			KREAD(ifmp, &ifm, struct ifmultiaddr);
279			if (ifm.ifma_addr == NULL)
280				goto nextmulti;
281			KREAD(ifm.ifma_addr, &sa, struct sockaddr);
282			if (sa.sa_family != AF_INET6)
283				goto nextmulti;
284			(void)in6_multientry((struct in6_multi *)
285					     ifm.ifma_protospec);
286			if (ifm.ifma_lladdr == 0)
287				goto nextmulti;
288			KREAD(ifm.ifma_lladdr, &sdl, struct sockaddr_dl);
289			printf("\t\t\tmcast-macaddr %s multicnt %d\n",
290			       ether_ntoa((struct ether_addr *)LLADDR(&sdl)),
291			       ifm.ifma_refcount);
292		    nextmulti:
293			ifmp = ifm.ifma_link.le_next;
294		}
295	}
296#else
297	if (mc)
298		in6_multilist(mc);
299#endif
300}
301
302struct in6_multi *
303in6_multientry(mc)
304	struct in6_multi *mc;
305{
306	static char mcbuf[BUFSIZ];
307	struct in6_multi multi;
308
309	KREAD(mc, &multi, struct in6_multi);
310	printf("\t\tgroup %s\n", inet_ntop(AF_INET6,
311					   (const void *)&multi.in6m_addr,
312					   mcbuf, sizeof(mcbuf)));
313	return(multi.in6m_entry.le_next);
314}
315
316void
317in6_multilist(mc)
318	struct in6_multi *mc;
319{
320	while (mc)
321		mc = in6_multientry(mc);
322}
323
324#if !defined(__NetBSD__) && !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__OpenBSD__)
325static char *
326ether_ntoa(e)
327	struct ether_addr *e;
328{
329	static char buf[20];
330	u_char *p;
331
332	p = (u_char *)e;
333
334	snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
335		p[0], p[1], p[2], p[3], p[4], p[5]);
336	return buf;
337}
338#endif
339