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