[PATCH] ws2_32: Reimplement SIO_GET_INTERFACE_LIST on top of GetIpAddrTable().

Paul Gofman pgofman at codeweavers.com
Mon Jan 18 05:33:00 CST 2021


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
 dlls/ws2_32/socket.c     | 208 ++++++++++++++++++++-------------------
 dlls/ws2_32/tests/sock.c |  31 ++++++
 2 files changed, 136 insertions(+), 103 deletions(-)

diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 33cbd3d9537..31ea9b339ed 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -4792,6 +4792,110 @@ static DWORD server_ioctl_sock( SOCKET s, DWORD code, LPVOID in_buff, DWORD in_s
     return NtStatusToWSAError( status );
 }
 
+static DWORD get_interface_list(SOCKET s, void *out_buff, DWORD out_size, DWORD *ret_size, DWORD *total_bytes)
+{
+    DWORD size, interface_count = 0, ret;
+    INTERFACE_INFO *info = out_buff;
+    PMIB_IPADDRTABLE table = NULL;
+    DWORD status = 0;
+    int fd;
+
+    if (!out_buff || !ret_size)
+        return WSAEFAULT;
+
+    if ((fd = get_sock_fd(s, 0, NULL)) == -1)
+        return SOCKET_ERROR;
+
+    if ((ret = GetIpAddrTable(NULL, &size, TRUE)) != ERROR_INSUFFICIENT_BUFFER)
+    {
+        if (ret != ERROR_NO_DATA)
+        {
+            ERR("Unable to get ip address table.\n");
+            status = WSAEINVAL;
+        }
+        goto done;
+    }
+    if (!(table = heap_alloc(size)))
+    {
+        ERR("No memory.\n");
+        status = WSAEINVAL;
+        goto done;
+    }
+    if (GetIpAddrTable(table, &size, TRUE) != NO_ERROR)
+    {
+        ERR("Unable to get interface table./\n");
+        status = WSAEINVAL;
+        goto done;
+    }
+    if (table->dwNumEntries * sizeof(INTERFACE_INFO) > out_size)
+    {
+        WARN("Buffer too small, dwNumEntries %u, out_size = %u.\n", table->dwNumEntries, out_size);
+        *ret_size = 0;
+        status = WSAEFAULT;
+        goto done;
+    }
+
+    for (; interface_count < table->dwNumEntries; ++interface_count, ++info)
+    {
+        unsigned int addr, mask;
+        struct ifreq if_info;
+
+        memset(info, 0, sizeof(*info));
+
+        if_info.ifr_ifindex = table->table[interface_count].dwIndex;
+        if (ioctl(fd, SIOCGIFNAME, &if_info) < 0)
+        {
+            ERR("Error obtaining interface name for ifindex %d.\n", if_info.ifr_ifindex);
+            status = WSAEINVAL;
+            break;
+        }
+
+        if (ioctl(fd, SIOCGIFFLAGS, &if_info) < 0)
+        {
+            ERR("Error obtaining status flags for socket!\n");
+            status = WSAEINVAL;
+            break;
+        }
+
+        if (if_info.ifr_flags & IFF_BROADCAST)
+            info->iiFlags |= WS_IFF_BROADCAST;
+#ifdef IFF_POINTOPOINT
+        if (if_info.ifr_flags & IFF_POINTOPOINT)
+            info->iiFlags |= WS_IFF_POINTTOPOINT;
+#endif
+        if (if_info.ifr_flags & IFF_LOOPBACK)
+            info->iiFlags |= WS_IFF_LOOPBACK;
+        if (if_info.ifr_flags & IFF_UP)
+            info->iiFlags |= WS_IFF_UP;
+        if (if_info.ifr_flags & IFF_MULTICAST)
+            info->iiFlags |= WS_IFF_MULTICAST;
+
+        addr = table->table[interface_count].dwAddr;
+        mask = table->table[interface_count].dwMask;
+
+        info->iiAddress.AddressIn.sin_family = WS_AF_INET;
+        info->iiAddress.AddressIn.sin_port = 0;
+        info->iiAddress.AddressIn.sin_addr.WS_s_addr = addr;
+
+        info->iiNetmask.AddressIn.sin_family = WS_AF_INET;
+        info->iiNetmask.AddressIn.sin_port = 0;
+        info->iiNetmask.AddressIn.sin_addr.WS_s_addr = mask;
+
+        if (if_info.ifr_flags & IFF_BROADCAST)
+        {
+            info->iiBroadcastAddress.AddressIn.sin_family = WS_AF_INET;
+            info->iiBroadcastAddress.AddressIn.sin_port = 0;
+            info->iiBroadcastAddress.AddressIn.sin_addr.WS_s_addr = addr | ~mask;
+        }
+    }
+
+done:
+    heap_free(table);
+    *total_bytes = sizeof(INTERFACE_INFO) * interface_count;
+    release_sock_fd(s, fd);
+    return status;
+}
+
 /**********************************************************************
  *              WSAIoctl                (WS2_32.50)
  *
@@ -4898,111 +5002,9 @@ INT WINAPI WSAIoctl(SOCKET s, DWORD code, LPVOID in_buff, DWORD in_size, LPVOID
 
    case WS_SIO_GET_INTERFACE_LIST:
        {
-           INTERFACE_INFO* intArray = out_buff;
-           DWORD size, numInt = 0, apiReturn;
-
            TRACE("-> SIO_GET_INTERFACE_LIST request\n");
 
-           if (!out_buff || !ret_size)
-           {
-               SetLastError(WSAEFAULT);
-               return SOCKET_ERROR;
-           }
-
-           fd = get_sock_fd( s, 0, NULL );
-           if (fd == -1) return SOCKET_ERROR;
-
-           apiReturn = GetAdaptersInfo(NULL, &size);
-           if (apiReturn == ERROR_BUFFER_OVERFLOW)
-           {
-               PIP_ADAPTER_INFO table = HeapAlloc(GetProcessHeap(),0,size);
-
-               if (table)
-               {
-                  if (GetAdaptersInfo(table, &size) == NO_ERROR)
-                  {
-                     PIP_ADAPTER_INFO ptr;
-
-                     for (ptr = table, numInt = 0; ptr; ptr = ptr->Next)
-                     {
-                        unsigned int addr, mask, bcast;
-                        struct ifreq ifInfo;
-
-                        /* Skip interfaces without an IPv4 address. */
-                        if (ptr->IpAddressList.IpAddress.String[0] == '\0')
-                            continue;
-
-                        if ((numInt + 1) * sizeof(INTERFACE_INFO) > out_size)
-                        {
-                            WARN("Buffer too small = %u, out_size = %u\n", numInt + 1, out_size);
-                            status = WSAEFAULT;
-                            if (ret_size) *ret_size = 0;
-                            break;
-                        }
-
-                        /* Socket Status Flags */
-                        lstrcpynA(ifInfo.ifr_name, ptr->AdapterName, IFNAMSIZ);
-                        if (ioctl(fd, SIOCGIFFLAGS, &ifInfo) < 0)
-                        {
-                           ERR("Error obtaining status flags for socket!\n");
-                           status = WSAEINVAL;
-                           break;
-                        }
-                        else
-                        {
-                           /* set flags; the values of IFF_* are not the same
-                              under Linux and Windows, therefore must generate
-                              new flags */
-                           intArray->iiFlags = 0;
-                           if (ifInfo.ifr_flags & IFF_BROADCAST)
-                              intArray->iiFlags |= WS_IFF_BROADCAST;
-#ifdef IFF_POINTOPOINT
-                           if (ifInfo.ifr_flags & IFF_POINTOPOINT)
-                              intArray->iiFlags |= WS_IFF_POINTTOPOINT;
-#endif
-                           if (ifInfo.ifr_flags & IFF_LOOPBACK)
-                              intArray->iiFlags |= WS_IFF_LOOPBACK;
-                           if (ifInfo.ifr_flags & IFF_UP)
-                              intArray->iiFlags |= WS_IFF_UP;
-                           if (ifInfo.ifr_flags & IFF_MULTICAST)
-                              intArray->iiFlags |= WS_IFF_MULTICAST;
-                        }
-
-                        addr = inet_addr(ptr->IpAddressList.IpAddress.String);
-                        mask = inet_addr(ptr->IpAddressList.IpMask.String);
-                        bcast = addr | ~mask;
-                        intArray->iiAddress.AddressIn.sin_family = WS_AF_INET;
-                        intArray->iiAddress.AddressIn.sin_port = 0;
-                        intArray->iiAddress.AddressIn.sin_addr.WS_s_addr = addr;
-
-                        intArray->iiNetmask.AddressIn.sin_family = WS_AF_INET;
-                        intArray->iiNetmask.AddressIn.sin_port = 0;
-                        intArray->iiNetmask.AddressIn.sin_addr.WS_s_addr = mask;
-
-                        intArray->iiBroadcastAddress.AddressIn.sin_family = WS_AF_INET;
-                        intArray->iiBroadcastAddress.AddressIn.sin_port = 0;
-                        intArray->iiBroadcastAddress.AddressIn.sin_addr.WS_s_addr = bcast;
-                        intArray++;
-                        numInt++;
-                     }
-                  }
-                  else
-                  {
-                     ERR("Unable to get interface table!\n");
-                     status = WSAEINVAL;
-                  }
-                  HeapFree(GetProcessHeap(),0,table);
-               }
-               else status = WSAEINVAL;
-           }
-           else if (apiReturn != ERROR_NO_DATA)
-           {
-               ERR("Unable to get interface table!\n");
-               status = WSAEINVAL;
-           }
-           /* Calculate the size of the array being returned */
-           total = sizeof(INTERFACE_INFO) * numInt;
-           release_sock_fd( s, fd );
+           status = get_interface_list(s, out_buff, out_size, ret_size, &total);
            break;
        }
 
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index 2b0a7354f4b..81536cb9dbe 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -10516,6 +10516,9 @@ static void test_WSCGetProviderPath(void)
 
 static void test_wsaioctl(void)
 {
+    unsigned int i, count;
+    INTERFACE_INFO *info;
+    BOOL loopback_found;
     char buffer[4096];
     DWORD size;
     SOCKET s;
@@ -10529,12 +10532,40 @@ static void test_wsaioctl(void)
     ok(!ret, "Got unexpected ret %d.\n", ret);
     ok(size && size != 0xdeadbeef && !(size % sizeof(INTERFACE_INFO)), "Got unexpected size %u.\n", size);
 
+    info = (INTERFACE_INFO *)buffer;
+    count = size / sizeof(INTERFACE_INFO);
+    loopback_found = FALSE;
+    for (i = 0; i < count; ++i)
+    {
+        if (info[i].iiFlags & IFF_LOOPBACK)
+            loopback_found = TRUE;
+
+        ok(info[i].iiAddress.AddressIn.sin_family == AF_INET, "Got unexpected sin_family %#x.\n",
+                info[i].iiAddress.AddressIn.sin_family);
+        ok(info[i].iiNetmask.AddressIn.sin_family == AF_INET, "Got unexpected sin_family %#x.\n",
+                info[i].iiNetmask.AddressIn.sin_family);
+        ok(info[i].iiBroadcastAddress.AddressIn.sin_family
+                == (info[i].iiFlags & IFF_BROADCAST) ? AF_INET : 0, "Got unexpected sin_family %#x.\n",
+                info[i].iiBroadcastAddress.AddressIn.sin_family);
+        ok(info[i].iiAddress.AddressIn.sin_addr.S_un.S_addr, "Got zero iiAddress.\n");
+        ok(info[i].iiNetmask.AddressIn.sin_addr.S_un.S_addr, "Got zero iiNetmask.\n");
+        ok((info[i].iiFlags & IFF_BROADCAST) ? info[i].iiBroadcastAddress.AddressIn.sin_addr.S_un.S_addr
+                : !info[i].iiBroadcastAddress.AddressIn.sin_addr.S_un.S_addr,
+                "Got unexpected iiBroadcastAddress %s.\n", inet_ntoa(info[i].iiBroadcastAddress.AddressIn.sin_addr));
+    }
+
+    ok(loopback_found, "Loopback interface not found.\n");
+
     size = 0xdeadbeef;
     ret = WSAIoctl(s, SIO_GET_INTERFACE_LIST, NULL, 0, buffer, sizeof(INTERFACE_INFO) - 1, &size, NULL, NULL);
     ok(ret == -1, "Got unexpected ret %d.\n", ret);
     ok(WSAGetLastError() == WSAEFAULT, "Got unexpected error %d.\n", WSAGetLastError());
     ok(!size, "Got unexpected size %u.\n", size);
 
+    ret = WSAIoctl(s, SIO_GET_INTERFACE_LIST, NULL, 0, buffer, sizeof(buffer), NULL, NULL, NULL);
+    ok(ret == -1, "Got unexpected ret %d.\n", ret);
+    ok(WSAGetLastError() == WSAEFAULT, "Got unexpected error %d.\n", WSAGetLastError());
+
     closesocket(s);
 }
 
-- 
2.29.2




More information about the wine-devel mailing list