]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Solaris does not return AF_LINK addresses in getifaddrs(3), so
authorRoy Marples <roy@marples.name>
Mon, 2 May 2016 01:55:50 +0000 (01:55 +0000)
committerRoy Marples <roy@marples.name>
Mon, 2 May 2016 01:55:50 +0000 (01:55 +0000)
link to dlpi, walk the interfaces and obtain the physical address
of each interface.

configure
if-sun.c
if.c
if.h

index eaa6db2be0c3eab8d904ccd39cdf4f0ec525aa58..0090c034605c83d86ccfd0a153738e630c5c20aa 100755 (executable)
--- a/configure
+++ b/configure
@@ -406,6 +406,7 @@ sunos*)
        echo "CPPFLAGS+=        -D_XPG4_2 -D__EXTENSIONS__ -DBSD_COMP" \
            >>$CONFIG_MK
        echo "DHCPCD_SRCS+=     if-sun.c" >>$CONFIG_MK
+       echo "LDADD+=           -ldlpi" >>$CONFIG_MK
 
        # IPv6 won't work, but it will at least compile.
        echo "CPPFLAGS+=        -DIN6_IFF_DETACHED=0" >>$CONFIG_MK
index 68986a42e60fce798f9ac52aa532373ddc1dc60a..bef4f59aeef6a5aa2776358b9b3e0ae16b64a31d 100644 (file)
--- a/if-sun.c
+++ b/if-sun.c
  * SUCH DAMAGE.
  */
 
+#include <sys/ioctl.h>
 #include <sys/utsname.h>
 
 #include <errno.h>
-#include <fcntl.h>
+#include <ifaddrs.h>
+#include <libdlpi.h>
+#include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
+#include <net/if_dl.h>
+#include <net/if_types.h>
+
 #include "config.h"
 #include "common.h"
 #include "dhcp.h"
@@ -58,8 +65,7 @@ int
 if_opensockets_os(struct dhcpcd_ctx *ctx)
 {
 
-       errno = ENOTSUP;
-       return -1;
+       return 0;
 }
 
 void
@@ -91,6 +97,7 @@ if_managelink(struct dhcpcd_ctx *ctx)
        return -1;
 }
 
+int
 if_machinearch(char *str, size_t len)
 {
 
@@ -98,6 +105,98 @@ if_machinearch(char *str, size_t len)
        return -1;
 }
 
+struct linkwalk {
+       struct ifaddrs  *lw_ifa;
+       int             lw_error;
+};
+
+static boolean_t
+if_newaddr(const char *ifname, void *arg)
+{
+       struct linkwalk         *lw = arg;
+       struct ifaddrs          *ifa;
+       dlpi_handle_t           dh;
+       dlpi_info_t             dlinfo;
+       uint8_t                 pa[DLPI_PHYSADDR_MAX];
+       unsigned int            pa_len;
+       struct sockaddr_dl      *sdl;
+
+       ifa = NULL;
+       if (dlpi_open(ifname, &dh, 0) != DLPI_SUCCESS)
+               goto failed1;
+       if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS)
+               goto failed;
+
+       /* For some reason, dlpi_info won't return the
+        * physical address, it's all zero's.
+        * So cal dlpi_get_physaddr. */
+       pa_len = DLPI_PHYSADDR_MAX;
+       if (dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR,
+           pa, &pa_len) != DLPI_SUCCESS)
+               goto failed;
+
+       if ((ifa = calloc(1, sizeof(*ifa))) == NULL)
+               goto failed;
+       if ((ifa->ifa_addr = calloc(1, sizeof(struct sockaddr_dl))) == NULL)
+               goto failed;
+
+       if ((ifa->ifa_name = strdup(ifname)) == NULL)
+               goto failed;
+
+       sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+
+       sdl->sdl_family = AF_LINK;
+       switch (dlinfo.di_mactype) {
+       case DL_ETHER:
+               sdl->sdl_type = IFT_ETHER;
+               break;
+       case DL_IB:
+               sdl->sdl_type = IFT_IB;
+               break;
+       default:
+               sdl->sdl_type = IFT_OTHER;
+               break;
+       }
+
+       sdl->sdl_alen = pa_len;
+       memcpy(sdl->sdl_data, pa, pa_len);
+
+       ifa->ifa_next = lw->lw_ifa;
+       lw->lw_ifa = ifa;
+       dlpi_close(dh);
+       return (B_FALSE);
+
+failed:
+       dlpi_close(dh);
+       if (ifa != NULL) {
+               free(ifa->ifa_name);
+               free(ifa->ifa_addr);
+               free(ifa);
+       }
+failed1:
+       lw->lw_error = errno;
+       return (B_TRUE);
+}
+
+/* all getifaddrs(3) should support AF_LINK, but hey ho */
+int
+if_getifaddrs(struct ifaddrs **ifap)
+{
+       struct linkwalk lw = { NULL, 0 };
+       int error;
+
+       error = 0;
+       dlpi_walk(if_newaddr, &lw, 0);
+       if (lw.lw_error != 0) {
+               freeifaddrs(lw.lw_ifa);
+               errno = lw.lw_error;
+               return -1;
+       }
+
+       *ifap = lw.lw_ifa;
+       return 0;
+}
+
 #ifdef INET
 const char *if_pfname = "SunOS";
 
diff --git a/if.c b/if.c
index b51b2d28a4065f797b8fec80cf77504066a191a1..7fe4132bbdb3bce8f57c21df911e9bc1fb8d8ed5 100644 (file)
--- a/if.c
+++ b/if.c
@@ -271,8 +271,13 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
        const struct sockaddr_ll *sll;
 #endif
 
+#ifdef GETIFADDRS_AFLINK
        if (getifaddrs(&ifaddrs) == -1)
                return NULL;
+#else
+       if (if_getifaddrs(&ifaddrs) == -1)
+               return NULL;
+#endif
        ifs = malloc(sizeof(*ifs));
        if (ifs == NULL)
                return NULL;
@@ -549,8 +554,15 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
                TAILQ_INSERT_TAIL(ifs, ifp, next);
        }
 
-       if_learnaddrs(ctx, ifs, ifaddrs);
+#ifdef GETIFADDRS_AFLINK
+       {
+#else
        freeifaddrs(ifaddrs);
+       if (getifaddrs(&ifaddrs) != -1) {
+#endif
+               if_learnaddrs(ctx, ifs, ifaddrs);
+               freeifaddrs(ifaddrs);
+       }
 
        return ifs;
 }
diff --git a/if.h b/if.h
index aaf74f1d0a175e1590b0fff55a30f023c44b0271..f174ee4ce8a39c2826dda0301a2045718039e924 100644 (file)
--- a/if.h
+++ b/if.h
 #define RAW_EOF                        1 << 0
 #define RAW_PARTIALCSUM                2 << 0
 
+#ifdef __sun
+/* platform does not supply AF_LINK with getifaddrs. */
+struct ifaddrs;
+int if_getifaddrs(struct ifaddrs **);
+#else
+#define GETIFADDRS_AFLINK
+#endif
+
 int if_setflag(struct interface *ifp, short flag);
 #define if_up(ifp) if_setflag((ifp), (IFF_UP | IFF_RUNNING))
 struct if_head *if_discover(struct dhcpcd_ctx *, int, char * const *);