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);
}

Attachment: pgp00000.pgp
Description: PGP signature

Reply via email to