/* * 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 */ #include #include #include #include #include #include #include /* FIXME */ #define AT_MIB_ADDRXLAT_INFO_ID 1 #define AT_MIB_ADDRXLAT_ENTRY_ID 0x101 /* 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: %s\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); }