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
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)
struct ifmaddrs { struct ifmaddrs *ifma_next; struct sockaddr *ifma_name; struct sockaddr *ifma_addr; struct sockaddr *ifma_gateway; void *ifma_data; };
#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); }
# $Id$ PROG= matest SRCS= getifmaddrs.c matest.c CFLAGS= -g3 -Wall NOMAN= defined .include <bsd.prog.mk>
#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); }
pgp00000.pgp
Description: PGP signature