]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
discover_interfaces now uses getifaddrs instead of OS specific implementation.
authorRoy Marples <roy@marples.name>
Fri, 17 Apr 2009 12:49:25 +0000 (12:49 +0000)
committerRoy Marples <roy@marples.name>
Fri, 17 Apr 2009 12:49:25 +0000 (12:49 +0000)
do_interface then becomes do_address and also uses getifaddrs.

Binary size is a little smaller, code size is now a lot smaller.

if-bsd.c
if-linux.c
net.c
net.h

index 2b8b93758649f96a318d71aa50731e81e3c78c0e..43170bd75367528128913b6e3eaf83eeb04f54d9 100644 (file)
--- a/if-bsd.c
+++ b/if-bsd.c
@@ -369,72 +369,3 @@ manage_link(int fd)
                }
        }
 }
-
-static void
-discover_link(struct interface **ifs, int argc, char * const *argv,
-    struct ifreq *ifr)
-{
-       struct interface *ifp, *ifl = NULL;
-       struct sockaddr_dl *sdl;
-       int n;
-
-       if (ifr->ifr_addr.sa_family != AF_LINK)
-               return;
-       for (ifp = *ifs; ifp; ifp = ifp->next) {
-               if (strcmp(ifp->name, ifr->ifr_name) == 0)
-                       return;
-               ifl = ifp;
-       }
-       if (argc > 0) {
-               for (n = 0; n < argc; n++)
-                       if (strcmp(ifr->ifr_name, argv[n]) == 0)
-                               break;
-               if (n == argc)
-                       return;
-       } else {
-               for (n = 0; n < ifdc; n++)
-                       if (fnmatch(ifdv[n], ifr->ifr_name, 0) == 0)
-                               return;
-               for (n = 0; n < ifac; n++)
-                       if (fnmatch(ifav[n], ifr->ifr_name, 0) == 0)
-                               break;
-               if (ifac && n == ifac)
-                       return;
-       }
-       if (!(ifp = init_interface(ifr->ifr_name)))
-               return;
-       sdl = (struct sockaddr_dl *)(void *)&ifr->ifr_addr;
-       switch(sdl->sdl_type) {
-       case IFT_ETHER:
-               ifp->family = ARPHRD_ETHER;
-               ifp->hwlen = sdl->sdl_alen;
-               break;
-       case IFT_IEEE1394:
-               ifp->family = ARPHRD_IEEE1394;
-               ifp->hwlen = sdl->sdl_alen;
-               break;
-       case IFT_LOOP:
-               /* We don't allow loopback unless requested */
-               if (argc == 0 && ifac == 0) {
-                       free(ifp);
-                       ifp = NULL;
-               }
-               break;
-       }
-       if (ifp && ifp->hwlen)
-               memcpy(ifp->hwaddr, LLADDR(sdl), ifp->hwlen);
-       if (ifl)
-               ifl->next = ifp;
-       else
-               *ifs = ifp;
-}
-
-struct interface *
-discover_interfaces(int argc, char * const *argv)
-{
-       struct interface *ifs = NULL;
-
-       do_interface(NULL, discover_link, &ifs, argc, argv,
-                       NULL, NULL, NULL, 2);
-       return ifs;
-}
index a2ecda36526253baf9de242fe1c99eff91f4b1f2..b56bfe0634e4f576bb6c1009aa730b017138263e 100644 (file)
@@ -29,7 +29,6 @@
 
 #include <sys/types.h>
 #include <sys/socket.h>
-#include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <sys/param.h>
 
 # define IFLA_WIRELESS (IFLA_MASTER + 1)
 #endif
 
-#include <arpa/inet.h>
-#include <net/if.h>
-#include <netinet/ether.h>
-#include <netpacket/packet.h>
-
 #include <errno.h>
 #include <ctype.h>
-#include <fnmatch.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -510,71 +503,3 @@ if_route(const struct interface *iface,
        free(nlm);
        return retval;
 }
-
-struct interface *
-discover_interfaces(int argc, char * const *argv)
-{
-       FILE *f;
-       char ifn[IF_NAMESIZE];
-       char *p, *c;
-       size_t ln = 0, n;
-       int i;
-       struct interface *ifs = NULL, *ifp, *ifl;
-
-       if ((f = fopen("/proc/net/dev", "r"))) {
-               while ((p = get_line(f))) {
-                       if (++ln < 2)
-                               continue;
-                       n = strcspn(p, ": \t");
-                       p[n]= '\0';
-                       ifl = NULL;
-                       for (ifp = ifs; ifp; ifp = ifp->next) {
-                               if (strcmp(ifp->name, p) == 0)
-                                       break;
-                               ifl = ifp;
-                       }
-                       if (ifp)
-                               continue;
-                       if (argc > 0) {
-                               for (i = 0; i < argc; i++) {
-                                       /* Check the real interface name */
-                                       strlcpy(ifn, argv[i], sizeof(ifn));
-                                       c = strchr(ifn, ':');
-                                       if (c)
-                                               *c = '\0';
-                                       if (strcmp(ifn, p) == 0)
-                                               break;
-                               }
-                               if (i == argc)
-                                       continue;
-                               p = argv[i];
-                       } else {
-                               for (i = 0; i < ifdc; i++)
-                                       if (!fnmatch(ifdv[i], p, 0))
-                                               break;
-                               if (i < ifdc)
-                                       continue;
-                               for (i = 0; i < ifac; i++)
-                                       if (!fnmatch(ifav[i], p, 0))
-                                               break;
-                               if (ifac && i == ifac)
-                                       continue;
-                       }
-                       if ((ifp = init_interface(p))) {
-                               /* Don't allow loopback unless explicit */
-                               if (ifp->flags & IFF_LOOPBACK &&
-                                   (argc != 0 || ifdc != 0))
-                               {
-                                       free_interface(ifp);
-                                       continue;
-                               }
-                               if (ifl)
-                                       ifl->next = ifp; 
-                               else
-                                       ifs = ifp;
-                       }
-               }
-               fclose(f);
-       }
-       return ifs;
-}
diff --git a/net.c b/net.c
index eb94db2fdca08d077e8db4387b108e5b22d4c9f8..062002e1facef9720ee02a1b90eb9d68f30bcee6 100644 (file)
--- a/net.c
+++ b/net.c
 #define __FAVOR_BSD /* Nasty glibc hack so we can use BSD semantics for UDP */
 #include <netinet/udp.h>
 #undef __FAVOR_BSD
+#ifdef AF_PACKET
+#  include <netpacket/packet.h>
+#endif
 #ifdef SIOCGIFMEDIA
-# include <net/if_media.h>
+#  include <net/if_media.h>
 #endif
 
 #include <ctype.h>
 #include <errno.h>
+#include <ifaddrs.h>
+#include <fnmatch.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -199,29 +204,6 @@ init_interface(const char *ifname)
                iface->metric += 100;
        }
 
-#ifdef SIOCGIFHWADDR
-       strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
-       if (ioctl(s, SIOCGIFHWADDR, &ifr) == -1)
-               goto eexit;
-
-       switch (ifr.ifr_hwaddr.sa_family) {
-       case ARPHRD_ETHER:
-       case ARPHRD_IEEE802:
-               iface->hwlen = ETHER_ADDR_LEN;
-               break;
-       case ARPHRD_IEEE1394:
-               iface->hwlen = EUI64_ADDR_LEN;
-       case ARPHRD_INFINIBAND:
-               iface->hwlen = INFINIBAND_ADDR_LEN;
-               break;
-       default:
-               iface->hwlen = 0;
-       }
-       iface->family = ifr.ifr_hwaddr.sa_family;
-       if (iface->hwlen != 0)
-               memcpy(iface->hwaddr, ifr.ifr_hwaddr.sa_data, iface->hwlen);
-#endif
-
        if (ioctl(s, SIOCGIFMTU, &ifr) == -1)
                goto eexit;
        /* Ensure that the MTU is big enough for DHCP */
@@ -265,114 +247,146 @@ free_interface(struct interface *iface)
        free(iface);
 }
 
-int
-do_interface(const char *ifname,
-    void (*do_link)(struct interface **, int, char * const *, struct ifreq *),
-    struct interface **ifs, int argc, char * const *argv,
-    struct in_addr *addr, struct in_addr *net, struct in_addr *dst, int act)
+struct interface *
+discover_interfaces(int argc, char * const *argv)
 {
-       int s;
-       struct ifconf ifc;
-       int retval = 0, found = 0;
-       int len = 10 * sizeof(struct ifreq);
-       int lastlen = 0;
-       char *p, *e;
-       in_addr_t address, netmask;
-       struct ifreq *ifr;
-       struct sockaddr_in *sin;
+       struct ifaddrs *ifaddrs, *ifa;
+       char *p;
+       int i;
+       struct interface *ifp, *ifs, *ifl;
+#ifdef __linux__
+       char ifn[IF_NAMESIZE];
+#endif
+#ifdef AF_LINK
+       const struct sockaddr_dl *sdl;
+#elif AF_PACKET
+       const struct sockaddr_ll *sll;
+#endif
 
-       if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
-               return -1;
+       if (getifaddrs(&ifaddrs) == -1)
+               return NULL;
 
-       /* Not all implementations return the needed buffer size for
-        * SIOGIFCONF so we loop like so for all until it works */
-       memset(&ifc, 0, sizeof(ifc));
-       for (;;) {
-               ifc.ifc_len = len;
-               ifc.ifc_buf = xmalloc((size_t)len);
-               if (ioctl(s, SIOCGIFCONF, &ifc) == -1) {
-                       if (errno != EINVAL || lastlen != 0) {
-                               close(s);
-                               free(ifc.ifc_buf);      
-                               return -1;
+       ifs = ifl = NULL;
+       for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
+#ifdef AF_LINK
+               if (ifa->ifa_addr->sa_family != AF_LINK)
+                       continue;
+#elif AF_PACKET
+               if (ifa->ifa_addr->sa_family != AF_PACKET)
+                       continue;
+#endif
+               if (argc > 0) {
+                       for (i = 0; i < argc; i++) {
+#ifdef __linux__
+                               /* Check the real interface name */
+                               strlcpy(ifn, argv[i], sizeof(ifn));
+                               p = strchr(ifn, ':');
+                               if (p)
+                                       *p = '\0';
+                               if (strcmp(ifn, ifa->ifa_name) == 0)
+                                       break;
+#else
+                               if (strcmp(argv[i], ifa->ifa_name) == 0)
+                                       break;
+#endif
+                       }
+                       if (i == argc)
+                               continue;
+                       p = argv[i];
+               } else {
+                       for (i = 0; i < ifdc; i++)
+                               if (!fnmatch(ifdv[i], ifa->ifa_name, 0))
+                                       break;
+                       if (i < ifdc)
+                               continue;
+                       for (i = 0; i < ifac; i++)
+                               if (!fnmatch(ifav[i], ifa->ifa_name, 0))
+                                       break;
+                       if (ifac && i == ifac)
+                               continue;
+                       p = ifa->ifa_name;
+               }
+               if ((ifp = init_interface(p)) == NULL)
+                       continue;
+               /* Don't allow loopback unless explicit */
+               if (ifp->flags & IFF_LOOPBACK) {
+                       if (argc == 0 && ifdc == 0) {
+                               free_interface(ifp);
+                               continue;
                        }
                } else {
-                       if (ifc.ifc_len == lastlen)
+#ifdef AF_LINK
+                       sdl = (const struct sockaddr_dl *)(void *)ifa->ifa_addr;
+                       switch(sdl->sdl_type) {
+                       case IFT_ETHER:
+                               ifp->family = ARPHRD_ETHER;
+                               break;
+                       case IFT_IEEE1394:
+                               ifp->family = ARPHRD_IEEE1394;
                                break;
-                       lastlen = ifc.ifc_len;
+                       }
+                       ifp->hwlen = sdl->sdl_alen;
+                       memcpy(ifp->hwaddr, LLADDR(sdl), ifp->hwlen);
+#elif AF_PACKET
+                       sll = (const struct sockaddr_ll *)(void *)ifa->ifa_addr;
+                       ifp->family = sll->sll_hatype;
+                       ifp->hwlen = sll->sll_halen;
+                       if (ifp->hwlen != 0)
+                               memcpy(ifp->hwaddr, sll->sll_addr, ifp->hwlen);
+#endif
                }
-
-               free(ifc.ifc_buf);
-               ifc.ifc_buf = NULL;
-               len *= 2;
-       }
-
-       e = (char *)ifc.ifc_buf + ifc.ifc_len;
-       for (p = ifc.ifc_buf; p < e;) {
-               ifr = (struct ifreq *)(void *)p;
-
-#ifndef __linux__
-               if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_ifru))
-                       p += offsetof(struct ifreq, ifr_ifru) +
-                           ifr->ifr_addr.sa_len;
+               if (ifl)
+                       ifl->next = ifp; 
                else
-#endif
-                       p += sizeof(*ifr);
+                       ifs = ifp;
+               ifl = ifp;
+       }
+       freeifaddrs(ifaddrs);
+       return ifs;
+}
 
-               if (ifname && strcmp(ifname, ifr->ifr_name) != 0)
-                       continue;
+int
+do_address(const char *ifname,
+    struct in_addr *addr, struct in_addr *net, struct in_addr *dst, int act)
+{
+       struct ifaddrs *ifaddrs, *ifa;
+       const struct sockaddr_in *a, *n, *d;
+       int retval;
 
-               found = 1;
+       if (getifaddrs(&ifaddrs) == -1)
+               return -1;
 
-               /* Interface discovery for BSD's */
-               if (act == 2 && do_link) {
-                       do_link(ifs, argc, argv, ifr);
+       retval = 0;
+       for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
+               if (ifa->ifa_addr->sa_family != AF_INET ||
+                   strcmp(ifa->ifa_name, ifname) != 0)
                        continue;
+               a = (const struct sockaddr_in *)(void *)&ifa->ifa_addr;
+               n = (const struct sockaddr_in *)(void *)&ifa->ifa_netmask;
+               if (ifa->ifa_flags & IFF_POINTOPOINT)
+                       d = (const struct sockaddr_in *)
+                               (void *)&ifa->ifa_ifu.ifu_dstaddr;
+               else
+                       d = NULL;
+               if (act == 1) {
+                       addr->s_addr = a->sin_addr.s_addr;
+                       net->s_addr = n->sin_addr.s_addr;
+                       if (dst && ifa->ifa_flags & IFF_POINTOPOINT)
+                               dst->s_addr = d->sin_addr.s_addr;
+                       retval = 1;
+                       break;
                }
-
-               if (ifr->ifr_addr.sa_family == AF_INET && addr) {
-                       sin = (struct sockaddr_in *)(void *)&ifr->ifr_addr;
-                       address = sin->sin_addr.s_addr;
-                       /* Some platforms only partially fill the bits
-                        * set by the netmask, so we need to zero it now. */
-                       sin->sin_addr.s_addr = 0;
-                       if (ioctl(s, SIOCGIFNETMASK, ifr) == -1)
-                               continue;
-                       netmask = sin->sin_addr.s_addr;
-                       if (act == 1) {
-                               if (dst) {
-                                       sin = (struct sockaddr_in *)
-                                               (void *)&ifr->ifr_dstaddr;
-                                       if (ioctl(s, SIOCGIFDSTADDR, ifr)
-                                           == -1)
-                                               dst->s_addr = INADDR_ANY;
-                                       else
-                                               dst->s_addr =
-                                                   sin->sin_addr.s_addr;
-                               }
-                               addr->s_addr = address;
-                               net->s_addr = netmask;
-                               retval = 1;
-                               break;
-                       } else {
-                               if (address == addr->s_addr &&
-                                   (!net || netmask == net->s_addr))
-                               {
-                                       retval = 1;
-                                       break;
-                               }
-                       }
+               if (addr->s_addr == a->sin_addr.s_addr &&
+                   (net == NULL || net->s_addr == n->sin_addr.s_addr))
+               {
+                       retval = 1;
+                       break;
                }
-
        }
-
-       if (!found)
-               errno = ENXIO;
-       close(s);
-       free(ifc.ifc_buf);
+       freeifaddrs(ifaddrs);
        return retval;
 }
-
+       
 int
 up_interface(const char *ifname)
 {
diff --git a/net.h b/net.h
index f0ff3ad0926afa745459f9cb5f6844d6e1669e55..0ee3e67aeabbc7287e03998ed449d0df8a62b444 100644 (file)
--- a/net.h
+++ b/net.h
@@ -66,8 +66,8 @@
  * 192.168/16
  */
 #ifndef IN_PRIVATE
-# define IN_PRIVATE(addr) (((addr & IN_CLASSA_NET) == 0x0a000000) ||   \
-           ((addr & 0xfff00000)    == 0xac100000) ||                   \
+# define IN_PRIVATE(addr) (((addr & IN_CLASSA_NET) == 0x0a000000) ||         \
+           ((addr & 0xfff00000)    == 0xac100000) ||                         \
            ((addr & IN_CLASSB_NET) == 0xc0a80000))
 #endif
 
@@ -103,31 +103,29 @@ int inet_ntocidr(struct in_addr);
 int inet_cidrtoaddr(int, struct in_addr *);
 
 int up_interface(const char *);
-int do_interface(const char *,
-    void (*)(struct interface **, int, char * const *, struct ifreq *),
-    struct interface **, int, char * const *,
+int do_address(const char *,
     struct in_addr *, struct in_addr *, struct in_addr *, int);
 int if_address(const struct interface *,
     const struct in_addr *, const struct in_addr *,
     const struct in_addr *, int);
-#define add_address(iface, addr, net, brd)                             \
+#define add_address(iface, addr, net, brd)                                   \
        if_address(iface, addr, net, brd, 1)
-#define del_address(iface, addr, net)                                  \
+#define del_address(iface, addr, net)                                        \
        if_address(iface, addr, net, NULL, -1)
-#define has_address(iface, addr, net)                                  \
-       do_interface(iface, NULL, NULL, 0, NULL, addr, net, NULL, 0)
-#define get_address(iface, addr, net, dst)                             \
-       do_interface(iface, NULL, NULL, 0, NULL, addr, net, dst, 1)
+#define has_address(iface, addr, net)                                        \
+       do_address(iface, addr, net, NULL, 0)
+#define get_address(iface, addr, net, dst)                                   \
+       do_address(iface, addr, net, dst, 1)
 
 int if_route(const struct interface *, const struct in_addr *,
     const struct in_addr *, const struct in_addr *, int, int);
-#define add_route(iface, dest, mask, gate, metric)                     \
+#define add_route(iface, dest, mask, gate, metric)                           \
        if_route(iface, dest, mask, gate, metric, 1)
-#define change_route(iface, dest, mask, gate, metric)                  \
+#define change_route(iface, dest, mask, gate, metric)                        \
        if_route(iface, dest, mask, gate, metric, 0)
-#define del_route(iface, dest, mask, gate, metric)                     \
+#define del_route(iface, dest, mask, gate, metric)                           \
        if_route(iface, dest, mask, gate, metric, -1)
-#define del_src_route(iface, dest, mask, gate, metric)                 \
+#define del_src_route(iface, dest, mask, gate, metric)                       \
        if_route(iface, dest, mask, gate, metric, -2)
 void free_routes(struct rt *);