Viewing multicast group membership?

Bruce M Simpson bms at spc.org
Thu Nov 13 15:37:28 PST 2003


On Tue, Nov 11, 2003 at 09:29:49AM +0100, Harti Brandt wrote:
> Here you are. This was even once (about a year ago) reviewed by someone,
> but did make it into the tree, because I did not insist.

Ok. The NET_RT_IFMALIST sysctl is not completely identical to the existing
NET_RT_IFLIST interface. I've made a few changes to your diff, and
rolled a userland interface; please review.

BMS
-------------- next part --------------
Index: rtsock.c
===================================================================
RCS file: /home/ncvs/src/sys/net/rtsock.c,v
retrieving revision 1.89
diff -u -r1.89 rtsock.c
--- rtsock.c	5 Mar 2003 19:24:22 -0000	1.89
+++ rtsock.c	12 Nov 2003 11:28:43 -0000
@@ -73,6 +73,7 @@
 static int	rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *);
 static int	sysctl_dumpentry(struct radix_node *rn, void *vw);
 static int	sysctl_iflist(int af, struct walkarg *w);
+static int	sysctl_ifmalist(int af, struct walkarg *w);
 static int	 route_output(struct mbuf *, struct socket *);
 static void	 rt_setmetrics(u_long, struct rt_metrics *, struct rt_metrics *);
 
@@ -658,6 +659,10 @@
 		len = sizeof(struct if_msghdr);
 		break;
 
+	case RTM_NEWMADDR:
+		len = sizeof(struct ifma_msghdr);
+		break;
+
 	default:
 		len = sizeof(struct rt_msghdr);
 	}
@@ -994,6 +999,61 @@
 	return (error);
 }
 
+int
+sysctl_ifmalist(af, w)
+	int	af;
+	register struct	walkarg *w;
+{
+	register struct ifnet *ifp;
+	struct ifmultiaddr *ifma;
+	struct	rt_addrinfo info;
+	int	len, error = 0;
+
+	bzero((caddr_t)&info, sizeof(info));
+	/* IFNET_RLOCK(); */		/* could sleep XXX */
+	TAILQ_FOREACH(ifp, &ifnet, if_link) {
+		if (w->w_arg && w->w_arg != ifp->if_index)
+			continue;
+		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+			if (af && af != ifma->ifma_addr->sa_family)
+				continue;
+			if (jailed(curproc->p_ucred) &&
+			    prison_if(curproc->p_ucred, ifma->ifma_addr))
+				continue;
+			info.rti_addrs = RTA_IFA;
+			info.rti_info[RTAX_IFA] = ifma->ifma_addr;
+			if (TAILQ_FIRST(&ifp->if_addrhead)) {
+				info.rti_addrs |= RTA_IFP;
+				info.rti_info[RTAX_IFP] =
+				    TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr;
+			} else
+				info.rti_info[RTAX_IFP] = NULL;
+
+			if (ifma->ifma_addr->sa_family != AF_LINK) {
+				info.rti_addrs |= RTA_GATEWAY;
+				info.rti_info[RTAX_GATEWAY] = ifma->ifma_lladdr;
+			} else
+				info.rti_info[RTAX_GATEWAY] = NULL;
+
+			len = rt_msg2(RTM_NEWMADDR, &info, 0, w);
+			if (w->w_req && w->w_tmem) {
+				register struct ifma_msghdr *ifmam;
+
+				ifmam = (struct ifma_msghdr *)w->w_tmem;
+				ifmam->ifmam_index = ifma->ifma_ifp->if_index;
+				ifmam->ifmam_flags = 0;
+				ifmam->ifmam_addrs = info.rti_addrs;
+				error = SYSCTL_OUT(w->w_req, w->w_tmem, len);
+				if (error)
+					goto done;
+			}
+		}
+	}
+done:
+	/* IFNET_RUNLOCK(); */ /* XXX */
+	return (error);
+}
+
 static int
 sysctl_rtsock(SYSCTL_HANDLER_ARGS)
 {
@@ -1046,6 +1106,11 @@
 
 	case NET_RT_IFLIST:
 		error = sysctl_iflist(af, &w);
+		break;
+
+	case NET_RT_IFMALIST:
+		error = sysctl_ifmalist(af, &w);
+		break;
 	}
 	splx(s);
 	if (w.w_tmem)
-------------- next part --------------

struct ifmaddrs {
	struct ifmaddrs	*ifma_next;
	struct sockaddr	*ifma_name;
	struct sockaddr	*ifma_addr;
	struct sockaddr	*ifma_gateway;
	void		*ifma_data;
};
-------------- next part --------------

#include <sys/cdefs.h>

#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <sys/param.h>
#include <net/route.h>
#include <sys/sysctl.h>
#include <net/if_dl.h>

#include <errno.h>
#include <stdlib.h>
#include <string.h>

#include "ifmaddrs.h"

#if !defined(AF_LINK)
#define	SA_LEN(sa)	sizeof(struct sockaddr)
#endif

#if !defined(SA_LEN)
#define	SA_LEN(sa)	(sa)->sa_len
#endif

#define	SALIGN	(sizeof(long) - 1)
#define	SA_RLEN(sa)	((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1))

#ifndef	ALIGNBYTES
/*
 * On systems with a routing socket, ALIGNBYTES should match the value
 * that the kernel uses when building the messages.
 */
#define	ALIGNBYTES	XXX
#endif
#ifndef	ALIGN
#define	ALIGN(p)	(((u_long)(p) + ALIGNBYTES) &~ ALIGNBYTES)
#endif

#define MAX_SYSCTL_TRY 5

int
getifmaddrs(struct ifmaddrs **pif)
{
	int icnt = 1;
	int dcnt = 0;
	int ncnt = 0;
	int ntry = 0;
	int mib[6];
	size_t needed;
	char *buf;
	char *next;
	char *p, *p0;
	struct rt_msghdr *rtm;
	struct ifma_msghdr *ifmam;
	struct sockaddr *sa;
	struct ifmaddrs *ifa, *ift;
	u_short idx = 0;
	int i;
	size_t len, alen;
	char *data;
	char *names;

	mib[0] = CTL_NET;
	mib[1] = PF_ROUTE;
	mib[2] = 0;             /* protocol */
	mib[3] = 0;             /* wildcard address family */
	mib[4] = NET_RT_IFMALIST;
	mib[5] = 0;             /* no flags */
	do {
		if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
			return (-1);
		if ((buf = malloc(needed)) == NULL)
			return (-1);
		if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
			if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
				free(buf);
				return (-1);
			}
			free(buf);
			buf = NULL;
		} 
	} while (buf == NULL);

	for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
		rtm = (struct rt_msghdr *)(void *)next;
		if (rtm->rtm_version != RTM_VERSION)
			continue;
		switch (rtm->rtm_type) {
		case RTM_NEWMADDR:
			ifmam = (struct ifma_msghdr *)(void *)rtm;
#define	RTA_MASKS	(RTA_GATEWAY | RTA_IFP | RTA_IFA)
			if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
				break;
			p = (char *)(void *)(ifmam + 1);
			++icnt;
#ifdef	HAVE_IFAM_DATA
			dcnt += sizeof(ifmam->ifmam_data) + ALIGNBYTES;
#endif	/* HAVE_IFAM_DATA */
			/* Scan to look for length of address */
			alen = 0;
			for (p0 = p, i = 0; i < RTAX_MAX; i++) {
				if ((RTA_MASKS & ifmam->ifmam_addrs & (1 << i))
				    == 0)
					continue;
				sa = (struct sockaddr *)(void *)p;
				len = SA_RLEN(sa);
				if (i == RTAX_IFA) {
					alen = len;
					break;
				}
				p += len;
			}
			for (p = p0, i = 0; i < RTAX_MAX; i++) {
				if ((RTA_MASKS & ifmam->ifmam_addrs & (1 << i))
				    == 0)
					continue;
				sa = (struct sockaddr *)(void *)p;
				len = SA_RLEN(sa);
				dcnt += len;
				p += len;
			}
			break;
		}
	}

	if (icnt + dcnt + ncnt == 1) {
		*pif = NULL;
		free(buf);
		return (0);
	}
	data = malloc(sizeof(struct ifmaddrs) * icnt + dcnt + ncnt);
	if (data == NULL) {
		free(buf);
		return(-1);
	}

	ifa = (struct ifmaddrs *)(void *)data;
	data += sizeof(struct ifmaddrs) * icnt;
	names = data + dcnt;

	memset(ifa, 0, sizeof(struct ifmaddrs) * icnt);
	ift = ifa;

	idx = 0;
	for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
		rtm = (struct rt_msghdr *)(void *)next;
		if (rtm->rtm_version != RTM_VERSION)
			continue;
		switch (rtm->rtm_type) {
		case RTM_NEWMADDR:
			ifmam = (struct ifma_msghdr *)(void *)rtm;
			if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
				break;
			ift->ifma_data = NULL;
			p = (char *)(void *)(ifmam + 1);
			/* Scan to look for length of address */
			alen = 0;
			for (p0 = p, i = 0; i < RTAX_MAX; i++) {
				if ((RTA_MASKS & ifmam->ifmam_addrs & (1 << i))
				    == 0)
					continue;
				sa = (struct sockaddr *)(void *)p;
				len = SA_RLEN(sa);
				if (i == RTAX_IFA) {
					alen = len;
					break;
				}
				p += len;
			}
			for (p = p0, i = 0; i < RTAX_MAX; i++) {
				if ((RTA_MASKS & ifmam->ifmam_addrs & (1 << i))
				    == 0)
					continue;
				sa = (struct sockaddr *)(void *)p;
				len = SA_RLEN(sa);
				switch (i) {
				case RTAX_GATEWAY:
					ift->ifma_gateway =
					    (struct sockaddr *)(void *)data;
					memcpy(data, p, len);
					data += len;
					break;

				case RTAX_IFP:
					ift->ifma_name =
					    (struct sockaddr *)(void *)data;
					memcpy(data, p, len);
					data += len;
					break;

				case RTAX_IFA:
					ift->ifma_addr =
					    (struct sockaddr *)(void *)data;
					memcpy(data, p, len);
					data += len;
					break;

				default:
					data += len;
					break;
				}
				p += len;
			}
			ift = (ift->ifma_next = ift + 1);
			break;
		}
	}

	free(buf);

	if (--ift >= ifa) {
		ift->ifma_next = NULL;
		*pif = ifa;
	} else {
		*pif = NULL;
		free(ifa);
	}
	return (0);
}

void
freeifmaddrs(struct ifmaddrs *ifp)
{

	free(ifp);
}
-------------- next part --------------
# $Id$

PROG= matest
SRCS= getifmaddrs.c matest.c

CFLAGS= -g3 -Wall

NOMAN=	defined

.include <bsd.prog.mk>
-------------- next part --------------
#include <sys/types.h>
#include <sys/socket.h>

#include <net/if.h>
#include <net/if_var.h>
#include <net/if_mib.h>
#include <net/if_types.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <arpa/inet.h>
#include <netdb.h>

#include <ctype.h>
#include <err.h>
#include <ifaddrs.h>
#include <sysexits.h>

#include <stddef.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>

#include "ifmaddrs.h"

extern int getifmaddrs(struct ifmaddrs **ifap);
extern void freeifmaddrs(struct ifmaddrs *ifp);
void ifmalist_dump(void);

int
main(int argc, char *argv[])
{
	ifmalist_dump();
	exit(EXIT_SUCCESS);
}

union sockunion {
        struct sockaddr_storage ss;
        struct sockaddr sa;
        struct sockaddr_dl sdl;
        struct sockaddr_in sin;
	struct sockaddr_in6 sin6;
};
typedef union sockunion sockunion_t;

void
ifmalist_dump(void)
{
	struct ifmaddrs *ifmap, *ifma;
	sockunion_t *psa;

	if (getifmaddrs(&ifmap))
		err(EX_OSERR, "getifmaddrs");

	for (ifma = ifmap; ifma; ifma = ifma->ifma_next) {
		fprintf(stderr, "%p: ", ifma);

		psa = (sockunion_t *)ifma->ifma_name;
		if (psa != NULL) {
			fprintf(stderr, "name AF(%d) ", psa->sa.sa_family);
			switch (psa->sa.sa_family) {
			case AF_INET:
				fprintf(stderr, "%s ",
				    inet_ntoa(psa->sin.sin_addr));
				break;

			case AF_LINK:
				fprintf(stderr, "%s ", link_ntoa(&psa->sdl));
				break;
			}
		} else
			fprintf(stderr, "name NULL ");

		psa = (sockunion_t *)ifma->ifma_addr;
		if (psa != NULL) {
			fprintf(stderr, "addr AF(%d) ", psa->sa.sa_family);
			switch (psa->sa.sa_family) {
			case AF_INET:
				fprintf(stderr, "%s ",
				    inet_ntoa(psa->sin.sin_addr));
				break;

			case AF_INET6: {
				void *addr;
				static char addrbuf[INET6_ADDRSTRLEN];

				addr = &psa->sin6.sin6_addr;
				inet_ntop(psa->sa.sa_family, addr, addrbuf, sizeof(addrbuf));
				fprintf(stderr, "%s ", addrbuf);
			}
			break;

			case AF_LINK:
				fprintf(stderr, "%s ", link_ntoa(&psa->sdl));
				break;
			}
		} else
			fprintf(stderr, "addr NULL ");

		psa = (sockunion_t *)ifma->ifma_gateway;
		if (psa != NULL) {
			fprintf(stderr, "gw AF(%d) ", psa->sa.sa_family);
			switch (psa->sa.sa_family) {
			case AF_INET:
				fprintf(stderr, "%s ",
				    inet_ntoa(psa->sin.sin_addr));
				break;

			case AF_LINK:
				fprintf(stderr, "%s ", link_ntoa(&psa->sdl));
				break;
			}
		} else
			fprintf(stderr, "gw NULL ");

		fputc('\n', stderr);
	}

	freeifmaddrs(ifmap);
}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 167 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-net/attachments/20031112/4a1d4047/attachment.bin


More information about the freebsd-net mailing list