1370 lines
42 KiB
C
1370 lines
42 KiB
C
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
netroot.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the routines for creating the SMB net root.
|
|
|
|
Author:
|
|
|
|
Balan Sethu Raman [SethuR] 7-March-1995
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#include "exsessup.h"
|
|
#include "dfsfsctl.h"
|
|
|
|
//
|
|
// The Bug check file id for this module
|
|
//
|
|
|
|
#define BugCheckFileId (RDBSS_BUG_CHECK_SMB_NETROOT)
|
|
|
|
//
|
|
// The local debug trace level
|
|
//
|
|
|
|
#define Dbg (DEBUG_TRACE_DISPATCH)
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, MRxSmbUpdateNetRootState)
|
|
#pragma alloc_text(PAGE, MRxSmbGetDialectFlagsFromSrvCall)
|
|
#pragma alloc_text(PAGE, MRxSmbCreateVNetRoot)
|
|
#pragma alloc_text(PAGE, MRxSmbFinalizeNetRoot)
|
|
#pragma alloc_text(PAGE, SmbCeReconnect)
|
|
#pragma alloc_text(PAGE, SmbCeEstablishConnection)
|
|
#pragma alloc_text(PAGE, SmbConstructNetRootExchangeStart)
|
|
#pragma alloc_text(PAGE, MRxSmbExtractNetRootName)
|
|
#endif
|
|
|
|
//
|
|
// Forward declarations ...
|
|
//
|
|
|
|
extern NTSTATUS
|
|
SmbCeParseConstructNetRootResponse(
|
|
PSMB_CONSTRUCT_NETROOT_EXCHANGE pNetRootExchange,
|
|
PSMB_HEADER pSmbHeader,
|
|
ULONG BytesAvailable,
|
|
ULONG BytesIndicated,
|
|
ULONG *pBytesTaken);
|
|
|
|
extern NTSTATUS
|
|
SmbConstructNetRootExchangeFinalize(
|
|
PSMB_EXCHANGE pExchange,
|
|
BOOLEAN *pPostFinalize);
|
|
|
|
typedef struct _SMBCE_NETROOT_CONSTRUCTION_CONTEXT {
|
|
NTSTATUS Status;
|
|
|
|
PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext;
|
|
PMRX_V_NET_ROOT pVNetRoot;
|
|
|
|
RX_WORK_QUEUE_ITEM WorkQueueItem;
|
|
} SMBCE_NETROOT_CONSTRUCTION_CONTEXT,
|
|
*PSMBCE_NETROOT_CONSTRUCTION_CONTEXT;
|
|
|
|
NTSTATUS
|
|
MRxSmbCreateVNetRootOffLine(
|
|
IN PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext);
|
|
|
|
NTSTATUS
|
|
MRxSmbUpdateNetRootState(
|
|
IN OUT PMRX_NET_ROOT pNetRoot)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine update the mini redirector state associated with a net root.
|
|
|
|
Arguments:
|
|
|
|
pNetRoot - the net root instance.
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
|
|
By diffrentiating the mini redirewctor state from the net rot condition it is possible
|
|
to permit a variety of reconnect strategies. It is conceivable that the RDBSS considers
|
|
a net root to be good while the underlying mini redirector might mark it as invalid
|
|
and reconnect on the fly.
|
|
|
|
--*/
|
|
{
|
|
if (pNetRoot->MRxNetRootState == MRX_NET_ROOT_STATE_GOOD) {
|
|
if (pNetRoot->Context == NULL) {
|
|
pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_ERROR;
|
|
} else {
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
|
|
|
pServerEntry = SmbCeReferenceAssociatedServerEntry(pNetRoot->pSrvCall);
|
|
if (pServerEntry != NULL) {
|
|
if (pServerEntry->Server.CscState == ServerCscDisconnected) {
|
|
pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_GOOD;
|
|
} else {
|
|
switch (pServerEntry->Header.State) {
|
|
case SMBCEDB_ACTIVE:
|
|
pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_GOOD;
|
|
break;
|
|
case SMBCEDB_INVALID:
|
|
pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_DISCONNECTED;
|
|
break;
|
|
case SMBCEDB_CONSTRUCTION_IN_PROGRESS:
|
|
pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_RECONN;
|
|
break;
|
|
default:
|
|
pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_ERROR;
|
|
break;
|
|
}
|
|
}
|
|
|
|
SmbCeDereferenceServerEntry(pServerEntry);
|
|
} else {
|
|
pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
ULONG
|
|
MRxSmbGetDialectFlagsFromSrvCall(
|
|
PMRX_SRV_CALL SrvCall
|
|
)
|
|
{
|
|
ULONG DialectFlags;
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
|
|
|
PAGED_CODE();
|
|
|
|
pServerEntry = SmbCeReferenceAssociatedServerEntry(SrvCall);
|
|
ASSERT(pServerEntry != NULL);
|
|
DialectFlags = pServerEntry->Server.DialectFlags;
|
|
SmbCeDereferenceServerEntry(pServerEntry);
|
|
return(DialectFlags);
|
|
}
|
|
|
|
BOOLEAN
|
|
MRxSmbIsThisACscAgentOpen(
|
|
IN PRX_CONTEXT RxContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines if the open was made by the user mode CSC agent.
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RDBSS context
|
|
|
|
Return Value:
|
|
|
|
TRUE - if it is an agent open, FALSE otherwise
|
|
|
|
Notes:
|
|
|
|
The agent opens are always satisfied by going to the server. They are never
|
|
satisfied from the cached copies. This enables reintegration using snapshots
|
|
even when the files are being currently used.
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN AgentOpen = FALSE;
|
|
ULONG EaInformationLength;
|
|
|
|
PDFS_NAME_CONTEXT pDfsNameContext;
|
|
|
|
if (RxContext->Create.EaLength > 0) {
|
|
PFILE_FULL_EA_INFORMATION pEaEntry;
|
|
|
|
pEaEntry = (PFILE_FULL_EA_INFORMATION)RxContext->Create.EaBuffer;
|
|
ASSERT(pEaEntry != NULL);
|
|
|
|
for(;;) {
|
|
if (strcmp(pEaEntry->EaName, EA_NAME_CSCAGENT) == 0) {
|
|
AgentOpen = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (pEaEntry->NextEntryOffset == 0) {
|
|
break;
|
|
} else {
|
|
pEaEntry = (PFILE_FULL_EA_INFORMATION)
|
|
((PCHAR) pEaEntry + pEaEntry->NextEntryOffset);
|
|
}
|
|
}
|
|
}
|
|
|
|
pDfsNameContext = RxContext->Create.NtCreateParameters.DfsNameContext;
|
|
|
|
if ((pDfsNameContext != NULL) &&
|
|
(pDfsNameContext->NameContextType == DFS_CSCAGENT_NAME_CONTEXT)) {
|
|
AgentOpen = TRUE;
|
|
}
|
|
|
|
return AgentOpen;
|
|
}
|
|
|
|
NTSTATUS
|
|
MRxSmbCreateVNetRoot(
|
|
IN PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine patches the RDBSS created net root instance with the information required
|
|
by the mini redirector.
|
|
|
|
In case the connection cannot be established, the mini redirector tries to transition
|
|
the VNetRoot into disconnected mode and establishes the connection off-line. If the
|
|
connection failes to establish in the synchronouse way, this routine will do the transition;
|
|
Otherwise, SmbConstructNetRootExchangeFinalize routine will try the transition. In both
|
|
cases, MRxSmbCreateVNetRoot will be called again to establish the connection in disconnected
|
|
mode.
|
|
|
|
Arguments:
|
|
|
|
pVNetRoot - the virtual net root instance.
|
|
|
|
pCreateNetRootContext - the net root context for calling back
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
CODE.IMPROVEMENT -- The net root create context must supply the open mode in order
|
|
to enable the mini redirector to implement a wide variety of reconnect strategies.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_MORE_PROCESSING_REQUIRED;
|
|
PRX_CONTEXT pRxContext = pCreateNetRootContext->RxContext;
|
|
PMRX_V_NET_ROOT pVNetRoot = (PMRX_V_NET_ROOT)pCreateNetRootContext->pVNetRoot;
|
|
|
|
PMRX_SRV_CALL pSrvCall;
|
|
PMRX_NET_ROOT pNetRoot;
|
|
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
|
|
|
PUNICODE_STRING pNetRootName,pSrvCallName;
|
|
|
|
BOOLEAN fInitializeNetRoot;
|
|
BOOLEAN fDeferNetworkInitialization = FALSE;
|
|
BOOLEAN fCscAgentOpen = FALSE;
|
|
BOOLEAN fDisconnectedOperation;
|
|
BOOLEAN CallBack = FALSE;
|
|
extern DWORD hShareReint;
|
|
|
|
PAGED_CODE();
|
|
|
|
pNetRoot = pVNetRoot->pNetRoot;
|
|
pSrvCall = pNetRoot->pSrvCall;
|
|
|
|
pServerEntry = SmbCeGetAssociatedServerEntry(pSrvCall);
|
|
|
|
if ((pRxContext != NULL) &&
|
|
(pRxContext->MajorFunction == IRP_MJ_CREATE)) {
|
|
fCscAgentOpen = MRxSmbIsThisACscAgentOpen(pRxContext);
|
|
|
|
if (pRxContext->Create.ThisIsATreeConnectOpen){
|
|
// Determine if this tree connect was initiated by a CSC agent
|
|
InterlockedIncrement(&MRxSmbStatistics.UseCount);
|
|
}
|
|
|
|
fDeferNetworkInitialization = pRxContext->Create.TreeConnectOpenDeferred;
|
|
}
|
|
|
|
SmbCeLog(("SmbCreateVNetRoot CscAgent %x %wZ \n",fCscAgentOpen,pNetRoot->pNetRootName));
|
|
|
|
SmbLog(LOG,
|
|
MRxSmbCreateVNetRoot,
|
|
LOGUCHAR(fCscAgentOpen)
|
|
LOGUSTR(*pNetRoot->pNetRootName));
|
|
|
|
fInitializeNetRoot = (pNetRoot->Context == NULL);
|
|
|
|
fDisconnectedOperation = (SmbCeIsServerInDisconnectedMode(pServerEntry) &&
|
|
!fCscAgentOpen);
|
|
|
|
if (fCscAgentOpen &&
|
|
SmbCeIsServerInDisconnectedMode(pServerEntry)) {
|
|
// this is an EA open. we want this one to succeed but want others to still
|
|
// stay offline till an ioctl comes down to say we want to transition
|
|
|
|
CscPrepareServerEntryForOnlineOperationPartial(pServerEntry);
|
|
}
|
|
|
|
ASSERT((NodeType(pNetRoot) == RDBSS_NTC_NETROOT) &&
|
|
(NodeType(pNetRoot->pSrvCall) == RDBSS_NTC_SRVCALL));
|
|
|
|
if (pNetRoot->Type == NET_ROOT_MAILSLOT) {
|
|
pVNetRoot->Context = NULL;
|
|
Status = STATUS_SUCCESS;
|
|
RxDbgTrace( 0, Dbg, ("Mailslot open\n"));
|
|
} else if ((pNetRoot->Type == NET_ROOT_PIPE) &&
|
|
(pServerEntry->Header.State == SMBCEDB_ACTIVE)) {
|
|
if (fDisconnectedOperation) {
|
|
pVNetRoot->Context = NULL;
|
|
Status = STATUS_BAD_NETWORK_NAME;
|
|
} else if (SmbCeGetServerType(pServerEntry) == SMBCEDB_FILE_SERVER &&
|
|
!FlagOn(MRxSmbGetDialectFlagsFromSrvCall(pSrvCall),DF_LANMAN10)) {
|
|
pVNetRoot->Context = NULL;
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
RxDbgTrace( 0, Dbg, ("pipe open to core server\n"));
|
|
}
|
|
}
|
|
|
|
if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
|
|
Status = SmbCeFindOrConstructVNetRootContext(
|
|
pVNetRoot,
|
|
fDeferNetworkInitialization,
|
|
fCscAgentOpen);
|
|
}
|
|
|
|
if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
|
|
// Update the flags on the VNetRootContext to indicate if this is a
|
|
// agent open
|
|
|
|
Status = SmbCeEstablishConnection(
|
|
pVNetRoot,
|
|
pCreateNetRootContext,
|
|
fInitializeNetRoot);
|
|
}
|
|
|
|
if (Status != STATUS_PENDING) {
|
|
if (fCscAgentOpen && Status == STATUS_RETRY) {
|
|
Status = STATUS_CONNECTION_DISCONNECTED;
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
if (!fCscAgentOpen &&
|
|
!SmbCeIsServerInDisconnectedMode(pServerEntry)) {
|
|
// if it cannot establish the connect and didn't get chance to transition
|
|
// into disconnected state, we should try the transition and if succeed,
|
|
// establish the connect again in the disconnected state.
|
|
|
|
Status = CscTransitionVNetRootForDisconnectedOperation(
|
|
pCreateNetRootContext->RxContext,
|
|
pVNetRoot,
|
|
Status);
|
|
}
|
|
|
|
if (fInitializeNetRoot &&
|
|
(pNetRoot->Context != NULL)) {
|
|
PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
|
|
|
|
SmbCeAcquireResource();
|
|
|
|
pNetRootEntry = SmbCeGetAssociatedNetRootEntry(pNetRoot);
|
|
|
|
if (pNetRootEntry != NULL) {
|
|
pNetRootEntry->pRdbssNetRoot = NULL;
|
|
SmbCeDereferenceNetRootEntry(pNetRootEntry);
|
|
}
|
|
|
|
pNetRoot->Context = NULL;
|
|
|
|
SmbCeReleaseResource();
|
|
}
|
|
|
|
SmbCeDestroyAssociatedVNetRootContext(pVNetRoot);
|
|
|
|
if ((pRxContext != NULL) &&
|
|
(pRxContext->MajorFunction == IRP_MJ_CREATE) &&
|
|
(pRxContext->Create.ThisIsATreeConnectOpen)) {
|
|
InterlockedIncrement(&MRxSmbStatistics.FailedUseCount);
|
|
}
|
|
}
|
|
|
|
pCreateNetRootContext->VirtualNetRootStatus = Status;
|
|
|
|
if (fInitializeNetRoot) {
|
|
pCreateNetRootContext->NetRootStatus = Status;
|
|
} else {
|
|
pCreateNetRootContext->NetRootStatus = STATUS_SUCCESS;
|
|
}
|
|
|
|
if (Status == STATUS_RETRY) {
|
|
// STATUS_RETRY is returned from CscTransitionVNetRootForDisconnectedOperation if the
|
|
// server entry is transitioned into disconnected mode.
|
|
Status = MRxSmbCreateVNetRootOffLine(pCreateNetRootContext);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
// Callback the RDBSS for resumption if create VNetRootOffLine fails
|
|
CallBack = TRUE;
|
|
}
|
|
} else {
|
|
CallBack = TRUE;
|
|
}
|
|
|
|
// Map the error code to STATUS_PENDING since this triggers the synchronization
|
|
// mechanism in the RDBSS.
|
|
Status = STATUS_PENDING;
|
|
}
|
|
|
|
if (CallBack) {
|
|
IF_NOT_MRXSMB_CSC_ENABLED{
|
|
NOTHING;
|
|
} else {
|
|
if (pCreateNetRootContext->NetRootStatus == STATUS_SUCCESS){
|
|
if ((pRxContext != NULL) &&
|
|
(pRxContext->MajorFunction == IRP_MJ_CREATE) &&
|
|
(pNetRoot->Type == NET_ROOT_DISK)) {
|
|
MRxSmbCscPartOfCreateVNetRoot(pRxContext,pNetRoot);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pServerEntry->Server.IsRemoteBootServer &&
|
|
pCreateNetRootContext->NetRootStatus != STATUS_SUCCESS) {
|
|
pCreateNetRootContext->NetRootStatus = STATUS_RETRY;
|
|
pCreateNetRootContext->VirtualNetRootStatus = STATUS_RETRY;
|
|
}
|
|
|
|
// Callback the RDBSS for resumption.
|
|
pCreateNetRootContext->Callback(pCreateNetRootContext);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
MRxSmbFinalizeVNetRoot(
|
|
IN PMRX_V_NET_ROOT pVNetRoot,
|
|
IN PBOOLEAN ForceDisconnect)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
pVNetRoot - the virtual net root
|
|
|
|
ForceDisconnect - disconnect is forced
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
|
|
PSMBCEDB_SESSION_ENTRY pDefaultSessionEntry;
|
|
|
|
// This cannot be paged code since we meed to protect the default session list with the lock
|
|
|
|
RxDbgTrace( 0, Dbg, ("MRxSmbFinalizeVNetRoot %lx\n",pVNetRoot));
|
|
|
|
if (pVNetRoot->Context != NULL) {
|
|
SmbCeDestroyAssociatedVNetRootContext(pVNetRoot);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MRxSmbFinalizeNetRoot(
|
|
IN PMRX_NET_ROOT pNetRoot,
|
|
IN PBOOLEAN ForceDisconnect)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
pVirtualNetRoot - the virtual net root
|
|
|
|
ForceDisconnect - disconnect is forced
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace( 0, Dbg, ("MRxSmbFinalizeNetRoot %lx\n",pNetRoot));
|
|
|
|
if (pNetRoot->Context != NULL) {
|
|
SmbCeAcquireResource();
|
|
|
|
pNetRootEntry = SmbCeGetAssociatedNetRootEntry(pNetRoot);
|
|
|
|
InterlockedCompareExchangePointer(
|
|
&pNetRootEntry->pRdbssNetRoot,
|
|
NULL,
|
|
pNetRoot);
|
|
|
|
SmbCeDereferenceNetRootEntry(pNetRootEntry);
|
|
|
|
ASSERT(!FlagOn(pNetRoot->Flags,NETROOT_FLAG_FINALIZE_INVOKED));
|
|
SetFlag(pNetRoot->Flags,NETROOT_FLAG_FINALIZE_INVOKED);
|
|
|
|
SmbCeReleaseResource();
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
SmbCeReconnectCallback(
|
|
PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine signals the completion of a reconnect attempt
|
|
|
|
Arguments:
|
|
|
|
pCreateNetRootContext - the net root context
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
KeSetEvent(&pCreateNetRootContext->FinishEvent, IO_NETWORK_INCREMENT, FALSE );
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbCeReconnect(
|
|
IN PMRX_V_NET_ROOT pVNetRoot)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine reconnects, i.e, establishes a new session and tree connect to a previously
|
|
connected serverb share
|
|
|
|
Arguments:
|
|
|
|
pVNetRoot - the virtual net root instance.
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
|
PSMBCEDB_SESSION_ENTRY pSessionEntry;
|
|
PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
|
|
PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = (PSMBCE_V_NET_ROOT_CONTEXT)pVNetRoot->Context;
|
|
|
|
PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext;
|
|
|
|
PAGED_CODE();
|
|
|
|
if ((pVNetRootContext != NULL) &&
|
|
(pVNetRootContext->Header.State == SMBCEDB_ACTIVE)) {
|
|
pServerEntry = pVNetRootContext->pServerEntry;
|
|
pSessionEntry = pVNetRootContext->pSessionEntry;
|
|
pNetRootEntry = pVNetRootContext->pNetRootEntry;
|
|
|
|
if ((pServerEntry->Header.State == SMBCEDB_ACTIVE) &&
|
|
(pSessionEntry->Header.State == SMBCEDB_ACTIVE) &&
|
|
(pNetRootEntry->Header.State == SMBCEDB_ACTIVE)) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
pCreateNetRootContext = (PMRX_CREATENETROOT_CONTEXT)
|
|
RxAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(MRX_CREATENETROOT_CONTEXT),
|
|
MRXSMB_NETROOT_POOLTAG);
|
|
|
|
if (pCreateNetRootContext != NULL) {
|
|
for (;;) {
|
|
pCreateNetRootContext->pVNetRoot = (PV_NET_ROOT)pVNetRoot;
|
|
pCreateNetRootContext->NetRootStatus = STATUS_SUCCESS;
|
|
pCreateNetRootContext->VirtualNetRootStatus = STATUS_SUCCESS;
|
|
pCreateNetRootContext->Callback = SmbCeReconnectCallback;
|
|
pCreateNetRootContext->RxContext = NULL;
|
|
|
|
KeInitializeEvent(
|
|
&pCreateNetRootContext->FinishEvent,
|
|
SynchronizationEvent,
|
|
FALSE );
|
|
|
|
// Since this is a reconnect instance the net root initialization is not required
|
|
Status = SmbCeEstablishConnection(
|
|
pVNetRoot,
|
|
pCreateNetRootContext,
|
|
FALSE);
|
|
|
|
if (Status == STATUS_PENDING) {
|
|
// Wait for the construction to be completed.
|
|
KeWaitForSingleObject(
|
|
&pCreateNetRootContext->FinishEvent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
Status = pCreateNetRootContext->VirtualNetRootStatus;
|
|
}
|
|
|
|
if (Status != STATUS_LINK_FAILED) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
RxFreePool(pCreateNetRootContext);
|
|
} else {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbCeEstablishConnection(
|
|
IN OUT PMRX_V_NET_ROOT pVNetRoot,
|
|
IN PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext,
|
|
IN BOOLEAN fInitializeNetRoot
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine triggers off the connection attempt for initial establishment of a
|
|
connection as well as subsequent reconnect attempts.
|
|
|
|
Arguments:
|
|
|
|
pVNetRoot - the virtual net root instance.
|
|
|
|
pCreateNetRootContext - the net root context for calling back
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
CODE.IMPROVEMENT -- The net root create context must supply the open mode in order
|
|
to enable the mini redirector to implement a wide variety of reconnect strategies.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
|
PSMBCEDB_SESSION_ENTRY pSessionEntry;
|
|
PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
|
|
PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
|
|
|
|
PAGED_CODE();
|
|
|
|
pVNetRootContext = SmbCeGetAssociatedVNetRootContext(pVNetRoot);
|
|
|
|
if (pVNetRootContext == NULL) {
|
|
Status = STATUS_BAD_NETWORK_PATH;
|
|
} else {
|
|
pServerEntry = pVNetRootContext->pServerEntry;
|
|
pSessionEntry = pVNetRootContext->pSessionEntry;
|
|
pNetRootEntry = pVNetRootContext->pNetRootEntry;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
//
|
|
// The following code initializes the NetRootEntry, VNetRootContext and
|
|
// the session entry under certain cases.
|
|
//
|
|
// The session entry to a doenlevel server needs to be initialized. This
|
|
// is not handled by the previous code since the session entry and the
|
|
// net root entry initialization can be combined into one exchange.
|
|
//
|
|
// The net root entry has not been initialized, i.e., this corresponds to
|
|
// the construction of the first SMBCE_V_NET_ROOT_CONTEXT instance for a
|
|
// given NetRootEntry.
|
|
//
|
|
// Subsequent SMBCE_V_NET_ROOT context constructions. In these cases the
|
|
// construction of each context must obtain a new TID
|
|
//
|
|
|
|
BOOLEAN fNetRootExchangeRequired;
|
|
|
|
fNetRootExchangeRequired = ((pSessionEntry->Header.State != SMBCEDB_ACTIVE) ||
|
|
!BooleanFlagOn(pVNetRootContext->Flags,SMBCE_V_NET_ROOT_CONTEXT_FLAG_VALID_TID));
|
|
|
|
if (fNetRootExchangeRequired) {
|
|
// This is a tree connect open which needs to be triggered immediately.
|
|
PSMB_EXCHANGE pSmbExchange;
|
|
PSMB_CONSTRUCT_NETROOT_EXCHANGE pNetRootExchange;
|
|
|
|
pSmbExchange = SmbMmAllocateExchange(CONSTRUCT_NETROOT_EXCHANGE,NULL);
|
|
if (pSmbExchange != NULL) {
|
|
Status = SmbCeInitializeExchange(
|
|
&pSmbExchange,
|
|
NULL,
|
|
pVNetRoot,
|
|
CONSTRUCT_NETROOT_EXCHANGE,
|
|
&ConstructNetRootExchangeDispatch);
|
|
|
|
if (Status == RX_MAP_STATUS(SUCCESS)) {
|
|
pNetRootExchange = (PSMB_CONSTRUCT_NETROOT_EXCHANGE)pSmbExchange;
|
|
|
|
// Attempt to reconnect( In this case it amounts to establishing the
|
|
// connection/session)
|
|
pNetRootExchange->SmbCeFlags |= (SMBCE_EXCHANGE_ATTEMPT_RECONNECTS |
|
|
SMBCE_EXCHANGE_TIMED_RECEIVE_OPERATION);
|
|
|
|
// Initialize the continuation for resumption upon completion of the
|
|
// tree connetcion.
|
|
pNetRootExchange->NetRootCallback = pCreateNetRootContext->Callback;
|
|
pNetRootExchange->pCreateNetRootContext = pCreateNetRootContext;
|
|
pNetRootExchange->RxContext = pCreateNetRootContext->RxContext;
|
|
|
|
pNetRootExchange->fInitializeNetRoot = fInitializeNetRoot;
|
|
|
|
IF_NOT_MRXSMB_BUILD_FOR_DISCONNECTED_CSC {
|
|
// Initiate the exchange.
|
|
Status = SmbCeInitiateExchange(pSmbExchange);
|
|
|
|
if (Status != STATUS_PENDING) {
|
|
SmbCeDiscardExchangeWorkerThreadRoutine(pSmbExchange);
|
|
}
|
|
} else {
|
|
if (!SmbCeIsServerInDisconnectedMode(pServerEntry) ||
|
|
FlagOn(
|
|
pVNetRootContext->Flags,
|
|
SMBCE_V_NET_ROOT_CONTEXT_CSCAGENT_INSTANCE)) {
|
|
// Initiate the exchange.
|
|
Status = SmbCeInitiateExchange(pSmbExchange);
|
|
|
|
if (Status != STATUS_PENDING) {
|
|
SmbCeDiscardExchangeWorkerThreadRoutine(pSmbExchange);
|
|
}
|
|
} else {
|
|
//dont really initiate...just set up to call the completion
|
|
//routine which BTW discards the exchange
|
|
Status = MRxSmbCscDisconnectedConnect(pNetRootExchange);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// The net roots are normally constructed as part of some other exchange, i.e., the SMB for
|
|
// Tree connect is compounded with other operations. However, there is one situation in which
|
|
// the tree connect SMB needs to be sent by itself. This case refers to the prefix claim
|
|
// situation ( net use command ). This is handled by the construct net root exchange.
|
|
//
|
|
|
|
#define CONSTRUCT_NETROOT_BUFFER_SIZE (4096)
|
|
|
|
NTSTATUS
|
|
SmbConstructNetRootExchangeStart(
|
|
PSMB_EXCHANGE pExchange)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the start routine for net root construction exchanges. This initiates the
|
|
construction of the appropriate SMB's if required.
|
|
|
|
Arguments:
|
|
|
|
pExchange - the exchange instance
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
NTSTATUS RequestLockStatus = STATUS_UNSUCCESSFUL;
|
|
NTSTATUS ResponseLockStatus = STATUS_UNSUCCESSFUL;
|
|
|
|
PVOID pSmbActualBuffer;
|
|
PVOID pSmbBuffer;
|
|
UCHAR SmbCommand,LastCommandInHeader;
|
|
ULONG SmbLength;
|
|
|
|
PUCHAR pCommand;
|
|
|
|
PMDL pSmbRequestMdl,pSmbResponseMdl;
|
|
ULONG SmbMdlSize;
|
|
|
|
PSMB_CONSTRUCT_NETROOT_EXCHANGE pNetRootExchange;
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
|
|
PMRX_NET_ROOT pNetRoot = pExchange->SmbCeContext.pVNetRoot->pNetRoot;
|
|
|
|
PAGED_CODE();
|
|
|
|
pNetRootExchange = (PSMB_CONSTRUCT_NETROOT_EXCHANGE)pExchange;
|
|
|
|
ASSERT(pNetRootExchange->Type == CONSTRUCT_NETROOT_EXCHANGE);
|
|
|
|
if ((pNetRoot->Type == NET_ROOT_PIPE) &&
|
|
!FlagOn(pServerEntry->Server.DialectFlags,DF_LANMAN10)) {
|
|
RxDbgTrace( 0, Dbg, ("pipe open to core server\n"));
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
pSmbRequestMdl = pSmbResponseMdl = NULL;
|
|
|
|
pSmbActualBuffer = RxAllocatePoolWithTag(
|
|
PagedPool | POOL_COLD_ALLOCATION,
|
|
(CONSTRUCT_NETROOT_BUFFER_SIZE + TRANSPORT_HEADER_SIZE),
|
|
MRXSMB_NETROOT_POOLTAG);
|
|
|
|
if (pSmbActualBuffer != NULL) {
|
|
PSMBCE_SERVER pServer = SmbCeGetExchangeServer(pExchange);
|
|
|
|
(PCHAR) pSmbBuffer = (PCHAR) pSmbActualBuffer + TRANSPORT_HEADER_SIZE;
|
|
|
|
Status = SmbCeBuildSmbHeader(
|
|
pExchange,
|
|
pSmbBuffer,
|
|
CONSTRUCT_NETROOT_BUFFER_SIZE,
|
|
&SmbLength,
|
|
&LastCommandInHeader,
|
|
&pCommand);
|
|
|
|
// Ensure that the NET_ROOT/SESSION still needs to be constructed before
|
|
// sending it. It is likely that they were costructed by an earlier exchange
|
|
if (NT_SUCCESS(Status) &&
|
|
(SmbLength > sizeof(SMB_HEADER))) {
|
|
|
|
if (LastCommandInHeader != SMB_COM_TREE_CONNECT){
|
|
*pCommand = SMB_COM_NO_ANDX_COMMAND;
|
|
}
|
|
|
|
RxAllocateHeaderMdl(
|
|
pSmbBuffer,
|
|
SmbLength,
|
|
pSmbRequestMdl
|
|
);
|
|
|
|
pSmbResponseMdl = RxAllocateMdl(pSmbBuffer,CONSTRUCT_NETROOT_BUFFER_SIZE);
|
|
|
|
if ((pSmbRequestMdl != NULL) &&
|
|
(pSmbResponseMdl != NULL)) {
|
|
|
|
RxProbeAndLockHeaderPages(
|
|
pSmbRequestMdl,
|
|
KernelMode,
|
|
IoModifyAccess,
|
|
RequestLockStatus);
|
|
|
|
RxProbeAndLockPages(
|
|
pSmbResponseMdl,
|
|
KernelMode,
|
|
IoModifyAccess,
|
|
ResponseLockStatus);
|
|
|
|
if ((Status == STATUS_SUCCESS) &&
|
|
((Status = RequestLockStatus) == STATUS_SUCCESS) &&
|
|
((Status = ResponseLockStatus) == STATUS_SUCCESS)) {
|
|
|
|
pNetRootExchange->pSmbResponseMdl = pSmbResponseMdl;
|
|
pNetRootExchange->pSmbRequestMdl = pSmbRequestMdl;
|
|
pNetRootExchange->pSmbActualBuffer = pSmbActualBuffer;
|
|
pNetRootExchange->pSmbBuffer = pSmbBuffer;
|
|
|
|
Status = SmbCeTranceive(
|
|
pExchange,
|
|
(RXCE_SEND_PARTIAL | RXCE_SEND_SYNCHRONOUS),
|
|
pNetRootExchange->pSmbRequestMdl,
|
|
SmbLength);
|
|
|
|
RxDbgTrace( 0, Dbg, ("Net Root SmbCeTranceive returned %lx\n",Status));
|
|
}
|
|
} else {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
if ((Status != STATUS_PENDING) &&
|
|
(Status != STATUS_SUCCESS)) {
|
|
|
|
pNetRootExchange->pSmbResponseMdl = NULL;
|
|
pNetRootExchange->pSmbRequestMdl = NULL;
|
|
pNetRootExchange->pSmbActualBuffer = NULL;
|
|
pNetRootExchange->pSmbBuffer = NULL;
|
|
|
|
if (pSmbResponseMdl != NULL) {
|
|
if (ResponseLockStatus == STATUS_SUCCESS) {
|
|
MmUnlockPages(pSmbResponseMdl);
|
|
}
|
|
|
|
IoFreeMdl(pSmbResponseMdl);
|
|
}
|
|
|
|
if (pSmbRequestMdl != NULL) {
|
|
if (RequestLockStatus == STATUS_SUCCESS) {
|
|
RxUnlockHeaderPages(pSmbRequestMdl);
|
|
}
|
|
|
|
IoFreeMdl(pSmbRequestMdl);
|
|
}
|
|
|
|
RxFreePool(pSmbActualBuffer);
|
|
}
|
|
} else {
|
|
|
|
RxFreePool(pSmbActualBuffer);
|
|
}
|
|
} else {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbConstructNetRootExchangeReceive(
|
|
IN struct _SMB_EXCHANGE *pExchange,
|
|
IN ULONG BytesIndicated,
|
|
IN ULONG BytesAvailable,
|
|
OUT ULONG *pBytesTaken,
|
|
IN PSMB_HEADER pSmbHeader,
|
|
OUT PMDL *pDataBufferPointer,
|
|
OUT PULONG pDataSize,
|
|
IN ULONG ReceiveFlags)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the recieve indication handling routine for net root construction exchanges
|
|
|
|
Arguments:
|
|
|
|
pExchange - the exchange instance
|
|
|
|
BytesIndicated - the number of bytes indicated
|
|
|
|
Bytes Available - the number of bytes available
|
|
|
|
pBytesTaken - the number of bytes consumed
|
|
|
|
pSmbHeader - the byte buffer
|
|
|
|
pDataBufferPointer - the buffer into which the remaining data is to be copied.
|
|
|
|
pDataSize - the buffer size.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
|
|
This routine is called at DPC level.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PSMB_CONSTRUCT_NETROOT_EXCHANGE pNetRootExchange;
|
|
|
|
pNetRootExchange = (PSMB_CONSTRUCT_NETROOT_EXCHANGE)pExchange;
|
|
|
|
RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseSmbHeader BytesIndicated/Available %ld %ld\n",BytesIndicated,BytesAvailable));
|
|
|
|
if (BytesAvailable > BytesIndicated ||
|
|
!FlagOn(ReceiveFlags,TDI_RECEIVE_ENTIRE_MESSAGE)) {
|
|
// The SMB response was not completely returned. Post a copy data request to
|
|
// get the remainder of the response. If the response is greater than the original
|
|
// buffer size, abort this connection request and consume the bytes available.
|
|
|
|
if (BytesAvailable > CONSTRUCT_NETROOT_BUFFER_SIZE) {
|
|
ASSERT(!"not enough bytes in parsesmbheader.....sigh.............."); // To be removed soon ...
|
|
pExchange->Status = STATUS_NOT_IMPLEMENTED;
|
|
*pBytesTaken = BytesAvailable;
|
|
Status = RX_MAP_STATUS(SUCCESS);
|
|
} else {
|
|
*pBytesTaken = 0;
|
|
*pDataBufferPointer = pNetRootExchange->pSmbResponseMdl;
|
|
*pDataSize = CONSTRUCT_NETROOT_BUFFER_SIZE;
|
|
Status = STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
} else {
|
|
// The SMB exchange completed without an error.
|
|
pExchange->Status = SmbCeParseConstructNetRootResponse(
|
|
pNetRootExchange,
|
|
pSmbHeader,
|
|
BytesAvailable,
|
|
BytesIndicated,
|
|
pBytesTaken);
|
|
|
|
RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseSmbHeader BytesTaken %ld\n",*pBytesTaken));
|
|
RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseSmbHeader Return Status %lx\n",pExchange->Status));
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbConstructNetRootExchangeCopyDataHandler(
|
|
IN PSMB_EXCHANGE pExchange,
|
|
IN PMDL pCopyDataBuffer,
|
|
IN ULONG DataSize)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the copy data handling routine for net root construction exchanges
|
|
|
|
Arguments:
|
|
|
|
pExchange - the exchange instance
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
PSMB_CONSTRUCT_NETROOT_EXCHANGE pNetRootExchange;
|
|
|
|
PSMB_HEADER pSmbHeader;
|
|
ULONG ResponseSize = DataSize;
|
|
ULONG ResponseBytesConsumed = 0;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
pNetRootExchange = (PSMB_CONSTRUCT_NETROOT_EXCHANGE)pExchange;
|
|
ASSERT(pCopyDataBuffer == pNetRootExchange->pSmbResponseMdl);
|
|
|
|
pSmbHeader = (PSMB_HEADER)MmGetSystemAddressForMdlSafe(pNetRootExchange->pSmbResponseMdl,LowPagePriority);
|
|
|
|
if (pSmbHeader != NULL) {
|
|
pExchange->Status = SmbCeParseConstructNetRootResponse(
|
|
pNetRootExchange,
|
|
pSmbHeader,
|
|
ResponseSize,
|
|
ResponseSize,
|
|
&ResponseBytesConsumed);
|
|
} else {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseSmbHeader BytesTaken %ld\n",ResponseBytesConsumed));
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbCeParseConstructNetRootResponse(
|
|
PSMB_CONSTRUCT_NETROOT_EXCHANGE pNetRootExchange,
|
|
PSMB_HEADER pSmbHeader,
|
|
ULONG BytesAvailable,
|
|
ULONG BytesIndicated,
|
|
ULONG *pBytesTaken)
|
|
{
|
|
NTSTATUS Status,SmbResponseStatus;
|
|
GENERIC_ANDX CommandToProcess;
|
|
|
|
RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseSmbHeader BytesIndicated %ld\n",BytesIndicated));
|
|
Status = SmbCeParseSmbHeader(
|
|
(PSMB_EXCHANGE)pNetRootExchange,
|
|
pSmbHeader,
|
|
&CommandToProcess,
|
|
&SmbResponseStatus,
|
|
BytesAvailable,
|
|
BytesIndicated,
|
|
pBytesTaken);
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
*pBytesTaken = BytesIndicated;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmbConstructNetRootExchangeFinalize(
|
|
PSMB_EXCHANGE pExchange,
|
|
BOOLEAN *pPostFinalize)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine finalizes the construct net root exchange. It resumes the RDBSS by invoking
|
|
the call back and discards the exchange
|
|
|
|
Arguments:
|
|
|
|
pExchange - the exchange instance
|
|
|
|
CurrentIrql - the current interrupt request level
|
|
|
|
pPostFinalize - a pointer to a BOOLEAN if the request should be posted
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
PSMB_CONSTRUCT_NETROOT_EXCHANGE pNetRootExchange;
|
|
PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext;
|
|
PMRX_NETROOT_CALLBACK pNetRootCallback;
|
|
|
|
PMRX_V_NET_ROOT pVNetRoot;
|
|
PMRX_NET_ROOT pNetRoot;
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
|
|
|
|
PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
|
|
NTSTATUS Status = pExchange->Status;
|
|
|
|
if (RxShouldPostCompletion()) {
|
|
*pPostFinalize = TRUE;
|
|
return STATUS_SUCCESS;
|
|
} else {
|
|
*pPostFinalize = FALSE;
|
|
}
|
|
|
|
pVNetRoot = SmbCeGetExchangeVNetRoot(pExchange);
|
|
pNetRoot = pVNetRoot->pNetRoot;
|
|
|
|
pVNetRootContext = SmbCeGetAssociatedVNetRootContext(pVNetRoot);
|
|
|
|
ASSERT((pVNetRoot == NULL) || (pVNetRoot->pNetRoot == pNetRoot));
|
|
pNetRootExchange = (PSMB_CONSTRUCT_NETROOT_EXCHANGE)pExchange;
|
|
pNetRootCallback = pNetRootExchange->NetRootCallback;
|
|
|
|
ASSERT(pNetRootExchange->Type == CONSTRUCT_NETROOT_EXCHANGE);
|
|
|
|
pCreateNetRootContext = pNetRootExchange->pCreateNetRootContext;
|
|
|
|
pCreateNetRootContext->VirtualNetRootStatus = RX_MAP_STATUS(SUCCESS);
|
|
pCreateNetRootContext->NetRootStatus = RX_MAP_STATUS(SUCCESS);
|
|
|
|
RxDbgTrace(0,Dbg,("SmbConstructNetRootExchangeFinalize: Net Root Exchange Status %lx\n", pExchange->Status));
|
|
if (!NT_SUCCESS(pExchange->Status)) {
|
|
if (pCreateNetRootContext->RxContext &&
|
|
pCreateNetRootContext->RxContext->Create.ThisIsATreeConnectOpen){
|
|
InterlockedIncrement(&MRxSmbStatistics.FailedUseCount);
|
|
}
|
|
|
|
if (!SmbCeIsServerInDisconnectedMode(pServerEntry) &&
|
|
!FlagOn(pVNetRootContext->Flags,SMBCE_V_NET_ROOT_CONTEXT_CSCAGENT_INSTANCE)) {
|
|
// if it cannot establish the connect and didn't get chance to transition
|
|
// into disconnected state, we should try the transition and if succeed,
|
|
// establish the connect again in the disconnected state.
|
|
|
|
Status = CscTransitionVNetRootForDisconnectedOperation(
|
|
pCreateNetRootContext->RxContext,
|
|
pVNetRoot,
|
|
pExchange->Status);
|
|
}
|
|
|
|
pCreateNetRootContext->VirtualNetRootStatus = Status;
|
|
|
|
if (pCreateNetRootContext->VirtualNetRootStatus == STATUS_INVALID_HANDLE) {
|
|
pCreateNetRootContext->VirtualNetRootStatus = STATUS_UNEXPECTED_NETWORK_ERROR;
|
|
}
|
|
|
|
if (pNetRootExchange->fInitializeNetRoot) {
|
|
pCreateNetRootContext->NetRootStatus = Status;
|
|
|
|
if (pCreateNetRootContext->NetRootStatus == STATUS_INVALID_HANDLE) {
|
|
pCreateNetRootContext->NetRootStatus = STATUS_UNEXPECTED_NETWORK_ERROR;
|
|
}
|
|
}
|
|
|
|
SmbCeUpdateVNetRootContextState(
|
|
pVNetRootContext,
|
|
SMBCEDB_MARKED_FOR_DELETION);
|
|
} else {
|
|
PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
|
|
|
|
pNetRootEntry = SmbCeGetExchangeNetRootEntry(pExchange);
|
|
|
|
if(pCreateNetRootContext->RxContext)
|
|
{
|
|
MRxSmbCscPartOfCreateVNetRoot(pCreateNetRootContext->RxContext, pNetRoot);
|
|
}
|
|
|
|
// Update the associated wrapper data structures.
|
|
SmbCeUpdateNetRoot(pNetRootEntry,pNetRoot);
|
|
}
|
|
|
|
SmbCeReferenceVNetRootContext(pVNetRootContext);
|
|
SmbCeCompleteVNetRootContextInitialization(pVNetRootContext);
|
|
pExchange->SmbCeFlags &= ~SMBCE_EXCHANGE_NETROOT_CONSTRUCTOR;
|
|
|
|
ASSERT((pCreateNetRootContext->VirtualNetRootStatus != STATUS_SUCCESS) || (pVNetRoot->Context != NULL));
|
|
|
|
if ((pCreateNetRootContext->NetRootStatus == STATUS_CONNECTION_RESET)||(pCreateNetRootContext->NetRootStatus == STATUS_IO_TIMEOUT))
|
|
{
|
|
SmbCeLog(("!!Remote Reset Status=%x\n", pCreateNetRootContext->NetRootStatus));
|
|
SmbLogError(pCreateNetRootContext->NetRootStatus,
|
|
LOG,
|
|
SmbConstructNetRootExchangeFinalize,
|
|
LOGULONG(pCreateNetRootContext->NetRootStatus)
|
|
LOGPTR(pNetRoot)
|
|
LOGUSTR(*pNetRoot->pNetRootName));
|
|
}
|
|
|
|
if (pNetRootExchange->pSmbResponseMdl != NULL) {
|
|
MmUnlockPages(pNetRootExchange->pSmbResponseMdl);
|
|
IoFreeMdl(pNetRootExchange->pSmbResponseMdl);
|
|
}
|
|
|
|
if (pNetRootExchange->pSmbRequestMdl != NULL) {
|
|
RxUnlockHeaderPages(pNetRootExchange->pSmbRequestMdl);
|
|
IoFreeMdl(pNetRootExchange->pSmbRequestMdl);
|
|
}
|
|
|
|
if (pNetRootExchange->pSmbActualBuffer != NULL) {
|
|
|
|
RxFreePool(pNetRootExchange->pSmbActualBuffer);
|
|
}
|
|
|
|
// Tear down the exchange instance ...
|
|
SmbCeDiscardExchangeWorkerThreadRoutine(pExchange);
|
|
|
|
if (Status == STATUS_RETRY) {
|
|
// create VNetRoot offline if server entry is transitioned into disconnected state
|
|
Status = MRxSmbCreateVNetRootOffLine(pCreateNetRootContext);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
// Callback the RDBSS for resumption if create VNetRoot offline fails
|
|
pNetRootCallback(pCreateNetRootContext);
|
|
}
|
|
} else {
|
|
if (pServerEntry->Server.IsRemoteBootServer &&
|
|
pCreateNetRootContext->NetRootStatus != STATUS_SUCCESS) {
|
|
pCreateNetRootContext->NetRootStatus = STATUS_RETRY;
|
|
pCreateNetRootContext->VirtualNetRootStatus = STATUS_RETRY;
|
|
}
|
|
|
|
// Callback the RDBSS for resumption
|
|
pNetRootCallback(pCreateNetRootContext);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
MRxSmbCreateVNetRootOffLine(
|
|
PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
Status = RxPostToWorkerThread(
|
|
MRxSmbDeviceObject,
|
|
CriticalWorkQueue,
|
|
&pCreateNetRootContext->WorkQueueItem,
|
|
MRxSmbCreateVNetRoot,
|
|
pCreateNetRootContext);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
SMB_EXCHANGE_DISPATCH_VECTOR
|
|
ConstructNetRootExchangeDispatch = {
|
|
SmbConstructNetRootExchangeStart,
|
|
SmbConstructNetRootExchangeReceive,
|
|
SmbConstructNetRootExchangeCopyDataHandler,
|
|
NULL, // No SendCompletionHandler
|
|
SmbConstructNetRootExchangeFinalize,
|
|
NULL
|
|
};
|
|
|
|
|
|
VOID
|
|
MRxSmbExtractNetRootName(
|
|
IN PUNICODE_STRING FilePathName,
|
|
IN PMRX_SRV_CALL SrvCall,
|
|
OUT PUNICODE_STRING NetRootName,
|
|
OUT PUNICODE_STRING RestOfName OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine parses the input name into srv, netroot, and the
|
|
rest.
|
|
|
|
Arguments:
|
|
|
|
|
|
--*/
|
|
{
|
|
UNICODE_STRING xRestOfName;
|
|
|
|
ULONG length = FilePathName->Length;
|
|
PWCH w = FilePathName->Buffer;
|
|
PWCH wlimit = (PWCH)(((PCHAR)w)+length);
|
|
PWCH wlow;
|
|
|
|
PAGED_CODE();
|
|
|
|
w += (SrvCall->pSrvCallName->Length/sizeof(WCHAR));
|
|
NetRootName->Buffer = wlow = w;
|
|
for (;;) {
|
|
if (w>=wlimit) break;
|
|
if ( (*w == OBJ_NAME_PATH_SEPARATOR) && (w!=wlow) ){
|
|
#if ZZZ_MODE
|
|
if (*(w-1) == L'z') {
|
|
w++;
|
|
continue;
|
|
}
|
|
#endif //if ZZZ_MODE
|
|
break;
|
|
}
|
|
w++;
|
|
}
|
|
NetRootName->Length = NetRootName->MaximumLength
|
|
= (USHORT)((PCHAR)w - (PCHAR)wlow);
|
|
|
|
if (!RestOfName) RestOfName = &xRestOfName;
|
|
RestOfName->Buffer = w;
|
|
RestOfName->Length = RestOfName->MaximumLength
|
|
= (USHORT)((PCHAR)wlimit - (PCHAR)w);
|
|
|
|
RxDbgTrace( 0,Dbg,(" MRxSmbExtractNetRootName FilePath=%wZ\n",FilePathName));
|
|
RxDbgTrace(0,Dbg,(" Srv=%wZ,Root=%wZ,Rest=%wZ\n",
|
|
SrvCall->pSrvCallName,NetRootName,RestOfName));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|