Leaked source code of windows server 2003
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

/*++
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