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