You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
667 lines
18 KiB
667 lines
18 KiB
/*++
|
|
|
|
Copyright (c) 2000-2002 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
httptdi.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the TDI/MUX/SSL component that is common between
|
|
ultdi and uctdi
|
|
|
|
Author:
|
|
|
|
Rajesh Sundaram (rajeshsu)
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "precomp.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, UxInitializeTdi )
|
|
#pragma alloc_text( PAGE, UxTerminateTdi )
|
|
#pragma alloc_text( PAGE, UxOpenTdiAddressObject )
|
|
#pragma alloc_text( PAGE, UxOpenTdiConnectionObject )
|
|
#pragma alloc_text( PAGE, UxpOpenTdiObjectHelper )
|
|
#pragma alloc_text( PAGE, UxSetEventHandler )
|
|
|
|
#endif
|
|
|
|
#if 0
|
|
|
|
NOT PAGEABLE - UxCreateDisconnectIrp
|
|
NOT PAGEABLE - UxInitializeDisconnectIrp
|
|
|
|
#endif
|
|
|
|
//
|
|
// Timeout for disconnects. This cannot be a stack-based local,
|
|
// so we make it a global.
|
|
//
|
|
BOOLEAN g_UxTdiInitialized;
|
|
|
|
UNICODE_STRING g_TCPDeviceName; // global transport device name (IP)
|
|
UNICODE_STRING g_TCP6DeviceName; // global transport device name (IPv6)
|
|
|
|
LARGE_INTEGER g_TdiDisconnectTimeout;
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Performs global initialization of this module.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Completion status.
|
|
|
|
--***************************************************************************/
|
|
NTSTATUS
|
|
UxInitializeTdi(
|
|
VOID
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT( !g_UxTdiInitialized );
|
|
|
|
status = UlInitUnicodeStringEx(&g_TCPDeviceName, DD_TCP_DEVICE_NAME);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
status = UlInitUnicodeStringEx(&g_TCP6DeviceName, DD_TCPV6_DEVICE_NAME);
|
|
}
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
g_TdiDisconnectTimeout = RtlConvertLongToLargeInteger( -1 );
|
|
|
|
g_UxTdiInitialized = TRUE;
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Performs global termination of this module.
|
|
|
|
--***************************************************************************/
|
|
VOID
|
|
UxTerminateTdi(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
PAGED_CODE();
|
|
|
|
if (g_UxTdiInitialized)
|
|
{
|
|
}
|
|
|
|
} // UxTerminateTdi
|
|
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Opens a TDI address object.
|
|
|
|
Arguments:
|
|
|
|
pTransportDeviceName - Supplies the device name of the TDI transport
|
|
to open.
|
|
|
|
pLocalAddress - Supplies the local address to bind to.
|
|
|
|
LocalAddressLength - Supplies the length of pLocalAddress.
|
|
|
|
pTdiObject - Receives the file handle, referenced FILE_OBJECT
|
|
pointer, and corresponding DEVICE_OBJECT pointer.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Completion status.
|
|
|
|
--***************************************************************************/
|
|
NTSTATUS
|
|
UxOpenTdiAddressObject(
|
|
IN PTRANSPORT_ADDRESS pLocalAddress,
|
|
IN ULONG LocalAddressLength,
|
|
OUT PUX_TDI_OBJECT pTdiObject
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PFILE_FULL_EA_INFORMATION pEaInfo;
|
|
ULONG eaLength;
|
|
UCHAR eaBuffer[MAX_ADDRESS_EA_BUFFER_LENGTH];
|
|
PUNICODE_STRING pTransportDeviceName;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
PAGED_CODE();
|
|
|
|
eaLength = sizeof(FILE_FULL_EA_INFORMATION) - 1 +
|
|
TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
|
|
LocalAddressLength;
|
|
|
|
ASSERT( eaLength <= sizeof(eaBuffer) );
|
|
|
|
ASSERT( LocalAddressLength == sizeof(TA_IP_ADDRESS) ||
|
|
LocalAddressLength == sizeof(TA_IP6_ADDRESS));
|
|
|
|
ASSERT( pLocalAddress->TAAddressCount == 1 );
|
|
|
|
ASSERT( pLocalAddress->Address[0].AddressLength == sizeof(TDI_ADDRESS_IP)
|
|
|| pLocalAddress->Address[0].AddressLength == sizeof(TDI_ADDRESS_IP6));
|
|
|
|
ASSERT( pLocalAddress->Address[0].AddressType == TDI_ADDRESS_TYPE_IP
|
|
|| pLocalAddress->Address[0].AddressType == TDI_ADDRESS_TYPE_IP6);
|
|
|
|
//
|
|
// Initialize the EA buffer. See UxpOpenTdiObjectHelper() for the
|
|
// gory details.
|
|
//
|
|
|
|
pEaInfo = (PFILE_FULL_EA_INFORMATION)eaBuffer;
|
|
|
|
pEaInfo->NextEntryOffset = 0;
|
|
pEaInfo->Flags = 0;
|
|
pEaInfo->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
|
|
pEaInfo->EaValueLength = (USHORT)LocalAddressLength;
|
|
|
|
RtlMoveMemory(
|
|
pEaInfo->EaName,
|
|
TdiTransportAddress,
|
|
pEaInfo->EaNameLength + 1
|
|
);
|
|
|
|
RtlMoveMemory(
|
|
&pEaInfo->EaName[pEaInfo->EaNameLength + 1],
|
|
pLocalAddress,
|
|
LocalAddressLength
|
|
);
|
|
|
|
//
|
|
// Initialize pTransportDeviceName
|
|
//
|
|
pTransportDeviceName =
|
|
(pLocalAddress->Address[0].AddressType == TDI_ADDRESS_TYPE_IP)?
|
|
&g_TCPDeviceName : &g_TCP6DeviceName;
|
|
|
|
//
|
|
// Let the helper do the dirty work.
|
|
//
|
|
|
|
status = UxpOpenTdiObjectHelper(
|
|
pTransportDeviceName,
|
|
eaBuffer,
|
|
eaLength,
|
|
pTdiObject
|
|
);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
//
|
|
// Enable Optimize for Interrupt Moderation if needed
|
|
//
|
|
|
|
if ( DEFAULT_OPT_FOR_INTR_MOD != g_UlOptForIntrMod )
|
|
{
|
|
status = UlpOptimizeForInterruptModeration( pTdiObject, g_UlOptForIntrMod );
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
UxCloseTdiObject( pTdiObject );
|
|
}
|
|
}
|
|
}
|
|
|
|
return status;
|
|
|
|
} // UxpOpenTdiAddressObject
|
|
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Opens a TDI connection object.
|
|
|
|
Arguments:
|
|
|
|
pTransportDeviceName - Supplies the device name of the TDI transport
|
|
to open.
|
|
|
|
pConnectionContext - Supplies the context to associate with the
|
|
new connection.
|
|
|
|
pTdiObject - Receives the file handle, referenced FILE_OBJECT
|
|
pointer, and corresponding DEVICE_OBJECT pointer.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Completion status.
|
|
|
|
--***************************************************************************/
|
|
NTSTATUS
|
|
UxOpenTdiConnectionObject(
|
|
IN USHORT AddressType,
|
|
IN CONNECTION_CONTEXT pConnectionContext,
|
|
OUT PUX_TDI_OBJECT pTdiObject
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PFILE_FULL_EA_INFORMATION pEaInfo;
|
|
ULONG eaLength;
|
|
UCHAR eaBuffer[MAX_CONNECTION_EA_BUFFER_LENGTH];
|
|
PUNICODE_STRING pTransportDeviceName;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT(AddressType == TDI_ADDRESS_TYPE_IP ||
|
|
AddressType == TDI_ADDRESS_TYPE_IP6);
|
|
|
|
pTransportDeviceName = (AddressType == TDI_ADDRESS_TYPE_IP)?
|
|
&g_TCPDeviceName : &g_TCP6DeviceName;
|
|
|
|
|
|
eaLength = sizeof(FILE_FULL_EA_INFORMATION) - 1 +
|
|
TDI_CONNECTION_CONTEXT_LENGTH + 1 +
|
|
sizeof(pConnectionContext);
|
|
|
|
ASSERT( eaLength <= sizeof(eaBuffer) );
|
|
ASSERT( pConnectionContext != NULL );
|
|
|
|
//
|
|
// Initialize the EA buffer. See UxpOpenTdiObjectHelper() for the
|
|
// gory details.
|
|
//
|
|
|
|
pEaInfo = (PFILE_FULL_EA_INFORMATION)eaBuffer;
|
|
|
|
pEaInfo->NextEntryOffset = 0;
|
|
pEaInfo->Flags = 0;
|
|
pEaInfo->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
|
|
pEaInfo->EaValueLength = (USHORT)sizeof(CONNECTION_CONTEXT);
|
|
|
|
RtlMoveMemory(
|
|
pEaInfo->EaName,
|
|
TdiConnectionContext,
|
|
pEaInfo->EaNameLength + 1
|
|
);
|
|
|
|
RtlMoveMemory(
|
|
&pEaInfo->EaName[pEaInfo->EaNameLength + 1],
|
|
&pConnectionContext,
|
|
sizeof(pConnectionContext)
|
|
);
|
|
|
|
//
|
|
// Let the helper do the dirty work.
|
|
//
|
|
|
|
status = UxpOpenTdiObjectHelper(
|
|
pTransportDeviceName,
|
|
eaBuffer,
|
|
eaLength,
|
|
pTdiObject
|
|
);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
//
|
|
// Enable/disable Nagle's Algorithm as appropriate.
|
|
//
|
|
|
|
status = UlpSetNagling( pTdiObject, g_UlEnableNagling );
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
UxCloseTdiObject( pTdiObject );
|
|
}
|
|
}
|
|
|
|
return status;
|
|
|
|
} // UxpOpenTdiConnectionObject
|
|
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Helper routine for UxpOpenTdiAddressObject and
|
|
UxpOpenTdiConnectionObject.
|
|
|
|
Arguments:
|
|
|
|
pTransportDeviceName - Supplies the device name of the TDI transport
|
|
to open.
|
|
|
|
pEaBuffer - Supplies a pointer to the EA to use when opening
|
|
the object. This buffer consists of a FILE_FULL_EA_INFORMATION
|
|
structure, followed by the EA Name, followed by the EA Value.
|
|
The EA Name and Value are use as follows:
|
|
|
|
Address Object:
|
|
Ea Name = TdiTransportAddress ("TransportAddress")
|
|
Ea Value = The local TRANSPORT_ADDRESS to bind to
|
|
|
|
Connection Object:
|
|
Ea Name = TdiConnectionContext ("ConnectionContext")
|
|
Ea Value = The connection context (basically a PVOID)
|
|
|
|
EaLength - Supplies the length of pEaBuffer.
|
|
|
|
pTdiObject - Receives the file handle, referenced FILE_OBJECT
|
|
pointer, and corresponding DEVICE_OBJECT pointer.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Completion status.
|
|
|
|
--***************************************************************************/
|
|
NTSTATUS
|
|
UxpOpenTdiObjectHelper(
|
|
IN PUNICODE_STRING pTransportDeviceName,
|
|
IN PVOID pEaBuffer,
|
|
IN ULONG EaLength,
|
|
OUT PUX_TDI_OBJECT pTdiObject
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Open the TDI object.
|
|
//
|
|
|
|
InitializeObjectAttributes(
|
|
&objectAttributes, // ObjectAttributes
|
|
pTransportDeviceName, // ObjectName
|
|
OBJ_CASE_INSENSITIVE | // Attributes
|
|
OBJ_KERNEL_HANDLE,
|
|
NULL, // RootHandle
|
|
NULL // SecurityDescriptor
|
|
);
|
|
|
|
status = IoCreateFile(
|
|
&pTdiObject->Handle, // FileHandle
|
|
GENERIC_READ | // DesiredAccess
|
|
GENERIC_WRITE |
|
|
SYNCHRONIZE,
|
|
&objectAttributes, // ObjectAttributes
|
|
&ioStatusBlock, // IoStatusBlock
|
|
NULL, // AllocationSize
|
|
0, // FileAttributes
|
|
0, // ShareAccess
|
|
0, // Disposition
|
|
0, // CreateOptions
|
|
pEaBuffer, // EaBuffer
|
|
EaLength, // EaLength
|
|
CreateFileTypeNone, // CreateFileType
|
|
NULL, // ExtraCreateParameters
|
|
IO_NO_PARAMETER_CHECKING // Options
|
|
);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
//
|
|
// Now that we have an open handle to the transport,
|
|
// reference it so we can get the file & device object
|
|
// pointers.
|
|
//
|
|
|
|
status = ObReferenceObjectByHandle(
|
|
pTdiObject->Handle, // Handle
|
|
FILE_READ_ACCESS, // DesiredAccess
|
|
*IoFileObjectType, // ObjectType
|
|
KernelMode, // AccessMode
|
|
(PVOID *)&pTdiObject->pFileObject, // Object
|
|
NULL // HandleInformation
|
|
);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
//
|
|
// Chase down the appropriate device object for the file
|
|
// object.
|
|
//
|
|
|
|
pTdiObject->pDeviceObject =
|
|
IoGetRelatedDeviceObject( pTdiObject->pFileObject );
|
|
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// The ObReferenceObjectByHandle() failed, so close the handle
|
|
// we managed to open & fail the call.
|
|
//
|
|
|
|
ZwClose( pTdiObject->Handle );
|
|
}
|
|
|
|
RtlZeroMemory(
|
|
pTdiObject,
|
|
sizeof(*pTdiObject)
|
|
);
|
|
|
|
return status;
|
|
|
|
} // UxpOpenTdiObjectHelper
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Establishes a TDI event handler for the specified endpoint.
|
|
|
|
Arguments:
|
|
|
|
pEndpoint - Supplies the endpoint for which to set the event handler.
|
|
|
|
EventType - Supplies the type of event to set. This should be one
|
|
of the TDI_EVENT_* values.
|
|
|
|
pEventHandler - Supplies a pointer to the indication handler function
|
|
to be invoked for the specified event type.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Completion status.
|
|
|
|
--***************************************************************************/
|
|
NTSTATUS
|
|
UxSetEventHandler(
|
|
IN PUX_TDI_OBJECT pUlTdiObject,
|
|
IN ULONG EventType,
|
|
IN ULONG_PTR pEventHandler,
|
|
IN PVOID pEventContext
|
|
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
TDI_REQUEST_KERNEL_SET_EVENT eventParams;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Build the parameter block.
|
|
//
|
|
|
|
eventParams.EventType = EventType;
|
|
eventParams.EventHandler = (PVOID) pEventHandler;
|
|
eventParams.EventContext = pEventContext;
|
|
|
|
//
|
|
// Make the call.
|
|
//
|
|
|
|
status = UlIssueDeviceControl(
|
|
pUlTdiObject, // pTdiObject
|
|
&eventParams, // pIrpParameters
|
|
sizeof(eventParams), // IrpParamtersLength
|
|
NULL, // pMdlBuffer
|
|
0, // MdlBufferLength
|
|
TDI_SET_EVENT_HANDLER // MinorFunction
|
|
);
|
|
|
|
return status;
|
|
|
|
} // UxSetEventHandler
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Allocates & initializes a new disconnect IRP.
|
|
|
|
Arguments:
|
|
|
|
pConnection - Supplies the UC_CONNECTION to be disconnected.
|
|
|
|
Flags - Supplies the TDI_DISCONNECT_* flags for the IRP.
|
|
|
|
pCompletionRoutine - Supplies the completion routine for the IRP.
|
|
|
|
pCompletionContext - Supplies an uninterpreted context for the
|
|
completion routine.
|
|
|
|
Return Value:
|
|
|
|
PIRP - Pointer to the IRP if successful, NULL otherwise.
|
|
|
|
--***************************************************************************/
|
|
PIRP
|
|
UxCreateDisconnectIrp(
|
|
IN PUX_TDI_OBJECT pTdiObject,
|
|
IN ULONG_PTR Flags,
|
|
IN PIO_COMPLETION_ROUTINE pCompletionRoutine,
|
|
IN PVOID pCompletionContext
|
|
)
|
|
{
|
|
PIRP pIrp;
|
|
|
|
ASSERT( IS_VALID_TDI_OBJECT( pTdiObject ) );
|
|
|
|
//
|
|
// Allocate an IRP for the disconnect.
|
|
//
|
|
|
|
pIrp = UlAllocateIrp(
|
|
pTdiObject->pDeviceObject->StackSize, // StackSize
|
|
FALSE // ChargeQuota
|
|
);
|
|
|
|
if (pIrp != NULL)
|
|
{
|
|
UxInitializeDisconnectIrp(
|
|
pIrp,
|
|
pTdiObject,
|
|
Flags,
|
|
pCompletionRoutine,
|
|
pCompletionContext
|
|
);
|
|
}
|
|
|
|
return pIrp;
|
|
|
|
} // UxCreateDisconnectIrp
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Initializes a disconnect IRP.
|
|
|
|
Arguments:
|
|
|
|
pIrp - Supplies the disconnect IRP.
|
|
|
|
pConnection - Supplies the UC_CONNECTION to be disconnected.
|
|
|
|
Flags - Supplies the TDI_DISCONNECT_* flags for the IRP.
|
|
|
|
pCompletionRoutine - Supplies the completion routine for the IRP.
|
|
|
|
pCompletionContext - Supplies an uninterpreted context for the
|
|
completion routine.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--***************************************************************************/
|
|
VOID
|
|
UxInitializeDisconnectIrp(
|
|
IN PIRP pIrp,
|
|
IN PUX_TDI_OBJECT pTdiObject,
|
|
IN ULONG_PTR Flags,
|
|
IN PIO_COMPLETION_ROUTINE pCompletionRoutine,
|
|
IN PVOID pCompletionContext
|
|
)
|
|
{
|
|
ASSERT( IS_VALID_TDI_OBJECT( pTdiObject ) );
|
|
ASSERT( pIrp != NULL );
|
|
|
|
//
|
|
// Initialize the IRP. Note that IRPs are always zero-initialized
|
|
// when allocated. Therefore, we don't need to explicitly set
|
|
// the zeroed fields.
|
|
//
|
|
|
|
pIrp->RequestorMode = KernelMode;
|
|
|
|
pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
|
|
pIrp->Tail.Overlay.OriginalFileObject = pTdiObject->pFileObject;
|
|
|
|
TdiBuildDisconnect(
|
|
pIrp, // Irp
|
|
pTdiObject->pDeviceObject, // DeviceObject
|
|
pTdiObject->pFileObject, // FileObject
|
|
pCompletionRoutine, // CompletionRoutine
|
|
pCompletionContext, // CompletionContext
|
|
&g_TdiDisconnectTimeout, // Timeout
|
|
Flags, // Flags
|
|
NULL, // RequestConnectionInfo
|
|
NULL // ReturnConnectionInfo
|
|
);
|
|
|
|
} // UxInitializeDisconnectIrp
|
|
|