1508 lines
44 KiB
C
1508 lines
44 KiB
C
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
vcsndrcv.c
|
|
|
|
Abstract:
|
|
|
|
This module implements all functions related to transmitting and recieving SMB's on a
|
|
connection based transport.
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#include "vcsndrcv.h"
|
|
|
|
RXDT_DefineCategory(VCSNDRCV);
|
|
#define Dbg (DEBUG_TRACE_VCSNDRCV)
|
|
|
|
// Move this def to a common .h file.
|
|
#define MAX_SMB_PACKET_SIZE (65536)
|
|
|
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
|
|
|
//
|
|
// Forward references of functions ....
|
|
//
|
|
|
|
extern NTSTATUS
|
|
VctTearDownServerTransport(PSMBCE_SERVER_TRANSPORT pTransport);
|
|
|
|
extern NTSTATUS
|
|
VctInitializeExchange(
|
|
PSMB_EXCHANGE pExchange);
|
|
|
|
extern PSMBCE_VC_ENTRY
|
|
VctSelectVc(
|
|
PSMBCE_SERVER_VC_TRANSPORT pVcTransport,
|
|
BOOLEAN fMultiplexed);
|
|
|
|
|
|
#define SmbMmInitializeVcEntry(pVcEntry) \
|
|
SmbMmInitializeHeader((pVcEntry)); \
|
|
InitializeListHead(&(pVcEntry)->Requests.ListHead)
|
|
|
|
#define SmbMmUninitializeVcEntry(pVcEntry) \
|
|
ASSERT(IsListEmpty(&(pVcEntry)->Requests.ListHead))
|
|
|
|
#define VctSelectMultiplexedVcEntry(pVcTransport) VctSelectVc(pVcTransport,TRUE)
|
|
#define VctSelectRawVcEntry(pVcTransport) VctSelectVc(pVcTransport,FALSE)
|
|
|
|
//
|
|
// Inline functions to update the state of a VC.
|
|
//
|
|
|
|
INLINE BOOLEAN
|
|
VctUpdateVcStateLite(
|
|
PSMBCE_VC_ENTRY pVcEntry,
|
|
SMBCE_VC_STATE NewState)
|
|
{
|
|
BOOLEAN Result = TRUE;
|
|
|
|
ASSERT(VctSpinLockAcquired());
|
|
|
|
if (NewState == SMBCE_VC_STATE_RAW) {
|
|
if (pVcEntry->SwizzleCount != 0) {
|
|
Result = FALSE;
|
|
} else {
|
|
pVcEntry->Vc.State = NewState;
|
|
}
|
|
} else {
|
|
pVcEntry->Vc.State = NewState;
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
INLINE BOOLEAN
|
|
VctUpdateVcState(
|
|
PSMBCE_VC_ENTRY pVcEntry,
|
|
SMBCE_VC_STATE NewState)
|
|
{
|
|
BOOLEAN Result = TRUE;
|
|
|
|
VctAcquireSpinLock();
|
|
|
|
Result = VctUpdateVcStateLite(pVcEntry,NewState);
|
|
|
|
VctReleaseSpinLock();
|
|
|
|
return Result;
|
|
}
|
|
|
|
NTSTATUS
|
|
VctTranceive(
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry,
|
|
PSMB_EXCHANGE pExchange,
|
|
ULONG SendOptions,
|
|
PMDL pSmbMdl,
|
|
ULONG SendLength,
|
|
PVOID pSendCompletionContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine transmits/receives a SMB for a give exchange
|
|
|
|
Arguments:
|
|
|
|
pServerEntry - the server entry
|
|
|
|
pExchange - the exchange instance issuing this SMB.
|
|
|
|
SendOptions - options for send
|
|
|
|
pSmbMdl - the SMB that needs to be sent.
|
|
|
|
SendLength - length of data to be transmitted
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - the server call construction has been finalized.
|
|
|
|
STATUS_PENDING - the open involves network traffic and the exchange has been
|
|
queued for notification ( pServerPointer is set to NULL)
|
|
|
|
Other Status codes correspond to error situations.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PSMBCE_VC_ENTRY pVcEntry;
|
|
PSMBCE_SERVER_VC_TRANSPORT pVcTransport;
|
|
PSMB_HEADER pSmbHeader = MmGetSystemAddressForMdl(pSmbMdl);
|
|
USHORT Mid;
|
|
BOOLEAN fInvokeSendCompleteHandler = TRUE;
|
|
|
|
ASSERT(pServerEntry->Header.ObjectType == SMBCEDB_OT_SERVER);
|
|
|
|
pVcTransport = (PSMBCE_SERVER_VC_TRANSPORT)pServerEntry->pTransport;
|
|
|
|
// Ensure that the connection is still active before satisfying the request.
|
|
if (SmbCeIsEntryInUse(&pServerEntry->Header)) {
|
|
pVcEntry = pExchange->SmbCeContext.TransportContext.Vcs.pVcEntry;
|
|
if (pVcEntry == NULL) {
|
|
// The transport connection was not initialized. Try and establish a connection if
|
|
// possible.
|
|
Status = VctInitializeExchange(pExchange);
|
|
if (Status != STATUS_SUCCESS) {
|
|
RxDbgTrace(0, Dbg, ("VctTranceive: VctInitializeExchange(Reconnect) returned %lx\n",Status));
|
|
} else {
|
|
pVcEntry = pExchange->SmbCeContext.TransportContext.Vcs.pVcEntry;
|
|
}
|
|
}
|
|
|
|
if ((Status == STATUS_SUCCESS) &&
|
|
(pVcEntry->Vc.State == SMBCE_VC_STATE_MULTIPLEXED)) {
|
|
Status = RxCeSend(
|
|
pVcEntry->Vc.hVc,
|
|
SendOptions,
|
|
pSmbMdl,
|
|
SendLength,
|
|
pSendCompletionContext);
|
|
|
|
if ((Status == STATUS_SUCCESS) || (Status == STATUS_PENDING)) {
|
|
Status = STATUS_PENDING;
|
|
// The underlying connection engine assumes the responsibility of
|
|
// invoking the send complete handler from this point.
|
|
fInvokeSendCompleteHandler = FALSE;
|
|
}
|
|
} else {
|
|
RxDbgTrace(0, Dbg, ("VctTranceive: Disconnected connection detected\n"));
|
|
Status = STATUS_CONNECTION_DISCONNECTED;
|
|
}
|
|
} else {
|
|
// The server entry is not valid ...
|
|
Status = STATUS_CONNECTION_DISCONNECTED;
|
|
}
|
|
|
|
if (Status != STATUS_PENDING) {
|
|
RxDbgTrace(0, Dbg, ("VctTranceive: Return Status %lx\n",Status));
|
|
}
|
|
|
|
// There are instances in which the send was aborted even before the underlying
|
|
// transport was invoked. In such cases the appropriate send complete handler
|
|
// needs to be called so that the associated exchange can be finalized.
|
|
|
|
if (fInvokeSendCompleteHandler) {
|
|
NTSTATUS LocalStatus;
|
|
|
|
LocalStatus = SmbCeSendCompleteInd(
|
|
pServerEntry,
|
|
pSendCompletionContext,
|
|
Status);
|
|
|
|
RxDbgTrace(0, Dbg, ("VctTranceive: Send Complete Handler Return Status %lx\n",LocalStatus));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
VctReceive(
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry,
|
|
PSMB_EXCHANGE pExchange)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine transmits/receives a SMB for a give exchange
|
|
|
|
Arguments:
|
|
|
|
pServerEntry - the server entry
|
|
|
|
pExchange - the exchange instance issuing this SMB.
|
|
|
|
Return Value:
|
|
|
|
STATUS_PENDING - the request has been queued
|
|
|
|
Other Status codes correspond to error situations.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
|
|
PSMBCE_VC_ENTRY pVcEntry;
|
|
PSMBCE_SERVER_VC_TRANSPORT pVcTransport;
|
|
|
|
ASSERT(pServerEntry->Header.ObjectType == SMBCEDB_OT_SERVER);
|
|
|
|
pVcTransport = (PSMBCE_SERVER_VC_TRANSPORT)pServerEntry->pTransport;
|
|
pVcEntry = pExchange->SmbCeContext.TransportContext.Vcs.pVcEntry;
|
|
|
|
// Ensure that the connection is still active before satisfying the request.
|
|
if (SmbCeIsEntryInUse(&pServerEntry->Header)) {
|
|
if ((pVcEntry == NULL) ||
|
|
(pVcEntry->Vc.State == SMBCE_VC_STATE_DISCONNECTED)) {
|
|
// The transport connection was disconnected. Try and reconnect if
|
|
// possible.
|
|
RxDbgTrace(0, Dbg, ("VctReceive: Disconnected connection detected, attempting to reconnect\n"));
|
|
pExchange->SmbCeContext.TransportContext.Vcs.pVcEntry = NULL;
|
|
Status = VctInitializeExchange(pExchange);
|
|
}
|
|
} else {
|
|
// The server entry is not valid ...
|
|
Status = STATUS_CONNECTION_DISCONNECTED;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
VctSend(
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry,
|
|
ULONG SendOptions,
|
|
PMDL pSmbMdl,
|
|
ULONG SendLength,
|
|
PVOID pSendCompletionContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens/creates a server entry in the connection engine database
|
|
|
|
Arguments:
|
|
|
|
pServer - the recepient server
|
|
|
|
pVc - the Vc on which the SMB is sent( if it is NULL SMBCE picks one)
|
|
|
|
SendOptions - options for send
|
|
|
|
pSmbMdl - the SMB that needs to be sent.
|
|
|
|
SendLength - length of data to be sent
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - the send was successful.
|
|
|
|
STATUS_PENDING - the send has been queued
|
|
|
|
Other Status codes correspond to error situations.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_CONNECTION_DISCONNECTED;
|
|
PSMBCE_VC_ENTRY pVcEntry;
|
|
PSMBCE_SERVER_VC_TRANSPORT pVcTransport;
|
|
BOOLEAN fInvokeSendCompleteHandler = TRUE;
|
|
|
|
ASSERT(pServerEntry->Header.ObjectType == SMBCEDB_OT_SERVER);
|
|
|
|
pVcTransport = (PSMBCE_SERVER_VC_TRANSPORT)pServerEntry->pTransport;
|
|
pVcEntry = VctSelectMultiplexedVcEntry(pVcTransport);
|
|
|
|
if (pVcEntry != NULL) {
|
|
if (pVcEntry->Vc.State == SMBCE_VC_STATE_MULTIPLEXED) {
|
|
Status = RxCeSend(
|
|
pVcEntry->Vc.hVc,
|
|
SendOptions,
|
|
pSmbMdl,
|
|
SendLength,
|
|
pSendCompletionContext);
|
|
|
|
if ((Status == STATUS_SUCCESS) || (Status == STATUS_PENDING)) {
|
|
// The underlying connection engine assumes the responsibility of
|
|
// invoking the send complete handler from this point.
|
|
fInvokeSendCompleteHandler = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
RxDbgTrace(0, Dbg, ("VctSend: RxCeSend returned %lx\n",Status));
|
|
}
|
|
|
|
// There are instances in which the send was aborted even before the underlying
|
|
// transport was invoked. In such cases the appropriate send complete handler
|
|
// needs to be called so that the associated exchange can be finalized.
|
|
|
|
if (fInvokeSendCompleteHandler) {
|
|
NTSTATUS LocalStatus;
|
|
|
|
LocalStatus = SmbCeSendCompleteInd(
|
|
pServerEntry,
|
|
pSendCompletionContext,
|
|
Status);
|
|
|
|
RxDbgTrace(0, Dbg, ("VctTranceive: Send Complete Handler Return Status %lx\n",LocalStatus));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
VctSendDatagram(
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry,
|
|
ULONG SendOptions,
|
|
PMDL pSmbMdl,
|
|
ULONG SendLength,
|
|
PVOID pSendCompletionContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens/creates a server entry in the connection engine database
|
|
|
|
Arguments:
|
|
|
|
pServer - the recepient server
|
|
|
|
SendOptions - options for send
|
|
|
|
pSmbMdl - the SMB that needs to be sent.
|
|
|
|
SendLength - length of data to be sent
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - the server call construction has been finalized.
|
|
|
|
STATUS_PENDING - the open involves network traffic and the exchange has been
|
|
queued for notification ( pServerPointer is set to NULL)
|
|
|
|
Other Status codes correspond to error situations.
|
|
|
|
--*/
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
PSMBCE_VC_ENTRY
|
|
VctSelectVc(
|
|
PSMBCE_SERVER_VC_TRANSPORT pVcTransport,
|
|
BOOLEAN fMultiplexed)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine embodies the logic for the selection of a VC on which the SMB exchange
|
|
will transpire
|
|
|
|
Arguments:
|
|
|
|
pVcTransport - the transport structure
|
|
|
|
fMultiplexed - the desired mode
|
|
|
|
Return Value:
|
|
|
|
a referenced VC entry if successful otherwise NULL
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PSMBCE_VC_ENTRY pVcEntry = NULL;
|
|
ULONG NumberOfActiveVcs = 0;
|
|
SMBCE_VC_STATE DesiredState;
|
|
|
|
if (fMultiplexed) {
|
|
RxDbgTrace(0, Dbg, ("VctSelectVc: Referencing Multiplexed entry\n"));
|
|
DesiredState = SMBCE_VC_STATE_MULTIPLEXED;
|
|
} else {
|
|
RxDbgTrace(0, Dbg, ("VctSelectVc: Referencing Raw entry\n"));
|
|
DesiredState = SMBCE_VC_STATE_RAW;
|
|
}
|
|
|
|
// Acquire the resource
|
|
SmbCeAcquireResource();
|
|
|
|
// Choose the first VC that can support multiplexed requests
|
|
pVcEntry = VctGetFirstVcEntry(&pVcTransport->Vcs);
|
|
while (pVcEntry != NULL) {
|
|
NumberOfActiveVcs++;
|
|
|
|
if (pVcEntry->Vc.State == SMBCE_VC_STATE_MULTIPLEXED) {
|
|
if (DesiredState == SMBCE_VC_STATE_MULTIPLEXED) {
|
|
break;
|
|
} else {
|
|
// If the current number of active references to a VC is zero, it can
|
|
// be transformed into the raw mode.
|
|
if (VctUpdateVcState(pVcEntry,SMBCE_VC_STATE_RAW)) {
|
|
break;
|
|
} else {
|
|
NumberOfActiveVcs++;
|
|
}
|
|
}
|
|
}
|
|
|
|
pVcEntry = VctGetNextVcEntry(&pVcTransport->Vcs,pVcEntry);
|
|
}
|
|
|
|
if (pVcEntry == NULL) {
|
|
// Check if it is O.K. to add VCs to this connection. Currently the server
|
|
// implementation supports only one VC per connection. Therefore if an
|
|
// active VC exists which has been grabbed for raw mode use an error is returned.
|
|
// Subsequently when the server is upgraded to handle multiple VCs the logic
|
|
// for adding a new VC will be implemented as part of this routine.
|
|
|
|
RxDbgTrace(0, Dbg, ("VctSelectVc: Allocating new VC entry\n"));
|
|
if (NumberOfActiveVcs < pVcTransport->MaximumNumberOfVCs) {
|
|
pVcEntry = (PSMBCE_VC_ENTRY)RxAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(SMBCE_VC_ENTRY),
|
|
MRXSMB_VC_POOLTAG);
|
|
if (pVcEntry != NULL) {
|
|
SmbMmInitializeVcEntry(pVcEntry);
|
|
Status = RxCeAddVC(pVcTransport->hConnection,&pVcEntry->Vc.hVc);
|
|
if (NT_SUCCESS(Status)) {
|
|
pVcEntry->Vc.State = DesiredState;
|
|
VctAddVcEntry(&pVcTransport->Vcs,pVcEntry);
|
|
} else {
|
|
RxFreePool(pVcEntry);
|
|
pVcEntry = NULL;
|
|
}
|
|
}
|
|
} else {
|
|
RxDbgTrace(0, Dbg, ("VctSelectVc: VC limit exceeded returning NULL\n"));
|
|
}
|
|
}
|
|
|
|
if (pVcEntry != NULL) {
|
|
VctReferenceVcEntry(pVcEntry);
|
|
}
|
|
|
|
// release the resource
|
|
SmbCeReleaseResource();
|
|
|
|
return pVcEntry;
|
|
}
|
|
|
|
NTSTATUS
|
|
VctInitializeExchange(
|
|
PSMB_EXCHANGE pExchange)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the transport information pertinent to a exchange
|
|
|
|
Arguments:
|
|
|
|
pTransport - the transport structure
|
|
|
|
pExchange - the exchange instance
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS -
|
|
|
|
Other Status codes correspond to error situations.
|
|
|
|
--*/
|
|
{
|
|
PSMBCE_SERVER_VC_TRANSPORT pVcTransport;
|
|
|
|
SmbCeReferenceServerTransport(pExchange->SmbCeContext.pServerEntry);
|
|
|
|
pVcTransport = (PSMBCE_SERVER_VC_TRANSPORT)pExchange->SmbCeContext.pServerEntry->pTransport;
|
|
|
|
ASSERT(pExchange->SmbCeContext.TransportContext.Vcs.pVcEntry == NULL);
|
|
|
|
pExchange->SmbCeContext.TransportContext.Vcs.pVcEntry
|
|
= VctSelectMultiplexedVcEntry(pVcTransport);
|
|
|
|
if (pExchange->SmbCeContext.TransportContext.Vcs.pVcEntry == NULL) {
|
|
RxDbgTrace(0, Dbg, ("VctInitializeExchange: Unsuccessful\n"));
|
|
return STATUS_CONNECTION_DISCONNECTED;
|
|
} else {
|
|
RxDbgTrace(0, Dbg, ("VctInitializeExchange: Successful\n"));
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
VctUninitializeExchange(
|
|
PSMB_EXCHANGE pExchange)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine uninitializes the transport information pertinent to a exchange
|
|
|
|
Arguments:
|
|
|
|
pExchange - the exchange instance
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS -
|
|
|
|
Other Status codes correspond to error situations.
|
|
|
|
--*/
|
|
{
|
|
PSMBCE_SERVER_VC_TRANSPORT pVcTransport;
|
|
|
|
pVcTransport = (PSMBCE_SERVER_VC_TRANSPORT)pExchange->SmbCeContext.pServerEntry->pTransport;
|
|
|
|
RxDbgTrace(0, Dbg, ("VctUninitializeExchange: Successful\n"));
|
|
|
|
if (pExchange->SmbCeContext.TransportContext.Vcs.pVcEntry != NULL) {
|
|
VctDereferenceVcEntry(pExchange->SmbCeContext.TransportContext.Vcs.pVcEntry);
|
|
}
|
|
|
|
SmbCeDereferenceServerTransport(pExchange->SmbCeContext.pServerEntry);
|
|
|
|
pExchange->SmbCeContext.TransportContext.Vcs.pVcEntry = NULL;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
VctIndReceive(
|
|
IN PVOID pEventContext,
|
|
IN RXCE_VC_HANDLE hVc,
|
|
IN ULONG ReceiveFlags,
|
|
IN ULONG BytesIndicated,
|
|
IN ULONG BytesAvailable,
|
|
OUT ULONG *pBytesTaken,
|
|
IN PVOID pTsdu, // pointer describing this TSDU, typically a lump of bytes
|
|
OUT PMDL *pDataBufferPointer, // the buffer in which data is to be copied.
|
|
OUT PULONG pDataBufferSize // amount of data to copy
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles the receive indication for SMB's along all vcs in a connection to a
|
|
server.
|
|
|
|
Arguments:
|
|
|
|
pEventContext - the server entry
|
|
|
|
hVc - the Vc on which the SMB has been received
|
|
|
|
ReceiveFlags - options for receive
|
|
|
|
BytesIndicated - the bytes that are present in the indication.
|
|
|
|
BytesAvailable - the total data available
|
|
|
|
pTsdu - the data
|
|
|
|
pDataBufferPointer - the buffer for copying the data not indicated.
|
|
|
|
pDataBufferSize - the length of the buffer
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS -
|
|
|
|
Other Status codes correspond to error situations.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
BYTE *pSmbCommand;
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = (PSMBCEDB_SERVER_ENTRY)pEventContext;
|
|
PSMBCE_VC_ENTRY pVcEntry;
|
|
PSMBCEDB_REQUEST_ENTRY pRequestEntry;
|
|
PSMB_EXCHANGE pExchange;
|
|
PSMB_HEADER pSmbHeader = (PSMB_HEADER)pTsdu;
|
|
PSMBCE_SERVER_VC_TRANSPORT pVcTransport = (PSMBCE_SERVER_VC_TRANSPORT)pServerEntry->pTransport;
|
|
|
|
Status = SmbCeReceiveInd(
|
|
pServerEntry,
|
|
BytesIndicated,
|
|
BytesAvailable,
|
|
pBytesTaken,
|
|
pTsdu,
|
|
pDataBufferPointer,
|
|
pDataBufferSize);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
VctIndDataReady(
|
|
IN PVOID pEventContext,
|
|
IN PMDL pBuffer,
|
|
IN ULONG DataSize,
|
|
IN NTSTATUS CopyDataStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles the indication when the requested data has been copied
|
|
|
|
Arguments:
|
|
|
|
pEventContext - the server instance
|
|
|
|
pBuffer - the buffer being returned
|
|
|
|
DataSize - the amount of data copied in bytes
|
|
|
|
CopyDataStatus - CopyDataStatus
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - the server call construction has been finalized.
|
|
|
|
Other Status codes correspond to error situations.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = (PSMBCEDB_SERVER_ENTRY)pEventContext;
|
|
|
|
Status = SmbCeDataReadyInd(
|
|
pServerEntry,
|
|
pBuffer,
|
|
DataSize,
|
|
CopyDataStatus);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
VctIndDisconnect(
|
|
IN PVOID pEventContext,
|
|
IN RXCE_VC_HANDLE hVc,
|
|
IN int DisconnectDataLength,
|
|
IN PVOID DisconnectData,
|
|
IN int DisconnectInformationLength,
|
|
IN PVOID DisconnectInformation,
|
|
IN ULONG DisconnectFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles the disconnect indication for a VC.
|
|
|
|
Arguments:
|
|
|
|
pEventContext - the server instance
|
|
|
|
hVc - the virtual circuit
|
|
|
|
DisconnectDataLength -
|
|
|
|
DisconnectData -
|
|
|
|
DisconnectInformationLength -
|
|
|
|
DisconnectInformation -
|
|
|
|
DisconnectFlags -
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - the disconnect indication has been handled
|
|
|
|
--*/
|
|
{
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = (PSMBCEDB_SERVER_ENTRY)pEventContext;
|
|
PSMBCEDB_SERVER_ENTRY pListEntry;
|
|
PSMBCE_VC_ENTRY pVcEntry;
|
|
PSMBCEDB_REQUEST_ENTRY pRequestEntry;
|
|
PSMB_EXCHANGE pExchange;
|
|
PSMBCE_SERVER_VC_TRANSPORT pVcTransport = (PSMBCE_SERVER_VC_TRANSPORT)pServerEntry->pTransport;
|
|
|
|
BOOLEAN fValidServerEntry = FALSE;
|
|
|
|
// Traverse the list of server entries to ensure that the disconnect was on a
|
|
// valid server entry. If it is not on a valid server entry ignore it.
|
|
|
|
SmbCeAcquireSpinLock();
|
|
|
|
pListEntry = SmbCeGetFirstServerEntry();
|
|
|
|
while (pListEntry != NULL) {
|
|
if (pListEntry == pServerEntry) {
|
|
fValidServerEntry = TRUE;
|
|
break;
|
|
}
|
|
pListEntry = SmbCeGetNextServerEntry(pListEntry);
|
|
}
|
|
|
|
// Since the two spin locks are currently aliased to be the same.
|
|
// VctAcquireSpinLock();
|
|
// SmbCeDbReleaseSpinLock();
|
|
|
|
if (fValidServerEntry && (pVcTransport != NULL)) {
|
|
pVcEntry = VctGetFirstVcEntry(&pVcTransport->Vcs);
|
|
while ((pVcEntry != NULL) && (pVcEntry->Vc.hVc != hVc)) {
|
|
pVcEntry = VctGetNextVcEntry(&pVcTransport->Vcs,pVcEntry);
|
|
}
|
|
|
|
if (pVcEntry != NULL) {
|
|
VctUpdateVcStateLite(pVcEntry,SMBCE_VC_STATE_DISCONNECTED);
|
|
pVcEntry->Status = STATUS_CONNECTION_DISCONNECTED;
|
|
}
|
|
}
|
|
|
|
// Release the resource
|
|
VctReleaseSpinLock();
|
|
|
|
if (fValidServerEntry) {
|
|
|
|
RxDbgTrace(0,Dbg,("@@@@@@ Disconnect Indication for %lx @@@@@\n",pServerEntry));
|
|
InterlockedIncrement(&MRxIfsStatistics.ServerDisconnects);
|
|
|
|
// Update the Server entry if this is the only VC associated with the transport.
|
|
SmbCeTransportDisconnectIndicated(pServerEntry);
|
|
|
|
RxDbgTrace(0, Dbg, ("VctIndDisconnect: Processing Disconnect indication on VC entry %lx\n",pVcEntry));
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
VctIndError(
|
|
IN PVOID pEventContext,
|
|
IN RXCE_VC_HANDLE hVc,
|
|
IN NTSTATUS IndicatedStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles the error indication
|
|
|
|
Arguments:
|
|
|
|
pEventContext - the server instance
|
|
|
|
hVc - the virtual circuit handle.
|
|
|
|
Status - the error
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = (PSMBCEDB_SERVER_ENTRY)pEventContext;
|
|
PSMBCE_VC_ENTRY pVcEntry;
|
|
PSMB_EXCHANGE pExchange;
|
|
PSMBCE_SERVER_VC_TRANSPORT pVcTransport = (PSMBCE_SERVER_VC_TRANSPORT)pServerEntry->pTransport;
|
|
|
|
// Acquire the resource
|
|
VctAcquireSpinLock();
|
|
|
|
// Map the RXCE vc handle to the appropriate SMBCE entry and get the request
|
|
// list associated with it.
|
|
|
|
pVcEntry = VctGetFirstVcEntry(&pVcTransport->Vcs);
|
|
while ((pVcEntry != NULL) && (pVcEntry->Vc.hVc != hVc)) {
|
|
pVcEntry = VctGetNextVcEntry(&pVcTransport->Vcs,pVcEntry);
|
|
}
|
|
|
|
if (pVcEntry != NULL) {
|
|
VctUpdateVcStateLite(pVcEntry,SMBCE_VC_STATE_DISCONNECTED);
|
|
pVcEntry->Status = IndicatedStatus;
|
|
}
|
|
|
|
// Release the resource
|
|
VctReleaseSpinLock();
|
|
|
|
RxDbgTrace(0, Dbg, ("VctIndError: Processing Error indication on VC entry %lx\n",pVcEntry));
|
|
|
|
Status = SmbCeErrorInd(
|
|
pServerEntry,
|
|
IndicatedStatus);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
VctIndEndpointError(
|
|
IN PVOID pEventContext,
|
|
IN NTSTATUS IndicatedStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles the error indication
|
|
|
|
Arguments:
|
|
|
|
pEventContext - the server instance
|
|
|
|
Status - the error
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
{
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
VctIndSendPossible(
|
|
IN PVOID pEventContext, // the event context.
|
|
IN RXCE_VC_HANDLE hVc,
|
|
IN ULONG BytesAvailable
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles the error indication
|
|
|
|
Arguments:
|
|
|
|
pEventContext - the server instance
|
|
|
|
hVc - the VC instance
|
|
|
|
BytesAvailable - the number of bytes that can be sent
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
{
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
VctIndReceiveDatagram(
|
|
IN PVOID pRxCeEventContext, // the event context
|
|
IN int SourceAddressLength, // length of the originator of the datagram
|
|
IN PVOID SourceAddress, // string describing the originator of the datagram
|
|
IN int OptionsLength, // options for the receive
|
|
IN PVOID Options, //
|
|
IN ULONG ReceiveDatagramFlags, //
|
|
IN ULONG BytesIndicated, // number of bytes this indication
|
|
IN ULONG BytesAvailable, // number of bytes in complete Tsdu
|
|
OUT ULONG *BytesTaken, // number of bytes used
|
|
IN PVOID Tsdu, // pointer describing this TSDU, typically a lump of bytes
|
|
OUT PMDL *pDataBufferPointer, // the buffer in which data is to be copied.
|
|
OUT PULONG pDataBufferSize // amount of data to copy
|
|
)
|
|
{
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
VctIndSendComplete(
|
|
IN PVOID pEventContext,
|
|
IN RXCE_VC_HANDLE hVc,
|
|
IN PVOID pCompletionContext,
|
|
IN NTSTATUS SendCompletionStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles the send complete indication for asynchronous sends
|
|
|
|
Arguments:
|
|
|
|
pEventContext - the server instance
|
|
|
|
hVc - the VC instance
|
|
|
|
pCompletionContext - the context for identifying the send request
|
|
|
|
SendCompletionStatus - the send completion status
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS always ..
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = (PSMBCEDB_SERVER_ENTRY)pEventContext;
|
|
|
|
Status = SmbCeSendCompleteInd(
|
|
pServerEntry,
|
|
pCompletionContext,
|
|
SendCompletionStatus);
|
|
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Static dispatch vectors for Virtual Circuit based transports
|
|
//
|
|
|
|
RXCE_ADDRESS_EVENT_HANDLER
|
|
MRxSmbVctAddressEventHandler = {
|
|
VctIndEndpointError,
|
|
VctIndReceiveDatagram,
|
|
VctIndDataReady,
|
|
VctIndSendPossible,
|
|
NULL
|
|
};
|
|
|
|
RXCE_CONNECTION_EVENT_HANDLER
|
|
MRxSmbVctConnectionEventHandler = {
|
|
VctIndDisconnect,
|
|
VctIndError,
|
|
VctIndReceive,
|
|
VctIndReceiveDatagram,
|
|
VctIndReceive,
|
|
VctIndSendPossible,
|
|
VctIndDataReady,
|
|
VctIndSendComplete
|
|
};
|
|
|
|
TRANSPORT_DISPATCH_VECTOR
|
|
MRxSmbVctTransportDispatch = {
|
|
VctSend,
|
|
VctSendDatagram,
|
|
VctTranceive,
|
|
VctReceive,
|
|
NULL,
|
|
VctInitializeExchange,
|
|
VctUninitializeExchange,
|
|
VctTearDownServerTransport
|
|
};
|
|
|
|
|
|
typedef enum _RXCE_VC_FUNCTION_CODE {
|
|
VcConnect,
|
|
VcDisconnect
|
|
} RXCE_VC_FUNCTION_CODE, *PRXCE_VC_FUNCTION_CODE;
|
|
|
|
typedef struct _RXCE_VC_CONNECT_CONTEXT {
|
|
RXCE_VC_FUNCTION_CODE FunctionCode;
|
|
PRX_WORKERTHREAD_ROUTINE pRoutine;
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
|
PSMBCE_SERVER_TRANSPORT pServerTransport;
|
|
NTSTATUS Status;
|
|
KEVENT SyncEvent;
|
|
} RXCE_VC_CONNECT_CONTEXT, *PRXCE_VC_CONNECT_CONTEXT;
|
|
|
|
NTSTATUS
|
|
VctInitialize(
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry,
|
|
PSMBCE_TRANSPORT pTransport,
|
|
RXCE_CONNECTION_HANDLE hConnection,
|
|
RXCE_VC_HANDLE hVc,
|
|
PSMBCE_SERVER_TRANSPORT *pServerTransportPtr)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the transport information corresponding to a server
|
|
|
|
Arguments:
|
|
|
|
pServerEntry - the server entry instance in the database
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - the server transport construction has been finalized.
|
|
|
|
Other Status codes correspond to error situations.
|
|
|
|
Notes:
|
|
|
|
The remote address can be either deduced from the information in the Rx Context
|
|
or a NETBIOS address needs to be built from the server name.
|
|
This transport address is used subsequently to establish the connection.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PSMBCE_SERVER_VC_TRANSPORT pVcTransport;
|
|
PSMBCE_VC_ENTRY pVcEntry;
|
|
|
|
pVcTransport = (PSMBCE_SERVER_VC_TRANSPORT)
|
|
SmbMmAllocateServerTransport(SMBCE_STT_VC);
|
|
|
|
pVcEntry = (PSMBCE_VC_ENTRY)
|
|
RxAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(SMBCE_VC_ENTRY),
|
|
MRXSMB_VC_POOLTAG);
|
|
|
|
if ((pVcTransport != NULL) && (pVcEntry != NULL)) {
|
|
RXCE_CONNECTION_INFO ConnectionInfo;
|
|
RXCE_TRANSPORT_PROVIDER_INFO ProviderInfo;
|
|
|
|
SmbMmInitializeVcEntry(pVcEntry);
|
|
|
|
|
|
// Query the transport information ...
|
|
Status = RxCeQueryInformation(
|
|
hConnection,
|
|
RxCeTransportProviderInformation,
|
|
&ProviderInfo,
|
|
sizeof(ProviderInfo));
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
pVcTransport->MaximumSendSize = MIN( ProviderInfo.MaxSendSize,
|
|
MAXIMUM_PARTIAL_BUFFER_SIZE );
|
|
} else {
|
|
ASSERT( 1024 <= MAXIMUM_PARTIAL_BUFFER_SIZE );
|
|
pVcTransport->MaximumSendSize = 1024;
|
|
}
|
|
|
|
|
|
|
|
// Query the connection information ....
|
|
Status = RxCeQueryInformation(
|
|
hConnection,
|
|
RxCeConnectionEndpointInformation,
|
|
&ConnectionInfo,
|
|
sizeof(ConnectionInfo));
|
|
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
// The setting of the delay parameter is an important heuristic
|
|
// that determines how quickly and how often timeouts occur. As
|
|
// a first cut a very conservative estimate for the time has been
|
|
// choosen, i.e., double the time required to transmit a 64 k packet.
|
|
// This parameter should be fine tuned.
|
|
|
|
pVcTransport->Delay.QuadPart = (-ConnectionInfo.Delay.QuadPart) +
|
|
(-ConnectionInfo.Delay.QuadPart);
|
|
if (ConnectionInfo.Throughput.LowPart != 0) {
|
|
pVcTransport->Delay.QuadPart +=
|
|
(MAX_SMB_PACKET_SIZE/ConnectionInfo.Throughput.LowPart) * 1000 * 10000;
|
|
}
|
|
|
|
RxDbgTrace( 0, Dbg, ("Connection delay set to %ld 100ns ticks\n",pVcTransport->Delay.LowPart));
|
|
|
|
pVcTransport->pDispatchVector = &MRxSmbVctTransportDispatch;
|
|
pVcTransport->hConnection = hConnection;
|
|
|
|
pVcEntry->Vc.hVc = hVc;
|
|
pVcEntry->Vc.State = SMBCE_VC_STATE_MULTIPLEXED;
|
|
VctAddVcEntry(&pVcTransport->Vcs,pVcEntry);
|
|
|
|
pVcTransport->State = SMBCEDB_ACTIVE;
|
|
} else {
|
|
RxDbgTrace(0, Dbg, ("VctInitialize : RxCeQueryInformation returned %lx\n",Status));
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
pVcTransport->pTransport = pTransport;
|
|
} else {
|
|
RxDbgTrace(0, Dbg, ("VctInitialize : Connection Initialization Failed %lx\n",Status));
|
|
}
|
|
} else {
|
|
RxDbgTrace(0, Dbg, ("VctInitialize : Memory Allocation failed\n"));
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
// Cleanup if not successful
|
|
if (!NT_SUCCESS(Status)) {
|
|
if (pVcTransport != NULL) {
|
|
RxFreePool(pVcTransport);
|
|
}
|
|
|
|
if (pVcEntry != NULL) {
|
|
RxFreePool(pVcEntry);
|
|
}
|
|
|
|
pVcTransport = NULL;
|
|
}
|
|
|
|
*pServerTransportPtr = (PSMBCE_SERVER_TRANSPORT)pVcTransport;
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
VctUninitialize(
|
|
PVOID pTransport)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine uninitializes the transport instance
|
|
|
|
Arguments:
|
|
|
|
pVcTransport - the VC transport instance
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - the server transport construction has been uninitialzied.
|
|
|
|
Other Status codes correspond to error situations.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PSMBCE_VC_ENTRY pVcEntry;
|
|
PSMBCE_SERVER_VC_TRANSPORT pVcTransport = (PSMBCE_SERVER_VC_TRANSPORT)pTransport;
|
|
ULONG TransportFlags;
|
|
SMBCE_VCS Vcs;
|
|
|
|
|
|
// The spinlock needs to be acquired for manipulating the list of Vcs because of
|
|
// indications that will be processed till the appropriate RXCE data structures are
|
|
// dismantled
|
|
|
|
VctAcquireSpinLock();
|
|
|
|
VctTransferVcs(pVcTransport,&Vcs);
|
|
|
|
VctReleaseSpinLock();
|
|
|
|
pVcEntry = VctGetFirstVcEntry(&Vcs);
|
|
while (pVcEntry != NULL) {
|
|
// Remove the VC entry from the list of transports associated with this
|
|
// transport instance.
|
|
VctRemoveVcEntryLite(&Vcs,pVcEntry);
|
|
|
|
// Assert the fact that the request list associated with the VC is empty.
|
|
// Tear down the VC entry
|
|
Status = RxCeTearDownVC(pVcEntry->Vc.hVc);
|
|
|
|
// Discard the VC
|
|
RxFreePool(pVcEntry);
|
|
|
|
pVcEntry = VctGetFirstVcEntry(&Vcs);
|
|
}
|
|
|
|
// Tear down the connection endpoint ..
|
|
Status = RxCeTearDownConnection(pVcTransport->hConnection);
|
|
RxDbgTrace(0, Dbg, ("VctUninitialize : RxCeDisconnect returned %lx\n",Status));
|
|
|
|
// Dereference the underlying transport
|
|
SmbCeDereferenceTransport(pVcTransport->pTransport);
|
|
|
|
// Free up the transport entry
|
|
RxFreePool(pVcTransport);
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
VctpInitializeServerTransport(
|
|
PRXCE_VC_CONNECT_CONTEXT pRxCeConnectContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the transport information corresponding to a server
|
|
|
|
Arguments:
|
|
|
|
pServerEntry - the server entry instance in the database
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - the server transport construction has been finalized.
|
|
|
|
Other Status codes correspond to error situations.
|
|
|
|
Notes:
|
|
|
|
Currently, only connection oriented transports are handled. The current TDI spec expects
|
|
handles to be passed in as part of the connect request. This implies that connect/
|
|
reconnect/disconnect requests need to be issued from the process which created the connection.
|
|
In the case of the SMB mini rdr there is no FSP associated with it ( threads are borrowed
|
|
/commandeered ) from the system process to do all the work. This is the reason for
|
|
special casing VC initialization into a separate routine. The server transport initialization
|
|
routine handles the other transport initialization and also provides the context for VC
|
|
initialization.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = pRxCeConnectContext->pServerEntry;
|
|
|
|
UNICODE_STRING ServerName;
|
|
RXCE_VC_HANDLE hVc;
|
|
RXCE_CONNECTION_HANDLE hConnection;
|
|
|
|
PSMBCE_TRANSPORT pTransport;
|
|
|
|
OEM_STRING OemServerName;
|
|
|
|
ULONG TransportAddressLength = FIELD_OFFSET(TRANSPORT_ADDRESS,Address)
|
|
+ FIELD_OFFSET(TA_ADDRESS,Address)
|
|
+ TDI_ADDRESS_LENGTH_NETBIOS;
|
|
CHAR TransportAddressBuffer[ FIELD_OFFSET(TRANSPORT_ADDRESS,Address)
|
|
+ FIELD_OFFSET(TA_ADDRESS,Address)
|
|
+ TDI_ADDRESS_LENGTH_NETBIOS];
|
|
|
|
PTRANSPORT_ADDRESS pTransportAddress = (PTRANSPORT_ADDRESS)TransportAddressBuffer;
|
|
PTDI_ADDRESS_NETBIOS pNetbiosAddress = (PTDI_ADDRESS_NETBIOS)pTransportAddress->Address[0].Address;
|
|
|
|
pRxCeConnectContext->pServerTransport = NULL;
|
|
|
|
SmbCeGetServerName(pServerEntry->pRdbssSrvCall,&ServerName);
|
|
|
|
pTransportAddress->TAAddressCount = 1;
|
|
pTransportAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_NETBIOS;
|
|
pTransportAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
|
|
pNetbiosAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
|
|
|
|
OemServerName.MaximumLength = NETBIOS_NAMESIZE;
|
|
OemServerName.Buffer = pNetbiosAddress->NetbiosName;
|
|
|
|
Status = RtlUpcaseUnicodeStringToOemString(&OemServerName,
|
|
&ServerName,
|
|
FALSE);
|
|
if (NT_SUCCESS(Status)) {
|
|
RXCE_CONNECTION_INFORMATION InitialConnectionInformation,
|
|
FinalConnectionInformation;
|
|
// Ensure that the name is always of the desired length by padding
|
|
// white space to the end.
|
|
RtlCopyMemory(&OemServerName.Buffer[OemServerName.Length],
|
|
" ",
|
|
NETBIOS_NAMESIZE - OemServerName.Length);
|
|
|
|
InitialConnectionInformation.UserDataLength = 0;
|
|
InitialConnectionInformation.OptionsLength = 0;
|
|
InitialConnectionInformation.RemoteAddressLength = TransportAddressLength;
|
|
InitialConnectionInformation.RemoteAddress = TransportAddressBuffer;
|
|
|
|
FinalConnectionInformation = InitialConnectionInformation;
|
|
|
|
// Try to establish a connection on any of the active transports.
|
|
pTransport = SmbCeGetNextTransport(NULL);
|
|
|
|
if (pTransport != NULL) {
|
|
BOOLEAN SynchronousConnect = TRUE;
|
|
PSMBCE_TRANSPORT pNextTransport;
|
|
|
|
do {
|
|
Status = RxCeCreateConnection(
|
|
pTransport->hAddress,
|
|
&ServerName,
|
|
&InitialConnectionInformation,
|
|
&MRxSmbVctConnectionEventHandler,
|
|
pServerEntry,
|
|
&hConnection,
|
|
&hVc);
|
|
if (SynchronousConnect && (Status == STATUS_SUCCESS)) {
|
|
break;
|
|
}
|
|
|
|
pNextTransport = SmbCeGetNextTransport(pTransport);
|
|
SmbCeDereferenceTransport(pTransport);
|
|
pTransport = pNextTransport;
|
|
} while (pTransport != NULL);
|
|
|
|
if (SynchronousConnect) {
|
|
if (pTransport == NULL) {
|
|
// all the active transports were exhausted and none of the
|
|
// connects succeeded
|
|
Status = STATUS_BAD_NETWORK_NAME;
|
|
}
|
|
} else {
|
|
// It is an asynchronous connect. Need to wait for the results
|
|
}
|
|
} else {
|
|
Status = STATUS_NETWORK_UNREACHABLE;
|
|
RxDbgTrace(0, Dbg, ("SmbCeInitializeServerTransport : No registered transports returning%lx\n",Status));
|
|
}
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = VctInitialize(
|
|
pServerEntry, // The server entry
|
|
pTransport, // the transport/address information
|
|
hConnection, // the connection
|
|
hVc, // the virtual circuit
|
|
&pRxCeConnectContext->pServerTransport);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
NTSTATUS CleanupStatus;
|
|
|
|
if (hVc != INVALID_RXCE_HANDLE) {
|
|
CleanupStatus = RxCeTearDownVC(hVc);
|
|
RxDbgTrace(0, Dbg, ("SmbCeInitializeServerTransport : RxCeRemoveVc returned %lx\n",CleanupStatus));
|
|
}
|
|
|
|
if (hConnection != INVALID_RXCE_HANDLE) {
|
|
CleanupStatus = RxCeTearDownConnection(hConnection);
|
|
RxDbgTrace(0, Dbg, ("SmbCeInitializeServerTransport : RxCeDisconnect returned %lx\n",CleanupStatus));
|
|
}
|
|
|
|
SmbCeDereferenceTransport(pTransport);
|
|
}
|
|
}
|
|
|
|
pRxCeConnectContext->Status = Status;
|
|
KeSetEvent( &pRxCeConnectContext->SyncEvent, 0, FALSE );
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
VctpUninitializeServerTransport(
|
|
PRXCE_VC_CONNECT_CONTEXT pRxCeConnectContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine uninitializes the transport information corresponding to a server
|
|
|
|
Arguments:
|
|
|
|
pServerEntry - the server entry instance in the database
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - the server transport construction has been finalized.
|
|
|
|
Other Status codes correspond to error situations.
|
|
|
|
Notes:
|
|
|
|
Currently, only connection oriented transports are handled.
|
|
|
|
--*/
|
|
{
|
|
PSMBCE_SERVER_TRANSPORT pServerTransport = pRxCeConnectContext->pServerTransport;
|
|
|
|
if (pServerTransport != NULL) {
|
|
VctUninitialize(pServerTransport);
|
|
}
|
|
|
|
pRxCeConnectContext->Status = STATUS_SUCCESS;
|
|
KeSetEvent( &pRxCeConnectContext->SyncEvent, 0, FALSE );
|
|
}
|
|
|
|
NTSTATUS
|
|
VctpInvokeTransportFunction(
|
|
PRXCE_VC_CONNECT_CONTEXT pRxCeConnectContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine invokes the iniytialization/uninitialization function for the VC
|
|
transport
|
|
|
|
Arguments:
|
|
|
|
pRxCeConnectContext -- the RxCe connection context.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - the server transport construction has been finalized.
|
|
|
|
Other Status codes correspond to error situations.
|
|
|
|
Notes:
|
|
|
|
Currently, only connection oriented transports are handled.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
if (IoGetCurrentProcess() != RxGetRDBSSProcess()) {
|
|
Status = RxDispatchToWorkerThread(
|
|
MRxIfsDeviceObject,
|
|
HyperCriticalWorkQueue,
|
|
pRxCeConnectContext->pRoutine,
|
|
pRxCeConnectContext);
|
|
} else {
|
|
Status = STATUS_SUCCESS;
|
|
(pRxCeConnectContext->pRoutine)(pRxCeConnectContext);
|
|
}
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
KeWaitForSingleObject(
|
|
&pRxCeConnectContext->SyncEvent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL );
|
|
|
|
Status = pRxCeConnectContext->Status;
|
|
}
|
|
|
|
KeResetEvent( &pRxCeConnectContext->SyncEvent );
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
VctInstantiateServerTransport(
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry,
|
|
PSMBCE_SERVER_TRANSPORT *pServerTransportPtr)
|
|
{
|
|
PRXCE_VC_CONNECT_CONTEXT pRxCeConnectContext;
|
|
|
|
NTSTATUS Status;
|
|
|
|
pRxCeConnectContext = (PRXCE_VC_CONNECT_CONTEXT)RxAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(RXCE_VC_CONNECT_CONTEXT),
|
|
MRXSMB_VC_POOLTAG);
|
|
|
|
if (pRxCeConnectContext != NULL) {
|
|
pRxCeConnectContext->pServerEntry = pServerEntry;
|
|
pRxCeConnectContext->Status = STATUS_SUCCESS;
|
|
pRxCeConnectContext->pServerTransport = NULL;
|
|
pRxCeConnectContext->FunctionCode = VcConnect;
|
|
pRxCeConnectContext->pRoutine = VctpInitializeServerTransport;
|
|
|
|
KeInitializeEvent(&pRxCeConnectContext->SyncEvent,NotificationEvent,FALSE);
|
|
|
|
Status = VctpInvokeTransportFunction(pRxCeConnectContext);
|
|
|
|
*pServerTransportPtr = pRxCeConnectContext->pServerTransport;
|
|
|
|
RxFreePool(pRxCeConnectContext);
|
|
} else {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
VctTearDownServerTransport(
|
|
PSMBCE_SERVER_TRANSPORT pServerTransport)
|
|
{
|
|
PRXCE_VC_CONNECT_CONTEXT pRxCeConnectContext;
|
|
|
|
NTSTATUS Status;
|
|
|
|
pRxCeConnectContext = (PRXCE_VC_CONNECT_CONTEXT)RxAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(RXCE_VC_CONNECT_CONTEXT),
|
|
MRXSMB_VC_POOLTAG);
|
|
|
|
if (pRxCeConnectContext != NULL) {
|
|
pRxCeConnectContext->pServerEntry = NULL;
|
|
pRxCeConnectContext->Status = STATUS_SUCCESS;
|
|
pRxCeConnectContext->pServerTransport = pServerTransport;
|
|
pRxCeConnectContext->FunctionCode = VcDisconnect;
|
|
pRxCeConnectContext->pRoutine = VctpUninitializeServerTransport;
|
|
|
|
KeInitializeEvent(&pRxCeConnectContext->SyncEvent,NotificationEvent,FALSE);
|
|
|
|
Status = VctpInvokeTransportFunction(pRxCeConnectContext);
|
|
|
|
RxFreePool(pRxCeConnectContext);
|
|
} else {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|