From e3c0e30db10622ddd7093db0f499f6d453fa7e85 Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Thu, 11 Mar 2010 18:36:46 -0800 Subject: [PATCH] iphlpapi: Implement GetAdaptersAddresses for IPv6 addresses. --- configure | 14 +++++++ configure.ac | 2 + dlls/iphlpapi/ifenum.c | 75 +++++++++++++++++++++++++++++++++++ dlls/iphlpapi/ifenum.h | 7 ++++ dlls/iphlpapi/iphlpapi_main.c | 50 ++++++++++++++++++++--- include/config.h.in | 3 ++ 6 files changed, 145 insertions(+), 6 deletions(-) diff --git a/configure b/configure index 110c350c7c9..92471609d75 100755 --- 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 +" +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 diff --git a/configure.ac b/configure.ac index b077e2d2f15..3d2711e68c3 100644 --- a/configure.ac +++ b/configure.ac @@ -556,6 +556,8 @@ AC_CHECK_HEADERS([resolv.h],,, # include #endif]) +AC_CHECK_HEADERS([ifaddrs.h],,,[#include ]) + AC_CHECK_HEADERS(ucontext.h,,,[#include ]) AC_CHECK_HEADERS([sys/thr.h],,, diff --git a/dlls/iphlpapi/ifenum.c b/dlls/iphlpapi/ifenum.c index 02c6a9d6363..8653454c1a3 100644 --- a/dlls/iphlpapi/ifenum.c +++ b/dlls/iphlpapi/ifenum.c @@ -87,7 +87,12 @@ #include #endif +#ifdef HAVE_IFADDRS_H +#include +#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) { diff --git a/dlls/iphlpapi/ifenum.h b/dlls/iphlpapi/ifenum.h index c348191912c..79e484b30d0 100644 --- a/dlls/iphlpapi/ifenum.h +++ b/dlls/iphlpapi/ifenum.h @@ -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. */ diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c index 6a0a8d92160..86008493611 100644 --- a/dlls/iphlpapi/iphlpapi_main.c +++ b/dlls/iphlpapi/iphlpapi_main.c @@ -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; } diff --git a/include/config.h.in b/include/config.h.in index fb8a79b35f8..0cdfb3fa669 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -255,6 +255,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_IEEEFP_H +/* Define to 1 if you have the header file. */ +#undef HAVE_IFADDRS_H + /* Define to 1 if you have the header file. */ #undef HAVE_INET_MIB2_H