mirror of
https://github.com/reactos/reactos.git
synced 2024-08-24 20:28:57 +00:00
273 lines
8.2 KiB
C
273 lines
8.2 KiB
C
/*
|
|
* PROJECT: ReactOS kernel-mode tests
|
|
* LICENSE: LGPLv2+ - See COPYING.LIB in the top level directory
|
|
* PURPOSE: Kernel-Mode Test Suite for TCPIP.sys
|
|
* PROGRAMMER: Jérôme Gardou <jerome.gardou@reactos.org>
|
|
*/
|
|
|
|
#include <kmt_test.h>
|
|
#include <tdikrnl.h>
|
|
#include <ndk/rtlfuncs.h>
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include "tcpip.h"
|
|
|
|
#define TAG_TEST 'tseT'
|
|
|
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
|
USHORT
|
|
htons(USHORT x)
|
|
{
|
|
return ((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8);
|
|
}
|
|
#else
|
|
#define htons(x) (x)
|
|
#endif
|
|
|
|
static
|
|
NTSTATUS
|
|
NTAPI
|
|
IrpCompletionRoutine(
|
|
_In_ PDEVICE_OBJECT DeviceObject,
|
|
_In_ PIRP Irp,
|
|
_In_ PVOID Context)
|
|
{
|
|
UNREFERENCED_PARAMETER(DeviceObject);
|
|
UNREFERENCED_PARAMETER(Irp);
|
|
|
|
KeSetEvent((PKEVENT)Context, IO_NETWORK_INCREMENT, FALSE);
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
static
|
|
VOID
|
|
TestTcpConnect(void)
|
|
{
|
|
PIRP Irp;
|
|
HANDLE AddressHandle, ConnectionHandle;
|
|
FILE_OBJECT* ConnectionFileObject;
|
|
DEVICE_OBJECT* DeviceObject;
|
|
UNICODE_STRING TcpDeviceName = RTL_CONSTANT_STRING(L"\\Device\\Tcp");
|
|
NTSTATUS Status;
|
|
PFILE_FULL_EA_INFORMATION FileInfo;
|
|
TA_IP_ADDRESS* IpAddress;
|
|
TA_IP_ADDRESS ConnectAddress, ReturnAddress;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
IO_STATUS_BLOCK StatusBlock;
|
|
ULONG FileInfoSize;
|
|
IN_ADDR InAddr;
|
|
LPCWSTR AddressTerminator;
|
|
CONNECTION_CONTEXT ConnectionContext = (CONNECTION_CONTEXT)0xC0CAC01A;
|
|
KEVENT Event;
|
|
TDI_CONNECTION_INFORMATION RequestInfo, ReturnInfo;
|
|
|
|
/* Create a TCP address file */
|
|
FileInfoSize = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[TDI_TRANSPORT_ADDRESS_LENGTH]) + 1 + sizeof(TA_IP_ADDRESS);
|
|
FileInfo = ExAllocatePoolWithTag(NonPagedPool,
|
|
FileInfoSize,
|
|
TAG_TEST);
|
|
ok(FileInfo != NULL, "");
|
|
RtlZeroMemory(FileInfo, FileInfoSize);
|
|
|
|
FileInfo->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
|
|
FileInfo->EaValueLength = sizeof(TA_IP_ADDRESS);
|
|
RtlCopyMemory(&FileInfo->EaName[0], TdiTransportAddress, TDI_TRANSPORT_ADDRESS_LENGTH);
|
|
|
|
IpAddress = (PTA_IP_ADDRESS)(&FileInfo->EaName[TDI_TRANSPORT_ADDRESS_LENGTH + 1]);
|
|
IpAddress->TAAddressCount = 1;
|
|
IpAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
|
|
IpAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
|
|
IpAddress->Address[0].Address[0].sin_port = htons(TEST_CONNECT_CLIENT_PORT);
|
|
Status = RtlIpv4StringToAddressW(L"127.0.0.1", TRUE, &AddressTerminator, &InAddr);
|
|
ok_eq_hex(Status, STATUS_SUCCESS);
|
|
IpAddress->Address[0].Address[0].in_addr = InAddr.S_un.S_addr;
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&TcpDeviceName,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = ZwCreateFile(
|
|
&AddressHandle,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
&ObjectAttributes,
|
|
&StatusBlock,
|
|
0,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OPEN_IF,
|
|
0L,
|
|
FileInfo,
|
|
FileInfoSize);
|
|
ok_eq_hex(Status, STATUS_SUCCESS);
|
|
|
|
ExFreePoolWithTag(FileInfo, TAG_TEST);
|
|
|
|
/* Create a TCP connection file */
|
|
FileInfoSize = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[TDI_CONNECTION_CONTEXT_LENGTH]) + 1 + sizeof(CONNECTION_CONTEXT);
|
|
FileInfo = ExAllocatePoolWithTag(NonPagedPool,
|
|
FileInfoSize,
|
|
TAG_TEST);
|
|
ok(FileInfo != NULL, "");
|
|
RtlZeroMemory(FileInfo, FileInfoSize);
|
|
|
|
FileInfo->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
|
|
FileInfo->EaValueLength = sizeof(CONNECTION_CONTEXT);
|
|
RtlCopyMemory(&FileInfo->EaName[0], TdiConnectionContext, TDI_CONNECTION_CONTEXT_LENGTH);
|
|
*((CONNECTION_CONTEXT*)&FileInfo->EaName[TDI_CONNECTION_CONTEXT_LENGTH + 1]) = ConnectionContext;
|
|
|
|
Status = ZwCreateFile(
|
|
&ConnectionHandle,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
&ObjectAttributes,
|
|
&StatusBlock,
|
|
0,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OPEN_IF,
|
|
0L,
|
|
FileInfo,
|
|
FileInfoSize);
|
|
ok_eq_hex(Status, STATUS_SUCCESS);
|
|
|
|
ExFreePoolWithTag(FileInfo, TAG_TEST);
|
|
|
|
/* Get the file and device object for the upcoming IRPs */
|
|
Status = ObReferenceObjectByHandle(
|
|
ConnectionHandle,
|
|
GENERIC_READ,
|
|
*IoFileObjectType,
|
|
KernelMode,
|
|
(PVOID*)&ConnectionFileObject,
|
|
NULL);
|
|
ok_eq_hex(Status, STATUS_SUCCESS);
|
|
DeviceObject = IoGetRelatedDeviceObject(ConnectionFileObject);
|
|
ok(DeviceObject != NULL, "Device object is NULL!\n");
|
|
|
|
/* Associate the connection file and the address */
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
|
|
ok(Irp != NULL, "IoAllocateIrp failed.\n");
|
|
|
|
TdiBuildAssociateAddress(Irp, DeviceObject, ConnectionFileObject, NULL, NULL, AddressHandle);
|
|
IoSetCompletionRoutine(Irp, IrpCompletionRoutine, &Event, TRUE, TRUE, TRUE);
|
|
|
|
Status = IoCallDriver(DeviceObject, Irp);
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
trace("Associate address IRP is pending.\n");
|
|
KeWaitForSingleObject(
|
|
&Event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
Status = Irp->IoStatus.Status;
|
|
}
|
|
ok_eq_hex(Status, STATUS_SUCCESS);
|
|
IoFreeIrp(Irp);
|
|
|
|
|
|
KeClearEvent(&Event);
|
|
|
|
/* Build the connect IRP. */
|
|
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
|
|
ok(Irp != NULL, "IoAllocateIrp failed.\n");
|
|
|
|
/* Prepare the request */
|
|
RtlZeroMemory(&RequestInfo, sizeof(RequestInfo));
|
|
RtlZeroMemory(&ConnectAddress, sizeof(ConnectAddress));
|
|
RequestInfo.RemoteAddressLength = sizeof(TA_IP_ADDRESS);
|
|
RequestInfo.RemoteAddress = &ConnectAddress;
|
|
ConnectAddress.TAAddressCount = 1;
|
|
ConnectAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
|
|
ConnectAddress.Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
|
|
ConnectAddress.Address[0].Address[0].sin_port = htons(TEST_CONNECT_SERVER_PORT);
|
|
Status = RtlIpv4StringToAddressW(L"127.0.0.1", TRUE, &AddressTerminator, &InAddr);
|
|
ConnectAddress.Address[0].Address[0].in_addr = InAddr.S_un.S_addr;
|
|
|
|
/* See what we will get in exchange */
|
|
RtlZeroMemory(&ReturnInfo, sizeof(ReturnInfo));
|
|
RtlZeroMemory(&ReturnAddress, sizeof(ReturnAddress));
|
|
ReturnInfo.RemoteAddressLength = sizeof(TA_IP_ADDRESS);
|
|
ReturnInfo.RemoteAddress = &ReturnAddress;
|
|
|
|
TdiBuildConnect(Irp,
|
|
DeviceObject,
|
|
ConnectionFileObject,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&RequestInfo,
|
|
&ReturnInfo);
|
|
IoSetCompletionRoutine(Irp, IrpCompletionRoutine, &Event, TRUE, TRUE, TRUE);
|
|
|
|
Status = IoCallDriver(DeviceObject, Irp);
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
trace("Connect IRP is pending.\n");
|
|
KeWaitForSingleObject(
|
|
&Event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
Status = Irp->IoStatus.Status;
|
|
trace("Connect IRP completed.\n");
|
|
}
|
|
ok_eq_hex(Status, STATUS_SUCCESS);
|
|
IoFreeIrp(Irp);
|
|
|
|
/* The IRP doesn't touch the return info */
|
|
ok_eq_long(ReturnInfo.RemoteAddressLength, sizeof(TA_IP_ADDRESS));
|
|
ok_eq_pointer(ReturnInfo.RemoteAddress, &ReturnAddress);
|
|
ok_eq_long(ReturnInfo.OptionsLength, 0);
|
|
ok_eq_pointer(ReturnInfo.Options, NULL);
|
|
ok_eq_long(ReturnInfo.UserDataLength, 0);
|
|
ok_eq_pointer(ReturnInfo.UserData, NULL);
|
|
|
|
ok_eq_long(ReturnAddress.TAAddressCount, 0);
|
|
ok_eq_hex(ReturnAddress.Address[0].AddressType, 0);
|
|
ok_eq_hex(ReturnAddress.Address[0].AddressLength, 0);
|
|
ok_eq_hex(ReturnAddress.Address[0].Address[0].sin_port, 0);
|
|
ok_eq_hex(ReturnAddress.Address[0].Address[0].in_addr, 0);
|
|
|
|
ObDereferenceObject(ConnectionFileObject);
|
|
|
|
ZwClose(ConnectionHandle);
|
|
ZwClose(AddressHandle);
|
|
}
|
|
|
|
static KSTART_ROUTINE RunTest;
|
|
static
|
|
VOID
|
|
NTAPI
|
|
RunTest(
|
|
_In_ PVOID Context)
|
|
{
|
|
UNREFERENCED_PARAMETER(Context);
|
|
|
|
TestTcpConnect();
|
|
}
|
|
|
|
KMT_MESSAGE_HANDLER TestConnect;
|
|
NTSTATUS
|
|
TestConnect(
|
|
_In_ PDEVICE_OBJECT DeviceObject,
|
|
_In_ ULONG ControlCode,
|
|
_In_opt_ PVOID Buffer,
|
|
_In_ SIZE_T InLength,
|
|
_Inout_ PSIZE_T OutLength
|
|
)
|
|
{
|
|
PKTHREAD Thread;
|
|
|
|
Thread = KmtStartThread(RunTest, NULL);
|
|
KmtFinishThread(Thread, NULL);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|