windows-nt/Source/XPSP1/NT/base/fs/rdr2/rxce/daytona/rxtdi.c

2133 lines
63 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
rxtdi.c
Abstract:
This module implements the NT TDI related routines used by RXCE. The wrappers are necessary to
ensure that all the OS dependencies can be localized to select modules like this for
customization.
Revision History:
Balan Sethu Raman [SethuR] 15-Feb-1995
Notes:
--*/
#include "precomp.h"
#pragma hdrstop
#include "tdikrnl.h"
#include "rxtdip.h"
//
// The debug trace level
//
#define Dbg (DEBUG_TRACE_RXCETDI)
LARGE_INTEGER ConnectionTimeOut = {0,0};
#define CANCELLED_CONNECT_IRP IntToPtr(0xffffffff)
#if DBG
void
DbgDumpTransportAddress(
PWSTR RoutineName,
PRXCE_TRANSPORT pTransport,
PTRANSPORT_ADDRESS pTA
);
#else
#define DbgDumpTransportAddress( r, t, a )
#endif
// Once a valid handle to a transport device object has been obtained subsequent
// opens to the same device object can be opened with a NULL relative name to
// this handle. This has two beneficial side effects --- one it is fast since
// we do not have to go through the object manager's logic for parsing names and
// in remote boot scenarios it minimizes the footprint that needs to be locked
// down.
UNICODE_STRING RelativeName = { 0,0,NULL};
NTSTATUS
RxTdiBindToTransport(
IN OUT PRXCE_TRANSPORT pTransport)
/*++
Routine Description:
This routine binds to the transport specified.
Arguments:
pTransport - the transport structure to be initialized
pRxBindingContext - the binding context containing a pointer to the
transport name and the quality of service for NT.
Return Value:
STATUS_SUCCESS - if the call was successfull.
Notes:
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES ChannelAttributes;
IO_STATUS_BLOCK IoStatusBlock;
RxProfile(RxTdi,RxTdiBindToTransport);
InitializeObjectAttributes(
&ChannelAttributes, // Tdi Control Channel attributes
&pTransport->Name, // Name
OBJ_CASE_INSENSITIVE, // Attributes
NULL, // RootDirectory
NULL); // SecurityDescriptor
Status = ZwCreateFile(
&pTransport->ControlChannel, // Handle
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, // Desired Access
&ChannelAttributes, // Object Attributes
&IoStatusBlock, // Final I/O status block
0, // Allocation Size
FILE_ATTRIBUTE_NORMAL, // Normal attributes
FILE_SHARE_READ, // Sharing attributes
FILE_OPEN_IF, // Create disposition
0, // CreateOptions
NULL, // EA Buffer
0); // EA length
if (NT_SUCCESS(Status)) {
// Obtain a referenced pointer to the file object.
Status = ObReferenceObjectByHandle(
pTransport->ControlChannel, // Object Handle
FILE_ANY_ACCESS, // Desired Access
NULL, // Object Type
KernelMode, // Processor mode
(PVOID *)&pTransport->pControlChannelFileObject,// Object pointer
NULL); // Object Handle information
if (NT_SUCCESS(Status)) {
PIRP pIrp = NULL;
// Obtain the related device object.
pTransport->pDeviceObject = IoGetRelatedDeviceObject(pTransport->pControlChannelFileObject);
pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE);
if (pIrp != NULL) {
PMDL pMdl;
// Obtain the provider information from the specified transport.
ASSERT(pTransport->pProviderInfo != NULL);
pMdl = RxAllocateMdl(
pTransport->pProviderInfo, // Virtual address for MDL construction
sizeof( RXCE_TRANSPORT_PROVIDER_INFO)); // size of the buffer
if ( pMdl != NULL ) {
try {
MmProbeAndLockPages( pMdl, KernelMode, IoModifyAccess );
} except( EXCEPTION_EXECUTE_HANDLER ) {
IoFreeMdl( pMdl );
Status = GetExceptionCode();
}
if (Status == STATUS_SUCCESS) {
TdiBuildQueryInformation(
pIrp,
pTransport->pDeviceObject,
pTransport->pControlChannelFileObject,
RxTdiRequestCompletion, // Completion routine
NULL, // Completion context
TDI_QUERY_PROVIDER_INFO,
pMdl);
Status = RxCeSubmitTdiRequest(
pTransport->pDeviceObject,
pIrp);
MmUnlockPages(pMdl);
IoFreeMdl(pMdl);
}
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
RxCeFreeIrp(pIrp);
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
}
return Status;
}
NTSTATUS
RxTdiUnbindFromTransport(
IN OUT PRXCE_TRANSPORT pTransport)
/*++
Routine Description:
This routine unbinds to the transport specified.
Arguments:
pTransport - the transport structure
Return Value:
STATUS_SUCCESS - if the call was successfull.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
RxProfile(RxTdi,RxTdiUnbindFromTransport);
// Dereference the control channel file object.
if (pTransport->pControlChannelFileObject != NULL) {
ObDereferenceObject(pTransport->pControlChannelFileObject);
}
// Close the control channel
if (pTransport->ControlChannel != INVALID_HANDLE_VALUE) {
Status = ZwClose(pTransport->ControlChannel);
}
pTransport->pControlChannelFileObject = NULL;
pTransport->ControlChannel = INVALID_HANDLE_VALUE;
return Status;
}
NTSTATUS
RxTdiOpenAddress(
IN PRXCE_TRANSPORT pTransport,
IN PTRANSPORT_ADDRESS pTransportAddress,
IN OUT PRXCE_ADDRESS pAddress)
/*++
Routine Description:
This routine opens an address object.
Arguments:
Return Value:
STATUS_SUCCESS - if the call was successfull.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES AddressAttributes;
IO_STATUS_BLOCK IoStatusBlock;
ULONG TransportAddressLength;
ULONG TransportEaBufferLength;
PFILE_FULL_EA_INFORMATION pTransportAddressEa;
RxProfile(RxTdi,RxTdiOpenAddress);
TransportAddressLength = ComputeTransportAddressLength(pTransportAddress);
// Build an EA buffer for the specified transport address
Status = BuildEaBuffer(
TDI_TRANSPORT_ADDRESS_LENGTH,
TdiTransportAddress,
TransportAddressLength,
pTransportAddress,
&pTransportAddressEa,
&TransportEaBufferLength);
if (!NT_SUCCESS(Status)) {
return Status;
}
InitializeObjectAttributes(
&AddressAttributes, // OBJECT_ATTRIBUTES instance
&RelativeName, // Name
0, // Attributes
pTransport->ControlChannel, // RootDirectory
NULL); // SecurityDescriptor
Status = ZwCreateFile(
&pAddress->hAddress, // Handle
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, // Desired Access
&AddressAttributes, // Object Attributes
&IoStatusBlock, // Final I/O status block
0, // Allocation Size
FILE_ATTRIBUTE_NORMAL, // Normal attributes
FILE_SHARE_READ, // Sharing attributes
FILE_OPEN_IF, // Create disposition
0, // CreateOptions
pTransportAddressEa, // EA Buffer
TransportEaBufferLength); // EA length
if (NT_SUCCESS(Status)) {
// Obtain a referenced pointer to the file object.
Status = ObReferenceObjectByHandle (
pAddress->hAddress, // Object Handle
FILE_ANY_ACCESS, // Desired Access
NULL, // Object Type
KernelMode, // Processor mode
(PVOID *)&pAddress->pFileObject, // Object pointer
NULL); // Object Handle information
Status = RxTdiSetEventHandlers(pTransport,pAddress);
//DbgPrint("RDR opened address %lx\n", pAddress->hAddress);
}
// Free up the EA buffer allocated.
RxFreePool(pTransportAddressEa);
RxDbgTrace(0, Dbg,("RxTdiOpenAddress returns %lx\n",Status));
return Status;
}
NTSTATUS
RxTdiSetEventHandlers(
PRXCE_TRANSPORT pTransport,
PRXCE_ADDRESS pRxCeAddress)
/*++
Routine Description:
This routine establishes the event handlers for a given address.
Arguments:
pRxCeAddress - the address object
Return Value:
STATUS_SUCCESS - if the call was successfull.
--*/
{
NTSTATUS Status;
PIRP pIrp;
RxProfile(RxTdi,RxTdiSetEventHandlers);
pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE);
if (pIrp == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
// The event handlers need to be set one at a time.
do {
// Connect Event handler
TdiBuildSetEventHandler(
pIrp,
pTransport->pDeviceObject,
pRxCeAddress->pFileObject,
NULL,
NULL,
TDI_EVENT_CONNECT,
RxTdiConnectEventHandler,
pRxCeAddress);
Status = RxCeSubmitTdiRequest(pTransport->pDeviceObject,pIrp);
if (!NT_SUCCESS(Status)) {
continue;
}
// Disconnect event handler
TdiBuildSetEventHandler(
pIrp,
pTransport->pDeviceObject,
pRxCeAddress->pFileObject,
NULL,
NULL,
TDI_EVENT_DISCONNECT,
RxTdiDisconnectEventHandler,
pRxCeAddress);
Status = RxCeSubmitTdiRequest(pTransport->pDeviceObject,pIrp);
if (!NT_SUCCESS(Status)) {
continue;
}
// Error event handler
TdiBuildSetEventHandler(
pIrp,
pTransport->pDeviceObject,
pRxCeAddress->pFileObject,
NULL,
NULL,
TDI_EVENT_ERROR,
RxTdiErrorEventHandler,
pRxCeAddress);
Status = RxCeSubmitTdiRequest(pTransport->pDeviceObject,pIrp);
if (!NT_SUCCESS(Status)) {
continue;
}
// Receive Event handler
TdiBuildSetEventHandler(
pIrp,
pTransport->pDeviceObject,
pRxCeAddress->pFileObject,
NULL,
NULL,
TDI_EVENT_RECEIVE,
RxTdiReceiveEventHandler,
pRxCeAddress);
Status = RxCeSubmitTdiRequest(pTransport->pDeviceObject,pIrp);
if (!NT_SUCCESS(Status)) {
continue;
}
#if 0
// Receive datagram event handler
TdiBuildSetEventHandler(
pIrp,
pTransport->pDeviceObject,
pRxCeAddress->pFileObject,
NULL,
NULL,
TDI_EVENT_RECEIVE_DATAGRAM,
RxTdiReceiveDatagramEventHandler,
pRxCeAddress);
Status = RxCeSubmitTdiRequest(pTransport->pDeviceObject,pIrp);
if (!NT_SUCCESS(Status)) {
continue;
}
#endif
// Receieve expedited event handler
TdiBuildSetEventHandler(
pIrp,
pTransport->pDeviceObject,
pRxCeAddress->pFileObject,
NULL,
NULL,
TDI_EVENT_RECEIVE_EXPEDITED,
RxTdiReceiveExpeditedEventHandler,
pRxCeAddress);
Status = RxCeSubmitTdiRequest(pTransport->pDeviceObject,pIrp);
if (!NT_SUCCESS(Status)) {
continue;
}
#if 0
// Send possible event handler
TdiBuildSetEventHandler(
pIrp,
pTransport->pDeviceObject,
pRxCeAddress->pFileObject,
NULL,
NULL,
TDI_EVENT_SEND_POSSIBLE,
RxTdiSendPossibleEventHandler,
RxCeGetAddressHandle(pRxCeAddress));
Status = RxCeSubmitTdiRequest(pTransport->pDeviceObject,pIrp);
#endif
if (NT_SUCCESS(Status)) {
// All the event handlers have been successfully set.
break;
}
} while (NT_SUCCESS(Status));
// Free the Irp
RxCeFreeIrp(pIrp);
return Status;
}
NTSTATUS
RxTdiConnect(
IN PRXCE_TRANSPORT pTransport,
IN OUT PRXCE_ADDRESS pAddress,
IN OUT PRXCE_CONNECTION pConnection,
IN OUT PRXCE_VC pVc)
/*++
Routine Description:
This routine establishes a connection between a local connection endpoint and
a remote transport address.
Arguments:
pTransport - the associated transport
pAddress - the address object to be closed
pConnection - the RxCe connection instance
pVc - the RxCe virtual circuit instance.
Return Value:
STATUS_SUCCESS - if the call was successfull.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES VcAttributes;
IO_STATUS_BLOCK IoStatusBlock;
PRXCE_CONNECTION_INFORMATION pReturnConnectionInformation = NULL;
ULONG ConnectionContextEaBufferLength;
PFILE_FULL_EA_INFORMATION pConnectionContextEa;
RxProfile(RxTdi,RxTdiConnect);
#if DBG
{
PTRANSPORT_ADDRESS pTA =
(PTRANSPORT_ADDRESS)(pConnection->pConnectionInformation->RemoteAddress);
RxDbgTrace(0, Dbg,("RxTdiConnect to %wZ address length %d type %d\n",
&(pTransport->Name),
pTA->Address[0].AddressLength,
pTA->Address[0].AddressType ));
}
#endif
// Build an EA buffer for the specified connection context
Status = BuildEaBuffer(
TDI_CONNECTION_CONTEXT_LENGTH,
TdiConnectionContext,
sizeof(PRXCE_VC),
&pVc,
&pConnectionContextEa,
&ConnectionContextEaBufferLength);
if (!NT_SUCCESS(Status)) {
return Status;
}
// Open the local connection endpoint.
InitializeObjectAttributes(
&VcAttributes, // OBJECT_ATTRIBUTES instance
&RelativeName, // Name
0, // Attributes
pTransport->ControlChannel, // RootDirectory
NULL); // SecurityDescriptor
Status = ZwCreateFile(
&pVc->hEndpoint, // Handle
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, // Desired Access
&VcAttributes, // Object Attributes
&IoStatusBlock, // Final I/O status block
0, // Allocation Size
FILE_ATTRIBUTE_NORMAL, // Normal attributes
FILE_SHARE_READ, // Sharing attributes
FILE_OPEN_IF, // Create disposition
0, // CreateOptions
pConnectionContextEa, // EA Buffer
ConnectionContextEaBufferLength); // EA length
if (NT_SUCCESS(Status)) {
PIRP pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE);
if (pIrp != NULL) {
// Obtain a referenced pointer to the file object.
Status = ObReferenceObjectByHandle (
pVc->hEndpoint, // Object Handle
FILE_ANY_ACCESS, // Desired Access
NULL, // Object Type
KernelMode, // Processor mode
(PVOID *)&pVc->pEndpointFileObject, // Object pointer
NULL); // Object Handle information
if (NT_SUCCESS(Status)) {
// Associate the local endpoint with the address object.
TdiBuildAssociateAddress(
pIrp,
pTransport->pDeviceObject,
pVc->pEndpointFileObject,
NULL,
NULL,
pAddress->hAddress);
Status = RxCeSubmitTdiRequest(
pTransport->pDeviceObject,
pIrp);
if (NT_SUCCESS(Status)) {
// issue the connect request to the underlying transport provider.
TdiBuildConnect(
pIrp,
pTransport->pDeviceObject,
pVc->pEndpointFileObject,
NULL,
NULL,
&ConnectionTimeOut,
pConnection->pConnectionInformation,
pReturnConnectionInformation);
Status = RxCeSubmitTdiRequest(
pTransport->pDeviceObject,
pIrp);
if (!NT_SUCCESS(Status)) {
// Disassociate address from the connection since the connect request was
// not successful.
NTSTATUS LocalStatus;
TdiBuildDisassociateAddress(
pIrp,
pTransport->pDeviceObject,
pVc->pEndpointFileObject,
NULL,
NULL);
LocalStatus = RxCeSubmitTdiRequest(
pTransport->pDeviceObject,
pIrp);
} else {
// The associate address was not successful.
RxDbgTrace(0, Dbg,("TDI connect returned %lx\n",Status));
}
} else {
// The associate address was not successful.
RxDbgTrace(0, Dbg,("TDI associate address returned %lx\n",Status));
}
if (!NT_SUCCESS(Status)) {
// Dereference the endpoint file object.
ObDereferenceObject(pVc->pEndpointFileObject);
}
} else {
// error obtaining the file object for the connection.
RxDbgTrace(0, Dbg,("error referencing endpoint file object %lx\n",Status));
}
RxCeFreeIrp(pIrp);
if (!NT_SUCCESS(Status)) {
// Close the endpoint file object handle
ZwClose(pVc->hEndpoint);
}
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
} else {
// error creating the connection object
RxDbgTrace(0, Dbg,("Connection object(ZwCreate) returned %lx\n",Status));
}
if (!NT_SUCCESS(Status)) {
pVc->hEndpoint = INVALID_HANDLE_VALUE;
pVc->pEndpointFileObject = NULL;
}
RxFreePool(pConnectionContextEa);
return Status;
}
NTSTATUS
RxTdiDereferenceAndFreeIrp(
IN PULONG IrpRefCount,
IN PIRP pIrp)
/*++
Routine Description:
This routine dereference the connect Irp and free it if ref count reaches 0
Arguments:
pParameters - the connection parameters
Return Value:
STATUS_SUCCESS - if the call was successfull.
--*/
{
ULONG RefCount;
RefCount = InterlockedDecrement(IrpRefCount);
if (RefCount == 0) {
RxCeFreeIrp(pIrp);
RxFreePool(IrpRefCount);
}
return STATUS_SUCCESS;
}
NTSTATUS
RxTdiAsynchronousConnectCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP pIrp,
IN PVOID Context)
/*++
Routine Description:
This routine completes an asynchronous connect request.
Arguments:
pDeviceObject - the device object
pIrp - the IRp
Context - the completion context
Return Value:
STATUS_SUCCESS - if the call was successfull.
--*/
{
PULONG IrpRefCount = NULL;
PRX_CREATE_CONNECTION_PARAMETERS_BLOCK pParameters;
RxDbgTrace(0, Dbg,("RxTdiAsynchronousConnectCompletion, irp 0x%x, status 0x%x\n",
pIrp, pIrp->IoStatus.Status));
pParameters = (PRX_CREATE_CONNECTION_PARAMETERS_BLOCK)Context;
pParameters->CallOutStatus = pIrp->IoStatus.Status;
IrpRefCount = pParameters->IrpRefCount;
RxWmiLogError(pParameters->CallOutStatus,
LOG,
RxTdiAsynchronousConnectCompletion,
LOGULONG(pParameters->CallOutStatus)
LOGUSTR(pParameters->Connection.pAddress->pTransport->Name));
if (pParameters->pCallOutContext != NULL) {
pParameters->pCallOutContext->pRxCallOutCompletion(
(PRX_CALLOUT_PARAMETERS_BLOCK)pParameters);
}
// Free the IRP.
RxTdiDereferenceAndFreeIrp(IrpRefCount,pIrp);
return STATUS_MORE_PROCESSING_REQUIRED;
UNREFERENCED_PARAMETER( DeviceObject );
}
NTSTATUS
RxTdiCancelAsynchronousConnect(
IN PRX_CREATE_CONNECTION_PARAMETERS_BLOCK pParameters)
/*++
Routine Description:
This routine cancels a connection between a local connection endpoint and
a remote transport address.
Arguments:
pParameters - the connection parameters
Return Value:
STATUS_CANCELLED - if the call was successfull.
--*/
{
KIRQL OldIrql;
PIRP pIrp = NULL;
PULONG IrpRefCount = NULL;
BOOLEAN ShouldCancel = FALSE;
NTSTATUS Status = STATUS_PENDING;
KeAcquireSpinLock(&pParameters->pCallOutContext->SpinLock,&OldIrql);
pIrp = InterlockedExchangePointer(
&pParameters->pConnectIrp,
CANCELLED_CONNECT_IRP);
if ((pIrp != NULL) && (pIrp != CANCELLED_CONNECT_IRP)) {
IrpRefCount = pParameters->IrpRefCount;
(*IrpRefCount) ++;
ShouldCancel = TRUE;
}
KeReleaseSpinLock(&pParameters->pCallOutContext->SpinLock,OldIrql);
if (ShouldCancel) {
if (IoCancelIrp(pIrp)) {
Status = STATUS_CANCELLED;
}
RxTdiDereferenceAndFreeIrp(IrpRefCount,pIrp);
}
return Status;
}
NTSTATUS
RxTdiCleanupAsynchronousConnect(
IN PRX_CREATE_CONNECTION_PARAMETERS_BLOCK pParameters)
/*++
Routine Description:
This routine disconnects all failed requests when asynchronous connection attempts
are made.
Arguments:
pParameters - the connection parameters
Return Value:
STATUS_SUCCESS - if the call was successfull.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PIRP pIrp;
PRXCE_CONNECTION pConnection;
PRXCE_VC pVc;
RxProfile(RxTdi,RxTdiConnect);
pConnection = &pParameters->Connection;
pVc = &pParameters->Vc;
RxProfile(RxTdi,RxTdiDisconnect);
if (pVc->pEndpointFileObject != NULL) {
PDEVICE_OBJECT pDeviceObject;
pDeviceObject = IoGetRelatedDeviceObject(pVc->pEndpointFileObject);
pIrp = RxCeAllocateIrp(pDeviceObject->StackSize,FALSE);
if (pIrp != NULL) {
TdiBuildDisassociateAddress(
pIrp,
pDeviceObject,
pVc->pEndpointFileObject,
NULL,
NULL);
Status = RxCeSubmitTdiRequest(
pDeviceObject,
pIrp);
if (Status != STATUS_SUCCESS) {
RxDbgTrace(0, Dbg,("RxTdiDisconnect: TDI disassociate returned %lx\n",Status));
}
if (pParameters->CallOutStatus == STATUS_SUCCESS) {
// Build the disconnect request to the underlying transport driver
TdiBuildDisconnect(
pIrp, // the IRP
pDeviceObject, // the device object
pVc->pEndpointFileObject, // the connection (VC) file object
NULL, // Completion routine
NULL, // completion context
NULL, // time
RXCE_DISCONNECT_ABORT, // disconnect options
pConnection->pConnectionInformation, // disconnect request connection information
NULL); // disconnect return connection information
Status = RxCeSubmitTdiRequest(
pDeviceObject,
pIrp);
if (!NT_SUCCESS(Status)) {
RxDbgTrace(0, Dbg,("RxTdiDisconnect: TDI disconnect returned %lx\n",Status));
}
}
RxCeFreeIrp(pIrp);
}
// Dereference the endpoint file object.
ObDereferenceObject(pVc->pEndpointFileObject);
// Close the endpoint file object handle
ZwClose(pVc->hEndpoint);
pVc->pEndpointFileObject = NULL;
pVc->hEndpoint = INVALID_HANDLE_VALUE;
}
return STATUS_SUCCESS;
}
NTSTATUS
RxTdiInitiateAsynchronousConnect(
IN PRX_CREATE_CONNECTION_PARAMETERS_BLOCK pParameters)
/*++
Routine Description:
This routine establishes a connection between a local connection endpoint and
a remote transport address.
Arguments:
pParameters - the connection parameters
Return Value:
STATUS_SUCCESS - if the call was successfull.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PRXCE_TRANSPORT pTransport;
PRXCE_ADDRESS pAddress;
PRXCE_CONNECTION pConnection;
PRXCE_VC pVc;
OBJECT_ATTRIBUTES VcAttributes;
IO_STATUS_BLOCK IoStatusBlock;
PIRP pIrp = NULL;
PRXCE_CONNECTION_INFORMATION pReturnConnectionInformation = NULL;
PFILE_FULL_EA_INFORMATION pConnectionContextEa;
ULONG ConnectionContextEaBufferLength;
PRX_CREATE_CONNECTION_CALLOUT_CONTEXT pContext;
RxProfile(RxTdi,RxTdiConnect);
pConnection = &pParameters->Connection;
pVc = &pParameters->Vc;
pVc->hEndpoint = INVALID_HANDLE_VALUE;
pVc->pEndpointFileObject = NULL;
if (pParameters->pConnectIrp == CANCELLED_CONNECT_IRP) {
return STATUS_CANCELLED;
}
pParameters->IrpRefCount = (PULONG)RxAllocatePoolWithTag(
NonPagedPool,
sizeof(ULONG),
RXCE_CONNECTION_POOLTAG);
if (pParameters->IrpRefCount == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
*(pParameters->IrpRefCount) = 1;
pContext = (PRX_CREATE_CONNECTION_CALLOUT_CONTEXT)pParameters->pCallOutContext;
pAddress = pConnection->pAddress;
pTransport = pAddress->pTransport;
DbgDumpTransportAddress(
L"RxInitiateAsynchronousConnect",
pTransport,
(PTRANSPORT_ADDRESS)(pConnection->pConnectionInformation->RemoteAddress)
);
// Build an EA buffer for the specified connection context
Status = BuildEaBuffer(
TDI_CONNECTION_CONTEXT_LENGTH,
TdiConnectionContext,
sizeof(PRXCE_VC),
&pContext->pConnectionContext,
&pConnectionContextEa,
&ConnectionContextEaBufferLength);
if (!NT_SUCCESS(Status)) {
if (pParameters->IrpRefCount != NULL) {
RxFreePool(pParameters->IrpRefCount);
pParameters->IrpRefCount = NULL;
}
return Status;
}
// Open the local connection endpoint.
InitializeObjectAttributes(
&VcAttributes, // OBJECT_ATTRIBUTES instance
&RelativeName, // Name
0, // Attributes
pTransport->ControlChannel, // RootDirectory
NULL); // SecurityDescriptor
Status = ZwCreateFile(
&pVc->hEndpoint, // Handle
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, // Desired Access
&VcAttributes, // Object Attributes
&IoStatusBlock, // Final I/O status block
0, // Allocation Size
FILE_ATTRIBUTE_NORMAL, // Normal attributes
FILE_SHARE_READ, // Sharing attributes
FILE_OPEN_IF, // Create disposition
0, // CreateOptions
pConnectionContextEa, // EA Buffer
ConnectionContextEaBufferLength); // EA length
// Free the connection context ea buffer.
RxFreePool(pConnectionContextEa);
if (NT_SUCCESS(Status)) {
pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE);
if (pIrp != NULL) {
// Obtain a referenced pointer to the file object.
Status = ObReferenceObjectByHandle (
pVc->hEndpoint, // Object Handle
FILE_ANY_ACCESS, // Desired Access
NULL, // Object Type
KernelMode, // Processor mode
(PVOID *)&pVc->pEndpointFileObject, // Object pointer
NULL); // Object Handle information
if (NT_SUCCESS(Status)) {
// Associate the local endpoint with the address object.
TdiBuildAssociateAddress(
pIrp,
pTransport->pDeviceObject,
pVc->pEndpointFileObject,
NULL,
NULL,
pAddress->hAddress);
Status = RxCeSubmitTdiRequest(
pTransport->pDeviceObject,
pIrp);
if (NT_SUCCESS(Status)) {
// issue the connect request to the underlying transport provider.
TdiBuildConnect(
pIrp,
pTransport->pDeviceObject,
pVc->pEndpointFileObject,
NULL,
NULL,
&ConnectionTimeOut,
pConnection->pConnectionInformation,
pReturnConnectionInformation);
IoSetCompletionRoutine(
pIrp, // The IRP
RxTdiAsynchronousConnectCompletion, // The completion routine
pParameters, // The completion context
TRUE, // Invoke On Success
TRUE, // Invoke On Error
TRUE); // Invoke On Cancel
InterlockedExchangePointer(
&pParameters->pConnectIrp,
pIrp);
// Submit the request
Status = IoCallDriver(
pTransport->pDeviceObject,
pIrp);
if (!NT_SUCCESS(Status)) {
RxDbgTrace(0,Dbg,("RxTdiAsynchronousConnect: Connect IRP initiation failed, irp %lx, status 0x%x\n",pIrp, Status));
}
Status = STATUS_PENDING;
} else {
// The associate address was not successful.
RxDbgTrace(0, Dbg,("TDI associate address returned %lx\n",Status));
}
} else {
// error obtaining the file object for the connection.
RxDbgTrace(0, Dbg,("error referencing endpoint file object %lx\n",Status));
}
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
if (Status != STATUS_PENDING) {
if (pIrp != NULL) {
RxCeFreeIrp(pIrp);
}
if (pParameters->IrpRefCount != NULL) {
RxFreePool(pParameters->IrpRefCount);
}
if (pVc->pEndpointFileObject != NULL) {
ObDereferenceObject(pVc->pEndpointFileObject);
pVc->pEndpointFileObject = NULL;
}
if (pVc->hEndpoint != INVALID_HANDLE_VALUE) {
// Close the endpoint file object handle
ZwClose(pVc->hEndpoint);
pVc->hEndpoint = INVALID_HANDLE_VALUE;
}
}
} else {
// error creating the connection object
RxDbgTrace(0, Dbg,("Connection object(ZwCreate) returned %lx\n",Status));
if (pParameters->IrpRefCount != NULL) {
RxFreePool(pParameters->IrpRefCount);
pParameters->IrpRefCount = NULL;
}
}
return Status;
}
NTSTATUS
RxTdiReconnect(
IN PRXCE_TRANSPORT pTransport,
IN OUT PRXCE_ADDRESS pAddress,
IN OUT PRXCE_CONNECTION pConnection,
IN OUT PRXCE_VC pVc)
/*++
Routine Description:
This routine establishes a connection between a local connection endpoint and
a remote transport address.
Arguments:
pTransport - the associated transport
pAddress - the address object to be closed
pConnection - the RxCe connection instance
pVc - the RxCe virtual circuit instance.
Return Value:
STATUS_SUCCESS - if the call was successfull.
--*/
{
NTSTATUS Status;
PRXCE_CONNECTION_INFORMATION pReturnConnectionInformation = NULL;
PIRP pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE);
RxProfile(RxTdi,RxTdiReconnect);
ASSERT(pVc->State == RXCE_VC_DISCONNECTED);
if (pIrp != NULL) {
// issue the connect request to the underlying transport provider.
TdiBuildConnect(
pIrp,
pTransport->pDeviceObject,
pVc->pEndpointFileObject,
NULL,
NULL,
&ConnectionTimeOut,
pConnection->pConnectionInformation,
pReturnConnectionInformation);
Status = RxCeSubmitTdiRequest(
pTransport->pDeviceObject,
pIrp);
if (NT_SUCCESS(Status)) {
InterlockedExchange(
&pVc->State,
RXCE_VC_ACTIVE);
} else {
// The reconnect request was not successful
RxDbgTrace(0, Dbg,("RxTdiReconnect: TDI connect returned %lx\n",Status));
}
RxCeFreeIrp(pIrp);
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
return Status;
}
NTSTATUS
RxTdiDisconnect(
IN PRXCE_TRANSPORT pTransport,
IN PRXCE_ADDRESS pAddress,
IN PRXCE_CONNECTION pConnection,
IN PRXCE_VC pVc,
IN ULONG DisconnectFlags)
/*++
Routine Description:
This routine closes down a previously established connection.
Arguments:
pTransport - the associated transport
pAddress - the address object
pConnection - the connection
pVc - the virtual circuit to be disconnected.
DisconnectFlags - DisconnectOptions
Return Value:
STATUS_SUCCESS - if the call was successfull.
--*/
{
NTSTATUS Status;
PIRP pIrp;
RxProfile(RxTdi,RxTdiDisconnect);
pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE);
if (pIrp == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
TdiBuildDisassociateAddress(
pIrp,
pTransport->pDeviceObject,
pVc->pEndpointFileObject,
NULL,
NULL);
Status = RxCeSubmitTdiRequest(
pTransport->pDeviceObject,
pIrp);
if (NT_SUCCESS(Status)) {
// Build the disconnect request to the underlying transport driver
TdiBuildDisconnect(
pIrp, // the IRP
pTransport->pDeviceObject, // the device object
pVc->pEndpointFileObject, // the connection (VC) file object
NULL, // Completion routine
NULL, // completion context
NULL, // time
DisconnectFlags, // disconnect options
pConnection->pConnectionInformation, // disconnect request connection information
NULL); // disconnect return connection information
Status = RxCeSubmitTdiRequest(
pTransport->pDeviceObject,
pIrp);
if (!NT_SUCCESS(Status)) {
RxDbgTrace(0, Dbg,("RxTdiDisconnect: TDI disconnect returned %lx\n",Status));
}
} else {
RxDbgTrace(0, Dbg,("RxTdiDisconnect: TDI disassociate returned %lx\n",Status));
}
RxCeFreeIrp(pIrp);
return STATUS_SUCCESS;
}
NTSTATUS
RxTdiCloseAddress(
IN OUT PRXCE_ADDRESS pAddress)
/*++
Routine Description:
This routine closes the address object.
Arguments:
pRxCeAddress - the address object to be closed
Return Value:
STATUS_SUCCESS - if the call was successfull.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
// Dereference the file object.
if (pAddress->pFileObject != NULL) {
ObDereferenceObject(pAddress->pFileObject);
}
// Close the address file object handle
ZwClose(pAddress->hAddress);
//DbgPrint("RDR closed address %lx\n", pAddress->hAddress);
return Status;
}
NTSTATUS
RxTdiQueryInformation(
IN PRXCE_TRANSPORT pTransport,
IN PRXCE_ADDRESS pAddress,
IN PRXCE_CONNECTION pConnection,
IN PRXCE_VC pVc,
IN ULONG QueryType,
IN PVOID pQueryBuffer,
IN ULONG QueryBufferLength)
/*++
Routine Description:
This routine queries the information w.r.t a connection
Arguments:
pTransport - the associated transport
pAddress - the address object to be closed
pConnection - the RxCe connection instance
pVc - the VC instance
QueryType - the class of information desired
pQueryBuffer - the buffer in whihc the data is to be returned
QueryBufferLength - the query buffer length.
Return Value:
STATUS_SUCCESS - if the call was successfull.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PIRP pIrp = NULL;
// Obtain the related device object.
pTransport->pDeviceObject = IoGetRelatedDeviceObject(pTransport->pControlChannelFileObject);
pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE);
if (pIrp != NULL) {
PMDL pMdl;
pMdl = RxAllocateMdl(
pQueryBuffer, // Virtual address for MDL construction
QueryBufferLength); // size of the buffer
if ( pMdl != NULL ) {
try {
MmProbeAndLockPages( pMdl, KernelMode, IoModifyAccess );
} except( EXCEPTION_EXECUTE_HANDLER ) {
IoFreeMdl( pMdl );
Status = GetExceptionCode();
}
if (Status == STATUS_SUCCESS) {
// Get the file object associated with trhe connection.
TdiBuildQueryInformation(
pIrp,
pTransport->pDeviceObject,
pVc->pEndpointFileObject,
RxTdiRequestCompletion, // Completion routine
NULL, // Completion context
QueryType,
pMdl);
Status = RxCeSubmitTdiRequest(
pTransport->pDeviceObject,
pIrp);
MmUnlockPages(pMdl);
IoFreeMdl(pMdl);
}
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
RxCeFreeIrp(pIrp);
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
return Status;
}
NTSTATUS
RxTdiQueryAdapterStatus(
IN PRXCE_TRANSPORT pTransport,
IN PADAPTER_STATUS pAdapterStatus)
/*++
Routine Description:
This routine queries the information w.r.t a connection
Arguments:
pTransport - the associated transport
pAdapterStatus - ADAPTER STATUS structure
Return Value:
STATUS_SUCCESS - if the call was successfull.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PIRP pIrp = NULL;
if (pTransport->pControlChannelFileObject != NULL) {
// Obtain the related device object.
pTransport->pDeviceObject = IoGetRelatedDeviceObject(pTransport->pControlChannelFileObject);
pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE);
if (pIrp != NULL) {
PMDL pMdl;
pMdl = RxAllocateMdl(
pAdapterStatus, // Virtual address for MDL construction
sizeof(ADAPTER_STATUS)); // size of the buffer
if ( pMdl != NULL ) {
try {
MmProbeAndLockPages( pMdl, KernelMode, IoModifyAccess );
} except( EXCEPTION_EXECUTE_HANDLER ) {
IoFreeMdl( pMdl );
Status = GetExceptionCode();
}
if (NT_SUCCESS(Status)) {
// Get the file object associated with the connection.
TdiBuildQueryInformation(
pIrp,
pTransport->pDeviceObject,
pTransport->pControlChannelFileObject,
NULL, // Completion routine
NULL, // Completion context
TDI_QUERY_ADAPTER_STATUS,
pMdl);
Status = RxCeSubmitTdiRequest(
pTransport->pDeviceObject,
pIrp);
MmUnlockPages(pMdl);
IoFreeMdl(pMdl);
}
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
RxCeFreeIrp(pIrp);
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
} else {
Status = STATUS_ADDRESS_NOT_ASSOCIATED;
}
return Status;
}
NTSTATUS
RxTdiSend(
IN PRXCE_TRANSPORT pTransport,
IN PRXCE_ADDRESS pAddress,
IN PRXCE_CONNECTION pConnection,
IN PRXCE_VC pVc,
IN ULONG SendOptions,
IN PMDL pMdl,
IN ULONG SendLength,
IN PVOID pCompletionContext)
/*++
Routine Description:
This routine closes down a previously established connection.
Arguments:
pTransport - the associated transport
pAddress - the address object
pConnection - the connection
pVc - the virtual circuit to be disconnected.
SendOptions - the options for transmitting the data
pMdl - the buffer to be transmitted.
SendLength - length of data to be transmitted
Return Value:
STATUS_SUCCESS - if the call was successfull.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PMDL pPartialMdl = NULL;
ULONG MdlByteCount = MmGetMdlByteCount(pMdl);
PVOID pMdlAddress = MmGetMdlVirtualAddress(pMdl);
ULONG TdiOptions = (~RXCE_FLAGS_MASK & SendOptions);
BOOLEAN SynchronousSend = ((SendOptions & RXCE_SEND_SYNCHRONOUS) != 0);
RxProfile(RxTdi,RxTdiSend);
ASSERT(pMdl->MdlFlags & (MDL_PAGES_LOCKED|MDL_SOURCE_IS_NONPAGED_POOL|MDL_PARTIAL));
if (SendOptions & RXCE_SEND_PARTIAL) {
if (MdlByteCount > SendLength) {
pPartialMdl = IoAllocateMdl(pMdlAddress,SendLength,FALSE,FALSE,NULL);
if (pPartialMdl == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
} else {
RxBuildPartialHeaderMdl(pMdl,pPartialMdl,pMdlAddress,SendLength);
}
} else if (MdlByteCount == SendLength) {
// No need to build a partial MDL, reuse the MDl
pPartialMdl = pMdl;
} else {
ASSERT(!"MdlByteCount > SendLength");
return STATUS_INVALID_PARAMETER;
}
} else {
pPartialMdl = pMdl;
}
if (NT_SUCCESS(Status)) {
PIRP pIrp = NULL;
PRXTDI_REQUEST_COMPLETION_CONTEXT pRequestContext = NULL;
pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE);
if (pIrp != NULL) {
// Build the Send request to the underlying transport driver
TdiBuildSend(
pIrp, // the IRP
pTransport->pDeviceObject, // the device object
pVc->pEndpointFileObject, // the connection (VC) file object
NULL, // Completion routine
NULL, // completion context
pPartialMdl, // the data buffer
TdiOptions, // send flags
SendLength); // send buffer length
if (SynchronousSend) {
// Synchronous Send Request
Status = RxCeSubmitTdiRequest(
pTransport->pDeviceObject,
pIrp);
if ((pConnection->pHandler != NULL) &&
(pConnection->pHandler->RxCeSendCompleteEventHandler != NULL)) {
(pConnection->pHandler->RxCeSendCompleteEventHandler)(
pConnection->pContext,
pVc,
pCompletionContext,
pIrp->IoStatus.Status);
}
} else {
// Aysnchronous Send Request
// CODE.IMPROVEMENT The assertion needs to be strengthened after
// max command enfocement is in place.
// (pCompletionContext != NULL) && // the caller provided a valid context
ASSERT((pConnection->pHandler != NULL) && // the connection has a handler
(pConnection->pHandler->RxCeSendCompleteEventHandler != NULL));
pRequestContext = (PRXTDI_REQUEST_COMPLETION_CONTEXT)
RxAllocatePoolWithTag(
NonPagedPool,
sizeof(RXTDI_REQUEST_COMPLETION_CONTEXT),
RXCE_TDI_POOLTAG);
if (pRequestContext != NULL) {
if (pPartialMdl != pMdl) {
pRequestContext->pPartialMdl = pPartialMdl;
} else {
pRequestContext->pPartialMdl = NULL;
}
pRequestContext->pVc = pVc;
pRequestContext->pCompletionContext = pCompletionContext;
pRequestContext->ConnectionSendCompletionHandler = pConnection->pHandler->RxCeSendCompleteEventHandler;
pRequestContext->pEventContext = pConnection->pContext;
Status = RxCeSubmitAsynchronousTdiRequest(
pTransport->pDeviceObject,
pIrp,
pRequestContext);
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
} else {
// Could not allocate the IRP.
Status = STATUS_INSUFFICIENT_RESOURCES;
}
if (SynchronousSend) {
if (pPartialMdl != pMdl) {
IoFreeMdl( pPartialMdl );
}
if (pRequestContext != NULL) {
RxFreePool(pRequestContext);
}
if (pIrp != NULL) {
RxCeFreeIrp(pIrp);
}
} else {
if (pIrp != NULL && Status != STATUS_PENDING) {
DbgPrint("RDBSS AsyncSendReq returned %x %x\n", pIrp,Status);
//DbgBreakPoint();
}
}
}
return Status;
}
NTSTATUS
RxTdiSendDatagram(
IN PRXCE_TRANSPORT pTransport,
IN PRXCE_ADDRESS pAddress,
IN PRXCE_CONNECTION_INFORMATION pConnectionInformation,
IN ULONG Options,
IN PMDL pMdl,
IN ULONG SendLength,
IN PVOID pCompletionContext)
/*++
Routine Description:
This routine closes down a previously established connection.
Arguments:
pTransport - the associated transport
pAddress - the address object
pConnectionInformation - the remote address
Options - the send options.
pMdl - the send buffer
SendLength - length of data to be sent
Return Value:
STATUS_SUCCESS - if the call was successfull.
Notes:
In the current implementation the SYNCHRONOUS flag is disregarded for sending
datagrams because the underlying transports do not block on datagram sends.
Submission of request and completion of request happen simultaneously.
If a different behaviour is noted for some transports then the code for
SendDatagrams need to be implemented along the lines of a send.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PMDL pPartialMdl = NULL;
ULONG MdlByteCount = MmGetMdlByteCount(pMdl);
PVOID pMdlAddress = MmGetMdlVirtualAddress(pMdl);
ULONG TdiOptions = (~RXCE_FLAGS_MASK & Options);
RxProfile(RxTdi,RxTdiSendDatagram);
ASSERT(pMdl->MdlFlags & (MDL_PAGES_LOCKED|MDL_SOURCE_IS_NONPAGED_POOL|MDL_PARTIAL));
DbgDumpTransportAddress(
L"RxTdiSendDatagram",
pTransport,
(PTRANSPORT_ADDRESS)(pConnectionInformation->RemoteAddress)
);
if (Options & RXCE_SEND_PARTIAL) {
if (MdlByteCount > SendLength) {
pPartialMdl = IoAllocateMdl(pMdlAddress,SendLength,FALSE,FALSE,NULL);
if (pPartialMdl == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
} else {
RxBuildPartialHeaderMdl(pMdl,pPartialMdl,pMdlAddress,SendLength);
}
} else if (MdlByteCount == SendLength) {
// No need to build a partial MDL, reuse the MDl
pPartialMdl = pMdl;
} else {
RxDbgTrace(0, Dbg,("Mdl Length - %lx Send Length %lx\n",MdlByteCount,SendLength));
ASSERT(!"MdlByteCount > SendLength");
Status = STATUS_INVALID_PARAMETER;
}
} else {
pPartialMdl = pMdl;
}
if (NT_SUCCESS(Status)) {
PIRP pIrp;
pIrp = RxCeAllocateIrp(pTransport->pDeviceObject->StackSize,FALSE);
if (pIrp != NULL) {
// Build the disconnect request to the underlying transport driver
TdiBuildSendDatagram(
pIrp, // the IRP
pTransport->pDeviceObject, // the device object
pAddress->pFileObject, // the connection (VC) file object
NULL, // Completion routine
NULL, // completion context
pPartialMdl, // the send data buffer
SendLength, // the send data buffer length
pConnectionInformation); // remote address information
Status = RxCeSubmitTdiRequest(
pTransport->pDeviceObject,
pIrp);
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
if ((pAddress->pHandler != NULL) &&
(pAddress->pHandler->RxCeSendCompleteEventHandler != NULL)) {
(pAddress->pHandler->RxCeSendCompleteEventHandler)(
pAddress->pContext,
pCompletionContext,
Status);
}
if (pIrp != NULL) {
RxCeFreeIrp(pIrp);
}
if ((pPartialMdl != pMdl) && (pPartialMdl != NULL)) {
IoFreeMdl( pPartialMdl );
}
}
return Status;
}
NTSTATUS
RxTdiRequestCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
This routine does not complete the Irp. It is used to signal to a
synchronous part of the driver that it can proceed.
Arguments:
DeviceObject - unused.
Irp - Supplies Irp that the transport has finished processing.
Context - Supplies the event associated with the Irp.
Return Value:
The STATUS_MORE_PROCESSING_REQUIRED so that the IO system stops
processing Irp stack locations at this point.
--*/
{
RxDbgTrace(0, Dbg, ("CompletionEvent\n"));
if (Context != NULL)
KeSetEvent((PKEVENT )Context, 0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
UNREFERENCED_PARAMETER( DeviceObject );
UNREFERENCED_PARAMETER( Irp );
}
NTSTATUS
RxCeSubmitTdiRequest (
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
/*++
Routine Description:
This routine submits a request to TDI and waits for it to complete.
Arguments:
IN PDevice_OBJECT DeviceObject - Connection or Address handle for TDI request
IN PIRP Irp - TDI request to submit.
Return Value:
NTSTATUS - Final status of request.
--*/
{
NTSTATUS Status;
KEVENT Event;
KeInitializeEvent (
&Event,
NotificationEvent,
FALSE);
IoSetCompletionRoutine(
pIrp, // The IRP
RxTdiRequestCompletion, // The completion routine
&Event, // The completion context
TRUE, // Invoke On Success
TRUE, // Invoke On Error
TRUE); // Invoke On Cancel
//
// Submit the request
//
RxDbgTrace(0, Dbg,("IoCallDriver(pDeviceObject = %lx)\n",pDeviceObject));
Status = IoCallDriver(pDeviceObject, pIrp);
if (!NT_SUCCESS(Status)) {
RxDbgTrace(0, Dbg, ("IoCallDriver(pDeviceObject = %lx) returned %lx\n",pDeviceObject,Status));
}
if ((Status == STATUS_PENDING) || (Status == STATUS_SUCCESS)) {
RxDbgTrace(0, Dbg,("Waiting for Tdi Request Completion ....\n"));
Status = KeWaitForSingleObject(
&Event, // Object to wait on.
Executive, // Reason for waiting
KernelMode, // Processor mode
FALSE, // Alertable
NULL); // Timeout
if (!NT_SUCCESS(Status)) {
RxDbgTrace(0, Dbg,("RxTdiSubmitRequest could not wait Wait returned %lx\n",Status));
return Status;
}
Status = pIrp->IoStatus.Status;
} else {
if (!KeReadStateEvent(&Event)) {
DbgBreakPoint();
}
}
RxDbgTrace(0, Dbg, ("RxCeSubmitTdiRequest returned %lx\n",Status));
return Status;
}
NTSTATUS
RxTdiAsynchronousRequestCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP pIrp,
IN PVOID Context
)
/*++
Routine Description:
This routine completes an asynchronous send request.
Arguments:
DeviceObject - unused.
Irp - Supplies Irp that the transport has finished processing.
Context - Supplies the event associated with the Irp.
Return Value:
The STATUS_MORE_PROCESSING_REQUIRED so that the IO system stops
processing Irp stack locations at this point.
--*/
{
PRXTDI_REQUEST_COMPLETION_CONTEXT pRequestContext;
RxDbgTrace(0, Dbg,("RxTdiAsynchronousRequestCompletion\n"));
pRequestContext = (PRXTDI_REQUEST_COMPLETION_CONTEXT)Context;
if (pRequestContext->pPartialMdl != NULL) {
// Free the partial MDL.
IoFreeMdl(pRequestContext->pPartialMdl);
}
// Invoke the Completion event handler if any.
if (pRequestContext->pVc == NULL) {
if (pRequestContext->SendCompletionHandler != NULL) {
(pRequestContext->SendCompletionHandler)(
pRequestContext->pEventContext,
pRequestContext->pCompletionContext,
pIrp->IoStatus.Status);
}
} else {
if (pRequestContext->ConnectionSendCompletionHandler != NULL) {
(pRequestContext->ConnectionSendCompletionHandler)(
pRequestContext->pEventContext,
pRequestContext->pVc,
pRequestContext->pCompletionContext,
pIrp->IoStatus.Status);
}
}
// Free the IRP.
RxCeFreeIrp(pIrp);
// Free the request context
RxFreePool(pRequestContext);
return STATUS_MORE_PROCESSING_REQUIRED;
UNREFERENCED_PARAMETER( DeviceObject );
}
NTSTATUS
RxCeSubmitAsynchronousTdiRequest (
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp,
IN PRXTDI_REQUEST_COMPLETION_CONTEXT pRequestContext
)
/*++
Routine Description:
This routine submits a request to TDI and waits for it to complete.
Arguments:
IN PDevice_OBJECT DeviceObject - Connection or Address handle for TDI request
IN PIRP Irp - TDI request to submit.
Return Value:
NTSTATUS - Final status of request.
--*/
{
NTSTATUS Status;
ASSERT(pRequestContext != NULL);
IoSetCompletionRoutine(
pIrp, // The IRP
RxTdiAsynchronousRequestCompletion, // The completion routine
pRequestContext, // The completion context
TRUE, // Invoke On Success
TRUE, // Invoke On Error
TRUE); // Invoke On Cancel
//
// Submit the request
//
RxDbgTrace(0, Dbg, ("IoCallDriver(pDeviceObject = %lx)\n",pDeviceObject));
Status = IoCallDriver(pDeviceObject, pIrp);
if (!NT_SUCCESS(Status)) {
RxDbgTrace(0, Dbg, ("IoCallDriver(pDeviceObject = %lx) returned %lx\n",pDeviceObject,Status));
}
RxDbgTrace(0, Dbg, ("RxCeSubmitAsynchronousTdiRequest returned %lx\n",Status));
return Status;
}
NTSTATUS
BuildEaBuffer (
IN ULONG EaNameLength,
IN PVOID pEaName,
IN ULONG EaValueLength,
IN PVOID pEaValue,
OUT PFILE_FULL_EA_INFORMATION *pEaBufferPointer,
OUT PULONG pEaBufferLength
)
/*++
Routine Description:
Builds an EA buffer.
Arguments:
EaNameLength - Length of the Extended attribute name
pEaName - the extended attriute name
EaValueLength - Length of the Extended attribute value
pEaValue - the extended attribute value
pBuffer - the buffer for constructing the EA
--*/
{
PFILE_FULL_EA_INFORMATION pEaBuffer;
ULONG Length;
RxDbgTrace(0, Dbg, ("BuildEaBuffer\n"));
// Allocate an EA buffer for passing down the transport address
*pEaBufferLength = FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0] ) +
EaNameLength + 1 +
EaValueLength;
pEaBuffer = (PFILE_FULL_EA_INFORMATION)
RxAllocatePoolWithTag(
PagedPool,
*pEaBufferLength,
RXCE_TDI_POOLTAG);
if (pEaBuffer == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
*pEaBufferPointer = pEaBuffer;
pEaBuffer->NextEntryOffset = 0;
pEaBuffer->Flags = 0;
pEaBuffer->EaNameLength = (UCHAR)EaNameLength;
pEaBuffer->EaValueLength = (USHORT)EaValueLength;
RtlCopyMemory (
pEaBuffer->EaName,
pEaName,
pEaBuffer->EaNameLength + 1);
RtlCopyMemory(
&pEaBuffer->EaName[EaNameLength + 1],
pEaValue,
EaValueLength);
return STATUS_SUCCESS;
}
NTSTATUS
RxTdiCancelConnect(
IN PRXCE_TRANSPORT pTransport,
IN PRXCE_ADDRESS pAddress,
IN PRXCE_CONNECTION pConnection)
{
return STATUS_NOT_IMPLEMENTED;
}
#if DBG
void
DbgDumpTransportAddress(
PWSTR RoutineName,
PRXCE_TRANSPORT pTransport,
PTRANSPORT_ADDRESS pTA
)
/*++
Routine Description:
Description
Arguments:
None
Return Value:
None
--*/
{
ULONG i;
PTA_ADDRESS taa;
RxDbgTrace(0, Dbg,("%ws on %wZ, address count = %d\n",
RoutineName, &(pTransport->Name), pTA->TAAddressCount) );
taa = pTA->Address;
for( i = 0; i < (ULONG) pTA->TAAddressCount; i++ ){
RxDbgTrace(0, Dbg, ("\t%d:Address length %d type %d: ",
i, taa->AddressLength, taa->AddressType ));
switch (taa->AddressType) {
case TDI_ADDRESS_TYPE_NETBIOS_EX: {
PTDI_ADDRESS_NETBIOS_EX address = (PTDI_ADDRESS_NETBIOS_EX) taa->Address;
RxDbgTrace( 0, Dbg, ("Endpoint: \"%16.16s\" type %d name \"%16.16s\"\n",
address->EndpointName,
address->NetbiosAddress.NetbiosNameType,
address->NetbiosAddress.NetbiosName) );
break;
}
case TDI_ADDRESS_TYPE_NETBIOS: {
PTDI_ADDRESS_NETBIOS address = (PTDI_ADDRESS_NETBIOS) taa->Address;
RxDbgTrace( 0, Dbg, ("NBType %d name \"%16.16s\"\n",
address->NetbiosNameType,
address->NetbiosName) );
break;
}
case TDI_ADDRESS_TYPE_IP: {
PTDI_ADDRESS_IP address = (PTDI_ADDRESS_IP) taa->Address;
RxDbgTrace( 0, Dbg, ("IP port %d addr 0x%x\n", address->sin_port, address->in_addr ) );
break;
}
default: {
RxDbgTrace( 0, Dbg, ("Unknown!\n") );
}
}
taa = (PTA_ADDRESS) (taa->Address + taa->AddressLength);
}
}
#endif