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.
1595 lines
52 KiB
1595 lines
52 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
rxcemgmt.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the RXCE routines related to connection management.
|
|
|
|
Revision History:
|
|
|
|
Balan Sethu Raman [SethuR] 15-Feb-1995
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, RxCepInitializeVC)
|
|
#pragma alloc_text(PAGE, RxCeBuildVC)
|
|
#pragma alloc_text(PAGE, RxCeTearDownVC)
|
|
#pragma alloc_text(PAGE, RxCeInitiateVCDisconnect)
|
|
#pragma alloc_text(PAGE, DuplicateConnectionInformation)
|
|
#pragma alloc_text(PAGE, RxCepInitializeConnection)
|
|
#pragma alloc_text(PAGE, RxCeBuildConnection)
|
|
#pragma alloc_text(PAGE, RxCeCleanupConnectCallOutContext)
|
|
#pragma alloc_text(PAGE, RxCeBuildConnectionOverMultipleTransports)
|
|
#pragma alloc_text(PAGE, RxCeTearDownConnection)
|
|
#pragma alloc_text(PAGE, RxCeCancelConnectRequest)
|
|
#pragma alloc_text(PAGE, RxCeQueryInformation)
|
|
#endif
|
|
|
|
//
|
|
// The debug trace level
|
|
//
|
|
|
|
#define Dbg (DEBUG_TRACE_RXCEMANAGEMENT)
|
|
|
|
NTSTATUS
|
|
RxCepInitializeVC(
|
|
PRXCE_VC pVc,
|
|
PRXCE_CONNECTION pConnection)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes a VCdata structure
|
|
|
|
Arguments:
|
|
|
|
pVc - the VC instance.
|
|
|
|
pConnection - the connection.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successfull.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
PAGED_CODE();
|
|
|
|
ASSERT(RxCeIsConnectionValid(pConnection));
|
|
|
|
RtlZeroMemory(
|
|
pVc,
|
|
sizeof(RXCE_VC));
|
|
|
|
pVc->Signature = RXCE_VC_SIGNATURE;
|
|
pVc->pConnection = pConnection;
|
|
pVc->hEndpoint = INVALID_HANDLE_VALUE;
|
|
pVc->State = RXCE_VC_DISCONNECTED;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxCeBuildVC(
|
|
IN OUT PRXCE_VC pVc,
|
|
IN PRXCE_CONNECTION pConnection)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine adds a virtual circuit to a specified connection
|
|
|
|
Arguments:
|
|
|
|
pConnection - the connection for which a VC is to be added
|
|
|
|
pVcPointer - the handle of the new virtual circuit
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successfull.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
|
|
|
PRXCE_TRANSPORT pTransport = NULL;
|
|
PRXCE_ADDRESS pAddress = NULL;
|
|
|
|
PAGED_CODE();
|
|
|
|
// Update profiling info.
|
|
RxProfile(RxCeManagement,RxCeBuildVc);
|
|
|
|
try {
|
|
pAddress = pConnection->pAddress;
|
|
pTransport = pAddress->pTransport;
|
|
|
|
if (RxCeIsConnectionValid(pConnection) &&
|
|
RxCeIsAddressValid(pAddress) &&
|
|
RxCeIsTransportValid(pTransport)) {
|
|
|
|
Status = RxCepInitializeVC(
|
|
pVc,
|
|
pConnection);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = RxTdiConnect(
|
|
pTransport, // the associated transport
|
|
pAddress, // the RxCe address
|
|
pConnection, // the RxCe connection
|
|
pVc); // the RxCe virtual circuit associated with the connection
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
pVc->State = RXCE_VC_ACTIVE;
|
|
}
|
|
}
|
|
}
|
|
} finally {
|
|
if (AbnormalTermination()) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
RxLog(("RxCeAddVC: VC: %lx Status %lx\n",pVc,Status));
|
|
RxWmiLog(LOG,
|
|
RxCeBuildVC,
|
|
LOGPTR(pVc)
|
|
LOGULONG(Status));
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
RxCeInitiateVCDisconnect(
|
|
IN PRXCE_VC pVc)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initiates a disconnect on the VC.
|
|
|
|
Arguments:
|
|
|
|
pVc - the VC instance to be disconnected
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successfull.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PRXCE_TRANSPORT pTransport = NULL;
|
|
PRXCE_ADDRESS pAddress = NULL;
|
|
PRXCE_CONNECTION pConnection = NULL;
|
|
|
|
PAGED_CODE();
|
|
|
|
// Update profiling info.
|
|
RxProfile(RxCeManagement,RxCeTearDownVc);
|
|
|
|
try {
|
|
if ((pVc->pEndpointFileObject != NULL) &&
|
|
(pVc->hEndpoint != INVALID_HANDLE_VALUE)) {
|
|
pConnection = pVc->pConnection;
|
|
pAddress = pConnection->pAddress;
|
|
pTransport = pAddress->pTransport;
|
|
|
|
if (RxCeIsVcValid(pVc) &&
|
|
RxCeIsConnectionValid(pConnection) &&
|
|
RxCeIsAddressValid(pAddress) &&
|
|
RxCeIsTransportValid(pTransport)) {
|
|
|
|
LONG VcState = InterlockedExchange(
|
|
&pVc->State,
|
|
RXCE_VC_TEARDOWN);
|
|
|
|
if (VcState != RXCE_VC_TEARDOWN) {
|
|
Status = RxTdiDisconnect(
|
|
pTransport, // the associated transport
|
|
pAddress, // the RxCe address
|
|
pConnection, // the RxCe connection
|
|
pVc, // the RxCe virtual circuit associated with the connection
|
|
RXCE_DISCONNECT_ABORT); // disconnect options
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
RxDbgTrace(0, Dbg,("RxCeTearDownVC returned %lx\n",Status));
|
|
}
|
|
} else {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
} else {
|
|
RxDbgTrace(0, Dbg,("RxCeTearDownVC -- Invalid VC %lx\n",pVc));
|
|
}
|
|
}
|
|
} finally {
|
|
if (AbnormalTermination()) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
RxLog(("RxCeInitiateVCDisconnect: VC: %lx Status %lx\n",pVc,Status));
|
|
RxWmiLog(LOG,
|
|
RxCeInitiateVCDisconnect,
|
|
LOGPTR(pVc)
|
|
LOGULONG(Status));
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxCeTearDownVC(
|
|
IN PRXCE_VC pVc)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine tears down the VC instance.
|
|
|
|
Arguments:
|
|
|
|
pVc - the VC instance to be torn down
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successfull.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PRXCE_TRANSPORT pTransport = NULL;
|
|
PRXCE_ADDRESS pAddress = NULL;
|
|
PRXCE_CONNECTION pConnection = NULL;
|
|
|
|
PAGED_CODE();
|
|
|
|
// Update profiling info.
|
|
RxProfile(RxCeManagement,RxCeTearDownVc);
|
|
|
|
try {
|
|
if (pVc->pCleanUpEvent != NULL) {
|
|
// wait for the clean up of connections over other transports to be completed
|
|
KeWaitForSingleObject(
|
|
pVc->pCleanUpEvent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
RxFreePool(pVc->pCleanUpEvent);
|
|
pVc->pCleanUpEvent = NULL;
|
|
}
|
|
|
|
if ((pVc->pEndpointFileObject != NULL) &&
|
|
(pVc->hEndpoint != INVALID_HANDLE_VALUE)) {
|
|
pConnection = pVc->pConnection;
|
|
pAddress = pConnection->pAddress;
|
|
pTransport = pAddress->pTransport;
|
|
|
|
if (RxCeIsVcValid(pVc) &&
|
|
RxCeIsConnectionValid(pConnection) &&
|
|
RxCeIsAddressValid(pAddress) &&
|
|
RxCeIsTransportValid(pTransport)) {
|
|
|
|
LONG VcState = InterlockedExchange(
|
|
&pVc->State,
|
|
RXCE_VC_TEARDOWN);
|
|
|
|
if (VcState != RXCE_VC_TEARDOWN) {
|
|
Status = RxTdiDisconnect(
|
|
pTransport, // the associated transport
|
|
pAddress, // the RxCe address
|
|
pConnection, // the RxCe connection
|
|
pVc, // the RxCe virtual circuit associated with the connection
|
|
RXCE_DISCONNECT_ABORT); // disconnect options
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
RxDbgTrace(0, Dbg,("RxCeTearDownVC returned %lx\n",Status));
|
|
}
|
|
} else {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
} else {
|
|
RxDbgTrace(0, Dbg,("RxCeTearDownVC -- Invalid VC %lx\n",pVc));
|
|
}
|
|
|
|
// Dereference the endpoint file object.
|
|
ObDereferenceObject(pVc->pEndpointFileObject);
|
|
|
|
// Close the endpoint file object handle
|
|
Status = ZwClose(pVc->hEndpoint);
|
|
|
|
ASSERT(Status == STATUS_SUCCESS);
|
|
|
|
pVc->hEndpoint = INVALID_HANDLE_VALUE;
|
|
pVc->pEndpointFileObject = NULL;
|
|
}
|
|
|
|
RtlZeroMemory(pVc,sizeof(RXCE_VC));
|
|
} finally {
|
|
if (AbnormalTermination()) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
RxLog(("RxCeTearDownVC: VC: %lx Status %lx\n",pVc,Status));
|
|
RxWmiLog(LOG,
|
|
RxCeTearDownVC,
|
|
LOGPTR(pVc)
|
|
LOGULONG(Status));
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DuplicateConnectionInformation(
|
|
PRXCE_CONNECTION_INFORMATION *pCopy,
|
|
PRXCE_CONNECTION_INFORMATION pOriginal,
|
|
POOL_TYPE PoolType)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine duplicates a connection information addresses.
|
|
|
|
Arguments:
|
|
|
|
pCopy - the pointer to the new copy
|
|
|
|
pOriginal - the original.
|
|
|
|
PoolType - type of pool for memory allocation
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
PVOID pUserData = NULL;
|
|
PVOID pRemoteAddress = NULL;
|
|
PVOID pOptions = NULL;
|
|
PRXCE_CONNECTION_INFORMATION pConnectionInformation = NULL;
|
|
BOOLEAN fFailed = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
pConnectionInformation = RxAllocatePoolWithTag(
|
|
PoolType,
|
|
sizeof(RXCE_CONNECTION_INFORMATION),
|
|
RXCE_CONNECTION_POOLTAG);
|
|
if (pConnectionInformation != NULL) {
|
|
RtlCopyMemory(
|
|
pConnectionInformation,
|
|
pOriginal,
|
|
sizeof(RXCE_CONNECTION_INFORMATION));
|
|
} else
|
|
fFailed = TRUE;
|
|
|
|
if (!fFailed && pOriginal->UserDataLength > 0) {
|
|
pUserData = RxAllocatePoolWithTag(
|
|
PoolType,
|
|
pOriginal->UserDataLength,
|
|
RXCE_CONNECTION_POOLTAG);
|
|
if (pUserData != NULL) {
|
|
RtlCopyMemory(
|
|
pUserData,
|
|
pOriginal->UserData,
|
|
pOriginal->UserDataLength);
|
|
} else
|
|
fFailed = TRUE;
|
|
}
|
|
|
|
if (!fFailed && pOriginal->RemoteAddressLength > 0) {
|
|
pRemoteAddress = RxAllocatePoolWithTag(
|
|
PoolType,
|
|
pOriginal->RemoteAddressLength,
|
|
RXCE_CONNECTION_POOLTAG);
|
|
if (pRemoteAddress != NULL) {
|
|
PTA_ADDRESS pTaAdress;
|
|
PTRANSPORT_ADDRESS pTransportAddress = (PTRANSPORT_ADDRESS)pRemoteAddress;
|
|
LONG NoOfAddress;
|
|
|
|
RtlCopyMemory(
|
|
pRemoteAddress,
|
|
pOriginal->RemoteAddress,
|
|
pOriginal->RemoteAddressLength);
|
|
|
|
pTaAdress = &pTransportAddress->Address[0];
|
|
|
|
for (NoOfAddress=0; NoOfAddress<pTransportAddress->TAAddressCount;NoOfAddress++) {
|
|
if (pTaAdress->AddressType == TDI_ADDRESS_TYPE_NETBIOS_UNICODE_EX) {
|
|
PTDI_ADDRESS_NETBIOS_UNICODE_EX pTdiNetbiosUnicodeExAddress;
|
|
|
|
pTdiNetbiosUnicodeExAddress = (PTDI_ADDRESS_NETBIOS_UNICODE_EX)pTaAdress->Address;
|
|
pTdiNetbiosUnicodeExAddress->EndpointName.Buffer = (PWSTR)pTdiNetbiosUnicodeExAddress->EndpointBuffer;
|
|
pTdiNetbiosUnicodeExAddress->RemoteName.Buffer = (PWSTR)pTdiNetbiosUnicodeExAddress->RemoteNameBuffer;
|
|
|
|
//DbgPrint("Rdbss copy NETBIOS_UNICODE_EX on TA %lx UA %lx %wZ %wZ\n",
|
|
// pTaAdress,
|
|
// pTdiNetbiosUnicodeExAddress,
|
|
// &pTdiNetbiosUnicodeExAddress->EndpointName,
|
|
// &pTdiNetbiosUnicodeExAddress->RemoteName);
|
|
break;
|
|
} else {
|
|
pTaAdress = (PTA_ADDRESS)((PCHAR)pTaAdress +
|
|
FIELD_OFFSET(TA_ADDRESS,Address) +
|
|
pTaAdress->AddressLength);
|
|
}
|
|
}
|
|
} else
|
|
fFailed = TRUE;
|
|
}
|
|
|
|
if (!fFailed && pOriginal->OptionsLength > 0) {
|
|
pOptions = RxAllocatePoolWithTag(
|
|
PoolType,
|
|
pOriginal->OptionsLength,
|
|
RXCE_CONNECTION_POOLTAG);
|
|
|
|
if (pOptions != NULL) {
|
|
RtlCopyMemory(
|
|
pOptions,
|
|
pOriginal->Options,
|
|
pOriginal->OptionsLength);
|
|
} else
|
|
fFailed = TRUE;
|
|
}
|
|
|
|
if (!fFailed) {
|
|
pConnectionInformation->UserData = pUserData;
|
|
pConnectionInformation->RemoteAddress = pRemoteAddress;
|
|
pConnectionInformation->Options = pOptions;
|
|
*pCopy = pConnectionInformation;
|
|
return STATUS_SUCCESS;
|
|
} else {
|
|
if (pOptions != NULL) {
|
|
RxFreePool(pOptions);
|
|
}
|
|
|
|
if (pRemoteAddress != NULL) {
|
|
RxFreePool(pRemoteAddress);
|
|
}
|
|
|
|
if (pUserData != NULL) {
|
|
RxFreePool(pUserData);
|
|
}
|
|
|
|
if (pConnectionInformation != NULL) {
|
|
RxFreePool(pConnectionInformation);
|
|
}
|
|
|
|
*pCopy = NULL;
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
RxCepInitializeConnection(
|
|
IN OUT PRXCE_CONNECTION pConnection,
|
|
IN PRXCE_ADDRESS pAddress,
|
|
IN PRXCE_CONNECTION_INFORMATION pConnectionInformation,
|
|
IN PRXCE_CONNECTION_EVENT_HANDLER pHandler,
|
|
IN PVOID pEventContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes a connection data structure
|
|
|
|
Arguments:
|
|
|
|
pConnection - the newly created connection.
|
|
|
|
pAddress - the local address
|
|
|
|
pConnectionInformation - the connection information specifying the remote address.
|
|
|
|
pHandler - the handler for processing receive indications
|
|
|
|
pEventContext - the context to be used for indications
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successfull.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
// Initialize the new connection
|
|
RtlZeroMemory(
|
|
pConnection,
|
|
sizeof(RXCE_CONNECTION));
|
|
|
|
pConnection->Signature = RXCE_CONNECTION_SIGNATURE;
|
|
pConnection->pAddress = pAddress;
|
|
|
|
// Duplicate the connection information if successful
|
|
if (pConnectionInformation != NULL) {
|
|
Status = DuplicateConnectionInformation(
|
|
&pConnection->pConnectionInformation,
|
|
pConnectionInformation,
|
|
NonPagedPool);
|
|
}
|
|
|
|
if (NT_SUCCESS(Status) &&
|
|
(pHandler != NULL)) {
|
|
pConnection->pHandler = (PRXCE_CONNECTION_EVENT_HANDLER)
|
|
RxAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(RXCE_CONNECTION_EVENT_HANDLER),
|
|
RXCE_CONNECTION_POOLTAG);
|
|
|
|
if (pConnection->pHandler != NULL) {
|
|
RtlZeroMemory(
|
|
pConnection->pHandler,
|
|
sizeof(RXCE_CONNECTION_EVENT_HANDLER));
|
|
|
|
*(pConnection->pHandler) = *pHandler;
|
|
pConnection->pContext = pEventContext;
|
|
} else {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxCeBuildConnection(
|
|
IN PRXCE_ADDRESS pAddress,
|
|
IN PRXCE_CONNECTION_INFORMATION pConnectionInformation,
|
|
IN PRXCE_CONNECTION_EVENT_HANDLER pHandler,
|
|
IN PVOID pEventContext,
|
|
IN OUT PRXCE_CONNECTION pConnection,
|
|
IN OUT PRXCE_VC pVc)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine establishes a connection between a local RxCe address and a given remote address
|
|
|
|
Arguments:
|
|
|
|
pAddress - the local address
|
|
|
|
pConnectionInformation - the connection information specifying the remote address.
|
|
|
|
pHandler - the handler for processing receive indications
|
|
|
|
pEventContext - the context to be used for indications
|
|
|
|
pConnection - the newly created connection.
|
|
|
|
pVc - the VC associated with the connection.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successfull.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PRXCE_TRANSPORT pTransport = NULL;
|
|
|
|
PAGED_CODE();
|
|
|
|
// Update profiling info.
|
|
RxProfile(RxCeManagement,RxCeBuildConnection);
|
|
|
|
try {
|
|
pTransport = pAddress->pTransport;
|
|
|
|
if (RxCeIsAddressValid(pAddress) &&
|
|
RxCeIsTransportValid(pTransport)) {
|
|
|
|
Status = RxCepInitializeConnection(
|
|
pConnection,
|
|
pAddress,
|
|
pConnectionInformation,
|
|
pHandler,
|
|
pEventContext);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = RxCeBuildVC(pVc,pConnection);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
RxCeTearDownVC(pVc);
|
|
RxCeTearDownConnection(pConnection);
|
|
RxDbgTrace(0, Dbg,("RxCeOpenConnection returned %lx\n",Status));
|
|
} else {
|
|
// NetBT may return the DNS name on Remote Address
|
|
RtlCopyMemory(pConnectionInformation->RemoteAddress,
|
|
pConnection->pConnectionInformation->RemoteAddress,
|
|
pConnection->pConnectionInformation->RemoteAddressLength);
|
|
}
|
|
} else {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
} finally {
|
|
if (AbnormalTermination()) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
RxLog(("RxCeCreateConnection %lx \n",pAddress));
|
|
RxWmiLog(LOG,
|
|
RxCeBuildConnection,
|
|
LOGPTR(pAddress));
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
extern
|
|
NTSTATUS
|
|
RxCeCompleteConnectRequest(
|
|
PRX_CALLOUT_PARAMETERS_BLOCK pParameterBlock);
|
|
|
|
NTSTATUS
|
|
RxCeInitiateConnectRequest(
|
|
PRX_CALLOUT_PARAMETERS_BLOCK pParameterBlock)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initiates a connection callout request to a particular transport
|
|
|
|
Arguments:
|
|
|
|
pParameterBlock - the parameter block for initaiting the connection.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
KIRQL OldIrql;
|
|
|
|
BOOLEAN InitiateConnectionRequest;
|
|
|
|
PRX_CREATE_CONNECTION_CALLOUT_CONTEXT pCreateConnectionContext;
|
|
|
|
pCreateConnectionContext = (PRX_CREATE_CONNECTION_CALLOUT_CONTEXT)
|
|
pParameterBlock->pCallOutContext;
|
|
|
|
KeAcquireSpinLock(&pCreateConnectionContext->SpinLock,&OldIrql);
|
|
|
|
InitiateConnectionRequest = (!pCreateConnectionContext->WinnerFound);
|
|
|
|
KeReleaseSpinLock(&pCreateConnectionContext->SpinLock,OldIrql);
|
|
|
|
if (InitiateConnectionRequest) {
|
|
Status = RxTdiInitiateAsynchronousConnect(
|
|
(PRX_CREATE_CONNECTION_PARAMETERS_BLOCK)pParameterBlock);
|
|
} else {
|
|
Status = STATUS_CANCELLED;
|
|
}
|
|
|
|
if (Status != STATUS_PENDING) {
|
|
pParameterBlock->CallOutStatus = Status;
|
|
|
|
RxCeCompleteConnectRequest(pParameterBlock);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
RxCeCleanupConnectCallOutContext(
|
|
PRX_CREATE_CONNECTION_CALLOUT_CONTEXT pCreateConnectionContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine cleansup a connection callout request. This cannot be done in
|
|
the context of any of the transport callback routines because of environmental
|
|
constraints, i.e., Transports can callback at DPC level.
|
|
|
|
Arguments:
|
|
|
|
pCreateConnectionContext - the connection context.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
// Walk through the list of parameter blocks associated with this
|
|
// callout context and initiate the appropriate tear down action.
|
|
|
|
PRX_CREATE_CONNECTION_PARAMETERS_BLOCK pTempParameterBlock;
|
|
PRDBSS_DEVICE_OBJECT pRxDeviceObject = NULL;
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
pRxDeviceObject = pCreateConnectionContext->pRxDeviceObject;
|
|
|
|
pTempParameterBlock = (PRX_CREATE_CONNECTION_PARAMETERS_BLOCK)
|
|
pCreateConnectionContext->pCallOutParameterBlock;
|
|
|
|
while (pTempParameterBlock != NULL) {
|
|
if (pTempParameterBlock->CallOutId != pCreateConnectionContext->WinnerCallOutId) {
|
|
RxTdiCleanupAsynchronousConnect(
|
|
pTempParameterBlock);
|
|
}
|
|
|
|
RxCeTearDownVC(
|
|
&pTempParameterBlock->Vc);
|
|
|
|
RxCeTearDownConnection(
|
|
&pTempParameterBlock->Connection);
|
|
|
|
pTempParameterBlock = (PRX_CREATE_CONNECTION_PARAMETERS_BLOCK)
|
|
pTempParameterBlock->pNextCallOutParameterBlock;
|
|
}
|
|
|
|
if (pCreateConnectionContext->pCallOutParameterBlock != NULL) {
|
|
RxLog(("Freeparamblock %x, %x\n",
|
|
pCreateConnectionContext->pCallOutParameterBlock, KeGetCurrentThread()));
|
|
RxWmiLog(LOG,
|
|
RxCeCleanupConnectCallOutContext,
|
|
LOGPTR(pCreateConnectionContext->pCallOutParameterBlock));
|
|
RxFreePool(pCreateConnectionContext->pCallOutParameterBlock);
|
|
}
|
|
|
|
if (pCreateConnectionContext->pCleanUpEvent != NULL) {
|
|
RxFreePool(pCreateConnectionContext->pCleanUpEvent);
|
|
} else {
|
|
PRXCE_VC pVc = pCreateConnectionContext->pConnectionContext;
|
|
|
|
KeSetEvent(pVc->pCleanUpEvent, 0, FALSE);
|
|
}
|
|
|
|
RxFreePool(pCreateConnectionContext);
|
|
|
|
if (pRxDeviceObject != NULL) {
|
|
RxDeregisterAsynchronousRequest(pRxDeviceObject);
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
RxCeCompleteConnectRequest(
|
|
PRX_CALLOUT_PARAMETERS_BLOCK pParameterBlock)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine completes a connection callout request
|
|
|
|
Arguments:
|
|
|
|
pParameterBlock - the parameter block instance.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN AllCallOutsCompleted = FALSE;
|
|
BOOLEAN AllCallOutsInitiated = FALSE;
|
|
BOOLEAN InvokeCompletionRoutine = FALSE;
|
|
BOOLEAN WinnerFound = FALSE;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
KIRQL OldIrql;
|
|
|
|
PRX_CREATE_CONNECTION_PARAMETERS_BLOCK pWinningParameterBlock;
|
|
|
|
PRX_CREATE_CONNECTION_CALLOUT_CONTEXT pCreateConnectionContext;
|
|
PRXCE_CONNECTION_COMPLETION_CONTEXT pCompletionContext;
|
|
PRXCE_CONNECTION_COMPLETION_ROUTINE pCompletionRoutine;
|
|
|
|
pCreateConnectionContext = (PRX_CREATE_CONNECTION_CALLOUT_CONTEXT)
|
|
pParameterBlock->pCallOutContext;
|
|
|
|
// save the two values below as the pCreateConnectionContext may be freed
|
|
|
|
pCompletionContext = pCreateConnectionContext->pCompletionContext;
|
|
pCompletionRoutine = pCreateConnectionContext->pCompletionRoutine;
|
|
|
|
pWinningParameterBlock = NULL;
|
|
|
|
KeAcquireSpinLock(&pCreateConnectionContext->SpinLock,&OldIrql);
|
|
|
|
if (!pCreateConnectionContext->WinnerFound) {
|
|
if (pParameterBlock->CallOutStatus == STATUS_SUCCESS) {
|
|
// This instance of the call out was successful. Determine if this
|
|
// instance is the winner.
|
|
|
|
// In those cases in which the option was to select the best possible transport
|
|
// the callout id of this instance must be less than the previously recorded
|
|
// winner for the expectations to be revised.
|
|
|
|
switch (pCreateConnectionContext->CreateOptions) {
|
|
case RxCeSelectBestSuccessfulTransport:
|
|
if (pParameterBlock->CallOutId != pCreateConnectionContext->BestPossibleWinner) {
|
|
break;
|
|
}
|
|
// lack of break intentional. The processing for the winner in the best transport case
|
|
// and the first transport case is identical and have been folded together
|
|
case RxCeSelectFirstSuccessfulTransport:
|
|
{
|
|
pWinningParameterBlock = (PRX_CREATE_CONNECTION_PARAMETERS_BLOCK)
|
|
pParameterBlock;
|
|
}
|
|
break;
|
|
|
|
case RxCeSelectAllSuccessfulTransports:
|
|
default:
|
|
ASSERT(!"RXCE connection create option not yet implemented");
|
|
break;
|
|
}
|
|
} else {
|
|
switch (pCreateConnectionContext->CreateOptions) {
|
|
case RxCeSelectBestSuccessfulTransport:
|
|
{
|
|
// This instance was not successful. This implies one of two things
|
|
// -- a previously completed transport can be the winner or we can
|
|
// adjust our expectations as regards the eventual winner.
|
|
|
|
if (pParameterBlock->CallOutId == pCreateConnectionContext->BestPossibleWinner) {
|
|
// The transport that was regarded as the best transport has reported
|
|
// failure. Revise our expectations as regards the best transport.
|
|
|
|
PRX_CREATE_CONNECTION_PARAMETERS_BLOCK pTempParameterBlock;
|
|
|
|
pTempParameterBlock = (PRX_CREATE_CONNECTION_PARAMETERS_BLOCK)
|
|
pCreateConnectionContext->pCallOutParameterBlock;
|
|
|
|
while (pTempParameterBlock != NULL) {
|
|
PRX_CREATE_CONNECTION_PARAMETERS_BLOCK pNextParameterBlock;
|
|
|
|
pNextParameterBlock = (PRX_CREATE_CONNECTION_PARAMETERS_BLOCK)
|
|
pTempParameterBlock->pNextCallOutParameterBlock;
|
|
|
|
if (pTempParameterBlock->CallOutId < pCreateConnectionContext->BestPossibleWinner) {
|
|
ASSERT(pTempParameterBlock->CallOutStatus != STATUS_SUCCESS);
|
|
} else {
|
|
if (pNextParameterBlock != NULL) {
|
|
if (pNextParameterBlock->CallOutStatus
|
|
== STATUS_PENDING) {
|
|
pCreateConnectionContext->BestPossibleWinner =
|
|
pNextParameterBlock->CallOutId;
|
|
break;
|
|
} else if (pNextParameterBlock->CallOutStatus
|
|
== STATUS_SUCCESS ) {
|
|
pWinningParameterBlock = pNextParameterBlock;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
pTempParameterBlock = pNextParameterBlock;
|
|
}
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case RxCeSelectAllSuccessfulTransports:
|
|
case RxCeSelectFirstSuccessfulTransport:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pWinningParameterBlock != NULL) {
|
|
// Transfer the parameters associated with the winning parameter block
|
|
// onto the original connection and prepare the call out parameter block
|
|
// for cleanup.
|
|
|
|
pCreateConnectionContext->WinnerFound = TRUE;
|
|
pCreateConnectionContext->WinnerCallOutId = pWinningParameterBlock->CallOutId;
|
|
|
|
pCompletionContext->Status = STATUS_SUCCESS;
|
|
pCompletionContext->AddressIndex = pWinningParameterBlock->CallOutId;
|
|
|
|
pCompletionContext->pConnection->pAddress =
|
|
pWinningParameterBlock->Connection.pAddress;
|
|
|
|
pCompletionContext->pVc->hEndpoint =
|
|
pWinningParameterBlock->Vc.hEndpoint;
|
|
|
|
pCompletionContext->pVc->pEndpointFileObject =
|
|
pWinningParameterBlock->Vc.pEndpointFileObject;
|
|
|
|
pCompletionContext->pVc->State = RXCE_VC_ACTIVE;
|
|
|
|
pCompletionContext->pVc->pCleanUpEvent = pCreateConnectionContext->pCleanUpEvent;
|
|
pCreateConnectionContext->pCleanUpEvent = NULL;
|
|
|
|
pWinningParameterBlock->Vc.hEndpoint = INVALID_HANDLE_VALUE;
|
|
pWinningParameterBlock->Vc.pEndpointFileObject = NULL;
|
|
|
|
//DbgPrint("Remote address src %lx target %lx\n",
|
|
// pWinningParameterBlock->Connection.pConnectionInformation->RemoteAddress,
|
|
// pCompletionContext->pConnectionInformation->RemoteAddress);
|
|
|
|
if (pCompletionContext->pConnectionInformation)
|
|
{
|
|
// Copy the buffer which may contain the DNS name returned back from TDI
|
|
RtlCopyMemory(pCompletionContext->pConnectionInformation->RemoteAddress,
|
|
pWinningParameterBlock->Connection.pConnectionInformation->RemoteAddress,
|
|
pWinningParameterBlock->Connection.pConnectionInformation->RemoteAddressLength);
|
|
}
|
|
|
|
//{
|
|
// PTRANSPORT_ADDRESS pTransportAddress = (PTRANSPORT_ADDRESS)pWinningParameterBlock->Connection.pConnectionInformation->RemoteAddress;
|
|
// DbgPrint("Number of TA returned %d %lx\n",pTransportAddress->TAAddressCount,pTransportAddress->Address);
|
|
//}
|
|
}
|
|
}
|
|
|
|
AllCallOutsInitiated = (pCreateConnectionContext->NumberOfCallOutsInitiated
|
|
== pCreateConnectionContext->NumberOfCallOuts);
|
|
|
|
((PRX_CREATE_CONNECTION_PARAMETERS_BLOCK)pParameterBlock)->pConnectIrp = NULL;
|
|
|
|
KeReleaseSpinLock(&pCreateConnectionContext->SpinLock,OldIrql);
|
|
|
|
// The winning transport has been located. Cancel all the other requests.
|
|
if (pWinningParameterBlock != NULL) {
|
|
PRX_CREATE_CONNECTION_PARAMETERS_BLOCK pTempParameterBlock, pNextTempBlock;
|
|
|
|
pTempParameterBlock = (PRX_CREATE_CONNECTION_PARAMETERS_BLOCK)
|
|
pCreateConnectionContext->pCallOutParameterBlock;
|
|
|
|
RxLog(("Use paramblock %x %x\n", pTempParameterBlock, KeGetCurrentThread()));
|
|
RxWmiLog(LOG,
|
|
RxCeCompleteConnectRequest,
|
|
LOGPTR(pTempParameterBlock));
|
|
while (pTempParameterBlock != NULL) {
|
|
|
|
pNextTempBlock = (PRX_CREATE_CONNECTION_PARAMETERS_BLOCK)
|
|
pTempParameterBlock->pNextCallOutParameterBlock;
|
|
|
|
if (pTempParameterBlock->CallOutStatus == STATUS_PENDING) {
|
|
|
|
// get the next block becfore we do the cancel and set the
|
|
// current guys status to cacncelled
|
|
// Don't touch it after cancellation as he may have gone away
|
|
// by then
|
|
|
|
pTempParameterBlock->CallOutStatus = STATUS_CANCELLED;
|
|
|
|
RxTdiCancelAsynchronousConnect(pTempParameterBlock);
|
|
}
|
|
|
|
pTempParameterBlock = pNextTempBlock;
|
|
}
|
|
}
|
|
|
|
KeAcquireSpinLock(&pCreateConnectionContext->SpinLock,&OldIrql);
|
|
|
|
AllCallOutsCompleted =
|
|
(InterlockedIncrement(&pCreateConnectionContext->NumberOfCallOutsCompleted) ==
|
|
pCreateConnectionContext->NumberOfCallOuts);
|
|
|
|
if (AllCallOutsCompleted) {
|
|
if (!pCreateConnectionContext->WinnerFound) {
|
|
pCompletionContext->Status = pParameterBlock->CallOutStatus;
|
|
}
|
|
}
|
|
|
|
if (AllCallOutsInitiated &&
|
|
(AllCallOutsCompleted || pCreateConnectionContext->WinnerFound) &&
|
|
!pCreateConnectionContext->CompletionRoutineInvoked) {
|
|
InvokeCompletionRoutine = TRUE;
|
|
pCreateConnectionContext->CompletionRoutineInvoked = TRUE;
|
|
}
|
|
|
|
KeReleaseSpinLock(&pCreateConnectionContext->SpinLock,OldIrql);
|
|
|
|
if ((Status == STATUS_SUCCESS) && AllCallOutsCompleted) {
|
|
Status = RxPostToWorkerThread(
|
|
RxFileSystemDeviceObject,
|
|
HyperCriticalWorkQueue,
|
|
&pCreateConnectionContext->WorkQueueItem,
|
|
RxCeCleanupConnectCallOutContext,
|
|
pCreateConnectionContext);
|
|
}
|
|
|
|
if (InvokeCompletionRoutine) {
|
|
if ((IoGetCurrentProcess() == RxGetRDBSSProcess()) &&
|
|
!RxShouldPostCompletion()) {
|
|
(pCompletionRoutine)(pCompletionContext);
|
|
} else {
|
|
Status = RxPostToWorkerThread(
|
|
RxFileSystemDeviceObject,
|
|
CriticalWorkQueue,
|
|
&pCompletionContext->WorkQueueItem,
|
|
pCompletionRoutine,
|
|
pCompletionContext);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxCeBuildConnectionOverMultipleTransports(
|
|
IN OUT PRDBSS_DEVICE_OBJECT pMiniRedirectorDeviceObject,
|
|
IN RXCE_CONNECTION_CREATE_OPTIONS CreateOptions,
|
|
IN ULONG NumberOfAddresses,
|
|
IN PRXCE_ADDRESS *pLocalAddressPointers,
|
|
IN PUNICODE_STRING pServerName,
|
|
IN PRXCE_CONNECTION_INFORMATION pConnectionInformation,
|
|
IN PRXCE_CONNECTION_EVENT_HANDLER pHandler,
|
|
IN PVOID pEventContext,
|
|
IN PRXCE_CONNECTION_COMPLETION_ROUTINE pCompletionRoutine,
|
|
IN OUT PRXCE_CONNECTION_COMPLETION_CONTEXT pCompletionContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine establishes a connection between a local RxCe address and a given remote address
|
|
|
|
Arguments:
|
|
|
|
pMiniRedirectorDeviceObject - the mini redriector device object
|
|
|
|
CreateOptions - the create options
|
|
|
|
NumberOfAddresses - the number of local addresses(transports)
|
|
|
|
pLocalAddressPointers - the local address handles
|
|
|
|
pServerName - the name of the server ( for connection enumeration )
|
|
|
|
pConnectionInformation - the connection information specifying the remote address.
|
|
|
|
pHandler - the connection handler
|
|
|
|
pEventContext - the connection handler context
|
|
|
|
pLocalAddressHandleIndex - the index of the successful address/transport
|
|
|
|
pConnectionHandle - the handle to the newly created connection.
|
|
|
|
pVcHandle - the handle to the VC associated with the connection.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successfull.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
PRXCE_CONNECTION pConnection;
|
|
PRXCE_VC pVc;
|
|
|
|
NTSTATUS Status;
|
|
|
|
PRX_CREATE_CONNECTION_CALLOUT_CONTEXT pCallOutContext=NULL;
|
|
PRX_CREATE_CONNECTION_PARAMETERS_BLOCK pParameterBlocks=NULL;
|
|
|
|
ULONG NumberOfCallOuts,i;
|
|
BOOLEAN InitiateCleanup = FALSE;
|
|
BOOLEAN AsynchronousRequestRegistered = FALSE;
|
|
|
|
KEVENT CompletionEvent;
|
|
BOOLEAN fCompletionContextFreed = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
pConnection = pCompletionContext->pConnection;
|
|
pVc = pCompletionContext->pVc;
|
|
|
|
pCallOutContext = (PRX_CREATE_CONNECTION_CALLOUT_CONTEXT)
|
|
RxAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(RX_CREATE_CONNECTION_CALLOUT_CONTEXT),
|
|
RXCE_CONNECTION_POOLTAG);
|
|
|
|
if (pCallOutContext != NULL) {
|
|
// Allocate one more parameter block then the number of addresses.
|
|
// This sentinel block is used in completing the connect request
|
|
// after ensuring that all of them have been initiated. This
|
|
// ensures that race conditions when a transport completes before
|
|
// the requests have been initiated on some transports are avoided.
|
|
|
|
pCallOutContext->pCleanUpEvent = (PKEVENT)RxAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(KEVENT),
|
|
RXCE_CONNECTION_POOLTAG);
|
|
|
|
pParameterBlocks = (PRX_CREATE_CONNECTION_PARAMETERS_BLOCK)
|
|
RxAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(RX_CREATE_CONNECTION_PARAMETERS_BLOCK) *
|
|
(NumberOfAddresses + 1),
|
|
RXCE_CONNECTION_POOLTAG);
|
|
}
|
|
|
|
|
|
if ((pParameterBlocks == NULL) ||
|
|
(pCallOutContext == NULL) ||
|
|
(pCallOutContext->pCleanUpEvent == NULL)) {
|
|
if (pCallOutContext != NULL) {
|
|
if (pCallOutContext->pCleanUpEvent != NULL) {
|
|
RxFreePool(pCallOutContext->pCleanUpEvent);
|
|
}
|
|
|
|
RxFreePool(pCallOutContext);
|
|
pCallOutContext = NULL;
|
|
}
|
|
if (pParameterBlocks)
|
|
{
|
|
RxFreePool(pParameterBlocks);
|
|
pParameterBlocks = NULL;
|
|
}
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto bailout;
|
|
}
|
|
|
|
// Before initiating the callouts ensure that the asynchronous
|
|
// request is registered. this will ensure that the mini
|
|
// redirector cannot be unloaded till the asynchronous request
|
|
// has been completed.
|
|
Status = RxRegisterAsynchronousRequest(pMiniRedirectorDeviceObject);
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
AsynchronousRequestRegistered = TRUE;
|
|
}
|
|
|
|
KeInitializeEvent(
|
|
pCallOutContext->pCleanUpEvent,
|
|
SynchronizationEvent,
|
|
FALSE);
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
Status = RxCepInitializeConnection(
|
|
pConnection,
|
|
NULL,
|
|
pConnectionInformation,
|
|
pHandler,
|
|
pEventContext);
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
Status = RxCepInitializeVC(
|
|
pVc,
|
|
pConnection);
|
|
}
|
|
}
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
try {
|
|
NumberOfCallOuts = 0;
|
|
|
|
// Fill up each of the parameter blocks
|
|
for (i = 0; i < NumberOfAddresses; i++) {
|
|
PRXCE_TRANSPORT pTransport;
|
|
PRXCE_ADDRESS pAddress;
|
|
|
|
pAddress = pLocalAddressPointers[i];
|
|
pTransport = pAddress->pTransport;
|
|
|
|
if (RxCeIsAddressValid(pAddress) &&
|
|
RxCeIsTransportValid(pTransport)) {
|
|
|
|
Status = RxCepInitializeConnection(
|
|
&pParameterBlocks[NumberOfCallOuts].Connection,
|
|
pAddress,
|
|
pConnectionInformation,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
Status = RxCepInitializeVC(
|
|
&pParameterBlocks[NumberOfCallOuts].Vc,
|
|
&pParameterBlocks[NumberOfCallOuts].Connection);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
RxCeTearDownConnection(
|
|
&pParameterBlocks[NumberOfCallOuts].Connection);
|
|
}
|
|
}
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
pParameterBlocks[NumberOfCallOuts].pConnectIrp = NULL;
|
|
pParameterBlocks[NumberOfCallOuts].IrpRefCount = NULL;
|
|
pParameterBlocks[NumberOfCallOuts].CallOutId = i;
|
|
pParameterBlocks[NumberOfCallOuts].pCallOutContext =
|
|
(PRX_CALLOUT_CONTEXT)pCallOutContext;
|
|
pParameterBlocks[NumberOfCallOuts].CallOutStatus = STATUS_PENDING;
|
|
NumberOfCallOuts++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NumberOfCallOuts > 0) {
|
|
NTSTATUS LocalStatus = STATUS_SUCCESS;
|
|
|
|
// Increment the number of callouts for the sentinel callout to
|
|
// ensure that all initiation is completed before we complete
|
|
// the connect request. Notice that the sentinel is not the very
|
|
// last one but the one after the number of callouts.
|
|
NumberOfCallOuts++;
|
|
|
|
// Also exclude the sentinel from the list
|
|
for (i = 0; i < NumberOfCallOuts - 1; i++) {
|
|
pParameterBlocks[i].pNextCallOutParameterBlock =
|
|
(PRX_CALLOUT_PARAMETERS_BLOCK)&pParameterBlocks[i + 1];
|
|
}
|
|
|
|
pParameterBlocks[NumberOfCallOuts - 2].pNextCallOutParameterBlock = NULL;
|
|
pParameterBlocks[NumberOfCallOuts - 1].pNextCallOutParameterBlock = NULL;
|
|
|
|
// Initialize the callout context.
|
|
pCallOutContext->CreateOptions = CreateOptions;
|
|
pCallOutContext->WinnerCallOutId = NumberOfCallOuts + 1;
|
|
pCallOutContext->BestPossibleWinner = 0;
|
|
pCallOutContext->NumberOfCallOuts = NumberOfCallOuts;
|
|
pCallOutContext->NumberOfCallOutsInitiated = 0;
|
|
pCallOutContext->NumberOfCallOutsCompleted = 0;
|
|
pCallOutContext->pRxCallOutInitiation = RxCeInitiateConnectRequest;
|
|
pCallOutContext->pRxCallOutCompletion = RxCeCompleteConnectRequest;
|
|
pCallOutContext->WinnerFound = FALSE;
|
|
pCallOutContext->CompletionRoutineInvoked = FALSE;
|
|
pCallOutContext->pCallOutParameterBlock =
|
|
(PRX_CALLOUT_PARAMETERS_BLOCK)pParameterBlocks;
|
|
|
|
pCompletionContext->AddressIndex = NumberOfCallOuts + 1;
|
|
|
|
pCallOutContext->pCompletionContext = pCompletionContext;
|
|
pCallOutContext->pCompletionRoutine = pCompletionRoutine;
|
|
pCallOutContext->pConnectionContext = pCompletionContext->pVc;
|
|
|
|
pCallOutContext->pRxDeviceObject = pMiniRedirectorDeviceObject;
|
|
|
|
KeInitializeSpinLock(
|
|
&pCallOutContext->SpinLock);
|
|
|
|
// Exclude the sentinel from the chain of parameter blocks
|
|
for (i = 0; i < NumberOfCallOuts - 1; i++) {
|
|
pCallOutContext->pRxCallOutInitiation(
|
|
(PRX_CALLOUT_PARAMETERS_BLOCK)&pParameterBlocks[i]);
|
|
}
|
|
|
|
pParameterBlocks[NumberOfCallOuts - 1].pConnectIrp = NULL;
|
|
pParameterBlocks[NumberOfCallOuts - 1].CallOutId = NumberOfCallOuts;
|
|
pParameterBlocks[NumberOfCallOuts - 1].pCallOutContext =
|
|
(PRX_CALLOUT_CONTEXT)pCallOutContext;
|
|
pParameterBlocks[NumberOfCallOuts - 1].CallOutStatus = STATUS_NETWORK_UNREACHABLE;
|
|
|
|
pCallOutContext->NumberOfCallOutsInitiated = NumberOfCallOuts;
|
|
|
|
|
|
if((LocalStatus = RxCeCompleteConnectRequest(
|
|
(PRX_CALLOUT_PARAMETERS_BLOCK)&pParameterBlocks[NumberOfCallOuts - 1])) != STATUS_SUCCESS)
|
|
{
|
|
InitiateCleanup = TRUE;
|
|
Status = LocalStatus;
|
|
RxLog(("LocalStatus %x\n", LocalStatus));
|
|
RxWmiLog(LOG,
|
|
RxCeBuildConnectionOverMultipleTransports_1,
|
|
LOGULONG(LocalStatus));
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_PENDING;
|
|
}
|
|
|
|
fCompletionContextFreed = TRUE;
|
|
} else {
|
|
InitiateCleanup = TRUE;
|
|
Status = STATUS_INVALID_HANDLE;
|
|
}
|
|
} finally {
|
|
if (AbnormalTermination()) {
|
|
InitiateCleanup = TRUE;
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (InitiateCleanup) {
|
|
RxFreePool(pParameterBlocks);
|
|
RxFreePool(pCallOutContext);
|
|
}
|
|
|
|
if (Status != STATUS_PENDING) {
|
|
NTSTATUS LocalStatus;
|
|
|
|
ASSERT(Status != STATUS_SUCCESS);
|
|
|
|
LocalStatus = RxCeTearDownVC(pVc);
|
|
ASSERT(LocalStatus == STATUS_SUCCESS);
|
|
|
|
LocalStatus = RxCeTearDownConnection(pConnection);
|
|
ASSERT(LocalStatus == STATUS_SUCCESS);
|
|
|
|
if (!fCompletionContextFreed)
|
|
{
|
|
pCompletionContext->Status = Status;
|
|
|
|
if ((IoGetCurrentProcess() == RxGetRDBSSProcess()) &&
|
|
!RxShouldPostCompletion()) {
|
|
(pCompletionRoutine)(pCompletionContext);
|
|
} else {
|
|
LocalStatus = RxPostToWorkerThread(
|
|
RxFileSystemDeviceObject,
|
|
CriticalWorkQueue,
|
|
&pCompletionContext->WorkQueueItem,
|
|
pCompletionRoutine,
|
|
pCompletionContext);
|
|
|
|
}
|
|
}
|
|
|
|
if (LocalStatus == STATUS_SUCCESS)
|
|
{
|
|
if (AsynchronousRequestRegistered) {
|
|
RxDeregisterAsynchronousRequest(pMiniRedirectorDeviceObject);
|
|
}
|
|
|
|
Status = STATUS_PENDING;
|
|
}
|
|
else
|
|
{
|
|
Status = LocalStatus;
|
|
RxLog(("RxCeBldOvrMult: Failed Status %lx\n", Status));
|
|
RxWmiLog(LOG,
|
|
RxCeBuildConnectionOverMultipleTransports_2,
|
|
LOGULONG(Status));
|
|
}
|
|
}
|
|
bailout:
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxCeTearDownConnection(
|
|
IN PRXCE_CONNECTION pConnection)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine tears down a given connection
|
|
|
|
Arguments:
|
|
|
|
pConnection - the connection to be torn down
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successfull.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
// Update profiling info.
|
|
RxProfile(RxCeManagement,RxCeTearDownConnection);
|
|
|
|
try {
|
|
if (RxCeIsConnectionValid(pConnection)) {
|
|
if (pConnection->pConnectionInformation != NULL) {
|
|
if (pConnection->pConnectionInformation->UserDataLength > 0) {
|
|
RxFreePool(pConnection->pConnectionInformation->UserData);
|
|
}
|
|
|
|
if (pConnection->pConnectionInformation->RemoteAddressLength > 0) {
|
|
RxFreePool(pConnection->pConnectionInformation->RemoteAddress);
|
|
}
|
|
|
|
if (pConnection->pConnectionInformation->OptionsLength > 0) {
|
|
RxFreePool(pConnection->pConnectionInformation->Options);
|
|
}
|
|
|
|
RxFreePool(pConnection->pConnectionInformation);
|
|
}
|
|
|
|
// free the memory allocated for the handler
|
|
if (pConnection->pHandler != NULL) {
|
|
RxFreePool(pConnection->pHandler);
|
|
}
|
|
|
|
RtlZeroMemory(
|
|
pConnection,
|
|
sizeof(RXCE_CONNECTION));
|
|
}
|
|
|
|
} finally {
|
|
if (AbnormalTermination()) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
RxLog(("RxCeTearDownConnection: C: %lx\n",pConnection));
|
|
RxWmiLog(LOG,
|
|
RxCeTearDownConnection,
|
|
LOGPTR(pConnection));
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxCeCancelConnectRequest(
|
|
IN PRXCE_ADDRESS pLocalAddress,
|
|
IN PUNICODE_STRING pServerName,
|
|
IN PRXCE_CONNECTION_INFORMATION pConnectionInformation)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine cancels a previously issued connection request.
|
|
|
|
Arguments:
|
|
|
|
pConnectionInformation - the connection information pertaining to a previsouly issued
|
|
connection request
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successfull.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
PAGED_CODE();
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
RxCeQueryInformation(
|
|
IN PRXCE_VC pVc,
|
|
IN RXCE_CONNECTION_INFORMATION_CLASS InformationClass,
|
|
OUT PVOID pInformation,
|
|
IN ULONG Length)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine queries information pertaining to a connection
|
|
|
|
Arguments:
|
|
|
|
pConnection - the connection for which the information is desired
|
|
|
|
InformationClass - the desired information class.
|
|
|
|
pInformation - the buffer for returning the information
|
|
|
|
Length - the length of the buffer.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successfull.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
|
|
|
PRXCE_TRANSPORT pTransport = NULL;
|
|
PRXCE_ADDRESS pAddress = NULL;
|
|
PRXCE_CONNECTION pConnection = NULL;
|
|
|
|
PAGED_CODE();
|
|
|
|
// Update profiling info.
|
|
RxProfile(RxCeManagement,RxCeQueryInformation);
|
|
|
|
try {
|
|
pConnection = pVc->pConnection;
|
|
pAddress = pConnection->pAddress;
|
|
pTransport = pAddress->pTransport;
|
|
|
|
if (RxCeIsVcValid(pVc) &&
|
|
RxCeIsConnectionValid(pConnection) &&
|
|
RxCeIsAddressValid(pAddress) &&
|
|
RxCeIsTransportValid(pTransport)) {
|
|
|
|
switch (InformationClass) {
|
|
case RxCeTransportProviderInformation:
|
|
if (sizeof(RXCE_TRANSPORT_PROVIDER_INFO) <= Length) {
|
|
// Copy the necessary provider information.
|
|
RtlCopyMemory(
|
|
pInformation,
|
|
pTransport->pProviderInfo,
|
|
sizeof(RXCE_TRANSPORT_PROVIDER_INFO));
|
|
|
|
Status = STATUS_SUCCESS;
|
|
} else {
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
break;
|
|
|
|
case RxCeConnectionInformation:
|
|
if (sizeof(RXCE_CONNECTION_INFORMATION) <= Length) {
|
|
RtlCopyMemory(
|
|
pInformation,
|
|
pConnection->pConnectionInformation,
|
|
sizeof(RXCE_CONNECTION_INFORMATION));
|
|
|
|
Status = STATUS_SUCCESS;
|
|
} else {
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
break;
|
|
|
|
case RxCeConnectionEndpointInformation:
|
|
if (sizeof(RXCE_CONNECTION_INFO) <= Length) {
|
|
Status = RxTdiQueryInformation(
|
|
pTransport,
|
|
pAddress,
|
|
pConnection,
|
|
pVc,
|
|
RXCE_QUERY_CONNECTION_INFO,
|
|
pInformation,
|
|
Length);
|
|
} else {
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
break;
|
|
|
|
case RxCeRemoteAddressInformation:
|
|
{
|
|
Status = RxTdiQueryInformation(
|
|
pTransport,
|
|
pAddress,
|
|
pConnection,
|
|
pVc,
|
|
RXCE_QUERY_ADDRESS_INFO,
|
|
pInformation,
|
|
Length);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
}
|
|
} finally {
|
|
if (AbnormalTermination()) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|