From: Roy Marples Date: Fri, 17 Apr 2009 12:49:25 +0000 (+0000) Subject: discover_interfaces now uses getifaddrs instead of OS specific implementation. X-Git-Tag: v5.0.0~19 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5ed586386c33ac859efeac16366768d060d9764b;p=thirdparty%2Fdhcpcd.git discover_interfaces now uses getifaddrs instead of OS specific implementation. do_interface then becomes do_address and also uses getifaddrs. Binary size is a little smaller, code size is now a lot smaller. --- diff --git a/if-bsd.c b/if-bsd.c index 2b8b9375..43170bd7 100644 --- 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; -} diff --git a/if-linux.c b/if-linux.c index a2ecda36..b56bfe06 100644 --- a/if-linux.c +++ b/if-linux.c @@ -29,7 +29,6 @@ #include #include -#include #include #include @@ -41,14 +40,8 @@ # define IFLA_WIRELESS (IFLA_MASTER + 1) #endif -#include -#include -#include -#include - #include #include -#include #include #include #include @@ -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 eb94db2f..062002e1 100644 --- a/net.c +++ b/net.c @@ -40,12 +40,17 @@ #define __FAVOR_BSD /* Nasty glibc hack so we can use BSD semantics for UDP */ #include #undef __FAVOR_BSD +#ifdef AF_PACKET +# include +#endif #ifdef SIOCGIFMEDIA -# include +# include #endif #include #include +#include +#include #include #include #include @@ -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 f0ff3ad0..0ee3e67a 100644 --- 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 *);