[TCPIP_DRVTEST]
authorJérôme Gardou <jerome.gardou@reactos.org>
Wed, 21 Jan 2015 15:55:00 +0000 (15:55 +0000)
committerJérôme Gardou <jerome.gardou@reactos.org>
Wed, 21 Jan 2015 15:55:00 +0000 (15:55 +0000)
 - Add quite a lot of tests for IOCTL_TCP_QUERY_INFORMATION_EX
This IOCTL is quite important because that's how iphlpapi gets data from it.
Also, this can be used as a viewer for quite a lot SNMP info as described here: http://www.oidview.com/mibs/0/RFC1213-MIB.html

svn path=/trunk/; revision=66070

rostests/drivers/tcpip/CMakeLists.txt
rostests/drivers/tcpip/tcp_info.c [new file with mode: 0644]
rostests/drivers/tcpip/testlist.c

index 06f14f0..b202971 100644 (file)
@@ -3,6 +3,7 @@ include_directories(../../apitests/include)
 
 list(APPEND SOURCE
     InterfaceInfo.c
+    tcp_info.c
     testlist.c)
 
 add_executable(tcpip_drvtest ${SOURCE})
diff --git a/rostests/drivers/tcpip/tcp_info.c b/rostests/drivers/tcpip/tcp_info.c
new file mode 100644 (file)
index 0000000..b76f196
--- /dev/null
@@ -0,0 +1,580 @@
+/*
+ * PROJECT:         ReactOS kernel-mode tests
+ * LICENSE:         GPLv2+ - See COPYING in the top level directory
+ * PURPOSE:         Tests for IOCTL_TCP_QUERY_INFORMATION_EX
+ * PROGRAMMER:      Jérôme Gardou <jerome.gardou@reactos.org>
+ */
+
+#include <apitest.h>
+
+#include <stdio.h>
+
+#include <winioctl.h>
+#include <tcpioctl.h>
+#include <tdiinfo.h>
+#include <iptypes.h>
+#include <winsock.h>
+
+/* Route info */
+typedef struct IPRouteEntry {
+    unsigned long ire_dest;
+    unsigned long ire_index;
+    unsigned long ire_metric1;
+    unsigned long ire_metric2;
+    unsigned long ire_metric3;
+    unsigned long ire_metric4;
+    unsigned long ire_nexthop;
+    unsigned long ire_type;
+    unsigned long ire_proto;
+    unsigned long ire_age;
+    unsigned long ire_mask;
+    unsigned long ire_metric5;
+    unsigned long ire_context;
+} IPRouteEntry;
+
+/* Present in headers for Vista+, but there in WinXP/2k3 ntdll */
+NTSYSAPI
+PSTR
+NTAPI
+RtlIpv4AddressToStringA(
+  _In_ const struct in_addr *Addr,
+  _Out_writes_(16) PSTR S);
+
+
+static HANDLE TcpFileHandle;
+
+static ULONG IndentationLevel = 0;
+
+static
+char*
+dbg_print_physaddr(const unsigned char* addr, unsigned long addr_len)
+{
+    static char buffer[24];
+
+    char* dest = buffer;
+    *dest = '\0';
+
+    while (addr_len--)
+    {
+        dest += sprintf(dest, "%02x", *addr);
+        addr++;
+        if (addr_len)
+            *dest++ = ':';
+    }
+
+    return buffer;
+}
+
+static
+int
+__cdecl
+indent_printf(const char* format, ...)
+{
+    ULONG Indent = IndentationLevel;
+    int ret;
+    va_list args;
+
+    while(Indent--)
+        printf("\t");
+
+    va_start(args, format);
+    ret = vprintf(format, args);
+    va_end(args);
+
+    ret += IndentationLevel;
+
+    return ret;
+}
+
+static
+void
+test_IF_MIB_STATS(
+    TDIEntityID Id,
+    ULONG EntityType)
+{
+    IFEntry* IfEntry;
+    TCP_REQUEST_QUERY_INFORMATION_EX Request;
+    ULONG BufferSize = sizeof(IFEntry) + MAX_ADAPTER_DESCRIPTION_LENGTH + 1;
+    BOOL Result;
+
+    /* Not valid for other entity types */
+    if (EntityType != IF_MIB)
+        return;
+
+    IfEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, BufferSize);
+    ok(IfEntry != NULL, "\n");
+
+    ZeroMemory(&Request, sizeof(Request));
+    Request.ID.toi_entity = Id;
+    Request.ID.toi_class = INFO_CLASS_PROTOCOL;
+    Request.ID.toi_type = INFO_TYPE_PROVIDER;
+    Request.ID.toi_id = IF_MIB_STATS_ID;
+
+    Result = DeviceIoControl(
+        TcpFileHandle,
+        IOCTL_TCP_QUERY_INFORMATION_EX,
+        &Request,
+        sizeof(Request),
+        IfEntry,
+        BufferSize,
+        &BufferSize,
+        NULL);
+    ok(Result, "DeviceIoControl failed.\n");
+
+    /* Dump it */
+    indent_printf("IF_MIB Statistics:\n");
+    IndentationLevel++;
+    indent_printf("if_index:           %lu\n", IfEntry->if_index);
+    indent_printf("if_type:            %lu\n", IfEntry->if_type);
+    indent_printf("if_mtu:             %lu\n", IfEntry->if_mtu);
+    indent_printf("if_speed:           %lu\n", IfEntry->if_speed);
+    indent_printf("if_physaddr:        %s\n",  dbg_print_physaddr(IfEntry->if_physaddr, IfEntry->if_physaddrlen));
+    indent_printf("if_adminstatus:     %lu\n", IfEntry->if_adminstatus);
+    indent_printf("if_operstatus:      %lu\n", IfEntry->if_operstatus);
+    indent_printf("if_lastchange:      %lu\n", IfEntry->if_lastchange);
+    indent_printf("if_inoctets:        %lu\n", IfEntry->if_inoctets);
+    indent_printf("if_inucastpkts:     %lu\n", IfEntry->if_inucastpkts);
+    indent_printf("if_innucastpkts:    %lu\n", IfEntry->if_innucastpkts);
+    indent_printf("if_indiscards:      %lu\n", IfEntry->if_indiscards);
+    indent_printf("if_inerrors:        %lu\n", IfEntry->if_inerrors);
+    indent_printf("if_inunknownprotos: %lu\n", IfEntry->if_inunknownprotos);
+    indent_printf("if_outoctets:       %lu\n", IfEntry->if_outoctets);
+    indent_printf("if_outucastpkts:    %lu\n", IfEntry->if_outucastpkts);
+    indent_printf("if_outnucastpkts:   %lu\n", IfEntry->if_outnucastpkts);
+    indent_printf("if_outdiscards:     %lu\n", IfEntry->if_outdiscards);
+    indent_printf("if_outerrors:       %lu\n", IfEntry->if_outerrors);
+    indent_printf("if_outqlen:         %lu\n", IfEntry->if_outqlen);
+    indent_printf("if_descr:           %*s\n", IfEntry->if_descrlen, IfEntry->if_descr);
+    IndentationLevel--;
+
+    HeapFree(GetProcessHeap(), 0, IfEntry);
+}
+
+static
+void
+test_IP_MIB_STATS(
+    TDIEntityID Id,
+    ULONG EntityType)
+{
+    IPSNMPInfo IpSnmpInfo;
+    TCP_REQUEST_QUERY_INFORMATION_EX Request;
+    ULONG BufferSize = 0;
+    BOOL Result;
+
+    /* Not valid for other entity types */
+    if (EntityType != CL_NL_IP)
+        return;
+
+    ZeroMemory(&IpSnmpInfo, sizeof(IpSnmpInfo));
+
+    ZeroMemory(&Request, sizeof(Request));
+    Request.ID.toi_entity = Id;
+    Request.ID.toi_class = INFO_CLASS_PROTOCOL;
+    Request.ID.toi_type = INFO_TYPE_PROVIDER;
+    Request.ID.toi_id = IP_MIB_STATS_ID;
+
+    Result = DeviceIoControl(
+        TcpFileHandle,
+        IOCTL_TCP_QUERY_INFORMATION_EX,
+        &Request,
+        sizeof(Request),
+        &IpSnmpInfo,
+        sizeof(IpSnmpInfo),
+        &BufferSize,
+        NULL);
+    ok(Result, "DeviceIoControl failed.\n");
+
+    /* Dump it */
+    indent_printf("IP_MIB Statistics:\n");
+    IndentationLevel++;
+    indent_printf("ipsi_forwarding:      %lu\n", IpSnmpInfo.ipsi_forwarding);
+    indent_printf("ipsi_defaultttl:      %lu\n", IpSnmpInfo.ipsi_defaultttl);
+    indent_printf("ipsi_inreceives:      %lu\n", IpSnmpInfo.ipsi_inreceives);
+    indent_printf("ipsi_inhdrerrors:     %lu\n", IpSnmpInfo.ipsi_inhdrerrors);
+    indent_printf("ipsi_inaddrerrors:    %lu\n", IpSnmpInfo.ipsi_inaddrerrors);
+    indent_printf("ipsi_forwdatagrams:   %lu\n", IpSnmpInfo.ipsi_forwdatagrams);
+    indent_printf("ipsi_inunknownprotos: %lu\n", IpSnmpInfo.ipsi_inunknownprotos);
+    indent_printf("ipsi_indiscards:      %lu\n", IpSnmpInfo.ipsi_indiscards);
+    indent_printf("ipsi_indelivers:      %lu\n", IpSnmpInfo.ipsi_indelivers);
+    indent_printf("ipsi_outrequests:     %lu\n", IpSnmpInfo.ipsi_outrequests);
+    indent_printf("ipsi_routingdiscards: %lu\n", IpSnmpInfo.ipsi_routingdiscards);
+    indent_printf("ipsi_outdiscards:     %lu\n", IpSnmpInfo.ipsi_outdiscards);
+    indent_printf("ipsi_outnoroutes:     %lu\n", IpSnmpInfo.ipsi_outnoroutes);
+    indent_printf("ipsi_reasmtimeout:    %lu\n", IpSnmpInfo.ipsi_reasmtimeout);
+    indent_printf("ipsi_reasmreqds:      %lu\n", IpSnmpInfo.ipsi_reasmreqds);
+    indent_printf("ipsi_reasmoks:        %lu\n", IpSnmpInfo.ipsi_reasmoks);
+    indent_printf("ipsi_reasmfails:      %lu\n", IpSnmpInfo.ipsi_reasmfails);
+    indent_printf("ipsi_fragoks:         %lu\n", IpSnmpInfo.ipsi_fragoks);
+    indent_printf("ipsi_fragfails:       %lu\n", IpSnmpInfo.ipsi_fragfails);
+    indent_printf("ipsi_fragcreates:     %lu\n", IpSnmpInfo.ipsi_fragcreates);
+    indent_printf("ipsi_numif:           %lu\n", IpSnmpInfo.ipsi_numif);
+    indent_printf("ipsi_numaddr:         %lu\n", IpSnmpInfo.ipsi_numaddr);
+    indent_printf("ipsi_numroutes:       %lu\n", IpSnmpInfo.ipsi_numroutes);
+
+    if (IpSnmpInfo.ipsi_numaddr != 0)
+    {
+        IPAddrEntry* AddrEntries;
+        ULONG i;
+
+        AddrEntries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, IpSnmpInfo.ipsi_numaddr * sizeof(AddrEntries[0]));
+        ok(AddrEntries != NULL, "\n");
+
+        ZeroMemory(&Request, sizeof(Request));
+        Request.ID.toi_entity = Id;
+        Request.ID.toi_class = INFO_CLASS_PROTOCOL;
+        Request.ID.toi_type = INFO_TYPE_PROVIDER;
+        Request.ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
+
+        Result = DeviceIoControl(
+            TcpFileHandle,
+            IOCTL_TCP_QUERY_INFORMATION_EX,
+            &Request,
+            sizeof(Request),
+            AddrEntries,
+            IpSnmpInfo.ipsi_numaddr * sizeof(AddrEntries[0]),
+            &BufferSize,
+            NULL);
+        ok(Result, "DeviceIoControl failed.\n");
+        ok_long(BufferSize, IpSnmpInfo.ipsi_numaddr * sizeof(AddrEntries[0]));
+
+        for(i = 0; i < IpSnmpInfo.ipsi_numaddr; i++)
+        {
+            CHAR AddressString[16];
+            struct in_addr Addr;
+
+            Addr.S_un.S_addr = AddrEntries[i].iae_addr;
+            RtlIpv4AddressToStringA(&Addr, AddressString);
+
+            indent_printf("Address %lu: %s\n", i, AddressString);
+
+            IndentationLevel++;
+
+            indent_printf("iae_addr:      %lx\n", AddrEntries[i].iae_addr);
+            indent_printf("iae_index:     %lu\n", AddrEntries[i].iae_index);
+            Addr.S_un.S_addr = AddrEntries[i].iae_mask;
+            RtlIpv4AddressToStringA(&Addr, AddressString);
+            indent_printf("iae_mask:      %lx (%s)\n", AddrEntries[i].iae_mask, AddressString);
+            indent_printf("iae_bcastaddr: %lu\n", AddrEntries[i].iae_bcastaddr);
+            indent_printf("iae_reasmsize: %lu\n", AddrEntries[i].iae_reasmsize);
+            indent_printf("iae_context:   %u\n",  AddrEntries[i].iae_context);
+
+            {
+                IPInterfaceInfo* InterfaceInfo;
+
+                /* Get the interface info */
+                BufferSize = sizeof(IPInterfaceInfo) + MAX_PHYSADDR_SIZE;
+                InterfaceInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, BufferSize);
+                ok(InterfaceInfo != NULL, "\n");
+
+                Request.ID.toi_id = IP_INTFC_INFO_ID;
+                Request.Context[0] = AddrEntries[i].iae_addr;
+                Result = DeviceIoControl(
+                    TcpFileHandle,
+                    IOCTL_TCP_QUERY_INFORMATION_EX,
+                    &Request,
+                    sizeof(Request),
+                    InterfaceInfo,
+                    BufferSize,
+                    &BufferSize,
+                    NULL);
+                ok(Result, "DeviceIoControl failed.\n");
+
+                indent_printf("Interface info:\n");
+                IndentationLevel++;
+
+                indent_printf("iii_flags:    %lu\n", InterfaceInfo->iii_flags);
+                indent_printf("iii_mtu  :    %lu\n", InterfaceInfo->iii_mtu);
+                indent_printf("iii_speed:    %lu\n", InterfaceInfo->iii_speed);
+                indent_printf("iii_physaddr: %s\n",  dbg_print_physaddr(InterfaceInfo->iii_addr, InterfaceInfo->iii_addrlength));
+
+                IndentationLevel--;
+            }
+
+            IndentationLevel--;
+        }
+
+        HeapFree(GetProcessHeap(), 0, AddrEntries);
+    }
+
+    /* See for the routes */
+    if (IpSnmpInfo.ipsi_numroutes)
+    {
+        IPRouteEntry* RouteEntries;
+        ULONG i;
+
+        RouteEntries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, IpSnmpInfo.ipsi_numroutes * sizeof(RouteEntries[0]));
+        ok(RouteEntries != NULL, "\n");
+
+        ZeroMemory(&Request, sizeof(Request));
+        Request.ID.toi_entity = Id;
+        Request.ID.toi_class = INFO_CLASS_PROTOCOL;
+        Request.ID.toi_type = INFO_TYPE_PROVIDER;
+        Request.ID.toi_id = IP_MIB_ARPTABLE_ENTRY_ID;
+
+        Result = DeviceIoControl(
+            TcpFileHandle,
+            IOCTL_TCP_QUERY_INFORMATION_EX,
+            &Request,
+            sizeof(Request),
+            RouteEntries,
+            IpSnmpInfo.ipsi_numroutes * sizeof(RouteEntries[0]),
+            &BufferSize,
+            NULL);
+        ok(Result, "DeviceIoControl failed.\n");
+        ok_long(BufferSize, IpSnmpInfo.ipsi_numroutes * sizeof(RouteEntries[0]));
+
+        for (i = 0; i < IpSnmpInfo.ipsi_numroutes; i++)
+        {
+            CHAR AddressString[16];
+            struct in_addr Addr;
+
+            Addr.S_un.S_addr = RouteEntries[i].ire_dest;
+            RtlIpv4AddressToStringA(&Addr, AddressString);
+
+            indent_printf("Route %lu:\n", i);
+
+            IndentationLevel++;
+
+            indent_printf("ire_dest:    %s (%lx)\n", AddressString, RouteEntries[i].ire_dest);
+            indent_printf("ire_index:   %lu\n", RouteEntries[i].ire_index);
+            indent_printf("ire_metric1: %#lx\n", RouteEntries[i].ire_metric1);
+            indent_printf("ire_metric2: %#lx\n", RouteEntries[i].ire_metric2);
+            indent_printf("ire_metric3: %#lx\n", RouteEntries[i].ire_metric3);
+            indent_printf("ire_metric4: %#lx\n", RouteEntries[i].ire_metric4);
+            Addr.S_un.S_addr = RouteEntries[i].ire_nexthop;
+            RtlIpv4AddressToStringA(&Addr, AddressString);
+            indent_printf("ire_nexthop: %s (%lx)\n", AddressString, RouteEntries[i].ire_nexthop);
+            indent_printf("ire_type:    %lu\n", RouteEntries[i].ire_type);
+            indent_printf("ire_proto:   %lu\n", RouteEntries[i].ire_proto);
+            indent_printf("ire_age:     %lu\n", RouteEntries[i].ire_age);
+            Addr.S_un.S_addr = RouteEntries[i].ire_mask;
+            RtlIpv4AddressToStringA(&Addr, AddressString);
+            indent_printf("ire_mask:    %s (%lx)\n", AddressString, RouteEntries[i].ire_mask);
+            indent_printf("ire_metric5: %lx\n", RouteEntries[i].ire_metric5);
+            indent_printf("ire_context: %lx\n", RouteEntries[i].ire_context);
+
+            IndentationLevel--;
+        }
+    }
+
+    IndentationLevel--;
+}
+
+typedef struct ARPInfo
+{
+    unsigned long ai_numroutes;
+    unsigned long ai_unknown;
+} ARPInfo;
+
+typedef struct ARPEntry
+{
+    unsigned long ae_index;
+    unsigned long ae_physaddrlen;
+    unsigned char ae_physaddr[MAX_PHYSADDR_SIZE];
+    unsigned long ae_address;
+    unsigned long ae_unknown;
+} ARPEntry;
+
+static
+void
+test_AT_ARP_STATS(
+    TDIEntityID Id,
+    ULONG EntityType)
+{
+    ARPInfo ArpInfo;
+    TCP_REQUEST_QUERY_INFORMATION_EX Request;
+    ULONG BufferSize = 0;
+    BOOL Result;
+
+    /* Not valid for other entity types */
+    if (EntityType != AT_ARP)
+        return;
+
+    ZeroMemory(&Request, sizeof(Request));
+    Request.ID.toi_entity = Id;
+    Request.ID.toi_class = INFO_CLASS_PROTOCOL;
+    Request.ID.toi_type = INFO_TYPE_PROVIDER;
+    Request.ID.toi_id = AT_MIB_ADDRXLAT_INFO_ID;
+
+    Result = DeviceIoControl(
+        TcpFileHandle,
+        IOCTL_TCP_QUERY_INFORMATION_EX,
+        &Request,
+        sizeof(Request),
+        &ArpInfo,
+        sizeof(ArpInfo),
+        &BufferSize,
+        NULL);
+    ok(Result, "DeviceIoControl failed.\n");
+    ok_long(BufferSize, sizeof(ArpInfo));
+
+    indent_printf("ARP Info:\n");
+    IndentationLevel++;
+
+    indent_printf("ai_numroutes: %lu\n", ArpInfo.ai_numroutes);
+    indent_printf("ai_unknown:   %lx\n", ArpInfo.ai_unknown);
+
+    if (ArpInfo.ai_numroutes)
+    {
+        ARPEntry* ArpEntries;
+        ULONG i;
+
+        Request.ID.toi_id = AT_MIB_ADDRXLAT_ENTRY_ID;
+
+        ArpEntries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ArpInfo.ai_numroutes * sizeof(ArpEntries[0]));
+        ok(ArpEntries != NULL, "\n");
+
+        Result = DeviceIoControl(
+            TcpFileHandle,
+            IOCTL_TCP_QUERY_INFORMATION_EX,
+            &Request,
+            sizeof(Request),
+            ArpEntries,
+            ArpInfo.ai_numroutes * sizeof(ArpEntries[0]),
+            &BufferSize,
+            NULL);
+        ok(Result, "DeviceIoControl failed.\n");
+        ok_long(BufferSize, ArpInfo.ai_numroutes * sizeof(ArpEntries[0]));
+
+        for (i = 0; i < ArpInfo.ai_numroutes; i++)
+        {
+            CHAR AddressString[16];
+            struct in_addr Addr;
+
+            Addr.S_un.S_addr = ArpEntries[i].ae_address;
+            RtlIpv4AddressToStringA(&Addr, AddressString);
+
+            indent_printf("ARP Entry %lu:\n", i);
+
+            IndentationLevel++;
+
+            indent_printf("ae_index:    %lu\n", ArpEntries[i].ae_index);
+            indent_printf("ae_physaddr: %lu\n", dbg_print_physaddr(ArpEntries[i].ae_physaddr, ArpEntries[i].ae_physaddrlen));
+            indent_printf("ae_address:  %lx (%s)\n", ArpEntries[i].ae_address, AddressString);
+            indent_printf("ae_unknown:  %lu.\n", ArpEntries[i].ae_unknown);
+
+            IndentationLevel--;
+        }
+
+        HeapFree(GetProcessHeap(), 0, ArpEntries);
+    }
+
+    IndentationLevel--;
+}
+
+START_TEST(tcp_info)
+{
+    TDIEntityID* Entities;
+    DWORD BufferSize;
+    BOOL Result;
+    ULONG i, EntityCount;
+    TCP_REQUEST_QUERY_INFORMATION_EX Request;
+
+    /* Open a control channel file for TCP */
+    TcpFileHandle = CreateFileW(
+        L"\\\\.\\Tcp",
+        FILE_READ_DATA | FILE_WRITE_DATA,
+        FILE_SHARE_READ | FILE_SHARE_WRITE,
+        NULL,
+        OPEN_EXISTING,
+        0,
+        NULL);
+    ok(TcpFileHandle != INVALID_HANDLE_VALUE, "CreateFile failed, GLE %lu\n", GetLastError());
+
+    /* Try the IOCTL */
+    BufferSize = 0;
+    Result = DeviceIoControl(
+        TcpFileHandle,
+        IOCTL_TCP_QUERY_INFORMATION_EX,
+        NULL,
+        0,
+        NULL,
+        0,
+        &BufferSize,
+        NULL);
+    ok(!Result, "DeviceIoControl succeeded.\n");
+    ok_long(GetLastError(), ERROR_INVALID_PARAMETER);
+    ok_long(BufferSize, 0);
+
+    ZeroMemory(&Request, sizeof(Request));
+    Request.ID.toi_entity.tei_entity = GENERIC_ENTITY;
+    Request.ID.toi_entity.tei_instance = 0;
+    Request.ID.toi_class = INFO_CLASS_GENERIC;
+    Request.ID.toi_type = INFO_TYPE_PROVIDER;
+    Request.ID.toi_id = ENTITY_LIST_ID;
+
+    BufferSize = 0;
+    Result = DeviceIoControl(
+        TcpFileHandle,
+        IOCTL_TCP_QUERY_INFORMATION_EX,
+        &Request,
+        sizeof(Request),
+        NULL,
+        0,
+        &BufferSize,
+        NULL);
+    ok(!Result, "DeviceIoControl succeeded.\n");
+    ok_long(GetLastError(), ERROR_INVALID_PARAMETER);
+    ok_long(BufferSize, 0);
+
+    BufferSize = 4 * sizeof(Entities[0]);
+    Entities = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, BufferSize);
+    ok(Entities != NULL, "\n");
+
+    while (TRUE)
+    {
+        Result = DeviceIoControl(
+            TcpFileHandle,
+            IOCTL_TCP_QUERY_INFORMATION_EX,
+            &Request,
+            sizeof(Request),
+            Entities,
+            BufferSize,
+            &BufferSize,
+            NULL);
+
+        if (Result)
+            break;
+
+        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+            break;
+
+        BufferSize *= 2;
+        Entities = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Entities, BufferSize);
+        ok(Entities != NULL, "\n");
+    }
+
+    ok(Result, "DeviceIoControl failed!\n");
+    EntityCount = BufferSize / sizeof(Entities[0]);
+    trace("Got %lu entities.\n", EntityCount);
+
+    for (i = 0; i < EntityCount; i++)
+    {
+        ULONG EntityType;
+
+        /* Get the type */
+        Request.ID.toi_entity = Entities[i];
+        Request.ID.toi_class = INFO_CLASS_GENERIC;
+        Request.ID.toi_type = INFO_TYPE_PROVIDER;
+        Request.ID.toi_id = ENTITY_TYPE_ID;
+
+        Result = DeviceIoControl(
+            TcpFileHandle,
+            IOCTL_TCP_QUERY_INFORMATION_EX,
+            &Request,
+            sizeof(Request),
+            &EntityType,
+            sizeof(EntityType),
+            &BufferSize,
+            NULL);
+        ok(Result, "DeviceIoControl failed.\n");
+
+        printf("Entity %lu: %#lx, %#lx, type %#lx\n", i, Entities[i].tei_entity, Entities[i].tei_instance, EntityType);
+        test_IF_MIB_STATS(Entities[i], EntityType);
+        test_IP_MIB_STATS(Entities[i], EntityType);
+        test_AT_ARP_STATS(Entities[i], EntityType);
+    }
+
+    HeapFree(GetProcessHeap(), 0, Entities);
+    CloseHandle(TcpFileHandle);
+}
index 9353863..3d8ab30 100644 (file)
@@ -4,10 +4,12 @@
 #include <apitest.h>
 
 extern void func_InterfaceInfo(void);
+extern void func_tcp_info(void);
 
 const struct test winetest_testlist[] =
 {
     { "InterfaceInfo", func_InterfaceInfo },
+    { "tcp_info", func_tcp_info },
 
     { 0, 0 }
 };