📄 tditest.c
字号:
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS TDI test driver
* FILE: tditest.c
* PURPOSE: Testing TDI drivers
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
* Vizzini (vizzini@plasmic.com)
* REVISIONS:
* CSH 01/08-2000 Created
* 26-Nov-2003 Vizzini Updated to run properly on Win2ksp4
*/
#include <tditest.h>
#ifdef DBG
/* See debug.h for debug/trace constants */
ULONG DebugTraceLevel = -1;
#endif /* DBG */
HANDLE TdiTransport = 0;
PFILE_OBJECT TdiTransportObject = NULL;
ULONG LocalAddress;
BOOLEAN OpenError;
KEVENT StopEvent;
HANDLE SendThread;
HANDLE ReceiveThread;
NTSTATUS TdiCall(
PIRP Irp,
PDEVICE_OBJECT DeviceObject,
PIO_STATUS_BLOCK IoStatusBlock,
BOOLEAN CanCancel)
/*
* FUNCTION: Calls a transport driver device
* ARGUMENTS:
* Irp = Pointer to I/O Request Packet
* DeviceObject = Pointer to device object to call
* IoStatusBlock = Address of buffer with I/O status block
* CanCancel = TRUE if the IRP can be cancelled, FALSE if not
* RETURNS:
* Status of operation
* NOTES
* All requests are completed synchronously. A request may be cancelled
*/
{
KEVENT Event;
PKEVENT Events[2];
NTSTATUS Status;
Events[0] = &StopEvent;
Events[1] = &Event;
KeInitializeEvent(&Event, NotificationEvent, FALSE);
Irp->UserEvent = &Event;
Irp->UserIosb = IoStatusBlock;
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
if (CanCancel)
{
Status = KeWaitForMultipleObjects(2, (PVOID)Events, WaitAny, Executive, KernelMode, FALSE, NULL, NULL);
if (KeReadStateEvent(&StopEvent) != 0)
{
if (IoCancelIrp(Irp))
{
TDI_DbgPrint(MAX_TRACE, ("Cancelled IRP.\n"));
}
else
{
TDI_DbgPrint(MIN_TRACE, ("Could not cancel IRP.\n"));
}
return STATUS_CANCELLED;
}
}
else
Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
}
return (Status == STATUS_SUCCESS)? IoStatusBlock->Status : STATUS_SUCCESS;
}
NTSTATUS TdiOpenDevice(
PWSTR Protocol,
ULONG EaLength,
PFILE_FULL_EA_INFORMATION EaInfo,
PHANDLE Handle,
PFILE_OBJECT *Object)
/*
* FUNCTION: Opens a device
* ARGUMENTS:
* Protocol = Pointer to buffer with name of device
* EaLength = Length of EA information
* EaInfo = Pointer to buffer with EA information
* Handle = Address of buffer to place device handle
* Object = Address of buffer to place device object
* RETURNS:
* Status of operation
*/
{
OBJECT_ATTRIBUTES Attr;
IO_STATUS_BLOCK Iosb;
UNICODE_STRING Name;
NTSTATUS Status;
RtlInitUnicodeString(&Name, Protocol);
InitializeObjectAttributes(
&Attr, /* Attribute buffer */
&Name, /* Device name */
OBJ_CASE_INSENSITIVE, /* Attributes */
NULL, /* Root directory */
NULL); /* Security descriptor */
Status = ZwCreateFile(
Handle, /* Return file handle */
GENERIC_READ | GENERIC_WRITE, /* Desired access */
&Attr, /* Object attributes */
&Iosb, /* IO status */
0, /* Initial allocation size */
FILE_ATTRIBUTE_NORMAL, /* File attributes */
FILE_SHARE_READ | FILE_SHARE_WRITE, /* Share access */
FILE_OPEN_IF, /* Create disposition */
0, /* Create options */
EaInfo, /* EA buffer */
EaLength); /* EA length */
if (NT_SUCCESS(Status))
{
Status = ObReferenceObjectByHandle(
*Handle, /* Handle to open file */
GENERIC_READ | GENERIC_WRITE, /* Access mode */
NULL, /* Object type */
KernelMode, /* Access mode */
(PVOID*)Object, /* Pointer to object */
NULL); /* Handle information */
if (!NT_SUCCESS(Status))
{
TDI_DbgPrint(MIN_TRACE, ("ObReferenceObjectByHandle() failed with status (0x%X).\n", Status));
ZwClose(*Handle);
}
}
else
{
TDI_DbgPrint(MIN_TRACE, ("ZwCreateFile() failed with status (0x%X)\n", Status));
}
return Status;
}
NTSTATUS TdiCloseDevice(
HANDLE Handle,
PFILE_OBJECT FileObject)
{
if (FileObject)
ObDereferenceObject(FileObject);
if (Handle)
ZwClose(Handle);
return STATUS_SUCCESS;
}
NTSTATUS TdiOpenTransport(
PWSTR Protocol,
USHORT Port,
PHANDLE Transport,
PFILE_OBJECT *TransportObject)
/*
* FUNCTION: Opens a transport driver
* ARGUMENTS:
* Protocol = Pointer to buffer with name of device
* Port = Port number to use
* Transport = Address of buffer to place transport device handle
* TransportObject = Address of buffer to place transport object
* RETURNS:
* Status of operation
*/
{
PFILE_FULL_EA_INFORMATION EaInfo;
PTA_IP_ADDRESS Address;
NTSTATUS Status;
ULONG EaLength;
/* EaName must be 0-termed, even though TDI_TRANSPORT_ADDRESS_LENGTH does *not* include the 0 */
EaLength = sizeof(FILE_FULL_EA_INFORMATION) + TDI_TRANSPORT_ADDRESS_LENGTH + sizeof(TA_IP_ADDRESS) + 1;
EaInfo = (PFILE_FULL_EA_INFORMATION)ExAllocatePool(NonPagedPool, EaLength);
if (!EaInfo)
{
TDI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(EaInfo, EaLength);
EaInfo->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
/* don't copy the 0; we have already zeroed it */
RtlCopyMemory(EaInfo->EaName, TdiTransportAddress, TDI_TRANSPORT_ADDRESS_LENGTH);
EaInfo->EaValueLength = sizeof(TA_IP_ADDRESS);
Address = (PTA_IP_ADDRESS)(EaInfo->EaName + TDI_TRANSPORT_ADDRESS_LENGTH + 1); // 0-term
Address->TAAddressCount = 1;
Address->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
Address->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
Address->Address[0].Address[0].sin_port = WH2N(Port);
Address->Address[0].Address[0].in_addr = 0;
Status = TdiOpenDevice(Protocol, EaLength, EaInfo, Transport, TransportObject);
ExFreePool(EaInfo);
return Status;
}
NTSTATUS TdiQueryDeviceControl(
PFILE_OBJECT FileObject,
ULONG IoControlCode,
PVOID InputBuffer,
ULONG InputBufferLength,
PVOID OutputBuffer,
ULONG OutputBufferLength,
PULONG Return)
/*
* FUNCTION: Queries a device for information
* ARGUMENTS:
* FileObject = Pointer to device object
* IoControlCode = I/O control code
* InputBuffer = Pointer to buffer with input data
* InputBufferLength = Length of InputBuffer
* OutputBuffer = Address of buffer to place output data
* OutputBufferLength = Length of OutputBuffer
* RETURNS:
* Status of operation
*/
{
PDEVICE_OBJECT DeviceObject;
PIO_STACK_LOCATION IoStack;
IO_STATUS_BLOCK Iosb;
NTSTATUS Status;
PIRP Irp;
DeviceObject = IoGetRelatedDeviceObject(FileObject);
Irp = IoBuildDeviceIoControlRequest(IoControlCode, DeviceObject, InputBuffer, InputBufferLength, OutputBuffer,
OutputBufferLength, FALSE, NULL, NULL);
if (!Irp)
{
TDI_DbgPrint(MIN_TRACE, ("IoBuildDeviceIoControlRequest() failed.\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
IoStack = IoGetNextIrpStackLocation(Irp);
IoStack->DeviceObject = DeviceObject;
IoStack->FileObject = FileObject;
Status = TdiCall(Irp, DeviceObject, &Iosb, FALSE);
if (Return)
*Return = Iosb.Information;
return Status;
}
NTSTATUS TdiQueryInformationEx(
PFILE_OBJECT FileObject,
ULONG Entity,
ULONG Instance,
ULONG Class,
ULONG Type,
ULONG Id,
PVOID OutputBuffer,
PULONG OutputLength)
/*
* FUNCTION: Extended query for information
* ARGUMENTS:
* FileObject = Pointer to transport object
* Entity = Entity
* Instance = Instance
* Class = Entity class
* Type = Entity type
* Id = Entity id
* OutputBuffer = Address of buffer to place data
* OutputLength = Address of buffer with length of OutputBuffer (updated)
* RETURNS:
* Status of operation
*/
{
TCP_REQUEST_QUERY_INFORMATION_EX QueryInfo;
RtlZeroMemory(&QueryInfo, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
QueryInfo.ID.toi_entity.tei_entity = Entity;
QueryInfo.ID.toi_entity.tei_instance = Instance;
QueryInfo.ID.toi_class = Class;
QueryInfo.ID.toi_type = Type;
QueryInfo.ID.toi_id = Id;
return TdiQueryDeviceControl(
FileObject, /* Transport/connection object */
IOCTL_TCP_QUERY_INFORMATION_EX, /* Control code */
&QueryInfo, /* Input buffer */
sizeof(TCP_REQUEST_QUERY_INFORMATION_EX), /* Input buffer length */
OutputBuffer, /* Output buffer */
*OutputLength, /* Output buffer length */
OutputLength); /* Return information */
}
NTSTATUS TdiQueryAddress(
PFILE_OBJECT FileObject,
PULONG Address)
/*
* FUNCTION: Queries for a local IP address
* ARGUMENTS:
* FileObject = Pointer to file object
* Address = Address of buffer to place local address
* RETURNS:
* Status of operation
*/
{
ULONG i;
TDIEntityID *Entities;
ULONG EntityCount;
ULONG EntityType;
IPSNMP_INFO SnmpInfo;
PIPADDR_ENTRY IpAddress;
ULONG BufferSize;
NTSTATUS Status = STATUS_SUCCESS;
TDI_DbgPrint(MAX_TRACE, ("Called\n"));
BufferSize = sizeof(TDIEntityID) * 20;
Entities = (TDIEntityID*)ExAllocatePool(NonPagedPool, BufferSize);
if (!Entities)
{
TDI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Query device for supported entities */
Status = TdiQueryInformationEx(
FileObject, /* File object */
GENERIC_ENTITY, /* Entity */
TL_INSTANCE, /* Instance */
INFO_CLASS_GENERIC, /* Entity class */
INFO_TYPE_PROVIDER, /* Entity type */
ENTITY_LIST_ID, /* Entity id */
Entities, /* Output buffer */
&BufferSize); /* Output buffer size */
if (!NT_SUCCESS(Status))
{
TDI_DbgPrint(MIN_TRACE, ("Unable to get list of supported entities (Status = 0x%X).\n", Status));
ExFreePool(Entities);
return Status;
}
/* Locate an IP entity */
EntityCount = BufferSize / sizeof(TDIEntityID);
TDI_DbgPrint(MAX_TRACE, ("EntityCount = %d\n", EntityCount));
for (i = 0; i < EntityCount; i++)
{
if (Entities[i].tei_entity == CL_NL_ENTITY)
{
/* Query device for entity type */
BufferSize = sizeof(EntityType);
Status = TdiQueryInformationEx(
FileObject, /* File object */
CL_NL_ENTITY, /* Entity */
Entities[i].tei_instance, /* Instance */
INFO_CLASS_GENERIC, /* Entity class */
INFO_TYPE_PROVIDER, /* Entity type */
ENTITY_TYPE_ID, /* Entity id */
&EntityType, /* Output buffer */
&BufferSize); /* Output buffer size */
if (!NT_SUCCESS(Status) || (EntityType != CL_NL_IP))
{
TDI_DbgPrint(MIN_TRACE, ("Unable to get entity of type IP (Status = 0x%X).\n", Status));
break;
}
/* Query device for SNMP information */
BufferSize = sizeof(SnmpInfo);
Status = TdiQueryInformationEx(
FileObject, /* File object */
CL_NL_ENTITY, /* Entity */
Entities[i].tei_instance, /* Instance */
INFO_CLASS_PROTOCOL, /* Entity class */
INFO_TYPE_PROVIDER, /* Entity type */
IP_MIB_STATS_ID, /* Entity id */
&SnmpInfo, /* Output buffer */
&BufferSize); /* Output buffer size */
if (!NT_SUCCESS(Status) || (SnmpInfo.NumAddr == 0))
{
TDI_DbgPrint(MIN_TRACE, ("Unable to get SNMP information or no IP addresses available (Status = 0x%X).\n", Status));
break;
}
/* Query device for all IP addresses */
if (SnmpInfo.NumAddr != 0)
{
BufferSize = SnmpInfo.NumAddr * sizeof(IPADDR_ENTRY);
IpAddress = (PIPADDR_ENTRY)ExAllocatePool(NonPagedPool, BufferSize);
if (!IpAddress)
{
TDI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
break;
}
Status = TdiQueryInformationEx(
FileObject, /* File object */
CL_NL_ENTITY, /* Entity */
Entities[i].tei_instance, /* Instance */
INFO_CLASS_PROTOCOL, /* Entity class */
INFO_TYPE_PROVIDER, /* Entity type */
IP_MIB_ADDRTABLE_ENTRY_ID, /* Entity id */
IpAddress, /* Output buffer */
&BufferSize); /* Output buffer size */
if (!NT_SUCCESS(Status))
{
TDI_DbgPrint(MIN_TRACE, ("Unable to get IP address (Status = 0x%X).\n", Status));
ExFreePool(IpAddress);
break;
}
if (SnmpInfo.NumAddr != 1)
{
/* Skip loopback address */
*Address = DN2H(((PIPADDR_ENTRY)((ULONG)IpAddress + sizeof(IPADDR_ENTRY)))->Addr);
}
else
{
/* Select the first address returned */
*Address = DN2H(IpAddress->Addr);
}
ExFreePool(IpAddress);
}
else
{
Status = STATUS_UNSUCCESSFUL;
break;
}
}
}
ExFreePool(Entities);
TDI_DbgPrint(MAX_TRACE, ("Leaving\n"));
return Status;
}
NTSTATUS TdiSendDatagram(
PFILE_OBJECT TransportObject,
USHORT Port,
ULONG Address,
PVOID Buffer,
ULONG BufferSize)
/*
* FUNCTION: Sends a datagram
* ARGUMENTS:
* TransportObject = Pointer to transport object
* Port = Remote port
* Address = Remote address
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -