From: Roy Marples Date: Wed, 25 Jul 2007 21:01:10 +0000 (+0000) Subject: Remove getifaddrs code and instead just use ioctls. X-Git-Tag: v3.2.3~228 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=68590c550d1ef7bc3574bda65c57b7ddbb2edcfc;p=thirdparty%2Fdhcpcd.git Remove getifaddrs code and instead just use ioctls. --- diff --git a/ChangeLog b/ChangeLog index 7e3052ce..ec94d638 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,5 @@ +Remove getifaddrs code and instead just use ioctls. + dhcpcd-3.1.0 Add new socket code to try and support InfiniBand better. Support RFC 3361 SIP Servers. diff --git a/Makefile b/Makefile index 2e90efe1..9377c600 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -VERSION = 3.1.0 +VERSION = 3.1.1_pre1 CFLAGS ?= -O2 -pipe # Should work for both GNU make and BSD make diff --git a/arp.c b/arp.c index 8f09d1de..c770e268 100644 --- a/arp.c +++ b/arp.c @@ -190,9 +190,6 @@ int arp_claim (interface_t *iface, struct in_addr address) continue; if (reply->ar_pln != sizeof (struct in_addr)) continue; - - if (reply->ar_hln != ETHER_ADDR_LEN) - continue; if ((unsigned) bytes < sizeof (reply) + 2 * (4 + reply->ar_hln)) continue; @@ -200,7 +197,8 @@ int arp_claim (interface_t *iface, struct in_addr address) rp.c = (unsigned char *) ar_spa (reply); rh.c = (unsigned char *) ar_sha (reply); logger (LOG_ERR, "ARPOP_REPLY received from %s (%s)", - inet_ntoa (*rp.a), ether_ntoa (rh.a)); + inet_ntoa (*rp.a), + hwaddr_ntoa (rh.a, reply->ar_hln)); retval = -1; goto eexit; } diff --git a/common.c b/common.c index df2f709d..b699dd61 100644 --- a/common.c +++ b/common.c @@ -52,7 +52,7 @@ void srandomdev (void) { /* strlcpy is nice, shame glibc does not define it */ #ifdef __GLIBC__ -# if ! defined(__UCLIBC__) && ! defined (__dietlibc__) +# if ! defined (__UCLIBC__) && ! defined (__dietlibc__) size_t strlcpy (char *dst, const char *src, size_t size) { const char *s = src; @@ -73,7 +73,7 @@ size_t strlcpy (char *dst, const char *src, size_t size) return (src - s - 1); } -#endif +# endif #endif /* This requires us to link to rt on glibc, so we use sysinfo instead */ diff --git a/duid.c b/duid.c index 78f02034..8ddbf2ca 100644 --- a/duid.c +++ b/duid.c @@ -33,7 +33,6 @@ #include "logger.h" #ifdef ENABLE_DUID -#define DUID_LEN 130 #define THIRTY_YEARS_IN_SECONDS 946707779 diff --git a/duid.h b/duid.h index d12aacf1..a00661a4 100644 --- a/duid.h +++ b/duid.h @@ -25,8 +25,8 @@ #include "config.h" #ifdef ENABLE_DUID -#ifndef DUID_LENGTH_MAX -#define DUID_LENGTH_MAX 128 + 2 +#ifndef DUID_LEN +# define DUID_LEN 128 + 2 #endif #include "interface.h" diff --git a/interface.c b/interface.c index 24a9ab08..7aa39f45 100644 --- a/interface.c +++ b/interface.c @@ -33,22 +33,11 @@ #include #include #include -/* Only glibc-2.3 ships with ifaddrs.h */ -#if defined (__GLIBC__) && defined (__GLIBC_PREREQ) -# if __GLIBC_PREREQ (2,3) -# define HAVE_IFADDRS_H -# include -# endif -#endif #else -#include /*dietlibc requires this - normally from - netinet/ether.h */ #include #include #include #include -#define HAVE_IFADDRS_H -# include #endif #include @@ -166,70 +155,129 @@ char *hwaddr_ntoa (const unsigned char *hwaddr, int hwlen) return (buffer); } -interface_t *read_interface (const char *ifname, int metric) +static int _do_interface (const char *ifname, + unsigned char *hwaddr, int *hwlen, + struct in_addr *addr, + bool flush, bool get) { - int s; - struct ifreq ifr; - interface_t *iface; - unsigned char hwaddr[16]; - int hwlen = 0; - sa_family_t family = 0; - unsigned short mtu; + struct ifconf ifc; + int retval = 0; + int len = 10 * sizeof (struct ifreq); + int lastlen = 0; + char *p; + + if ((s = socket (AF_INET, SOCK_DGRAM, 0)) == -1) { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return -1; + } + + /* Not all implementations return the needed buffer size for + * SIOGIFCONF so we loop like so for all until it works */ + memset (&ifc, 0, sizeof (struct ifconf)); + while (1) { + ifc.ifc_len = len; + ifc.ifc_buf = xmalloc (len); + if (ioctl (s, SIOCGIFCONF, &ifc) == -1) { + if (errno != EINVAL || lastlen != 0) { + logger (LOG_ERR, "ioctl SIOCGIFCONF: %s", strerror (errno)); + close (s); + free (ifc.ifc_buf); + return -1; + } + } else { + if (ifc.ifc_len == lastlen) + break; + lastlen = ifc.ifc_len; + } + + free (ifc.ifc_buf); + ifc.ifc_buf = NULL; + len *= 2; + } + + for (p = ifc.ifc_buf; p < ifc.ifc_buf + ifc.ifc_len;) { + struct ifreq *ifr = (struct ifreq *) p; + struct sockaddr_in address; #ifdef __linux__ - char *p; + p += sizeof (struct ifreq); #else - struct ifaddrs *ifap; - struct ifaddrs *p; + p += sizeof (ifr->ifr_name) + + MAX (ifr->ifr_addr.sa_len, sizeof (struct sockaddr)); #endif - if (! ifname) - return NULL; - - memset (hwaddr, sizeof (hwaddr), 0); + if (strcmp (ifname, ifr->ifr_name) != 0) + continue; -#ifndef __linux__ - if (getifaddrs (&ifap) != 0) - return NULL; +#ifdef __linux__ + /* Do something with the values at least */ + if (hwaddr && hwlen) + *hwlen = 0; +#else + if (hwaddr && hwlen && ifr->ifr_addr.sa_family == AF_LINK) { + struct sockaddr_dl sdl; - for (p = ifap; p; p = p->ifa_next) { - union { - struct sockaddr *sa; - struct sockaddr_dl *sdl; - } us; + memcpy (&sdl, &ifr->ifr_addr, sizeof (struct sockaddr_dl)); + *hwlen = sdl.sdl_alen; + memcpy (hwaddr, sdl.sdl_data + sdl.sdl_nlen, sdl.sdl_alen); + retval = 1; + break; + } +#endif - if (strcmp (p->ifa_name, ifname) != 0) - continue; + if (ifr->ifr_addr.sa_family == AF_INET) { + memcpy (&address, &ifr->ifr_addr, sizeof (struct sockaddr_in)); + if (flush) { + struct sockaddr_in netmask; - us.sa = p->ifa_addr; + if (ioctl (s, SIOCGIFNETMASK, ifr) == -1) { + logger (LOG_ERR, "ioctl SIOCGIFNETMASK: %s", + strerror (errno)); + continue; + } + memcpy (&netmask, &ifr->ifr_addr, sizeof (struct sockaddr_in)); - if (p->ifa_addr->sa_family != AF_LINK - || (us.sdl->sdl_type != IFT_ETHER)) - /* - && us.sdl->sdl_type != IFT_ISO88025)) - */ - { - logger (LOG_ERR, "interface is not Ethernet"); - freeifaddrs (ifap); - return NULL; + if (del_address (ifname, + address.sin_addr, netmask.sin_addr) == -1) + retval = -1; + } else if (get) { + addr->s_addr = address.sin_addr.s_addr; + retval = 1; + break; + } else if (address.sin_addr.s_addr == addr->s_addr) { + retval = 1; + break; + } } - memcpy (hwaddr, us.sdl->sdl_data + us.sdl->sdl_nlen, ETHER_ADDR_LEN); - family = ARPHRD_ETHER; - hwlen = ETHER_ADDR_LEN; - break; } - freeifaddrs (ifap); - if (! p) { - logger (LOG_ERR, "could not find interface %s", ifname); - return NULL; - } + close (s); + free (ifc.ifc_buf); + return retval; +} + +interface_t *read_interface (const char *ifname, int metric) +{ + int s; + struct ifreq ifr; + interface_t *iface; + unsigned char hwaddr[20]; + int hwlen = 0; + sa_family_t family = 0; + unsigned short mtu; +#ifdef __linux__ + char *p; #endif + if (! ifname) + return NULL; + + memset (hwaddr, sizeof (hwaddr), 0); memset (&ifr, 0, sizeof (struct ifreq)); strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + if ((s = socket (AF_INET, SOCK_DGRAM, 0)) == -1) { logger (LOG_ERR, "socket: %s", strerror (errno)); return NULL; @@ -271,6 +319,14 @@ interface_t *read_interface (const char *ifname, int metric) close (s); return NULL; } + + if (_do_interface (ifname, hwaddr, &hwlen, NULL, false, false) != 1) { + logger (LOG_ERR, "could not find interface %s", ifname); + close (s); + return NULL; + } + + family = ARPHRD_ETHER; #endif strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); @@ -512,27 +568,23 @@ static int do_route (const char *ifname, ADDADDR (destination); if (netmask.s_addr == INADDR_BROADCAST) { - struct ifaddrs *ifap, *ifa; - - if (getifaddrs (&ifap)) { - logger (LOG_ERR, "getifaddrs: %s", strerror (errno)); - close (s); - return -1; - } - - for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - if (ifa->ifa_addr->sa_family != AF_LINK) - continue; - - if (strcmp (ifname, ifa->ifa_name)) - continue; - - l = SA_SIZE (ifa->ifa_addr); - memcpy (bp, ifa->ifa_addr, l); - bp += l; - break; - } - freeifaddrs (ifap); + /* Make us a link layer socket */ + unsigned char hwaddr[HWADDR_LEN]; + int hwlen = 0; + + _do_interface (ifname, hwaddr, &hwlen, NULL, false, false); + memset (&su, 0, sizeof (struct sockaddr_storage)); + su.sdl.sdl_len = sizeof (struct sockaddr_dl); + su.sdl.sdl_family = AF_LINK; + su.sdl.sdl_nlen = strlen (ifname); + memcpy (&su.sdl.sdl_data, ifname, su.sdl.sdl_nlen); + su.sdl.sdl_alen = hwlen; + memcpy (((unsigned char *) &su.sdl.sdl_data) + su.sdl.sdl_nlen, + hwaddr, su.sdl.sdl_alen); + + l = SA_SIZE (&(su.sa)); + memcpy (bp, &su, l); + bp += l; } else { ADDADDR (gateway); } @@ -910,128 +962,26 @@ int del_route (const char *ifname, struct in_addr destination, return (do_route (ifname, destination, netmask, gateway, metric, 0, 1)); } -#ifdef HAVE_IFADDRS_H -static int _do_addresses (const char *ifname, struct in_addr *addr, bool flush, bool get) -{ - struct ifaddrs *ifap; - struct ifaddrs *p; - int retval = 0; - - if (! ifname) - return -1; - if (getifaddrs (&ifap) != 0) - return -1; - - for (p = ifap; p; p = p->ifa_next) { - union - { - struct sockaddr *sa; - struct sockaddr_in *sin; - } us_a, us_m; - - if (strcmp (p->ifa_name, ifname) != 0) - continue; - - us_a.sa = p->ifa_addr; - us_m.sa = p->ifa_netmask; - - if (us_a.sin->sin_family == AF_INET) { - if (flush) { - if (del_address (ifname, us_a.sin->sin_addr, us_m.sin->sin_addr) - == -1) - retval = -1; - } else if (get) { - addr->s_addr = us_a.sin->sin_addr.s_addr; - retval = 1; - break; - } else { - if (us_a.sin->sin_addr.s_addr == addr->s_addr) { - retval = 1; - break; - } - } - } - } - freeifaddrs (ifap); - - return retval; -} - -#else -static int _do_addresses (const char *ifname, struct in_addr address, bool flush) -{ - int s; - struct ifconf ifc; - int retval = 0; - int i; - void *ifrs; - int nifs; - struct ifreq *ifr; - - if ((s = socket (AF_INET, SOCK_DGRAM, 0)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return -1; - } - - memset (&ifc, 0, sizeof (struct ifconf)); - ifc.ifc_buf = NULL; - if (ioctl (s, SIOCGIFCONF, &ifc) == -1) { - logger (LOG_ERR, "ioctl SIOCGIFCONF: %s", strerror (errno)); - close (s); - } - - ifrs = xmalloc (ifc.ifc_len); - ifc.ifc_buf = ifrs; - if (ioctl (s, SIOCGIFCONF, &ifc) == -1) { - logger (LOG_ERR, "ioctl SIOCGIFCONF: %s", strerror (errno)); - close (s); - free (ifrs); - return -1; - } - - close (s); - - nifs = ifc.ifc_len / sizeof (struct ifreq); - ifr = ifrs; - for (i = 0; i < nifs; i++) { - struct sockaddr_in *addr = (struct sockaddr_in *) &ifr->ifr_addr; - struct sockaddr_in *netm = (struct sockaddr_in *) &ifr->ifr_netmask; - - if (ifr->ifr_addr.sa_family == AF_INET - && strcmp (ifname, ifr->ifr_name) == 0) - { - if (flush) { - if (del_address (ifname, addr->sin_addr, netm->sin_addr) == -1) - retval = -1; - } else if (addr->sin_addr.s_addr == address.s_addr) { - retval = 1; - break; - } - } - ifr++; - } - - free (ifrs); - return retval; -} -#endif int flush_addresses (const char *ifname) { struct in_addr address; - return (_do_addresses (ifname, &address, true, false)); + unsigned char buf[1024]; + int len = 0; + + memset (buf, 0, 1023); + return (_do_interface (ifname, buf, &len, &address, true, false)); } unsigned long get_address (const char *ifname) { struct in_addr address; - if (_do_addresses (ifname, &address, false, true) > 0) + if (_do_interface (ifname, NULL, NULL, &address, false, true) > 0) return (address.s_addr); return (0); } int has_address (const char *ifname, struct in_addr address) { - return (_do_addresses (ifname, &address, false, false)); + return (_do_interface (ifname, NULL, NULL, &address, false, false)); } - diff --git a/interface.h b/interface.h index dd079881..eae71dd5 100644 --- a/interface.h +++ b/interface.h @@ -33,8 +33,8 @@ #include "config.h" #ifdef ENABLE_DUID -#ifndef DUID_LENGTH_MAX -#define DUID_LENGTH_MAX 128 + 2 +#ifndef DUID_LEN +# define DUID_LEN 128 + 2 #endif #endif @@ -51,6 +51,8 @@ # define ARPHRD_INFINIBAND 27 #endif +#define HWADDR_LEN 20 + typedef struct route_t { struct in_addr destination; @@ -69,7 +71,7 @@ typedef struct interface_t { char name[IF_NAMESIZE]; sa_family_t family; - unsigned char hwaddr[20]; + unsigned char hwaddr[HWADDR_LEN]; int hwlen; bool arpable; unsigned short mtu; @@ -91,7 +93,7 @@ typedef struct interface_t long start_uptime; #ifdef ENABLE_DUID - unsigned char duid[DUID_LENGTH_MAX]; + unsigned char duid[DUID_LEN]; int duid_length; #endif } interface_t;