Signed-off-by: Paul Gofman <pgofman(a)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