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