1 /*
2  * PROJECT:         ReactOS kernel-mode tests
3  * LICENSE:         GPLv2+ - See COPYING in the top level directory
4  * PURPOSE:         Tests for IOCTL_TCP_QUERY_INFORMATION_EX
5  * PROGRAMMER:      Jérôme Gardou <jerome.gardou@reactos.org>
6  */
7 
8 #include <apitest.h>
9 
10 #include <stdio.h>
11 
12 #include <winioctl.h>
13 #include <tcpioctl.h>
14 #include <tdiinfo.h>
15 #include <iptypes.h>
16 #include <winsock.h>
17 
18 /* FIXME */
19 #define AT_MIB_ADDRXLAT_INFO_ID 1
20 #define AT_MIB_ADDRXLAT_ENTRY_ID 0x101
21 
22 /* Route info */
23 typedef struct IPRouteEntry {
24     unsigned long ire_dest;
25     unsigned long ire_index;
26     unsigned long ire_metric1;
27     unsigned long ire_metric2;
28     unsigned long ire_metric3;
29     unsigned long ire_metric4;
30     unsigned long ire_nexthop;
31     unsigned long ire_type;
32     unsigned long ire_proto;
33     unsigned long ire_age;
34     unsigned long ire_mask;
35     unsigned long ire_metric5;
36     unsigned long ire_context;
37 } IPRouteEntry;
38 
39 /* Present in headers for Vista+, but there in WinXP/2k3 ntdll */
40 NTSYSAPI
41 PSTR
42 NTAPI
43 RtlIpv4AddressToStringA(
44   _In_ const struct in_addr *Addr,
45   _Out_writes_(16) PSTR S);
46 
47 
48 static HANDLE TcpFileHandle;
49 
50 static ULONG IndentationLevel = 0;
51 
52 static
53 char*
dbg_print_physaddr(const unsigned char * addr,unsigned long addr_len)54 dbg_print_physaddr(const unsigned char* addr, unsigned long addr_len)
55 {
56     static char buffer[24];
57 
58     char* dest = buffer;
59     *dest = '\0';
60 
61     while (addr_len--)
62     {
63         dest += sprintf(dest, "%02x", *addr);
64         addr++;
65         if (addr_len)
66             *dest++ = ':';
67     }
68 
69     return buffer;
70 }
71 
72 static
73 int
74 __cdecl
indent_printf(const char * format,...)75 indent_printf(const char* format, ...)
76 {
77     ULONG Indent = IndentationLevel;
78     int ret;
79     va_list args;
80 
81     while(Indent--)
82         printf("\t");
83 
84     va_start(args, format);
85     ret = vprintf(format, args);
86     va_end(args);
87 
88     ret += IndentationLevel;
89 
90     return ret;
91 }
92 
93 static
94 void
test_IF_MIB_STATS(TDIEntityID Id,ULONG EntityType)95 test_IF_MIB_STATS(
96     TDIEntityID Id,
97     ULONG EntityType)
98 {
99     IFEntry* IfEntry;
100     TCP_REQUEST_QUERY_INFORMATION_EX Request;
101     ULONG BufferSize = sizeof(IFEntry) + MAX_ADAPTER_DESCRIPTION_LENGTH + 1;
102     BOOL Result;
103 
104     /* Not valid for other entity types */
105     if (EntityType != IF_MIB)
106         return;
107 
108     IfEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, BufferSize);
109     ok(IfEntry != NULL, "\n");
110 
111     ZeroMemory(&Request, sizeof(Request));
112     Request.ID.toi_entity = Id;
113     Request.ID.toi_class = INFO_CLASS_PROTOCOL;
114     Request.ID.toi_type = INFO_TYPE_PROVIDER;
115     Request.ID.toi_id = IF_MIB_STATS_ID;
116 
117     Result = DeviceIoControl(
118         TcpFileHandle,
119         IOCTL_TCP_QUERY_INFORMATION_EX,
120         &Request,
121         sizeof(Request),
122         IfEntry,
123         BufferSize,
124         &BufferSize,
125         NULL);
126     ok(Result, "DeviceIoControl failed.\n");
127 
128     /* Dump it */
129     indent_printf("IF_MIB Statistics:\n");
130     IndentationLevel++;
131     indent_printf("if_index:           %lu\n", IfEntry->if_index);
132     indent_printf("if_type:            %lu\n", IfEntry->if_type);
133     indent_printf("if_mtu:             %lu\n", IfEntry->if_mtu);
134     indent_printf("if_speed:           %lu\n", IfEntry->if_speed);
135     indent_printf("if_physaddr:        %s\n",  dbg_print_physaddr(IfEntry->if_physaddr, IfEntry->if_physaddrlen));
136     indent_printf("if_adminstatus:     %lu\n", IfEntry->if_adminstatus);
137     indent_printf("if_operstatus:      %lu\n", IfEntry->if_operstatus);
138     indent_printf("if_lastchange:      %lu\n", IfEntry->if_lastchange);
139     indent_printf("if_inoctets:        %lu\n", IfEntry->if_inoctets);
140     indent_printf("if_inucastpkts:     %lu\n", IfEntry->if_inucastpkts);
141     indent_printf("if_innucastpkts:    %lu\n", IfEntry->if_innucastpkts);
142     indent_printf("if_indiscards:      %lu\n", IfEntry->if_indiscards);
143     indent_printf("if_inerrors:        %lu\n", IfEntry->if_inerrors);
144     indent_printf("if_inunknownprotos: %lu\n", IfEntry->if_inunknownprotos);
145     indent_printf("if_outoctets:       %lu\n", IfEntry->if_outoctets);
146     indent_printf("if_outucastpkts:    %lu\n", IfEntry->if_outucastpkts);
147     indent_printf("if_outnucastpkts:   %lu\n", IfEntry->if_outnucastpkts);
148     indent_printf("if_outdiscards:     %lu\n", IfEntry->if_outdiscards);
149     indent_printf("if_outerrors:       %lu\n", IfEntry->if_outerrors);
150     indent_printf("if_outqlen:         %lu\n", IfEntry->if_outqlen);
151     indent_printf("if_descr:           %*s\n", IfEntry->if_descrlen, IfEntry->if_descr);
152     IndentationLevel--;
153 
154     HeapFree(GetProcessHeap(), 0, IfEntry);
155 }
156 
157 static
158 void
test_IP_MIB_STATS(TDIEntityID Id,ULONG EntityType)159 test_IP_MIB_STATS(
160     TDIEntityID Id,
161     ULONG EntityType)
162 {
163     IPSNMPInfo IpSnmpInfo;
164     TCP_REQUEST_QUERY_INFORMATION_EX Request;
165     ULONG BufferSize = 0;
166     BOOL Result;
167 
168     /* Not valid for other entity types */
169     if (EntityType != CL_NL_IP)
170         return;
171 
172     ZeroMemory(&IpSnmpInfo, sizeof(IpSnmpInfo));
173 
174     ZeroMemory(&Request, sizeof(Request));
175     Request.ID.toi_entity = Id;
176     Request.ID.toi_class = INFO_CLASS_PROTOCOL;
177     Request.ID.toi_type = INFO_TYPE_PROVIDER;
178     Request.ID.toi_id = IP_MIB_STATS_ID;
179 
180     Result = DeviceIoControl(
181         TcpFileHandle,
182         IOCTL_TCP_QUERY_INFORMATION_EX,
183         &Request,
184         sizeof(Request),
185         &IpSnmpInfo,
186         sizeof(IpSnmpInfo),
187         &BufferSize,
188         NULL);
189     ok(Result, "DeviceIoControl failed.\n");
190 
191     /* Dump it */
192     indent_printf("IP_MIB Statistics:\n");
193     IndentationLevel++;
194     indent_printf("ipsi_forwarding:      %lu\n", IpSnmpInfo.ipsi_forwarding);
195     indent_printf("ipsi_defaultttl:      %lu\n", IpSnmpInfo.ipsi_defaultttl);
196     indent_printf("ipsi_inreceives:      %lu\n", IpSnmpInfo.ipsi_inreceives);
197     indent_printf("ipsi_inhdrerrors:     %lu\n", IpSnmpInfo.ipsi_inhdrerrors);
198     indent_printf("ipsi_inaddrerrors:    %lu\n", IpSnmpInfo.ipsi_inaddrerrors);
199     indent_printf("ipsi_forwdatagrams:   %lu\n", IpSnmpInfo.ipsi_forwdatagrams);
200     indent_printf("ipsi_inunknownprotos: %lu\n", IpSnmpInfo.ipsi_inunknownprotos);
201     indent_printf("ipsi_indiscards:      %lu\n", IpSnmpInfo.ipsi_indiscards);
202     indent_printf("ipsi_indelivers:      %lu\n", IpSnmpInfo.ipsi_indelivers);
203     indent_printf("ipsi_outrequests:     %lu\n", IpSnmpInfo.ipsi_outrequests);
204     indent_printf("ipsi_routingdiscards: %lu\n", IpSnmpInfo.ipsi_routingdiscards);
205     indent_printf("ipsi_outdiscards:     %lu\n", IpSnmpInfo.ipsi_outdiscards);
206     indent_printf("ipsi_outnoroutes:     %lu\n", IpSnmpInfo.ipsi_outnoroutes);
207     indent_printf("ipsi_reasmtimeout:    %lu\n", IpSnmpInfo.ipsi_reasmtimeout);
208     indent_printf("ipsi_reasmreqds:      %lu\n", IpSnmpInfo.ipsi_reasmreqds);
209     indent_printf("ipsi_reasmoks:        %lu\n", IpSnmpInfo.ipsi_reasmoks);
210     indent_printf("ipsi_reasmfails:      %lu\n", IpSnmpInfo.ipsi_reasmfails);
211     indent_printf("ipsi_fragoks:         %lu\n", IpSnmpInfo.ipsi_fragoks);
212     indent_printf("ipsi_fragfails:       %lu\n", IpSnmpInfo.ipsi_fragfails);
213     indent_printf("ipsi_fragcreates:     %lu\n", IpSnmpInfo.ipsi_fragcreates);
214     indent_printf("ipsi_numif:           %lu\n", IpSnmpInfo.ipsi_numif);
215     indent_printf("ipsi_numaddr:         %lu\n", IpSnmpInfo.ipsi_numaddr);
216     indent_printf("ipsi_numroutes:       %lu\n", IpSnmpInfo.ipsi_numroutes);
217 
218     if (IpSnmpInfo.ipsi_numaddr != 0)
219     {
220         IPAddrEntry* AddrEntries;
221         ULONG i;
222 
223         AddrEntries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, IpSnmpInfo.ipsi_numaddr * sizeof(AddrEntries[0]));
224         ok(AddrEntries != NULL, "\n");
225 
226         ZeroMemory(&Request, sizeof(Request));
227         Request.ID.toi_entity = Id;
228         Request.ID.toi_class = INFO_CLASS_PROTOCOL;
229         Request.ID.toi_type = INFO_TYPE_PROVIDER;
230         Request.ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
231 
232         Result = DeviceIoControl(
233             TcpFileHandle,
234             IOCTL_TCP_QUERY_INFORMATION_EX,
235             &Request,
236             sizeof(Request),
237             AddrEntries,
238             IpSnmpInfo.ipsi_numaddr * sizeof(AddrEntries[0]),
239             &BufferSize,
240             NULL);
241         ok(Result, "DeviceIoControl failed.\n");
242         ok_long(BufferSize, IpSnmpInfo.ipsi_numaddr * sizeof(AddrEntries[0]));
243 
244         for(i = 0; i < IpSnmpInfo.ipsi_numaddr; i++)
245         {
246             CHAR AddressString[16];
247             struct in_addr Addr;
248 
249             Addr.S_un.S_addr = AddrEntries[i].iae_addr;
250             RtlIpv4AddressToStringA(&Addr, AddressString);
251 
252             indent_printf("Address %lu: %s\n", i, AddressString);
253 
254             IndentationLevel++;
255 
256             indent_printf("iae_addr:      %lx\n", AddrEntries[i].iae_addr);
257             indent_printf("iae_index:     %lu\n", AddrEntries[i].iae_index);
258             Addr.S_un.S_addr = AddrEntries[i].iae_mask;
259             RtlIpv4AddressToStringA(&Addr, AddressString);
260             indent_printf("iae_mask:      %lx (%s)\n", AddrEntries[i].iae_mask, AddressString);
261             indent_printf("iae_bcastaddr: %lu\n", AddrEntries[i].iae_bcastaddr);
262             indent_printf("iae_reasmsize: %lu\n", AddrEntries[i].iae_reasmsize);
263             indent_printf("iae_context:   %u\n",  AddrEntries[i].iae_context);
264 
265             {
266                 IPInterfaceInfo* InterfaceInfo;
267 
268                 /* Get the interface info */
269                 BufferSize = sizeof(IPInterfaceInfo) + MAX_PHYSADDR_SIZE;
270                 InterfaceInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, BufferSize);
271                 ok(InterfaceInfo != NULL, "\n");
272 
273                 Request.ID.toi_id = IP_INTFC_INFO_ID;
274                 Request.Context[0] = AddrEntries[i].iae_addr;
275                 Result = DeviceIoControl(
276                     TcpFileHandle,
277                     IOCTL_TCP_QUERY_INFORMATION_EX,
278                     &Request,
279                     sizeof(Request),
280                     InterfaceInfo,
281                     BufferSize,
282                     &BufferSize,
283                     NULL);
284                 ok(Result, "DeviceIoControl failed.\n");
285 
286                 indent_printf("Interface info:\n");
287                 IndentationLevel++;
288 
289                 indent_printf("iii_flags:    %lu\n", InterfaceInfo->iii_flags);
290                 indent_printf("iii_mtu  :    %lu\n", InterfaceInfo->iii_mtu);
291                 indent_printf("iii_speed:    %lu\n", InterfaceInfo->iii_speed);
292                 indent_printf("iii_physaddr: %s\n",  dbg_print_physaddr(InterfaceInfo->iii_addr, InterfaceInfo->iii_addrlength));
293 
294                 IndentationLevel--;
295             }
296 
297             IndentationLevel--;
298         }
299 
300         HeapFree(GetProcessHeap(), 0, AddrEntries);
301     }
302 
303     /* See for the routes */
304     if (IpSnmpInfo.ipsi_numroutes)
305     {
306         IPRouteEntry* RouteEntries;
307         ULONG i;
308 
309         RouteEntries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, IpSnmpInfo.ipsi_numroutes * sizeof(RouteEntries[0]));
310         ok(RouteEntries != NULL, "\n");
311 
312         ZeroMemory(&Request, sizeof(Request));
313         Request.ID.toi_entity = Id;
314         Request.ID.toi_class = INFO_CLASS_PROTOCOL;
315         Request.ID.toi_type = INFO_TYPE_PROVIDER;
316         Request.ID.toi_id = IP_MIB_ARPTABLE_ENTRY_ID;
317 
318         Result = DeviceIoControl(
319             TcpFileHandle,
320             IOCTL_TCP_QUERY_INFORMATION_EX,
321             &Request,
322             sizeof(Request),
323             RouteEntries,
324             IpSnmpInfo.ipsi_numroutes * sizeof(RouteEntries[0]),
325             &BufferSize,
326             NULL);
327         ok(Result, "DeviceIoControl failed.\n");
328         ok_long(BufferSize, IpSnmpInfo.ipsi_numroutes * sizeof(RouteEntries[0]));
329 
330         for (i = 0; i < IpSnmpInfo.ipsi_numroutes; i++)
331         {
332             CHAR AddressString[16];
333             struct in_addr Addr;
334 
335             Addr.S_un.S_addr = RouteEntries[i].ire_dest;
336             RtlIpv4AddressToStringA(&Addr, AddressString);
337 
338             indent_printf("Route %lu:\n", i);
339 
340             IndentationLevel++;
341 
342             indent_printf("ire_dest:    %s (%lx)\n", AddressString, RouteEntries[i].ire_dest);
343             indent_printf("ire_index:   %lu\n", RouteEntries[i].ire_index);
344             indent_printf("ire_metric1: %#lx\n", RouteEntries[i].ire_metric1);
345             indent_printf("ire_metric2: %#lx\n", RouteEntries[i].ire_metric2);
346             indent_printf("ire_metric3: %#lx\n", RouteEntries[i].ire_metric3);
347             indent_printf("ire_metric4: %#lx\n", RouteEntries[i].ire_metric4);
348             Addr.S_un.S_addr = RouteEntries[i].ire_nexthop;
349             RtlIpv4AddressToStringA(&Addr, AddressString);
350             indent_printf("ire_nexthop: %s (%lx)\n", AddressString, RouteEntries[i].ire_nexthop);
351             indent_printf("ire_type:    %lu\n", RouteEntries[i].ire_type);
352             indent_printf("ire_proto:   %lu\n", RouteEntries[i].ire_proto);
353             indent_printf("ire_age:     %lu\n", RouteEntries[i].ire_age);
354             Addr.S_un.S_addr = RouteEntries[i].ire_mask;
355             RtlIpv4AddressToStringA(&Addr, AddressString);
356             indent_printf("ire_mask:    %s (%lx)\n", AddressString, RouteEntries[i].ire_mask);
357             indent_printf("ire_metric5: %lx\n", RouteEntries[i].ire_metric5);
358             indent_printf("ire_context: %lx\n", RouteEntries[i].ire_context);
359 
360             IndentationLevel--;
361         }
362     }
363 
364     IndentationLevel--;
365 }
366 
367 typedef struct ARPInfo
368 {
369     unsigned long ai_numroutes;
370     unsigned long ai_unknown;
371 } ARPInfo;
372 
373 typedef struct ARPEntry
374 {
375     unsigned long ae_index;
376     unsigned long ae_physaddrlen;
377     unsigned char ae_physaddr[MAX_PHYSADDR_SIZE];
378     unsigned long ae_address;
379     unsigned long ae_unknown;
380 } ARPEntry;
381 
382 static
383 void
test_AT_ARP_STATS(TDIEntityID Id,ULONG EntityType)384 test_AT_ARP_STATS(
385     TDIEntityID Id,
386     ULONG EntityType)
387 {
388     ARPInfo ArpInfo;
389     TCP_REQUEST_QUERY_INFORMATION_EX Request;
390     ULONG BufferSize = 0;
391     BOOL Result;
392 
393     /* Not valid for other entity types */
394     if (EntityType != AT_ARP)
395         return;
396 
397     ZeroMemory(&Request, sizeof(Request));
398     Request.ID.toi_entity = Id;
399     Request.ID.toi_class = INFO_CLASS_PROTOCOL;
400     Request.ID.toi_type = INFO_TYPE_PROVIDER;
401     Request.ID.toi_id = AT_MIB_ADDRXLAT_INFO_ID;
402 
403     Result = DeviceIoControl(
404         TcpFileHandle,
405         IOCTL_TCP_QUERY_INFORMATION_EX,
406         &Request,
407         sizeof(Request),
408         &ArpInfo,
409         sizeof(ArpInfo),
410         &BufferSize,
411         NULL);
412     ok(Result, "DeviceIoControl failed.\n");
413     ok_long(BufferSize, sizeof(ArpInfo));
414 
415     indent_printf("ARP Info:\n");
416     IndentationLevel++;
417 
418     indent_printf("ai_numroutes: %lu\n", ArpInfo.ai_numroutes);
419     indent_printf("ai_unknown:   %lx\n", ArpInfo.ai_unknown);
420 
421     if (ArpInfo.ai_numroutes)
422     {
423         ARPEntry* ArpEntries;
424         ULONG i;
425 
426         Request.ID.toi_id = AT_MIB_ADDRXLAT_ENTRY_ID;
427 
428         ArpEntries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ArpInfo.ai_numroutes * sizeof(ArpEntries[0]));
429         ok(ArpEntries != NULL, "\n");
430 
431         Result = DeviceIoControl(
432             TcpFileHandle,
433             IOCTL_TCP_QUERY_INFORMATION_EX,
434             &Request,
435             sizeof(Request),
436             ArpEntries,
437             ArpInfo.ai_numroutes * sizeof(ArpEntries[0]),
438             &BufferSize,
439             NULL);
440         ok(Result, "DeviceIoControl failed.\n");
441         ok_long(BufferSize, ArpInfo.ai_numroutes * sizeof(ArpEntries[0]));
442 
443         for (i = 0; i < ArpInfo.ai_numroutes; i++)
444         {
445             CHAR AddressString[16];
446             struct in_addr Addr;
447 
448             Addr.S_un.S_addr = ArpEntries[i].ae_address;
449             RtlIpv4AddressToStringA(&Addr, AddressString);
450 
451             indent_printf("ARP Entry %lu:\n", i);
452 
453             IndentationLevel++;
454 
455             indent_printf("ae_index:    %lu\n", ArpEntries[i].ae_index);
456             indent_printf("ae_physaddr: %s\n", dbg_print_physaddr(ArpEntries[i].ae_physaddr, ArpEntries[i].ae_physaddrlen));
457             indent_printf("ae_address:  %lx (%s)\n", ArpEntries[i].ae_address, AddressString);
458             indent_printf("ae_unknown:  %lu.\n", ArpEntries[i].ae_unknown);
459 
460             IndentationLevel--;
461         }
462 
463         HeapFree(GetProcessHeap(), 0, ArpEntries);
464     }
465 
466     IndentationLevel--;
467 }
468 
START_TEST(tcp_info)469 START_TEST(tcp_info)
470 {
471     TDIEntityID* Entities;
472     DWORD BufferSize;
473     BOOL Result;
474     ULONG i, EntityCount;
475     TCP_REQUEST_QUERY_INFORMATION_EX Request;
476 
477     /* Open a control channel file for TCP */
478     TcpFileHandle = CreateFileW(
479         L"\\\\.\\Tcp",
480         FILE_READ_DATA | FILE_WRITE_DATA,
481         FILE_SHARE_READ | FILE_SHARE_WRITE,
482         NULL,
483         OPEN_EXISTING,
484         0,
485         NULL);
486     ok(TcpFileHandle != INVALID_HANDLE_VALUE, "CreateFile failed, GLE %lu\n", GetLastError());
487 
488     /* Try the IOCTL */
489     BufferSize = 0;
490     Result = DeviceIoControl(
491         TcpFileHandle,
492         IOCTL_TCP_QUERY_INFORMATION_EX,
493         NULL,
494         0,
495         NULL,
496         0,
497         &BufferSize,
498         NULL);
499     ok(!Result, "DeviceIoControl succeeded.\n");
500     ok_long(GetLastError(), ERROR_INVALID_PARAMETER);
501     ok_long(BufferSize, 0);
502 
503     ZeroMemory(&Request, sizeof(Request));
504     Request.ID.toi_entity.tei_entity = GENERIC_ENTITY;
505     Request.ID.toi_entity.tei_instance = 0;
506     Request.ID.toi_class = INFO_CLASS_GENERIC;
507     Request.ID.toi_type = INFO_TYPE_PROVIDER;
508     Request.ID.toi_id = ENTITY_LIST_ID;
509 
510     BufferSize = 0;
511     Result = DeviceIoControl(
512         TcpFileHandle,
513         IOCTL_TCP_QUERY_INFORMATION_EX,
514         &Request,
515         sizeof(Request),
516         NULL,
517         0,
518         &BufferSize,
519         NULL);
520     ok(!Result, "DeviceIoControl succeeded.\n");
521     ok_long(GetLastError(), ERROR_INVALID_PARAMETER);
522     ok_long(BufferSize, 0);
523 
524     BufferSize = 4 * sizeof(Entities[0]);
525     Entities = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, BufferSize);
526     ok(Entities != NULL, "\n");
527 
528     while (TRUE)
529     {
530         Result = DeviceIoControl(
531             TcpFileHandle,
532             IOCTL_TCP_QUERY_INFORMATION_EX,
533             &Request,
534             sizeof(Request),
535             Entities,
536             BufferSize,
537             &BufferSize,
538             NULL);
539 
540         if (Result)
541             break;
542 
543         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
544             break;
545 
546         BufferSize *= 2;
547         Entities = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Entities, BufferSize);
548         ok(Entities != NULL, "\n");
549     }
550 
551     ok(Result, "DeviceIoControl failed!\n");
552     EntityCount = BufferSize / sizeof(Entities[0]);
553     trace("Got %lu entities.\n", EntityCount);
554 
555     for (i = 0; i < EntityCount; i++)
556     {
557         ULONG EntityType;
558 
559         /* Get the type */
560         Request.ID.toi_entity = Entities[i];
561         Request.ID.toi_class = INFO_CLASS_GENERIC;
562         Request.ID.toi_type = INFO_TYPE_PROVIDER;
563         Request.ID.toi_id = ENTITY_TYPE_ID;
564 
565         Result = DeviceIoControl(
566             TcpFileHandle,
567             IOCTL_TCP_QUERY_INFORMATION_EX,
568             &Request,
569             sizeof(Request),
570             &EntityType,
571             sizeof(EntityType),
572             &BufferSize,
573             NULL);
574         ok(Result, "DeviceIoControl failed.\n");
575 
576         printf("Entity %lu: %#lx, %#lx, type %#lx\n", i, Entities[i].tei_entity, Entities[i].tei_instance, EntityType);
577         test_IF_MIB_STATS(Entities[i], EntityType);
578         test_IP_MIB_STATS(Entities[i], EntityType);
579         test_AT_ARP_STATS(Entities[i], EntityType);
580     }
581 
582     HeapFree(GetProcessHeap(), 0, Entities);
583     CloseHandle(TcpFileHandle);
584 }
585