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.
2139 lines
65 KiB
2139 lines
65 KiB
/*++
|
|
|
|
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( Status != STATUS_PENDING &&
|
|
pPartialMdl != pMdl ) {
|
|
|
|
IoFreeMdl( pPartialMdl );
|
|
}
|
|
|
|
// 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
|
|
|