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