1118 lines
27 KiB
C
1118 lines
27 KiB
C
/*************************************************************************
|
|
* tdlib.c
|
|
*
|
|
* TDI library functions.
|
|
*
|
|
* Copyright 1998 Microsoft
|
|
*************************************************************************/
|
|
|
|
/*
|
|
* Includes
|
|
*/
|
|
#include <ntddk.h>
|
|
#include <tdi.h>
|
|
#include <tdikrnl.h>
|
|
|
|
#include "tdtdi.h"
|
|
|
|
#include <winstaw.h>
|
|
#define _DEFCHARINFO_
|
|
#include <icadd.h>
|
|
#include <ctxdd.h>
|
|
#include <sdapi.h>
|
|
|
|
#include <td.h>
|
|
|
|
|
|
#define _TDI_POLL_TIMEOUT (30 * 1000) // 30 seconds
|
|
#define _TDI_CONNECT_TIMEOUT 45
|
|
#define _TDI_DISCONNECT_TIMEOUT 60
|
|
|
|
#if DBG
|
|
ULONG
|
|
DbgPrint(
|
|
PCH Format,
|
|
...
|
|
);
|
|
#define DBGPRINT(x) DbgPrint x
|
|
#if DBGTRACE
|
|
#define TRACE0(x) DbgPrint x
|
|
#define TRACE1(x) DbgPrint x
|
|
#else
|
|
#define TRACE0(x)
|
|
#define TRACE1(x)
|
|
#endif
|
|
#else
|
|
#define DBGPRINT(x)
|
|
#define TRACE0(x)
|
|
#define TRACE1(x)
|
|
#endif
|
|
|
|
/*
|
|
* To use TDI:
|
|
*
|
|
* To connect to a remote server:
|
|
*
|
|
* Create Address EndPoint
|
|
*
|
|
* Create Connection Object
|
|
*
|
|
* Associate the Address EndPoint with the Connection Object
|
|
*
|
|
* Do a Connect
|
|
*
|
|
* To receive connections:
|
|
*
|
|
* Create Address EndPoint
|
|
*
|
|
* Create Connection Object
|
|
*
|
|
* Associate the Address EndPoint with the Connection Object
|
|
*
|
|
* Listen for a connection.
|
|
*
|
|
* Return connection
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
* Global data
|
|
*/
|
|
|
|
//
|
|
// Wait for xx seconds before polling on thread deletion.
|
|
//
|
|
|
|
ULONG
|
|
_TdiPollTimeout = _TDI_POLL_TIMEOUT;
|
|
|
|
/*
|
|
* Forward references
|
|
*/
|
|
|
|
PIRP
|
|
_TdiAllocateIrp(
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PDEVICE_OBJECT DeviceObject OPTIONAL
|
|
);
|
|
|
|
NTSTATUS
|
|
_TdiRequestComplete (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Ctx
|
|
);
|
|
|
|
NTSTATUS
|
|
_TdiSetEventHandler (
|
|
IN PTD pTd,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PFILE_OBJECT FileObject,
|
|
IN ULONG EventType,
|
|
IN PVOID EventHandler,
|
|
IN PVOID EventContext
|
|
);
|
|
|
|
NTSTATUS
|
|
_TdiSubmitRequest (
|
|
IN PTD pTd,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN BOOLEAN bKeepLock
|
|
);
|
|
|
|
/*
|
|
* External references
|
|
*/
|
|
NTSTATUS MemoryAllocate( ULONG, PVOID * );
|
|
VOID MemoryFree( PVOID );
|
|
|
|
BOOLEAN
|
|
PsIsThreadTerminating(
|
|
IN PETHREAD Thread
|
|
);
|
|
|
|
|
|
/*
|
|
* Functions
|
|
*/
|
|
|
|
NTSTATUS
|
|
_TdiCreateAddress (
|
|
IN PUNICODE_STRING pTransportName,
|
|
IN PVOID TdiAddress,
|
|
IN ULONG TdiAddressLength,
|
|
OUT PHANDLE pHandle,
|
|
OUT PFILE_OBJECT *ppFileObject,
|
|
OUT PDEVICE_OBJECT *ppDeviceObject
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
OBJECT_ATTRIBUTES AddressAttributes;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
PFILE_FULL_EA_INFORMATION EABuffer;
|
|
PDEVICE_OBJECT DeviceObject;
|
|
HANDLE TdiHandle = NULL;
|
|
PFILE_OBJECT FileObject = NULL;
|
|
|
|
/*
|
|
* The TDI interfaces uses an EA of name "TdiTransportName"
|
|
* to specify the structure TA_ADDRESS.
|
|
*/
|
|
Status = MemoryAllocate( (sizeof(FILE_FULL_EA_INFORMATION)-1 +
|
|
TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
|
|
TdiAddressLength), &EABuffer);
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
EABuffer->NextEntryOffset = 0;
|
|
EABuffer->Flags = 0;
|
|
EABuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
|
|
EABuffer->EaValueLength = (USHORT)TdiAddressLength;
|
|
|
|
// Copy in the EA name
|
|
RtlCopyMemory(EABuffer->EaName, TdiTransportAddress, EABuffer->EaNameLength+1);
|
|
|
|
// Copy the TA_ADDRESS parameter
|
|
RtlCopyMemory(&EABuffer->EaName[TDI_TRANSPORT_ADDRESS_LENGTH+1], TdiAddress,
|
|
EABuffer->EaValueLength);
|
|
|
|
TRACE0(("TdiCreateAddress Create endpoint of %wZ\n",pTransportName));
|
|
|
|
InitializeObjectAttributes (
|
|
&AddressAttributes,
|
|
pTransportName,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE ,
|
|
NULL, // RootDirectory
|
|
NULL // SecurityDescriptor
|
|
);
|
|
|
|
Status = ZwCreateFile(
|
|
&TdiHandle, // Handle
|
|
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
|
|
&AddressAttributes, // Object Attributes
|
|
&IoStatusBlock, // Final I/O status block
|
|
NULL, // Allocation Size
|
|
FILE_ATTRIBUTE_NORMAL, // Normal attributes
|
|
0, // Sharing attributes
|
|
FILE_OPEN_IF, // Create disposition
|
|
0, // CreateOptions
|
|
EABuffer, // EA Buffer
|
|
FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) +
|
|
TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
|
|
TdiAddressLength // EA length
|
|
);
|
|
|
|
MemoryFree(EABuffer);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
DBGPRINT(("TdiCreateAddress: Error Status 0x%x from function\n",Status));
|
|
return( Status );
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status = IoStatusBlock.Status)) {
|
|
DBGPRINT(("TdiCreateAddress: Error Status 0x%x from Iosb\n",Status));
|
|
return( Status );
|
|
}
|
|
|
|
//
|
|
// Obtain a referenced pointer to the file object.
|
|
//
|
|
Status = ObReferenceObjectByHandle (
|
|
TdiHandle,
|
|
0,
|
|
*IoFileObjectType,
|
|
KernelMode,
|
|
(PVOID *)&FileObject,
|
|
NULL
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
DBGPRINT(("TdiCreateAddress: Error Status 0x%x Referencing FileObject\n",Status));
|
|
goto error_cleanup;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Get the address of the device object for the endpoint.
|
|
//
|
|
|
|
DeviceObject = IoGetRelatedDeviceObject(FileObject);
|
|
|
|
// Copy the out parameters
|
|
*pHandle = TdiHandle;
|
|
*ppFileObject = FileObject;
|
|
*ppDeviceObject = DeviceObject;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
error_cleanup:
|
|
|
|
if ( FileObject != NULL ) {
|
|
ObDereferenceObject( FileObject );
|
|
}
|
|
|
|
if ( TdiHandle != NULL ) {
|
|
ZwClose( TdiHandle );
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
_TdiOpenConnection (
|
|
IN PUNICODE_STRING pTransportName,
|
|
IN PVOID ConnectionContext,
|
|
OUT PHANDLE pHandle,
|
|
OUT PFILE_OBJECT *ppFileObject,
|
|
OUT PDEVICE_OBJECT *ppDeviceObject
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
OBJECT_ATTRIBUTES AddressAttributes;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
PFILE_FULL_EA_INFORMATION EABuffer;
|
|
CONNECTION_CONTEXT UNALIGNED *ContextPointer;
|
|
PDEVICE_OBJECT DeviceObject;
|
|
HANDLE ConnHandle = NULL;
|
|
PFILE_OBJECT FileObject = NULL;
|
|
|
|
Status = MemoryAllocate( (sizeof(FILE_FULL_EA_INFORMATION)-1 +
|
|
TDI_CONNECTION_CONTEXT_LENGTH+1 +
|
|
sizeof(CONNECTION_CONTEXT)), &EABuffer);
|
|
|
|
if( !NT_SUCCESS(Status) ) {
|
|
return( Status );
|
|
}
|
|
|
|
EABuffer->NextEntryOffset = 0;
|
|
EABuffer->Flags = 0;
|
|
EABuffer->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
|
|
EABuffer->EaValueLength = sizeof(CONNECTION_CONTEXT);
|
|
|
|
// Copy in the EA name
|
|
RtlCopyMemory(EABuffer->EaName, TdiConnectionContext, TDI_CONNECTION_CONTEXT_LENGTH+1);
|
|
|
|
// Copy in the EA data
|
|
ContextPointer =
|
|
(CONNECTION_CONTEXT UNALIGNED *)&EABuffer->EaName[TDI_CONNECTION_CONTEXT_LENGTH+1];
|
|
*ContextPointer = ConnectionContext;
|
|
|
|
TRACE0(("_TdiOpenConnection: Create connection object on transport %wZ\n",pTransportName));
|
|
|
|
InitializeObjectAttributes (&AddressAttributes,
|
|
pTransportName, // Name
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE , // Attributes
|
|
NULL, // RootDirectory
|
|
NULL); // SecurityDescriptor
|
|
|
|
Status = ZwCreateFile(&ConnHandle, // Handle
|
|
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
|
|
&AddressAttributes, // Object Attributes
|
|
&IoStatusBlock, // Final I/O status block
|
|
NULL, // Allocation Size
|
|
FILE_ATTRIBUTE_NORMAL, // Normal attributes
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, // Sharing attributes
|
|
FILE_OPEN_IF, // Create disposition
|
|
0, // CreateOptions
|
|
EABuffer, // EA Buffer
|
|
sizeof(FILE_FULL_EA_INFORMATION) +
|
|
TDI_CONNECTION_CONTEXT_LENGTH + 1 +
|
|
sizeof(CONNECTION_CONTEXT));
|
|
|
|
|
|
MemoryFree(EABuffer);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
DBGPRINT(("_TdiOpenConnection: Error 0x%x Creating Connection object\n",Status));
|
|
return(Status);
|
|
}
|
|
|
|
Status = IoStatusBlock.Status;
|
|
if (!NT_SUCCESS(Status)) {
|
|
DBGPRINT(("_TdiOpenConnection: Error 0x%x Creating Connection object in Iosb\n",Status));
|
|
return(Status);
|
|
}
|
|
|
|
TRACE0(("_TdiOpenConnection: Returning connection handle %lx\n", ConnHandle));
|
|
|
|
|
|
//
|
|
// Obtain a referenced pointer to the file object.
|
|
//
|
|
Status = ObReferenceObjectByHandle (
|
|
ConnHandle,
|
|
0,
|
|
*IoFileObjectType,
|
|
KernelMode,
|
|
(PVOID *)&FileObject,
|
|
NULL
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
DBGPRINT(("_TdiOpenConnection: Error Status 0x%x Referencing FileObject\n",Status));
|
|
ZwClose( ConnHandle );
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Get the address of the device object for the endpoint.
|
|
//
|
|
|
|
DeviceObject = IoGetRelatedDeviceObject(FileObject);
|
|
|
|
// Copy the out parameters
|
|
*pHandle = ConnHandle;
|
|
*ppFileObject = FileObject;
|
|
*ppDeviceObject = DeviceObject;
|
|
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
_TdiListen(
|
|
IN PTD pTd,
|
|
IN PIRP Irp OPTIONAL,
|
|
IN PFILE_OBJECT ConnectionFileObject,
|
|
IN PDEVICE_OBJECT ConnectionDeviceObject
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
BOOLEAN IrpAllocated = FALSE;
|
|
TDI_CONNECTION_INFORMATION RequestInfo;
|
|
TDI_CONNECTION_INFORMATION ReturnInfo;
|
|
|
|
if (!ARGUMENT_PRESENT(Irp)) {
|
|
|
|
Irp = _TdiAllocateIrp( ConnectionFileObject, ConnectionDeviceObject );
|
|
if (Irp == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
return Status;
|
|
}
|
|
|
|
IrpAllocated = TRUE;
|
|
}
|
|
|
|
RtlZeroMemory( &RequestInfo, sizeof(RequestInfo) );
|
|
RtlZeroMemory( &ReturnInfo, sizeof(ReturnInfo) );
|
|
|
|
TdiBuildListen(
|
|
Irp,
|
|
ConnectionDeviceObject,
|
|
ConnectionFileObject,
|
|
NULL, // Completion routine
|
|
NULL, // Context
|
|
0, // Flags
|
|
&RequestInfo,
|
|
&ReturnInfo
|
|
);
|
|
|
|
Status = _TdiSubmitRequest(pTd, ConnectionDeviceObject, Irp, FALSE);
|
|
|
|
TRACE0(("_TdiListen: Status 0x%x\n",Status));
|
|
|
|
if (IrpAllocated) {
|
|
IoFreeIrp( Irp );
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
_TdiAccept(
|
|
IN PTD pTd,
|
|
IN PIRP Irp OPTIONAL,
|
|
IN PFILE_OBJECT ConnectionFileObject,
|
|
IN PDEVICE_OBJECT ConnectionDeviceObject
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
BOOLEAN IrpAllocated = FALSE;
|
|
TDI_CONNECTION_INFORMATION RequestInfo;
|
|
TDI_CONNECTION_INFORMATION ReturnInfo;
|
|
|
|
if (!ARGUMENT_PRESENT(Irp)) {
|
|
|
|
Irp = _TdiAllocateIrp( ConnectionFileObject, ConnectionDeviceObject );
|
|
if (Irp == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
return Status;
|
|
}
|
|
|
|
IrpAllocated = TRUE;
|
|
}
|
|
|
|
RtlZeroMemory( &RequestInfo, sizeof(RequestInfo) );
|
|
RtlZeroMemory( &ReturnInfo, sizeof(ReturnInfo) );
|
|
|
|
TdiBuildAccept(
|
|
Irp,
|
|
ConnectionDeviceObject,
|
|
ConnectionFileObject,
|
|
NULL, // Completion routine
|
|
NULL, // Context
|
|
&RequestInfo,
|
|
&ReturnInfo
|
|
);
|
|
|
|
Status = _TdiSubmitRequest(pTd, ConnectionDeviceObject, Irp, FALSE);
|
|
|
|
if (IrpAllocated) {
|
|
IoFreeIrp( Irp );
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
_TdiConnect(
|
|
IN PTD pTd,
|
|
IN PIRP Irp OPTIONAL,
|
|
IN PLARGE_INTEGER pTimeout OPTIONAL,
|
|
IN PFILE_OBJECT ConnectionFileObject,
|
|
IN PDEVICE_OBJECT ConnectionDeviceObject,
|
|
IN ULONG RemoteTransportAddressLength,
|
|
IN PTRANSPORT_ADDRESS pRemoteTransportAddress
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
BOOLEAN IrpAllocated = FALSE;
|
|
TDI_CONNECTION_INFORMATION RequestInfo;
|
|
TDI_CONNECTION_INFORMATION ReturnInfo;
|
|
|
|
|
|
if (!ARGUMENT_PRESENT(Irp)) {
|
|
|
|
Irp = _TdiAllocateIrp( ConnectionFileObject, ConnectionDeviceObject );
|
|
if (Irp == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
return Status;
|
|
}
|
|
|
|
IrpAllocated = TRUE;
|
|
}
|
|
|
|
RtlZeroMemory( &RequestInfo, sizeof(RequestInfo) );
|
|
RtlZeroMemory( &ReturnInfo, sizeof(ReturnInfo) );
|
|
|
|
RequestInfo.RemoteAddressLength = RemoteTransportAddressLength;
|
|
RequestInfo.RemoteAddress = pRemoteTransportAddress;
|
|
|
|
|
|
TdiBuildConnect(
|
|
Irp,
|
|
ConnectionDeviceObject,
|
|
ConnectionFileObject,
|
|
NULL, // Completion routine
|
|
NULL, // Context
|
|
pTimeout,
|
|
&RequestInfo,
|
|
&ReturnInfo
|
|
);
|
|
|
|
Status = _TdiSubmitRequest(pTd, ConnectionDeviceObject, Irp, TRUE);
|
|
|
|
if (IrpAllocated) {
|
|
IoFreeIrp( Irp );
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
_TdiAssociateAddress(
|
|
IN PTD pTd,
|
|
IN PIRP Irp OPTIONAL,
|
|
IN PFILE_OBJECT ConnectionFileObject,
|
|
IN HANDLE AddressHandle,
|
|
IN PDEVICE_OBJECT AddressDeviceObject
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
BOOLEAN IrpAllocated = FALSE;
|
|
|
|
if (!ARGUMENT_PRESENT(Irp)) {
|
|
|
|
Irp = _TdiAllocateIrp( ConnectionFileObject, AddressDeviceObject );
|
|
if (Irp == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
return Status;
|
|
}
|
|
|
|
IrpAllocated = TRUE;
|
|
}
|
|
|
|
TdiBuildAssociateAddress(
|
|
Irp,
|
|
AddressDeviceObject,
|
|
ConnectionFileObject,
|
|
NULL, // Completion routine
|
|
NULL, // Context
|
|
AddressHandle
|
|
);
|
|
|
|
Status = _TdiSubmitRequest(pTd, AddressDeviceObject, Irp, FALSE);
|
|
|
|
if (IrpAllocated) {
|
|
IoFreeIrp( Irp );
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
_TdiDisconnect(
|
|
IN PTD pTd,
|
|
IN PFILE_OBJECT ConnectionFileObject,
|
|
IN PDEVICE_OBJECT ConnectionDeviceObject
|
|
)
|
|
{
|
|
PIRP Irp;
|
|
NTSTATUS Status;
|
|
BOOLEAN IrpAllocated = FALSE;
|
|
|
|
Irp = _TdiAllocateIrp( ConnectionFileObject, ConnectionDeviceObject );
|
|
if (Irp == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
return Status;
|
|
}
|
|
|
|
TdiBuildDisconnect(
|
|
Irp,
|
|
ConnectionDeviceObject,
|
|
ConnectionFileObject,
|
|
NULL, // Completion routine
|
|
NULL, // Context
|
|
0,
|
|
TDI_DISCONNECT_ABORT,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = _TdiSubmitRequest(pTd, ConnectionDeviceObject, Irp, TRUE);
|
|
|
|
IoFreeIrp( Irp );
|
|
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
_TdiSetEventHandler (
|
|
IN PTD pTd,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PFILE_OBJECT FileObject,
|
|
IN ULONG EventType,
|
|
IN PVOID EventHandler,
|
|
IN PVOID EventContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine registers an event handler with a TDI transport provider.
|
|
|
|
Arguments:
|
|
|
|
IN PDEVICE_OBJECT DeviceObject - Supplies the device object of the transport provider.
|
|
IN PFILE_OBJECT FileObject - Supplies the address object's file object.
|
|
IN ULONG EventType, - Supplies the type of event.
|
|
IN PVOID EventHandler - Supplies the event handler.
|
|
IN PVOID EventContext - Supplies the context for the event handler.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Final status of the set event operation
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PIRP Irp;
|
|
|
|
Irp = _TdiAllocateIrp( FileObject, NULL );
|
|
|
|
if (Irp == NULL) {
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
TdiBuildSetEventHandler(Irp, DeviceObject, FileObject,
|
|
NULL, NULL,
|
|
EventType, EventHandler, EventContext);
|
|
|
|
Status = _TdiSubmitRequest(pTd, DeviceObject, Irp, FALSE);
|
|
|
|
IoFreeIrp( Irp );
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
_TdiSubmitRequest (
|
|
IN PTD pTd,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN BOOLEAN bKeepLock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine submits a request to TDI and waits for it to complete.
|
|
|
|
Arguments:
|
|
|
|
IN PFILE_OBJECT FileObject - Connection or Address handle for TDI request
|
|
IN PIRP Irp - TDI request to submit.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Final status of request.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PKEVENT Event;
|
|
|
|
Status = MemoryAllocate( sizeof(KEVENT), &Event );
|
|
if( !NT_SUCCESS(Status) ) {
|
|
return( Status );
|
|
}
|
|
|
|
KeInitializeEvent (Event, NotificationEvent, FALSE);
|
|
|
|
IoSetCompletionRoutine(Irp, _TdiRequestComplete, Event, TRUE, TRUE, TRUE);
|
|
|
|
//
|
|
// Submit the request
|
|
//
|
|
|
|
Status = IoCallDriver(DeviceObject, Irp);
|
|
|
|
//
|
|
// If it failed immediately, return now, otherwise wait.
|
|
//
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
DBGPRINT(("_TdiSubmitRequest: submit request. Status = %X", Status));
|
|
MemoryFree( Event );
|
|
return Status;
|
|
}
|
|
|
|
if (Status == STATUS_PENDING) {
|
|
|
|
TRACE0(("TDI request issued, waiting..."));
|
|
|
|
do {
|
|
|
|
//
|
|
// Wait for a couple of seconds for the request to complete
|
|
//
|
|
// If it times out, and the thread is terminating, cancel the
|
|
// request and unwind that way.
|
|
//
|
|
|
|
if ( !bKeepLock ) {
|
|
Status = IcaWaitForSingleObject(
|
|
pTd->pContext,
|
|
Event,
|
|
_TdiPollTimeout
|
|
);
|
|
} else {
|
|
LARGE_INTEGER WaitTimeout;
|
|
PLARGE_INTEGER pWaitTimeout = NULL;
|
|
|
|
WaitTimeout = RtlEnlargedIntegerMultiply( _TdiPollTimeout, -10000 );
|
|
pWaitTimeout = &WaitTimeout;
|
|
|
|
Status = KeWaitForSingleObject(
|
|
Event,
|
|
UserRequest,
|
|
UserMode,
|
|
FALSE,
|
|
pWaitTimeout
|
|
);
|
|
}
|
|
|
|
TRACE0(("_TdiSubmitRequest: Status 0x%x from IcaWaitForSingleObject\n",Status));
|
|
|
|
//
|
|
// If we timed out the wait, and the thread is terminating,
|
|
// give up and cancel the IRP.
|
|
//
|
|
|
|
if ( (Status == STATUS_TIMEOUT)
|
|
|
|
&&
|
|
|
|
ARGUMENT_PRESENT(Irp)
|
|
|
|
&&
|
|
|
|
PsIsThreadTerminating( Irp->Tail.Overlay.Thread ) ) {
|
|
|
|
//
|
|
// Ask the I/O system to cancel this IRP. This will cause
|
|
// everything to unwind properly.
|
|
//
|
|
DBGPRINT(("_TdiSubmitRequest: Irp being canceled\n"));
|
|
|
|
IoCancelIrp(Irp);
|
|
}
|
|
|
|
} while ( Status == STATUS_TIMEOUT );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
DBGPRINT(("Could not wait for connection to complete\n"));
|
|
MemoryFree( Event );
|
|
return Status;
|
|
}
|
|
|
|
Status = Irp->IoStatus.Status;
|
|
}
|
|
|
|
TRACE0(("TDI request complete Status 0x%x\n",Status));
|
|
|
|
MemoryFree( Event );
|
|
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
_TdiRequestComplete (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Ctx
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completion routine for _TdiRequestSubmit operation.
|
|
|
|
Arguments:
|
|
|
|
IN PDEVICE_OBJECT DeviceObject, - Supplies a pointer to the device object
|
|
IN PIRP Irp, - Supplies the IRP submitted
|
|
IN PVOID Context - Supplies a pointer to the kernel event to release
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Status of KeSetEvent
|
|
|
|
|
|
We return STATUS_MORE_PROCESSING_REQUIRED to prevent the IRP completion
|
|
code from processing this puppy any more.
|
|
|
|
--*/
|
|
|
|
{
|
|
UNREFERENCED_PARAMETER(Irp);
|
|
UNREFERENCED_PARAMETER(DeviceObject);
|
|
|
|
TRACE0(("_TdiRequestComplete: Context %lx\n", Ctx));
|
|
|
|
//
|
|
// Set the event to the Signalled state with 0 priority increment and
|
|
// indicate that we will not be blocking soon.
|
|
//
|
|
|
|
KeSetEvent((PKEVENT) Ctx, 0, FALSE);
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
|
|
}
|
|
|
|
PIRP
|
|
_TdiAllocateIrp(
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PDEVICE_OBJECT DeviceObject OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function allocates and builds an I/O request packet.
|
|
|
|
Arguments:
|
|
|
|
FileObject - Supplies a pointer to the file object for which this
|
|
request is directed. This pointer is copied into the IRP, so
|
|
that the called driver can find its file-based context. NOTE
|
|
THAT THIS IS NOT A REFERENCED POINTER. The caller must ensure
|
|
that the file object is not deleted while the I/O operation is
|
|
in progress. The redir accomplishes this by incrementing a
|
|
reference count in a local block to account for the I/O; the
|
|
local block in turn references the file object.
|
|
|
|
DeviceObject - Supplies a pointer to a device object to direct this
|
|
request to. If this is not supplied, it uses the file object to
|
|
determine the device object.
|
|
|
|
Return Value:
|
|
|
|
PIRP - Returns a pointer to the constructed IRP.
|
|
|
|
--*/
|
|
|
|
{
|
|
PIRP Irp;
|
|
|
|
if (ARGUMENT_PRESENT(DeviceObject)) {
|
|
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
|
|
} else {
|
|
Irp = IoAllocateIrp(IoGetRelatedDeviceObject(FileObject)->StackSize, FALSE);
|
|
}
|
|
|
|
if (Irp == NULL) {
|
|
return(NULL);
|
|
}
|
|
|
|
Irp->Tail.Overlay.OriginalFileObject = FileObject;
|
|
|
|
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
|
|
|
|
Irp->RequestorMode = KernelMode;
|
|
|
|
return Irp;
|
|
}
|
|
|
|
NTSTATUS
|
|
_TdiReceiveDatagram(
|
|
IN PTD pTd,
|
|
IN PIRP Irp OPTIONAL,
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PTRANSPORT_ADDRESS pRemoteAddress,
|
|
IN ULONG RemoteAddressLength,
|
|
IN ULONG RecvFlags,
|
|
IN PVOID pBuffer,
|
|
IN ULONG BufferLength,
|
|
OUT PULONG pReturnLength
|
|
)
|
|
{
|
|
PMDL pMdl;
|
|
NTSTATUS Status;
|
|
BOOLEAN IrpAllocated = FALSE;
|
|
TDI_CONNECTION_INFORMATION RequestInfo;
|
|
TDI_CONNECTION_INFORMATION ReturnInfo;
|
|
|
|
if (!ARGUMENT_PRESENT(Irp)) {
|
|
|
|
Irp = _TdiAllocateIrp( FileObject, DeviceObject );
|
|
if (Irp == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
return Status;
|
|
}
|
|
|
|
IrpAllocated = TRUE;
|
|
}
|
|
|
|
RtlZeroMemory( &RequestInfo, sizeof(RequestInfo) );
|
|
RtlZeroMemory( &ReturnInfo, sizeof(ReturnInfo) );
|
|
|
|
// Copy in info to return remote address
|
|
ReturnInfo.RemoteAddress = pRemoteAddress;
|
|
ReturnInfo.RemoteAddressLength = RemoteAddressLength;
|
|
|
|
// Build MDL for buffer
|
|
pMdl = IoAllocateMdl(
|
|
pBuffer,
|
|
BufferLength,
|
|
FALSE,
|
|
FALSE,
|
|
(PIRP)NULL
|
|
);
|
|
|
|
if( pMdl == NULL ) {
|
|
if (IrpAllocated) {
|
|
IoFreeIrp( Irp );
|
|
}
|
|
return( STATUS_INSUFFICIENT_RESOURCES );
|
|
}
|
|
|
|
MmBuildMdlForNonPagedPool ( pMdl );
|
|
|
|
TdiBuildReceiveDatagram(
|
|
Irp,
|
|
DeviceObject,
|
|
FileObject,
|
|
NULL, // Completion routine
|
|
NULL, // Context
|
|
pMdl, // Mdl address
|
|
BufferLength,
|
|
&RequestInfo,
|
|
&ReturnInfo,
|
|
RecvFlags // InFlags
|
|
);
|
|
|
|
Status = _TdiSubmitRequest(pTd, DeviceObject, Irp, FALSE);
|
|
|
|
IoFreeMdl( pMdl );
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
// Packet length returned is in the Iosb
|
|
*pReturnLength = (ULONG)Irp->IoStatus.Information;
|
|
TRACE0(("_TdiReceiveDatagram: Irp DataLength 0x%x UserDataLength 0x%x, "
|
|
"OptionsLength 0x%x, RemoteAddressLength 0x%x\n", *pReturnLength,
|
|
ReturnInfo.UserDataLength, ReturnInfo.OptionsLength,
|
|
ReturnInfo.RemoteAddressLength));
|
|
}
|
|
|
|
if (IrpAllocated) {
|
|
IoFreeIrp( Irp );
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
_TdiSendDatagram(
|
|
IN PTD pTd,
|
|
IN PIRP Irp OPTIONAL,
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PTRANSPORT_ADDRESS pRemoteAddress,
|
|
IN ULONG RemoteAddressLength,
|
|
IN PVOID pBuffer,
|
|
IN ULONG BufferLength
|
|
)
|
|
{
|
|
PMDL pMdl;
|
|
NTSTATUS Status;
|
|
BOOLEAN IrpAllocated = FALSE;
|
|
TDI_CONNECTION_INFORMATION SendInfo;
|
|
|
|
if (!ARGUMENT_PRESENT(Irp)) {
|
|
|
|
Irp = _TdiAllocateIrp( FileObject, DeviceObject );
|
|
if (Irp == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
return Status;
|
|
}
|
|
|
|
IrpAllocated = TRUE;
|
|
}
|
|
|
|
RtlZeroMemory( &SendInfo, sizeof(SendInfo) );
|
|
|
|
// We must fill in our destination address
|
|
SendInfo.RemoteAddress = pRemoteAddress;
|
|
SendInfo.RemoteAddressLength = RemoteAddressLength;
|
|
|
|
// Build MDL for buffer
|
|
pMdl = IoAllocateMdl(
|
|
pBuffer,
|
|
BufferLength,
|
|
FALSE,
|
|
FALSE,
|
|
(PIRP)NULL
|
|
);
|
|
|
|
if( pMdl == NULL ) {
|
|
if (IrpAllocated) {
|
|
IoFreeIrp( Irp );
|
|
}
|
|
return( STATUS_INSUFFICIENT_RESOURCES );
|
|
}
|
|
|
|
MmBuildMdlForNonPagedPool ( pMdl );
|
|
|
|
TdiBuildSendDatagram(
|
|
Irp,
|
|
DeviceObject,
|
|
FileObject,
|
|
NULL, // Completion routine
|
|
NULL, // Context
|
|
pMdl, // Mdl address
|
|
BufferLength,
|
|
&SendInfo
|
|
);
|
|
|
|
Status = _TdiSubmitRequest(pTd, DeviceObject, Irp, FALSE);
|
|
|
|
IoFreeMdl( pMdl );
|
|
|
|
if (IrpAllocated) {
|
|
IoFreeIrp( Irp );
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
_TdiQueryAddressInfo(
|
|
IN PTD pTd,
|
|
IN PIRP Irp OPTIONAL,
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PTDI_ADDRESS_INFO pAddressInfo,
|
|
IN ULONG AddressInfoLength
|
|
)
|
|
{
|
|
PMDL pMdl;
|
|
NTSTATUS Status;
|
|
BOOLEAN IrpAllocated = FALSE;
|
|
|
|
if (!ARGUMENT_PRESENT(Irp)) {
|
|
|
|
Irp = _TdiAllocateIrp( FileObject, DeviceObject );
|
|
if (Irp == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
return Status;
|
|
}
|
|
|
|
IrpAllocated = TRUE;
|
|
}
|
|
|
|
// Build MDL for buffer
|
|
pMdl = IoAllocateMdl(
|
|
pAddressInfo,
|
|
AddressInfoLength,
|
|
FALSE,
|
|
FALSE,
|
|
(PIRP)NULL
|
|
);
|
|
|
|
if( pMdl == NULL ) {
|
|
if (IrpAllocated) {
|
|
IoFreeIrp( Irp );
|
|
}
|
|
return( STATUS_INSUFFICIENT_RESOURCES );
|
|
}
|
|
|
|
MmBuildMdlForNonPagedPool ( pMdl );
|
|
|
|
TdiBuildQueryInformation(
|
|
Irp,
|
|
DeviceObject,
|
|
FileObject,
|
|
NULL, // Completion routine
|
|
NULL, // Context
|
|
TDI_QUERY_ADDRESS_INFO,
|
|
pMdl
|
|
);
|
|
|
|
Status = _TdiSubmitRequest(pTd, DeviceObject, Irp, FALSE);
|
|
|
|
IoFreeMdl( pMdl );
|
|
|
|
if (IrpAllocated) {
|
|
IoFreeIrp( Irp );
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|