iphlpapi: Implement GetAdaptersAddresses for IPv6 addresses.
authorJuan Lang <juan.lang@gmail.com>
Fri, 12 Mar 2010 02:36:46 +0000 (18:36 -0800)
committerAlexandre Julliard <julliard@winehq.org>
Mon, 15 Mar 2010 13:18:05 +0000 (14:18 +0100)
configure
configure.ac
dlls/iphlpapi/ifenum.c
dlls/iphlpapi/ifenum.h
dlls/iphlpapi/iphlpapi_main.c
include/config.h.in

index 110c350c7c976ca289125c79eb340a4f24083d8a..92471609d7579f39cd01ca537d0349c076f74e7d 100755 (executable)
--- a/configure
+++ b/configure
@@ -6064,6 +6064,20 @@ fi
 done
 
 
+for ac_header in ifaddrs.h
+do :
+  ac_fn_c_check_header_compile "$LINENO" "ifaddrs.h" "ac_cv_header_ifaddrs_h" "#include <sys/types.h>
+"
+if test "x$ac_cv_header_ifaddrs_h" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_IFADDRS_H 1
+_ACEOF
+
+fi
+
+done
+
+
 for ac_header in ucontext.h
 do :
   ac_fn_c_check_header_compile "$LINENO" "ucontext.h" "ac_cv_header_ucontext_h" "#include <signal.h>
index b077e2d2f157a83b1aa5dc0ea6ef89b5c47a6c95..3d2711e68c3879ac8eea206e34aef44befb178eb 100644 (file)
@@ -556,6 +556,8 @@ AC_CHECK_HEADERS([resolv.h],,,
      # include <arpa/nameser.h>
      #endif])
 
+AC_CHECK_HEADERS([ifaddrs.h],,,[#include <sys/types.h>])
+
 AC_CHECK_HEADERS(ucontext.h,,,[#include <signal.h>])
 
 AC_CHECK_HEADERS([sys/thr.h],,,
index 02c6a9d6363b4a98fdbf14894aabd95998853d76..8653454c1a3d2aa396a85defc93fe30f08e83738 100644 (file)
 #include <net/if_types.h>
 #endif
 
+#ifdef HAVE_IFADDRS_H
+#include <ifaddrs.h>
+#endif
+
 #include "ifenum.h"
+#include "ws2ipdef.h"
 
 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
 #define ifreq_len(ifr) \
@@ -788,6 +793,76 @@ DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
   return ret;
 }
 
+#ifdef HAVE_IFADDRS_H
+ULONG v6addressesFromIndex(DWORD index, SOCKET_ADDRESS **addrs, ULONG *num_addrs)
+{
+  struct ifaddrs *ifa;
+  ULONG ret;
+
+  if (!getifaddrs(&ifa))
+  {
+    struct ifaddrs *p;
+    ULONG n;
+    char name[IFNAMSIZ];
+
+    getInterfaceNameByIndex(index, name);
+    for (p = ifa, n = 0; p; p = p->ifa_next)
+      if (p->ifa_addr->sa_family == AF_INET6 && !strcmp(name, p->ifa_name))
+        n++;
+    if (n)
+    {
+      *addrs = HeapAlloc(GetProcessHeap(), 0, n * (sizeof(SOCKET_ADDRESS) +
+                         sizeof(struct WS_sockaddr_in6)));
+      if (*addrs)
+      {
+        struct WS_sockaddr_in6 *next_addr = (struct WS_sockaddr_in6 *)(
+            (BYTE *)*addrs + n * sizeof(SOCKET_ADDRESS));
+
+        for (p = ifa, n = 0; p; p = p->ifa_next)
+        {
+          if (p->ifa_addr->sa_family == AF_INET6 && !strcmp(name, p->ifa_name))
+          {
+            struct sockaddr_in6 *addr = (struct sockaddr_in6 *)p->ifa_addr;
+
+            next_addr->sin6_family = WS_AF_INET6;
+            next_addr->sin6_port = addr->sin6_port;
+            next_addr->sin6_flowinfo = addr->sin6_flowinfo;
+            memcpy(&next_addr->sin6_addr, &addr->sin6_addr,
+             sizeof(next_addr->sin6_addr));
+            next_addr->sin6_scope_id = addr->sin6_scope_id;
+            (*addrs)[n].lpSockaddr = (LPSOCKADDR)next_addr;
+            (*addrs)[n].iSockaddrLength = sizeof(struct WS_sockaddr_in6);
+            next_addr++;
+            n++;
+          }
+        }
+        *num_addrs = n;
+        ret = ERROR_SUCCESS;
+      }
+      else
+        ret = ERROR_OUTOFMEMORY;
+    }
+    else
+    {
+      *addrs = NULL;
+      *num_addrs = 0;
+      ret = ERROR_SUCCESS;
+    }
+    freeifaddrs(ifa);
+  }
+  else
+    ret = ERROR_NO_DATA;
+  return ret;
+}
+#else
+ULONG v6addressesFromIndex(DWORD index, SOCKET_ADDRESS **addrs, ULONG *num_addrs)
+{
+  *addrs = NULL;
+  *num_addrs = 0;
+  return ERROR_SUCCESS;
+}
+#endif
+
 char *toIPAddressString(unsigned int addr, char string[16])
 {
   if (string) {
index c348191912c1552651bf7a76d2f64972407d1a59..79e484b30d0210290119bc9cada662e8020bedab 100644 (file)
@@ -38,6 +38,8 @@
 #include "windef.h"
 #include "winbase.h"
 #include "iprtrmib.h"
+#define USE_WS_PREFIX
+#include "winsock2.h"
 
 #define MAX_INTERFACE_PHYSADDR    8
 #define MAX_INTERFACE_DESCRIPTION 256
@@ -105,6 +107,11 @@ DWORD getNumIPAddresses(void);
  */
 DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags);
 
+/* Returns the IPv6 addresses for a particular interface index.
+ * Returns NO_ERROR on success, something else on failure.
+ */
+ULONG v6addressesFromIndex(DWORD index, SOCKET_ADDRESS **addrs, ULONG *num_addrs);
+
 /* Converts the network-order bytes in addr to a printable string.  Returns
  * string.
  */
index 6a0a8d92160b090d9f74d9c90edf9d44ee2f81ca..86008493611ada77798864414fce1edc87666d84 100644 (file)
@@ -49,6 +49,7 @@
 #include "winreg.h"
 #define USE_WS_PREFIX
 #include "winsock2.h"
+#include "ws2ipdef.h"
 #include "iphlpapi.h"
 #include "ifenum.h"
 #include "ipstats.h"
@@ -634,22 +635,23 @@ static ULONG v4addressesFromIndex(DWORD index, DWORD **addrs, ULONG *num_addrs)
 
 static ULONG adapterAddressesFromIndex(ULONG family, DWORD index, IP_ADAPTER_ADDRESSES *aa, ULONG *size)
 {
-    ULONG ret, i, num_v4addrs = 0, total_size;
+    ULONG ret, i, num_v4addrs = 0, num_v6addrs = 0, total_size;
     DWORD *v4addrs = NULL;
+    SOCKET_ADDRESS *v6addrs = NULL;
 
     if (family == AF_INET)
         ret = v4addressesFromIndex(index, &v4addrs, &num_v4addrs);
+    else if (family == AF_INET6)
+        ret = v6addressesFromIndex(index, &v6addrs, &num_v6addrs);
     else if (family == AF_UNSPEC)
     {
-        WARN("no support for IPv6 addresses\n");
         ret = v4addressesFromIndex(index, &v4addrs, &num_v4addrs);
+        if (!ret)
+            ret = v6addressesFromIndex(index, &v6addrs, &num_v6addrs);
     }
     else
     {
-        if (family == AF_INET6)
-            FIXME("no support for IPv6 addresses\n");
-        else
-            FIXME("address family %u unsupported\n", family);
+        FIXME("address family %u unsupported\n", family);
         ret = ERROR_NO_DATA;
     }
     if (ret) return ret;
@@ -659,6 +661,10 @@ static ULONG adapterAddressesFromIndex(ULONG family, DWORD index, IP_ADAPTER_ADD
     total_size += IF_NAMESIZE * sizeof(WCHAR);
     total_size += sizeof(IP_ADAPTER_UNICAST_ADDRESS) * num_v4addrs;
     total_size += sizeof(struct sockaddr_in) * num_v4addrs;
+    total_size += sizeof(IP_ADAPTER_UNICAST_ADDRESS) * num_v6addrs;
+    total_size += sizeof(SOCKET_ADDRESS) * num_v6addrs;
+    for (i = 0; i < num_v6addrs; i++)
+        total_size += v6addrs[i].iSockaddrLength;
 
     if (aa && *size >= total_size)
     {
@@ -706,6 +712,37 @@ static ULONG adapterAddressesFromIndex(ULONG family, DWORD index, IP_ADAPTER_ADD
                 }
             }
         }
+        if (num_v6addrs)
+        {
+            IP_ADAPTER_UNICAST_ADDRESS *ua;
+            struct WS_sockaddr_in6 *sa;
+
+            if (aa->FirstUnicastAddress)
+            {
+                for (ua = aa->FirstUnicastAddress; ua->Next; ua = ua->Next)
+                    ;
+                ua->Next = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
+            }
+            else
+                ua = aa->FirstUnicastAddress = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
+            for (i = 0; i < num_v6addrs; i++)
+            {
+                memset(ua, 0, sizeof(IP_ADAPTER_UNICAST_ADDRESS));
+                ua->u.s.Length              = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
+                ua->Address.iSockaddrLength = v6addrs[i].iSockaddrLength;
+                ua->Address.lpSockaddr      = (SOCKADDR *)((char *)ua + ua->u.s.Length);
+
+                sa = (struct WS_sockaddr_in6 *)ua->Address.lpSockaddr;
+                memcpy(sa, v6addrs[i].lpSockaddr, sizeof(*sa));
+
+                ptr += ua->u.s.Length + ua->Address.iSockaddrLength;
+                if (i < num_v6addrs - 1)
+                {
+                    ua->Next = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
+                    ua = ua->Next;
+                }
+            }
+        }
 
         buflen = MAX_INTERFACE_PHYSADDR;
         getInterfacePhysicalByIndex(index, &buflen, aa->PhysicalAddress, &type);
@@ -720,6 +757,7 @@ static ULONG adapterAddressesFromIndex(ULONG family, DWORD index, IP_ADAPTER_ADD
         else aa->OperStatus = IfOperStatusUnknown;
     }
     *size = total_size;
+    HeapFree(GetProcessHeap(), 0, v6addrs);
     HeapFree(GetProcessHeap(), 0, v4addrs);
     return ERROR_SUCCESS;
 }
index fb8a79b35f83d3db6f07fd7d3611b84d08bc8699..0cdfb3fa669e4f7b02853d74b22567c8a85a6e51 100644 (file)
 /* Define to 1 if you have the <ieeefp.h> header file. */
 #undef HAVE_IEEEFP_H
 
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+#undef HAVE_IFADDRS_H
+
 /* Define to 1 if you have the <inet/mib2.h> header file. */
 #undef HAVE_INET_MIB2_H