iphlpapi: Add support for GAA_FLAG_INCLUDE_PREFIX in GetAdaptersAddresses.

Hans Leidekker hans at codeweavers.com
Tue Oct 8 06:30:00 CDT 2013


---
 dlls/iphlpapi/ifenum.c        |  27 +++++++-
 dlls/iphlpapi/ifenum.h        |   3 +-
 dlls/iphlpapi/iphlpapi_main.c | 157 +++++++++++++++++++++++++++++++++++-------
 3 files changed, 160 insertions(+), 27 deletions(-)

diff --git a/dlls/iphlpapi/ifenum.c b/dlls/iphlpapi/ifenum.c
index 2dec193..a12450e 100644
--- a/dlls/iphlpapi/ifenum.c
+++ b/dlls/iphlpapi/ifenum.c
@@ -886,7 +886,7 @@ DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
   return ret;
 }
 
-ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs)
+ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs, SOCKET_ADDRESS **masks)
 {
   struct ifaddrs *ifa;
   ULONG ret;
@@ -906,10 +906,14 @@ ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_ad
     {
       *addrs = HeapAlloc(GetProcessHeap(), 0, n * (sizeof(SOCKET_ADDRESS) +
                          sizeof(struct WS_sockaddr_in6)));
-      if (*addrs)
+      *masks = HeapAlloc(GetProcessHeap(), 0, n * (sizeof(SOCKET_ADDRESS) +
+                         sizeof(struct WS_sockaddr_in6)));
+      if (*addrs && *masks)
       {
         struct WS_sockaddr_in6 *next_addr = (struct WS_sockaddr_in6 *)(
             (BYTE *)*addrs + n * sizeof(SOCKET_ADDRESS));
+        struct WS_sockaddr_in6 *mask_addr = (struct WS_sockaddr_in6 *)(
+            (BYTE *)*masks + n * sizeof(SOCKET_ADDRESS));
 
         for (p = ifa, n = 0; p; p = p->ifa_next)
         {
@@ -917,6 +921,7 @@ ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_ad
               !strcmp(name, p->ifa_name))
           {
             struct sockaddr_in6 *addr = (struct sockaddr_in6 *)p->ifa_addr;
+            struct sockaddr_in6 *mask = (struct sockaddr_in6 *)p->ifa_netmask;
 
             next_addr->sin6_family = WS_AF_INET6;
             next_addr->sin6_port = addr->sin6_port;
@@ -927,6 +932,16 @@ ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_ad
             (*addrs)[n].lpSockaddr = (LPSOCKADDR)next_addr;
             (*addrs)[n].iSockaddrLength = sizeof(struct WS_sockaddr_in6);
             next_addr++;
+
+            mask_addr->sin6_family = WS_AF_INET6;
+            mask_addr->sin6_port = mask->sin6_port;
+            mask_addr->sin6_flowinfo = mask->sin6_flowinfo;
+            memcpy(&mask_addr->sin6_addr, &mask->sin6_addr,
+             sizeof(mask_addr->sin6_addr));
+            mask_addr->sin6_scope_id = mask->sin6_scope_id;
+            (*masks)[n].lpSockaddr = (LPSOCKADDR)mask_addr;
+            (*masks)[n].iSockaddrLength = sizeof(struct WS_sockaddr_in6);
+            mask_addr++;
             n++;
           }
         }
@@ -934,12 +949,17 @@ ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_ad
         ret = ERROR_SUCCESS;
       }
       else
+      {
+        HeapFree(GetProcessHeap(), 0, *addrs);
+        HeapFree(GetProcessHeap(), 0, *masks);
         ret = ERROR_OUTOFMEMORY;
+      }
     }
     else
     {
       *addrs = NULL;
       *num_addrs = 0;
+      *masks = NULL;
       ret = ERROR_SUCCESS;
     }
     freeifaddrs(ifa);
@@ -1073,10 +1093,11 @@ DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
   return ret;
 }
 
-ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs)
+ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs, SOCKET_ADDRESS **masks)
 {
   *addrs = NULL;
   *num_addrs = 0;
+  *masks = NULL;
   return ERROR_SUCCESS;
 }
 
diff --git a/dlls/iphlpapi/ifenum.h b/dlls/iphlpapi/ifenum.h
index 49b6e7b..c6bf957 100644
--- a/dlls/iphlpapi/ifenum.h
+++ b/dlls/iphlpapi/ifenum.h
@@ -106,7 +106,8 @@ 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(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs) DECLSPEC_HIDDEN;
+ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs,
+ SOCKET_ADDRESS **masks) DECLSPEC_HIDDEN;
 
 /* 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 141dbd8..bbb177c 100644
--- a/dlls/iphlpapi/iphlpapi_main.c
+++ b/dlls/iphlpapi/iphlpapi_main.c
@@ -623,7 +623,7 @@ static NET_IF_CONNECTION_TYPE connectionTypeFromMibType(DWORD mib_type)
     }
 }
 
-static ULONG v4addressesFromIndex(IF_INDEX index, DWORD **addrs, ULONG *num_addrs)
+static ULONG v4addressesFromIndex(IF_INDEX index, DWORD **addrs, ULONG *num_addrs, DWORD **masks)
 {
     ULONG ret, i, j;
     MIB_IPADDRTABLE *at;
@@ -639,9 +639,20 @@ static ULONG v4addressesFromIndex(IF_INDEX index, DWORD **addrs, ULONG *num_addr
         HeapFree(GetProcessHeap(), 0, at);
         return ERROR_OUTOFMEMORY;
     }
+    if (!(*masks = HeapAlloc(GetProcessHeap(), 0, *num_addrs * sizeof(DWORD))))
+    {
+        HeapFree(GetProcessHeap(), 0, *addrs);
+        HeapFree(GetProcessHeap(), 0, at);
+        return ERROR_OUTOFMEMORY;
+    }
     for (i = 0, j = 0; i < at->dwNumEntries; i++)
     {
-        if (at->table[i].dwIndex == index) (*addrs)[j++] = at->table[i].dwAddr;
+        if (at->table[i].dwIndex == index)
+        {
+            (*addrs)[j] = at->table[i].dwAddr;
+            (*masks)[j] = at->table[i].dwMask;
+            j++;
+        }
     }
     HeapFree(GetProcessHeap(), 0, at);
     return ERROR_SUCCESS;
@@ -724,41 +735,35 @@ static PMIB_IPFORWARDROW findIPv4Gateway(DWORD index,
 static ULONG adapterAddressesFromIndex(ULONG family, ULONG flags, IF_INDEX index,
                                        IP_ADAPTER_ADDRESSES *aa, ULONG *size)
 {
-    ULONG ret = ERROR_SUCCESS, i, num_v4addrs = 0, num_v4_gateways = 0, num_v6addrs = 0, total_size;
-    DWORD *v4addrs = NULL;
-    SOCKET_ADDRESS *v6addrs = NULL;
+    ULONG ret = ERROR_SUCCESS, i, j, num_v4addrs = 0, num_v4_gateways = 0, num_v6addrs = 0, total_size;
+    DWORD *v4addrs = NULL, *v4masks = NULL;
+    SOCKET_ADDRESS *v6addrs = NULL, *v6masks = NULL;
     PMIB_IPFORWARDTABLE routeTable = NULL;
 
     if (family == WS_AF_INET)
     {
-        if (!(flags & GAA_FLAG_SKIP_UNICAST))
-            ret = v4addressesFromIndex(index, &v4addrs, &num_v4addrs);
+        ret = v4addressesFromIndex(index, &v4addrs, &num_v4addrs, &v4masks);
+
         if (!ret && flags & GAA_FLAG_INCLUDE_ALL_GATEWAYS)
         {
-            ret = AllocateAndGetIpForwardTableFromStack(&routeTable, FALSE,
-                                                        GetProcessHeap(), 0);
-            if (!ret)
-                num_v4_gateways = count_v4_gateways(index, routeTable);
+            ret = AllocateAndGetIpForwardTableFromStack(&routeTable, FALSE, GetProcessHeap(), 0);
+            if (!ret) num_v4_gateways = count_v4_gateways(index, routeTable);
         }
     }
     else if (family == WS_AF_INET6)
     {
-        if (!(flags & GAA_FLAG_SKIP_UNICAST))
-            ret = v6addressesFromIndex(index, &v6addrs, &num_v6addrs);
+        ret = v6addressesFromIndex(index, &v6addrs, &num_v6addrs, &v6masks);
     }
     else if (family == WS_AF_UNSPEC)
     {
-        if (!(flags & GAA_FLAG_SKIP_UNICAST))
-            ret = v4addressesFromIndex(index, &v4addrs, &num_v4addrs);
+        ret = v4addressesFromIndex(index, &v4addrs, &num_v4addrs, &v4masks);
+
         if (!ret && flags & GAA_FLAG_INCLUDE_ALL_GATEWAYS)
         {
-            ret = AllocateAndGetIpForwardTableFromStack(&routeTable, FALSE,
-                                                        GetProcessHeap(), 0);
-            if (!ret)
-                num_v4_gateways = count_v4_gateways(index, routeTable);
+            ret = AllocateAndGetIpForwardTableFromStack(&routeTable, FALSE, GetProcessHeap(), 0);
+            if (!ret) num_v4_gateways = count_v4_gateways(index, routeTable);
         }
-        if (!ret && !(flags & GAA_FLAG_SKIP_UNICAST))
-            ret = v6addressesFromIndex(index, &v6addrs, &num_v6addrs);
+        if (!ret) ret = v6addressesFromIndex(index, &v6addrs, &num_v6addrs, &v6masks);
     }
     else
     {
@@ -768,6 +773,9 @@ static ULONG adapterAddressesFromIndex(ULONG family, ULONG flags, IF_INDEX index
     if (ret)
     {
         HeapFree(GetProcessHeap(), 0, v4addrs);
+        HeapFree(GetProcessHeap(), 0, v4masks);
+        HeapFree(GetProcessHeap(), 0, v6addrs);
+        HeapFree(GetProcessHeap(), 0, v6masks);
         HeapFree(GetProcessHeap(), 0, routeTable);
         return ret;
     }
@@ -777,6 +785,14 @@ static ULONG adapterAddressesFromIndex(ULONG family, ULONG flags, IF_INDEX index
     total_size += IF_NAMESIZE * sizeof(WCHAR);
     if (!(flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
         total_size += IF_NAMESIZE * sizeof(WCHAR);
+    if (flags & GAA_FLAG_INCLUDE_PREFIX)
+    {
+        total_size += sizeof(IP_ADAPTER_PREFIX) * num_v4addrs;
+        total_size += sizeof(IP_ADAPTER_PREFIX) * num_v6addrs;
+        total_size += sizeof(struct sockaddr_in) * num_v4addrs;
+        for (i = 0; i < num_v6addrs; i++)
+            total_size += v6masks[i].iSockaddrLength;
+    }
     total_size += sizeof(IP_ADAPTER_UNICAST_ADDRESS) * num_v4addrs;
     total_size += sizeof(struct sockaddr_in) * num_v4addrs;
     total_size += (sizeof(IP_ADAPTER_GATEWAY_ADDRESS) + sizeof(SOCKADDR_IN)) * num_v4_gateways;
@@ -841,7 +857,7 @@ static ULONG adapterAddressesFromIndex(ULONG family, ULONG flags, IF_INDEX index
                 ptr += sizeof(SOCKADDR_IN);
             }
         }
-        if (num_v4addrs)
+        if (num_v4addrs && !(flags & GAA_FLAG_SKIP_UNICAST))
         {
             IP_ADAPTER_UNICAST_ADDRESS *ua;
             struct WS_sockaddr_in *sa;
@@ -871,7 +887,7 @@ static ULONG adapterAddressesFromIndex(ULONG family, ULONG flags, IF_INDEX index
                 }
             }
         }
-        if (num_v6addrs)
+        if (num_v6addrs && !(flags & GAA_FLAG_SKIP_UNICAST))
         {
             IP_ADAPTER_UNICAST_ADDRESS *ua;
             struct WS_sockaddr_in6 *sa;
@@ -908,6 +924,99 @@ static ULONG adapterAddressesFromIndex(ULONG family, ULONG flags, IF_INDEX index
                 }
             }
         }
+        if (num_v4addrs && (flags & GAA_FLAG_INCLUDE_PREFIX))
+        {
+            IP_ADAPTER_PREFIX *prefix;
+
+            prefix = aa->FirstPrefix = (IP_ADAPTER_PREFIX *)ptr;
+            for (i = 0; i < num_v4addrs; i++)
+            {
+                char addr_buf[16];
+                struct WS_sockaddr_in *sa;
+
+                prefix->u.s.Length = sizeof(*prefix);
+                prefix->u.s.Flags  = 0;
+                prefix->Next       = NULL;
+                prefix->Address.iSockaddrLength = sizeof(struct sockaddr_in);
+                prefix->Address.lpSockaddr      = (SOCKADDR *)((char *)prefix + prefix->u.s.Length);
+
+                sa = (struct WS_sockaddr_in *)prefix->Address.lpSockaddr;
+                sa->sin_family           = WS_AF_INET;
+                sa->sin_addr.S_un.S_addr = v4addrs[i] & v4masks[i];
+                sa->sin_port             = 0;
+
+                prefix->PrefixLength = 0;
+                for (j = 0; j < sizeof(*v4masks) * 8; j++)
+                {
+                    if (v4masks[i] & 1 << j) prefix->PrefixLength++;
+                    else break;
+                }
+                TRACE("IPv4 network: %s/%u\n",
+                      debugstr_ipv4((const in_addr_t *)&sa->sin_addr.S_un.S_addr, addr_buf),
+                      prefix->PrefixLength);
+
+                ptr += prefix->u.s.Length + prefix->Address.iSockaddrLength;
+                if (i < num_v4addrs - 1)
+                {
+                    prefix->Next = (IP_ADAPTER_PREFIX *)ptr;
+                    prefix = prefix->Next;
+                }
+            }
+        }
+        if (num_v6addrs && (flags & GAA_FLAG_INCLUDE_PREFIX))
+        {
+            IP_ADAPTER_PREFIX *prefix;
+
+            if (aa->FirstPrefix)
+            {
+                for (prefix = aa->FirstPrefix; prefix->Next; prefix = prefix->Next)
+                    ;
+                prefix->Next = (IP_ADAPTER_PREFIX *)ptr;
+                prefix = (IP_ADAPTER_PREFIX *)ptr;
+            }
+            else
+                prefix = aa->FirstPrefix = (IP_ADAPTER_PREFIX *)ptr;
+            for (i = 0; i < num_v6addrs; i++)
+            {
+                char addr_buf[46];
+                struct WS_sockaddr_in6 *sa;
+                const IN6_ADDR *addr, *mask;
+                BOOL done = FALSE;
+
+                prefix->u.s.Length = sizeof(*prefix);
+                prefix->u.s.Flags  = 0;
+                prefix->Next       = NULL;
+                prefix->Address.iSockaddrLength = sizeof(struct sockaddr_in6);
+                prefix->Address.lpSockaddr      = (SOCKADDR *)((char *)prefix + prefix->u.s.Length);
+
+                sa = (struct WS_sockaddr_in6 *)prefix->Address.lpSockaddr;
+                sa->sin6_family   = WS_AF_INET6;
+                sa->sin6_port     = 0;
+                sa->sin6_flowinfo = 0;
+                addr = &((struct WS_sockaddr_in6 *)v6addrs[i].lpSockaddr)->sin6_addr;
+                mask = &((struct WS_sockaddr_in6 *)v6masks[i].lpSockaddr)->sin6_addr;
+                for (j = 0; j < 8; j++) sa->sin6_addr.u.Word[j] = addr->u.Word[j] & mask->u.Word[j]; 
+                sa->sin6_scope_id = 0;
+
+                prefix->PrefixLength = 0;
+                for (i = 0; i < 8 && !done; i++)
+                {
+                    for (j = 0; j < sizeof(WORD) * 8 && !done; j++)
+                    {
+                        if (mask->u.Word[i] & 1 << j) prefix->PrefixLength++;
+                        else done = TRUE;
+                    }
+                }
+                TRACE("IPv6 network: %s/%u\n", debugstr_ipv6(sa, addr_buf), prefix->PrefixLength);
+
+                ptr += prefix->u.s.Length + prefix->Address.iSockaddrLength;
+                if (i < num_v6addrs - 1)
+                {
+                    prefix->Next = (IP_ADAPTER_PREFIX *)ptr;
+                    prefix = prefix->Next;
+                }
+            }
+        }
 
         buflen = MAX_INTERFACE_PHYSADDR;
         getInterfacePhysicalByIndex(index, &buflen, aa->PhysicalAddress, &type);
@@ -925,7 +1034,9 @@ static ULONG adapterAddressesFromIndex(ULONG family, ULONG flags, IF_INDEX index
     *size = total_size;
     HeapFree(GetProcessHeap(), 0, routeTable);
     HeapFree(GetProcessHeap(), 0, v6addrs);
+    HeapFree(GetProcessHeap(), 0, v6masks);
     HeapFree(GetProcessHeap(), 0, v4addrs);
+    HeapFree(GetProcessHeap(), 0, v4masks);
     return ERROR_SUCCESS;
 }
 
-- 
1.8.1.5






More information about the wine-patches mailing list