Huw Davies : iphlpapi: Add interface enumeration for Android.

Alexandre Julliard julliard at winehq.org
Thu Sep 19 17:21:06 CDT 2013


Module: wine
Branch: master
Commit: 21dc848378318519d28a535517fe0997e63f3fe3
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=21dc848378318519d28a535517fe0997e63f3fe3

Author: Huw Davies <huw at codeweavers.com>
Date:   Thu Sep 19 15:39:21 2013 +0100

iphlpapi: Add interface enumeration for Android.

---

 configure              |    3 +-
 configure.ac           |    3 +-
 dlls/iphlpapi/ifenum.c |  200 +++++++++++++++++++++++++++++++++++++++++++++++-
 include/config.h.in    |    6 ++
 4 files changed, 209 insertions(+), 3 deletions(-)

diff --git a/configure b/configure
index e6f6971..a2f8e22 100755
--- a/configure
+++ b/configure
@@ -6235,7 +6235,7 @@ fi
 done
 
 
-for ac_header in linux/ipx.h linux/irda.h
+for ac_header in linux/ipx.h linux/irda.h linux/rtnetlink.h
 do :
   as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
 ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#include <sys/types.h>
@@ -13405,6 +13405,7 @@ for ac_func in \
 	getpwuid \
 	gettimeofday \
 	getuid \
+	if_nameindex \
 	kqueue \
 	lstat \
 	memmove \
diff --git a/configure.ac b/configure.ac
index e03928c..b687119 100644
--- a/configure.ac
+++ b/configure.ac
@@ -606,7 +606,7 @@ AC_CHECK_HEADERS([netinet/tcp_timer.h netinet/udp_var.h netinet/icmp_var.h netin
      #include <netinet/tcp_timer.h>
      #endif])
 
-AC_CHECK_HEADERS([linux/ipx.h linux/irda.h],,,
+AC_CHECK_HEADERS([linux/ipx.h linux/irda.h linux/rtnetlink.h],,,
     [#include <sys/types.h>
      #ifdef HAVE_ASM_TYPES_H
      # include <asm/types.h>
@@ -2032,6 +2032,7 @@ AC_CHECK_FUNCS(\
 	getpwuid \
 	gettimeofday \
 	getuid \
+	if_nameindex \
 	kqueue \
 	lstat \
 	memmove \
diff --git a/dlls/iphlpapi/ifenum.c b/dlls/iphlpapi/ifenum.c
index 6ad08a8..03c1b1a 100644
--- a/dlls/iphlpapi/ifenum.c
+++ b/dlls/iphlpapi/ifenum.c
@@ -79,6 +79,10 @@
 #include <ifaddrs.h>
 #endif
 
+#ifdef HAVE_LINUX_RTNETLINK_H
+#include <linux/rtnetlink.h>
+#endif
+
 #include "ifenum.h"
 #include "ws2ipdef.h"
 
@@ -161,7 +165,7 @@ BOOL isIfIndexLoopback(ULONG idx)
   return ret;
 }
 
-
+#ifdef HAVE_IF_NAMEINDEX
 DWORD get_interface_indices( BOOL skip_loopback, InterfaceIndexTable **table )
 {
     DWORD count = 0, i;
@@ -199,6 +203,200 @@ end:
     return count;
 }
 
+#elif defined(HAVE_LINUX_RTNETLINK_H)
+static int open_netlink( int *pid )
+{
+    int fd = socket( AF_NETLINK, SOCK_RAW, NETLINK_ROUTE );
+    struct sockaddr_nl addr;
+    socklen_t len;
+
+    if (fd < 0) return fd;
+
+    memset( &addr, 0, sizeof(addr) );
+    addr.nl_family = AF_NETLINK;
+
+    if (bind( fd, (struct sockaddr *)&addr, sizeof(addr) ) < 0)
+        goto fail;
+
+    len = sizeof(addr);
+    if (getsockname( fd, (struct sockaddr *)&addr, &len ) < 0)
+        goto fail;
+
+    *pid = addr.nl_pid;
+    return fd;
+fail:
+    close( fd );
+    return -1;
+}
+
+static int send_netlink_req( int fd, int pid, int type, int *seq_no )
+{
+    static LONG seq;
+    struct request
+    {
+        struct nlmsghdr hdr;
+        struct rtgenmsg gen;
+    } req;
+    struct sockaddr_nl addr;
+
+    req.hdr.nlmsg_len = sizeof(req);
+    req.hdr.nlmsg_type = type;
+    req.hdr.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
+    req.hdr.nlmsg_pid = pid;
+    req.hdr.nlmsg_seq = InterlockedIncrement( &seq );
+    req.gen.rtgen_family = AF_UNSPEC;
+
+    memset( &addr, 0, sizeof(addr) );
+    addr.nl_family = AF_NETLINK;
+    if (sendto( fd, &req, sizeof(req), 0, (struct sockaddr *)&addr, sizeof(addr) ) != sizeof(req))
+        return -1;
+    *seq_no = req.hdr.nlmsg_seq;
+    return 0;
+}
+
+struct netlink_reply
+{
+    struct netlink_reply *next;
+    int size;
+    struct nlmsghdr *hdr;
+};
+
+static void free_netlink_reply( struct netlink_reply *data )
+{
+    struct netlink_reply *ptr;
+    while( data )
+    {
+        ptr = data->next;
+        HeapFree( GetProcessHeap(), 0, data );
+        data = ptr;
+    }
+}
+
+static int recv_netlink_reply( int fd, int pid, int seq, struct netlink_reply **data )
+{
+    int bufsize = getpagesize();
+    int left, read, done = 0;
+    socklen_t sa_len;
+    struct sockaddr_nl addr;
+    struct netlink_reply *cur, *last = NULL;
+    struct nlmsghdr *hdr;
+    char *buf;
+
+    *data = NULL;
+    buf = HeapAlloc( GetProcessHeap(), 0, bufsize );
+    if (!buf) return -1;
+
+    do
+    {
+        left = read = recvfrom( fd, buf, bufsize, 0, (struct sockaddr *)&addr, &sa_len );
+        if (read < 0) goto fail;
+        if (addr.nl_pid != 0) continue; /* not from kernel */
+
+        for (hdr = (struct nlmsghdr *)buf; NLMSG_OK(hdr, left); hdr = NLMSG_NEXT(hdr, left))
+        {
+            if (hdr->nlmsg_pid != pid || hdr->nlmsg_seq != seq) continue;
+            if (hdr->nlmsg_type == NLMSG_DONE)
+            {
+                done = 1;
+                break;
+            }
+        }
+
+        cur = HeapAlloc( GetProcessHeap(), 0, sizeof(*cur) + read );
+        if (!cur) goto fail;
+        cur->next = NULL;
+        cur->size = read;
+        cur->hdr = (struct nlmsghdr *)(cur + 1);
+        memcpy( cur->hdr, buf, read );
+        if (last) last->next = cur;
+        else *data = cur;
+        last = cur;
+    } while (!done);
+
+    HeapFree( GetProcessHeap(), 0, buf );
+    return 0;
+
+fail:
+    free_netlink_reply( *data );
+    HeapFree( GetProcessHeap(), 0, buf );
+    return -1;
+}
+
+
+static DWORD get_indices_from_reply( struct netlink_reply *reply, int pid, int seq,
+                                     BOOL skip_loopback, InterfaceIndexTable *table )
+{
+    struct nlmsghdr *hdr;
+    struct netlink_reply *r;
+    int count = 0;
+
+    for (r = reply; r; r = r->next)
+    {
+        int size = r->size;
+        for (hdr = r->hdr; NLMSG_OK(hdr, size); hdr = NLMSG_NEXT(hdr, size))
+        {
+            if (hdr->nlmsg_pid != pid || hdr->nlmsg_seq != seq) continue;
+            if (hdr->nlmsg_type == NLMSG_DONE) break;
+
+            if (hdr->nlmsg_type == RTM_NEWLINK)
+            {
+                struct ifinfomsg *info = NLMSG_DATA(hdr);
+
+                if (skip_loopback && (info->ifi_flags & IFF_LOOPBACK)) continue;
+                if (table) table->indexes[count] = info->ifi_index;
+                count++;
+            }
+        }
+    }
+    return count;
+}
+
+DWORD get_interface_indices( BOOL skip_loopback, InterfaceIndexTable **table )
+{
+    int fd, pid, seq;
+    struct netlink_reply *reply = NULL;
+    DWORD count = 0;
+
+    if (table) *table = NULL;
+    fd = open_netlink( &pid );
+    if (fd < 0) return 0;
+
+    if (send_netlink_req( fd, pid, RTM_GETLINK, &seq ) < 0)
+        goto end;
+
+    if (recv_netlink_reply( fd, pid, seq, &reply ) < 0)
+        goto end;
+
+    count = get_indices_from_reply( reply, pid, seq, skip_loopback, NULL );
+
+    if (table)
+    {
+        InterfaceIndexTable *ret = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET(InterfaceIndexTable, indexes[count]) );
+        if (!ret)
+        {
+            count = 0;
+            goto end;
+        }
+
+        ret->numIndexes = count;
+        get_indices_from_reply( reply, pid, seq, skip_loopback, ret );
+        *table = ret;
+    }
+
+end:
+    free_netlink_reply( reply );
+    close( fd );
+    return count;
+}
+
+#else
+DWORD get_interface_indices( BOOL skip_loopback, InterfaceIndexTable **table )
+{
+    if (table) *table = NULL;
+    return 0;
+}
+#endif
+
 static DWORD getInterfaceBCastAddrByName(const char *name)
 {
   DWORD ret = INADDR_ANY;
diff --git a/include/config.h.in b/include/config.h.in
index 62bee90..1f0bfea 100644
--- a/include/config.h.in
+++ b/include/config.h.in
@@ -258,6 +258,9 @@
 /* Define to 1 if you have the <ifaddrs.h> header file. */
 #undef HAVE_IFADDRS_H
 
+/* Define to 1 if you have the `if_nameindex' function. */
+#undef HAVE_IF_NAMEINDEX
+
 /* Define to 1 if you have the <inet/mib2.h> header file. */
 #undef HAVE_INET_MIB2_H
 
@@ -432,6 +435,9 @@
 /* Define to 1 if you have the <linux/param.h> header file. */
 #undef HAVE_LINUX_PARAM_H
 
+/* Define to 1 if you have the <linux/rtnetlink.h> header file. */
+#undef HAVE_LINUX_RTNETLINK_H
+
 /* Define to 1 if you have the <linux/serial.h> header file. */
 #undef HAVE_LINUX_SERIAL_H
 




More information about the wine-cvs mailing list