mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2207 lines
67 KiB
2207 lines
67 KiB
/*++ Copyright (c) 1987-1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
SmbPse.c
|
|
|
|
Abstract:
|
|
|
|
This module defines the types and functions related to the SMB protocol
|
|
selection engine: the component that translates minirdr calldowns into
|
|
SMBs.
|
|
|
|
Author:
|
|
|
|
Joe Linn [JoeLi] -- Implemented Ordinary Exchange
|
|
|
|
Notes:
|
|
|
|
The Ordinary exchange bridges the mismatch between the connection engine exchange
|
|
which is oriented towards sending a single SMB request to the server and processing
|
|
the response from the server and the requests recieved from RDBSS.
|
|
|
|
The requests from RDBSS come in one of two flavours -- synchronous and asynchronous.
|
|
There are requests which often translate into multiple SMB's being sent to the
|
|
server and the associated response processing. There is no one to one mapping
|
|
between the requests and the SMBs that need to be sent. In some cases a reconnection
|
|
attempt needs to be made and in others a delayed open needs to be sent before the
|
|
associated request can be processed. There are instances of requests which are
|
|
inherently multi SMB, e.g., large read and write requests.
|
|
|
|
The ordinary exchange provides the framework for dealing with all these variations.
|
|
The ORDINARY_EXCHANGE wraps a connection engine exchange and extends it with
|
|
different hooks for customization. The custromization of ORDINARY_EXCHANGE is
|
|
possible both from the data and control viewpoint. The data portion is provided
|
|
by a union at the tail end of the ORDINARY_EXCHANGE which provides for the
|
|
appropriate state to be captured.
|
|
|
|
The code customization consists of three routines that can be specified as
|
|
part of the ORDIANRY_EXCHANGE. These are the Asynchronous Resumption routine
|
|
(AsyncResumptionRoutine), the continuation routine (ContinuationRoutine) and
|
|
the start routine (StartRoutine).
|
|
|
|
The SmbPseCreateOrdinaryExchange, SmbPseSubmitOrdinaryExchange and
|
|
SmbPseFinalizeOrdinaryExchange provide the necessay mechanism for creating an
|
|
ordinary exchange, triggering the action and finalizing it upon completion.
|
|
|
|
The ordinary exchange implementation tailors the dispatch vector associated
|
|
with the underlying connection engine exchange using extensive tables. All
|
|
the routines suffixed with _default are the default routines for the
|
|
underlying connection engine exchange.
|
|
|
|
The typical course of exchange in response to a request from the RDBSS is to
|
|
|
|
1) create an ordinary exchange (SmbPseCreateOrdinaryExchange)
|
|
|
|
2) submit it for processing (SmbPseSubmitOrdinaryExchange)
|
|
|
|
2.1) The Ordinary exchange completes the initialization w.r.t the state
|
|
associated with it and initiates the processing in the connection
|
|
engine (SmbCeInitiateExchange)
|
|
|
|
2.2) The connection engine completes the initialization associated
|
|
with the connection engine and invokes the Start routine provided in
|
|
the dispatch vector.
|
|
|
|
2.3) This results in the Start routine provided to the Ordinary exchange
|
|
being invoked. The request specific initialization is carried out followed
|
|
by a call to SmbCeTranceive or SmbCeSend.
|
|
|
|
2.4) The resulting exchange is suspended while the underlying connection
|
|
engine interfaces with the transport to ship the packet over and receive
|
|
the response.
|
|
|
|
2.5) Once the connection engine quiesces the SMbPseContinueOrdinaryExchange
|
|
is called. This routine either invokes the continuation routine to resume
|
|
processing or wrap up the ordianry exchange processing and return to
|
|
the caller. this involves either setting the event for synchronous
|
|
requests or invoking the AsyncResumption routine for asynchronous requests.
|
|
|
|
The request for read/write which involve multiple packets use the continuation
|
|
routine to spin up further requests. These can be network exchanges which are wired
|
|
to the original exchange and are referred to as associated exchanges. On completion
|
|
of all associated exchanges the connection engine invokes the
|
|
AssociatedExchangeCompletionHandler which results in the resumption of
|
|
ORDINARY_EXCHANGE processing in 2.5.
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
#include <dfsfsctl.h>
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, __SmbPseDbgCheckOEMdls)
|
|
#pragma alloc_text(PAGE, SmbPseContinueOrdinaryExchange)
|
|
#pragma alloc_text(PAGE, SmbPseOrdinaryExchange)
|
|
#pragma alloc_text(PAGE, __SmbPseCreateOrdinaryExchange)
|
|
#pragma alloc_text(PAGE, SmbPseFinalizeOrdinaryExchange)
|
|
#pragma alloc_text(PAGE, SmbPseExchangeStart_default)
|
|
#pragma alloc_text(PAGE, SmbPseExchangeCopyDataHandler_Read)
|
|
#pragma alloc_text(PAGE, __SmbPseRMTableEntry)
|
|
#pragma alloc_text(PAGE, SmbPseInitializeTables)
|
|
#pragma alloc_text(PAGE, MRxSmbQueryDosVolumeInformation)
|
|
#endif
|
|
|
|
RXDT_DefineCategory(SMBPSE);
|
|
#define Dbg (DEBUG_TRACE_SMBPSE)
|
|
|
|
#define MINIMUM_SEND_SIZE 512
|
|
|
|
PVOID LastOE;
|
|
|
|
#define MIN(x,y) ((x) < (y) ? (x) : (y))
|
|
|
|
#define IM_THE_LAST_GUY (*Response==0)
|
|
|
|
//
|
|
// Generic AndX request
|
|
//
|
|
|
|
GENERIC_ANDX NullGenericAndX = {
|
|
// typedef struct _GENERIC_ANDX {
|
|
0, // UCHAR WordCount; // Count of parameter words
|
|
// UCHAR AndXCommand; // Secondary (X) command; 0xFF = none
|
|
SMB_COM_NO_ANDX_COMMAND,
|
|
0, // UCHAR AndXReserved; // Reserved
|
|
0 // _USHORT( AndXOffset ); // Offset (from SMB header start)
|
|
// } GENERIC_ANDX;
|
|
};
|
|
|
|
NTSTATUS
|
|
SmbPseExchangeStart_default(
|
|
IN OUT PSMB_EXCHANGE pExchange);
|
|
|
|
NTSTATUS
|
|
SmbPseExchangeSendCallbackHandler_default(
|
|
IN PSMB_EXCHANGE pExchange,
|
|
IN PMDL pXmitBuffer,
|
|
IN NTSTATUS SendCompletionStatus);
|
|
|
|
NTSTATUS
|
|
SmbPseExchangeCopyDataHandler_default(
|
|
IN PSMB_EXCHANGE pExchange,
|
|
IN PMDL pDataBuffer,
|
|
IN ULONG DataSize);
|
|
|
|
NTSTATUS
|
|
SmbPseExchangeCopyDataHandler_Read(
|
|
IN PSMB_EXCHANGE pExchange,
|
|
IN PMDL pDataBuffer,
|
|
IN ULONG DataSize);
|
|
|
|
NTSTATUS
|
|
SmbPseExchangeReceive_default(
|
|
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);
|
|
|
|
NTSTATUS
|
|
SmbPseExchangeFinalize_default(
|
|
IN OUT struct _SMB_EXCHANGE *pExchange,
|
|
OUT BOOLEAN *pPostFinalize);
|
|
|
|
SMB_EXCHANGE_DISPATCH_VECTOR
|
|
SmbPseOEDispatch = {
|
|
SmbPseExchangeStart_default,
|
|
SmbPseExchangeReceive_default,
|
|
SmbPseExchangeCopyDataHandler_default,
|
|
SmbPseExchangeSendCallbackHandler_default,
|
|
SmbPseExchangeFinalize_default,
|
|
NULL
|
|
};
|
|
|
|
#if DBG
|
|
#define P__ASSERT(exp) { \
|
|
if (!(exp)) { \
|
|
DbgPrint("NOT %s\n",#exp); \
|
|
errors++; \
|
|
}}
|
|
|
|
VOID
|
|
__SmbPseOEAssertConsistentLinkage(
|
|
PSZ MsgPrefix,
|
|
PSZ File,
|
|
unsigned Line,
|
|
PRX_CONTEXT RxContext,
|
|
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
|
|
PSMBSTUFFER_BUFFER_STATE StufferState,
|
|
ULONG Flags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine performs a variety of checks to ensure that the linkage between the rxcontext, the OE, and
|
|
the stufferstate is correct and that various fields have correct values. if anything is bad....print stuff out and brkpoint;
|
|
|
|
Arguments:
|
|
|
|
MsgPrefix an identifying msg
|
|
RxContext duh
|
|
OrdinaryExchange .
|
|
StufferState .
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
|
|
ULONG errors = 0;
|
|
|
|
PMRXSMB_RX_CONTEXT pMRxSmbContext;
|
|
PSMB_EXCHANGE Exchange = &OrdinaryExchange->Exchange;
|
|
|
|
pMRxSmbContext = MRxSmbGetMinirdrContext(RxContext);
|
|
|
|
if (Exchange->CancellationStatus != SMBCE_EXCHANGE_CANCELLED) {
|
|
P__ASSERT( OrdinaryExchange->SerialNumber == RxContext->SerialNumber );
|
|
P__ASSERT( NodeType(RxContext) == RDBSS_NTC_RX_CONTEXT );
|
|
}
|
|
|
|
P__ASSERT( NodeType(OrdinaryExchange)==SMB_EXCHANGE_NTC(ORDINARY_EXCHANGE) );
|
|
P__ASSERT( OrdinaryExchange->RxContext == RxContext );
|
|
P__ASSERT( NodeType(StufferState) == SMB_NTC_STUFFERSTATE );
|
|
P__ASSERT( Exchange == StufferState->Exchange);
|
|
P__ASSERT( StufferState->RxContext == RxContext );
|
|
|
|
if(StufferState->HeaderMdl!=NULL){
|
|
P__ASSERT( !RxMdlIsPartial(StufferState->HeaderMdl) );
|
|
}
|
|
|
|
if (FlagOn(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_OE_HDR_PARTIAL_INITIALIZED)) {
|
|
P__ASSERT( RxMdlIsPartial(StufferState->HeaderPartialMdl) );
|
|
}
|
|
|
|
if (errors==0) {
|
|
return;
|
|
}
|
|
|
|
DbgPrint("%s INCONSISTENT OE STATE: %d errors at %s line %d\n",
|
|
MsgPrefix,errors,File,Line);
|
|
//DbgBreakPoint();
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
__SmbPseDbgRunMdlChain(
|
|
PMDL MdlChain,
|
|
ULONG CountToCompare,
|
|
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
|
|
PSZ MsgPrefix,
|
|
PSZ File,
|
|
unsigned Line
|
|
)
|
|
{
|
|
ULONG i,total;
|
|
|
|
RxDbgTrace(0,Dbg,("__SmbPseRunMdlChain: -------------%08lx\n",MdlChain));
|
|
for (total=i=0;MdlChain!=NULL;i++,MdlChain=MdlChain->Next) {
|
|
total+=MdlChain->ByteCount;
|
|
RxDbgTrace(0,Dbg,("--->%02d %08lx %08lx %08lx %6d %6d\n",i,MdlChain,MdlChain->MdlFlags,
|
|
MmGetMdlVirtualAddress(MdlChain),MdlChain->ByteCount,total));
|
|
}
|
|
|
|
if (total == CountToCompare) return;
|
|
|
|
DbgPrint("%s: MdlChain.Count!=CountToCompart c1,c2,xch.st=%08lx %08lx %08lx\n",
|
|
MsgPrefix,
|
|
total,CountToCompare,OrdinaryExchange->Status,
|
|
|
|
File,Line);
|
|
//DbgBreakPoint();
|
|
}
|
|
|
|
#define SmbPseDbgRunMdlChain(a,b,c,d) {\
|
|
__SmbPseDbgRunMdlChain(a,b,c,d,__FILE__,__LINE__);\
|
|
}
|
|
|
|
VOID
|
|
__SmbPseDbgCheckOEMdls(
|
|
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
|
|
PSZ MsgPrefix,
|
|
PSZ File,
|
|
unsigned Line
|
|
)
|
|
{
|
|
ULONG errors = 0;
|
|
PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
|
|
PMDL SubmitMdl = StufferState->HeaderPartialMdl;
|
|
|
|
PAGED_CODE();
|
|
|
|
P__ASSERT (OrdinaryExchange->SaveDataMdlForDebug == SubmitMdl->Next);
|
|
P__ASSERT (OrdinaryExchange->SaveDataMdlForDebug == StufferState->DataMdl);
|
|
P__ASSERT (SubmitMdl != NULL);
|
|
|
|
if (errors==0) {
|
|
return;
|
|
}
|
|
|
|
DbgPrint("%s CheckOEMdls failed: %d errors at %s line %d: OE=%08lx\n",
|
|
MsgPrefix,errors,File,Line,OrdinaryExchange);
|
|
//DbgBreakPoint();
|
|
|
|
return;
|
|
}
|
|
|
|
#define SmbPseDbgCheckOEMdls(a,b) {\
|
|
__SmbPseDbgCheckOEMdls(a,b,__FILE__,__LINE__);\
|
|
}
|
|
|
|
ULONG SmbPseShortStatus(ULONG Status)
|
|
{
|
|
ULONG ShortStatus;
|
|
|
|
ShortStatus = Status & 0xc0003fff;
|
|
ShortStatus = ShortStatus | (ShortStatus >>16);
|
|
return(ShortStatus);
|
|
}
|
|
|
|
VOID SmbPseUpdateOEHistory(
|
|
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
|
|
ULONG Tag1,
|
|
ULONG Tag2
|
|
)
|
|
{
|
|
ULONG MyIndex,Long0,Long1;
|
|
|
|
MyIndex = InterlockedIncrement(&OrdinaryExchange->History.Next);
|
|
MyIndex = (MyIndex-1) & (SMBPSE_OE_HISTORY_SIZE-1);
|
|
Long0 = (Tag1<<16) | (Tag2 & 0xffff);
|
|
Long1 = (SmbPseShortStatus(OrdinaryExchange->SmbStatus)<<16) | OrdinaryExchange->Flags;
|
|
OrdinaryExchange->History.Markers[MyIndex].Longs[0] = Long0;
|
|
OrdinaryExchange->History.Markers[MyIndex].Longs[1] = Long1;
|
|
}
|
|
|
|
VOID SmbPseVerifyDataPartialAllocationPerFlags(
|
|
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange
|
|
)
|
|
{
|
|
BOOLEAN FlagsSayPartialAllocated,TheresADataPartial;
|
|
ULONG t = OrdinaryExchange->Flags & (SMBPSE_OE_FLAG_OE_ALLOCATED_DATA_PARTIAL|SMBPSE_OE_FLAG_MUST_SUCCEED_ALLOCATED_SMBBUF);
|
|
|
|
FlagsSayPartialAllocated = (t!=0)?TRUE:FALSE; //the compiler is getting confused
|
|
TheresADataPartial = (OrdinaryExchange->DataPartialMdl != NULL)?TRUE:FALSE; //the compiler is getting confused
|
|
if ( FlagsSayPartialAllocated != TheresADataPartial){
|
|
DbgPrint("Flags %08lx datapartial %08lx t %08lx fspa %08lx tadp %08lx\n",
|
|
OrdinaryExchange->Flags, OrdinaryExchange->DataPartialMdl,
|
|
t, FlagsSayPartialAllocated, TheresADataPartial);
|
|
ASSERT ( FlagsSayPartialAllocated == TheresADataPartial);
|
|
}
|
|
}
|
|
|
|
#else
|
|
|
|
#define SmbPseDbgRunMdlChain(a,b,c,d) {NOTHING;}
|
|
#define SmbPseDbgCheckOEMdls(a,b) {NOTHING;}
|
|
#define SmbPseVerifyDataPartialAllocationPerFlags(a) {NOTHING;}
|
|
|
|
#endif
|
|
|
|
#define UPDATE_OE_HISTORY_WITH_STATUS(a) \
|
|
UPDATE_OE_HISTORY_2SHORTS(a,SmbPseShortStatus(OrdinaryExchange->Status))
|
|
|
|
|
|
|
|
|
|
VOID
|
|
MRxSmbResumeAsyncReadWriteRequests(
|
|
PRX_CONTEXT RxContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Asynchronous read write requests can be deferred because of SMB FCB resource
|
|
acquistion. In all such cases this routine resumes the request. We
|
|
cannot directly reume execution with MRxSmbRead/MRxSmbWrite routine because
|
|
we need to invoke LowIoCompletion in certain failure cases. We have two choices
|
|
to do so .... either we can include this logic in the MRxSmbRead/MRxSmbWrite
|
|
routine or consolidate it in pne place. This routine implements the later
|
|
approach.
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RDBSS context
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PMRX_CALLDOWN ResumptionRoutine;
|
|
|
|
switch (RxContext->MajorFunction) {
|
|
case IRP_MJ_READ:
|
|
ResumptionRoutine = MRxSmbRead;
|
|
break;
|
|
case IRP_MJ_WRITE:
|
|
ResumptionRoutine = MRxSmbWrite;
|
|
break;
|
|
default:
|
|
ASSERT(!"Valid IRP Major Function code for CscResumeReadWrite");
|
|
return;
|
|
}
|
|
|
|
Status = (ResumptionRoutine)(RxContext);
|
|
|
|
if (Status != STATUS_PENDING) {
|
|
if (Status != STATUS_SUCCESS) {
|
|
DbgPrint("RxContext Async CSC Status %lx\n",Status);
|
|
RxContext->StoredStatus = Status;
|
|
RxContext->InformationToReturn = 0;
|
|
}
|
|
// Invoke the Low Io Resumption routine
|
|
RxLowIoCompletion(RxContext);
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbPseContinueOrdinaryExchange(
|
|
IN OUT PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine resumes processing on an exchange. This is called when work is
|
|
required to finish processing a request that cannot be completed at DPC
|
|
level. This happens either because the parse routine needs access to
|
|
structures that are not locks OR because the operation if asynchronous and
|
|
there maybe more work to be done.
|
|
|
|
The two cases are regularized by delaying the parse if we know that we're
|
|
going to post: this is indicated by the presense of a resume routine.
|
|
|
|
Arguments:
|
|
|
|
RxContext - the context of the operation. .
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PRX_CONTEXT RxContext = OrdinaryExchange->RxContext;
|
|
RxCaptureFobx;
|
|
|
|
PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange;
|
|
|
|
PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
|
|
PMDL SubmitMdl, HeaderFullMdl;
|
|
|
|
BOOLEAN InvokeContinuationRoutine = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("SmbPseContinueOrdinaryExchange entering........OE=%08lx\n",OrdinaryExchange));
|
|
|
|
Status = Exchange->Status;
|
|
|
|
if (OrdinaryExchange->OpSpecificState !=
|
|
SmbPseOEInnerIoStates_OperationCompleted) {
|
|
|
|
ClearFlag(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_OE_AWAITING_DISPATCH);
|
|
|
|
SmbPseOEAssertConsistentLinkageFromOE("SmbPseContinueOrdinaryExchange:");
|
|
|
|
UPDATE_OE_HISTORY_WITH_STATUS('0c');
|
|
|
|
SubmitMdl = StufferState->HeaderPartialMdl;
|
|
HeaderFullMdl = StufferState->HeaderMdl;
|
|
|
|
ASSERT(FlagOn(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_OE_HDR_PARTIAL_INITIALIZED));
|
|
|
|
SmbPseOEAssertConsistentLinkage("Top of OE continue: ");
|
|
|
|
RxUnprotectMdlFromFree(SubmitMdl);
|
|
RxUnprotectMdlFromFree(HeaderFullMdl);
|
|
|
|
SmbPseDbgCheckOEMdls(
|
|
OrdinaryExchange,"SmbPseContinueOrdinaryExchange(top)");
|
|
|
|
SmbPseDbgRunMdlChain(
|
|
SubmitMdl,
|
|
OrdinaryExchange->SaveLengthForDebug,
|
|
OrdinaryExchange,
|
|
"SmbPseContinueOrdinaryExchange(top)");
|
|
|
|
MmPrepareMdlForReuse(SubmitMdl);
|
|
|
|
ClearFlag(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_OE_HDR_PARTIAL_INITIALIZED);
|
|
|
|
SmbPseVerifyDataPartialAllocationPerFlags(OrdinaryExchange);
|
|
|
|
if ( OrdinaryExchange->DataPartialMdl ) {
|
|
MmPrepareMdlForReuse( OrdinaryExchange->DataPartialMdl );
|
|
}
|
|
|
|
RxDbgTrace( 0, Dbg, (" --> P4Reuse %08lx, full %08lx is no longer unlocked here\n"
|
|
,SubmitMdl,HeaderFullMdl));
|
|
}
|
|
|
|
if (OrdinaryExchange->ContinuationRoutine == NULL) {
|
|
if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
|
|
ULONG BytesTaken;
|
|
ULONG DataSize = 0;
|
|
ULONG MessageLength = OrdinaryExchange->MessageLength;
|
|
PMDL DataBufferPointer = NULL;
|
|
PSMB_HEADER SmbHeader = (PSMB_HEADER)StufferState->BufferBase;
|
|
|
|
Status = SMB_EXCHANGE_DISPATCH(
|
|
Exchange,
|
|
Receive,
|
|
(
|
|
Exchange, // IN struct SMB_EXCHANGE *pExchange,
|
|
MessageLength, // IN ULONG BytesIndicated,
|
|
MessageLength, // IN ULONG BytesAvailable,
|
|
&BytesTaken, // OUT ULONG *pBytesTaken,
|
|
SmbHeader, // IN PSMB_HEADER pSmbHeader,
|
|
&DataBufferPointer, // OUT PMDL *pDataBufferPointer,
|
|
&DataSize, // OUT PULONG pDataSize)
|
|
TDI_RECEIVE_ENTIRE_MESSAGE
|
|
));
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
Status = Exchange->Status;
|
|
UPDATE_OE_HISTORY_WITH_STATUS('2c');
|
|
} else {
|
|
UPDATE_OE_HISTORY_WITH_STATUS('dd');
|
|
}
|
|
|
|
if (DataSize != 0 ||
|
|
DataBufferPointer != NULL ||
|
|
BytesTaken != MessageLength ||
|
|
Status == STATUS_MORE_PROCESSING_REQUIRED) {
|
|
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
|
}
|
|
|
|
InvokeContinuationRoutine = TRUE;
|
|
}
|
|
} else {
|
|
InvokeContinuationRoutine = TRUE;
|
|
}
|
|
|
|
|
|
if (InvokeContinuationRoutine) {
|
|
if ( OrdinaryExchange->ContinuationRoutine != NULL ) {
|
|
if ( Status == STATUS_MORE_PROCESSING_REQUIRED){
|
|
Exchange->Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
Status = OrdinaryExchange->ContinuationRoutine( OrdinaryExchange );
|
|
|
|
UPDATE_OE_HISTORY_WITH_STATUS('1c');
|
|
|
|
if (Status != STATUS_PENDING) {
|
|
Exchange->Status = Status;
|
|
OrdinaryExchange->ContinuationRoutine = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Status != STATUS_PENDING) {
|
|
if (Status != STATUS_SUCCESS) {
|
|
if (RxContext->MajorFunction != IRP_MJ_CLOSE) {
|
|
// There is no point in transitioning CLOSE operations since
|
|
// the context is lost anycase.
|
|
Status = CscTransitionVNetRootForDisconnectedOperation(
|
|
RxContext,
|
|
SmbCeGetExchangeVNetRoot(
|
|
(PSMB_EXCHANGE)OrdinaryExchange),
|
|
Status);
|
|
}
|
|
|
|
OrdinaryExchange->Status = OrdinaryExchange->SmbStatus = Status;
|
|
}
|
|
|
|
if (OrdinaryExchange->AsyncResumptionRoutine ) {
|
|
|
|
//call the continuation is it's async
|
|
Status = OrdinaryExchange->AsyncResumptionRoutine(
|
|
OrdinaryExchange,
|
|
RxContext );
|
|
|
|
UPDATE_OE_HISTORY_WITH_STATUS('3c');
|
|
}
|
|
|
|
//remove my references, if i'm the last guy then do the putaway...
|
|
UPDATE_OE_HISTORY_WITH_STATUS('4c');
|
|
SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
|
|
}
|
|
|
|
RxDbgTrace(-1, Dbg, ("SmbPseContinueOrdinaryExchange returning %08lx.\n", Status));
|
|
return(Status);
|
|
} // SmbPseContinueOrdinaryExchange
|
|
|
|
|
|
NTSTATUS
|
|
SmbPseOrdinaryExchange(
|
|
SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE,
|
|
IN SMB_PSE_ORDINARY_EXCHANGE_TYPE OEType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine implements an ordinary exchange as viewed by the protocol
|
|
selection routines.
|
|
|
|
Arguments:
|
|
|
|
OrdinaryExchange - the exchange to be conducted.
|
|
OEType - Ordinary Exchange Type
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
RxCaptureFobx;
|
|
RxCaptureFcb;
|
|
|
|
PMRXSMB_RX_CONTEXT pMRxSmbContext = MRxSmbGetMinirdrContext(RxContext);
|
|
|
|
PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange;
|
|
|
|
PSMBSTUFFER_BUFFER_STATE StufferState;
|
|
PSMB_PSE_OE_START_ROUTINE Continuation;
|
|
ULONG SmbLength;
|
|
PMDL SubmitMdl,HeaderFullMdl;
|
|
ULONG SendOptions;
|
|
DEBUG_ONLY_DECL( ULONG LengthP; ULONG LengthF; )
|
|
KEVENT SyncEvent;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("SmbPseOrdinaryExchange entering.......OE=%08lx\n",OrdinaryExchange));
|
|
|
|
SmbPseOEAssertConsistentLinkageFromOE("SmbPseOrdinaryExchange:");
|
|
|
|
OrdinaryExchange->OEType = OEType;
|
|
StufferState = &OrdinaryExchange->AssociatedStufferState;
|
|
|
|
KeInitializeEvent(
|
|
&SyncEvent,
|
|
NotificationEvent,
|
|
FALSE );
|
|
|
|
HeaderFullMdl = StufferState->HeaderMdl;
|
|
ASSERT( HeaderFullMdl != NULL );
|
|
SmbLength = (ULONG)(StufferState->CurrentPosition - StufferState->BufferBase);
|
|
|
|
SubmitMdl = StufferState->HeaderPartialMdl;
|
|
|
|
ASSERT(RxMdlIsOwned(SubmitMdl));
|
|
|
|
RxBuildPartialHeaderMdl(
|
|
StufferState->HeaderMdl,
|
|
SubmitMdl,
|
|
StufferState->BufferBase,
|
|
SmbLength );
|
|
|
|
SetFlag(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_OE_HDR_PARTIAL_INITIALIZED);
|
|
|
|
//
|
|
// If there is a data MDL associated with this request, then
|
|
// we'll have to chain it.
|
|
//
|
|
|
|
SubmitMdl->Next = StufferState->DataMdl;
|
|
|
|
if (StufferState->DataMdl) {
|
|
SmbLength += StufferState->DataSize;
|
|
}
|
|
|
|
DbgDoit(
|
|
SmbPseDbgRunMdlChain(
|
|
SubmitMdl,
|
|
SmbLength,
|
|
OrdinaryExchange,
|
|
"SmbPseOrdinaryExchange(before)");
|
|
|
|
OrdinaryExchange->SaveDataMdlForDebug = SubmitMdl->Next;
|
|
OrdinaryExchange->SaveLengthForDebug = SmbLength;
|
|
|
|
if (OrdinaryExchange->RxContextCapturedRequestPacket != NULL) {
|
|
OrdinaryExchange->SaveIrpMdlForDebug =
|
|
OrdinaryExchange->RxContextCapturedRequestPacket->MdlAddress;
|
|
}
|
|
)
|
|
|
|
RxDbgTrace(
|
|
0,
|
|
Dbg,
|
|
(" --> mdllength/smblength %08lx/%08lx headermdl %08lx\n",
|
|
MmGetMdlByteCount(SubmitMdl), SmbLength, StufferState->HeaderMdl) );
|
|
|
|
ClearFlag(
|
|
OrdinaryExchange->Flags,
|
|
(SMBPSE_OE_FLAG_HEADER_ALREADY_PARSED |
|
|
SMBPSE_OE_FLAG_OE_ALREADY_RESUMED) );
|
|
|
|
SendOptions = OrdinaryExchange->SendOptions;
|
|
|
|
SmbCeReferenceExchange( Exchange ); //this one is taken away in ContinueOE
|
|
SmbCeReferenceExchange( Exchange ); //this one is taken away below...
|
|
//i must NOT finalize before SmbCe returns
|
|
SmbCeResetExchange(Exchange);
|
|
|
|
Continuation = OrdinaryExchange->AsyncResumptionRoutine;
|
|
|
|
if (((OrdinaryExchange->OEType == SMBPSE_OETYPE_WRITE) ||
|
|
(OrdinaryExchange->OEType == SMBPSE_OETYPE_READ) ||
|
|
(OrdinaryExchange->OEType == SMBPSE_OETYPE_LOCKS)) &&
|
|
BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION)
|
|
) {
|
|
ASSERT(Continuation!=NULL);
|
|
}
|
|
|
|
if (Continuation == NULL) {
|
|
OrdinaryExchange->pSmbCeSynchronizationEvent = &SyncEvent;
|
|
}
|
|
|
|
DbgDoit((LengthP = MmGetMdlByteCount(SubmitMdl),LengthF = MmGetMdlByteCount(HeaderFullMdl)));
|
|
|
|
RxProtectMdlFromFree(SubmitMdl);
|
|
RxProtectMdlFromFree(HeaderFullMdl);
|
|
|
|
SmbPseOEAssertConsistentLinkage("just before transceive: ");
|
|
|
|
UPDATE_OE_HISTORY_2SHORTS('eo',(Continuation!=NULL)?'!!':0);
|
|
|
|
DbgDoit( InterlockedIncrement(&OrdinaryExchange->History.Submits); )
|
|
|
|
if (FlagOn(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_VALIDATE_FID)) {
|
|
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(OrdinaryExchange);
|
|
|
|
if (smbSrvOpen->Version == pServerEntry->Server.Version) {
|
|
Status = STATUS_SUCCESS;
|
|
} else {
|
|
Exchange->Status = Exchange->SmbStatus = Status = STATUS_CONNECTION_DISCONNECTED;
|
|
capFcb->fShouldBeOrphaned = TRUE;
|
|
}
|
|
|
|
IF_DEBUG {
|
|
PSMB_HEADER pSmbHeader = (PSMB_HEADER)MmGetSystemAddressForMdlSafe(SubmitMdl,LowPagePriority);
|
|
USHORT Flags2 = 0;
|
|
|
|
if (pSmbHeader) {
|
|
Flags2 = SmbGetUshort(&pSmbHeader->Flags2);
|
|
}
|
|
|
|
RxDbgTrace(0, Dbg, ("Flags2 Value for Exchange %lx is %lx\n",Exchange,Flags2));
|
|
}
|
|
} else {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
if (FlagOn(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_NO_RESPONSE_EXPECTED)) {
|
|
Status = SmbCeSend(
|
|
Exchange,
|
|
SendOptions,
|
|
SubmitMdl,
|
|
SmbLength);
|
|
} else {
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(OrdinaryExchange);
|
|
|
|
Status = SmbCeTranceive(
|
|
Exchange,
|
|
SendOptions,
|
|
SubmitMdl,
|
|
SmbLength);
|
|
}
|
|
}
|
|
|
|
SmbPseFinalizeOrdinaryExchange(OrdinaryExchange); //okay to finalize now that we're back
|
|
|
|
if ( Status == STATUS_PENDING) {
|
|
if ( Continuation != NULL ) {
|
|
goto FINALLY;
|
|
}
|
|
|
|
UPDATE_OE_HISTORY_WITH_STATUS('1o');
|
|
KeWaitForSingleObject(&SyncEvent,Executive, KernelMode, FALSE, NULL );
|
|
OrdinaryExchange->pSmbCeSynchronizationEvent = NULL;
|
|
|
|
ASSERT(RxMdlIsOwned(SubmitMdl));
|
|
|
|
DbgDoit (
|
|
//variables in the assert are only declared for DBG
|
|
//asserts can be enabled separately
|
|
ASSERT(
|
|
LengthP == MmGetMdlByteCount(SubmitMdl) &&
|
|
LengthF == MmGetMdlByteCount(HeaderFullMdl) );
|
|
)
|
|
} else {
|
|
RxDbgTrace (0, Dbg, (" -->Status after transceive %08lx\n",Status));
|
|
DbgDoit (
|
|
//variables in the assert are only declared for DBG
|
|
//asserts can be enabled separately
|
|
ASSERT(
|
|
LengthP == MmGetMdlByteCount(SubmitMdl) &&
|
|
LengthF == MmGetMdlByteCount(HeaderFullMdl) );
|
|
)
|
|
|
|
RxUnprotectMdlFromFree(SubmitMdl);
|
|
RxUnprotectMdlFromFree(HeaderFullMdl);
|
|
SmbPseOEAssertConsistentLinkage("nonpending return from transceive: ");
|
|
|
|
// if it's an error, remove the references that i placed and get out
|
|
if (NT_ERROR(Status)) {
|
|
SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
|
|
goto FINALLY;
|
|
}
|
|
}
|
|
|
|
//at last, call the continuation........
|
|
|
|
SmbPseOEAssertConsistentLinkage("just before continueOE: ");
|
|
UPDATE_OE_HISTORY_WITH_STATUS('9b');
|
|
|
|
Status = SmbPseContinueOrdinaryExchange( OrdinaryExchange );
|
|
|
|
UPDATE_OE_HISTORY_WITH_STATUS('9o');
|
|
|
|
FINALLY:
|
|
RxDbgTrace(-1, Dbg, ("SmbPseOrdinaryExchange returning %08lx.\n", Status));
|
|
|
|
return(Status);
|
|
|
|
} // SmbPseOrdinaryExchange
|
|
|
|
NTSTATUS
|
|
__SmbPseCreateOrdinaryExchange (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PMRX_V_NET_ROOT VNetRoot,
|
|
IN SMB_PSE_ORDINARY_EXCHANGE_ENTRYPOINTS EntryPoint,
|
|
IN PSMB_PSE_OE_START_ROUTINE StartRoutine,
|
|
IN OUT SMBFCB_HOLDING_STATE *SmbFcbHoldingState OPTIONAL,
|
|
OUT PSMB_PSE_ORDINARY_EXCHANGE *OrdinaryExchangePtr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allocates and initializes an SMB header buffer. Currently,
|
|
we just allocate them from pool except when must_succeed is specified.
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RDBSS context
|
|
VNetRoot -
|
|
DispatchVector -
|
|
|
|
Return Value:
|
|
|
|
A buffer ready to go, OR NULL.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
PMRXSMB_RX_CONTEXT pMRxSmbContext = MRxSmbGetMinirdrContext(RxContext);
|
|
PSMBSTUFFER_BUFFER_STATE StufferState = NULL;
|
|
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange = NULL;
|
|
PCHAR SmbBuffer = NULL;
|
|
PMDL HeaderFullMdl = NULL;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
RxCaptureFobx;
|
|
SMBFCB_HOLDING_STATE TempHoldingState = SmbFcb_NotHeld;
|
|
|
|
PAGED_CODE();
|
|
|
|
/*
|
|
Other size improvement stuff: //CODE.IMPROVEMENT
|
|
finalize renamed to transitiontoquiescent
|
|
big fix - remove unwanted capture macros
|
|
longname - delete top part of routine by using the studcode
|
|
smbutils - we could reduce the table size by a factor of 2-3 by storing s 16bit representation of the ntstatus
|
|
*/
|
|
|
|
RxDbgTrace(+1, Dbg, ("SmbPseCreateOrdinaryExchange\n") );
|
|
|
|
if (SmbFcbHoldingState == NULL) {
|
|
SmbFcbHoldingState = &TempHoldingState;
|
|
}
|
|
|
|
IF_NOT_MRXSMB_CSC_ENABLED{
|
|
ASSERT(*SmbFcbHoldingState == SmbFcb_NotHeld);
|
|
}
|
|
|
|
OrdinaryExchange = (PSMB_PSE_ORDINARY_EXCHANGE)SmbMmAllocateExchange(ORDINARY_EXCHANGE,NULL);
|
|
|
|
//we rely on the fact that SmbMmAllocate Zeros the exchange.............
|
|
if (OrdinaryExchange == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto UNWIND;
|
|
}
|
|
|
|
StufferState = &OrdinaryExchange->AssociatedStufferState;
|
|
StufferState->NodeTypeCode = SMB_NTC_STUFFERSTATE;
|
|
StufferState->NodeByteSize = sizeof(SMBSTUFFER_BUFFER_STATE);
|
|
StufferState->Exchange = &OrdinaryExchange->Exchange;
|
|
|
|
DbgDoit(OrdinaryExchange->SerialNumber = RxContext->SerialNumber); //CODE.IMPROVEMENT should this be in the SMB_EXCHANGE?
|
|
|
|
//
|
|
// Initialize the exchange packet
|
|
//
|
|
|
|
Status = SmbCeInitializeExchange(
|
|
&StufferState->Exchange,
|
|
RxContext,
|
|
(PMRX_V_NET_ROOT)VNetRoot,
|
|
ORDINARY_EXCHANGE,
|
|
&SmbPseOEDispatch);
|
|
|
|
if (StufferState->Exchange != NULL) {
|
|
SmbCeReferenceExchange(StufferState->Exchange);
|
|
|
|
RxDbgTrace(0, Dbg, (" exchng=%08lx,type=%08lx\n",&StufferState->Exchange,StufferState->Exchange->Type));
|
|
}
|
|
|
|
StufferState->RxContext = RxContext;
|
|
|
|
//place a reference on the rxcontext until we are finished
|
|
InterlockedIncrement( &RxContext->ReferenceCount );
|
|
|
|
OrdinaryExchange->StufferStateDbgPtr = StufferState;
|
|
OrdinaryExchange->RxContext = RxContext;
|
|
OrdinaryExchange->EntryPoint = EntryPoint;
|
|
OrdinaryExchange->StartRoutine = StartRoutine;
|
|
OrdinaryExchange->SmbBufSize = MAXIMUM_SMB_BUFFER_SIZE;
|
|
|
|
DbgDoit(OrdinaryExchange->RxContextCapturedRequestPacket = RxContext->CurrentIrp;);
|
|
|
|
//note: create path must turn this flag on.
|
|
OrdinaryExchange->SmbCeFlags &= ~(SMBCE_EXCHANGE_ATTEMPT_RECONNECTS);
|
|
|
|
ASSERT( (FlagOn(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_MUST_SUCCEED_ALLOCATED_OE))
|
|
|| (OrdinaryExchange->Flags == 0) );
|
|
ASSERT( OrdinaryExchange->SendOptions == 0 );
|
|
ASSERT( OrdinaryExchange->DataPartialMdl == NULL );
|
|
|
|
pMRxSmbContext->pExchange = &OrdinaryExchange->Exchange;
|
|
pMRxSmbContext->pStufferState = StufferState;
|
|
|
|
if (capFobx != NULL) {
|
|
if (BooleanFlagOn(capFobx->Flags,FOBX_FLAG_DFS_OPEN)) {
|
|
SetFlag(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_TURNON_DFS_FLAG);
|
|
}
|
|
} else if (BooleanFlagOn(VNetRoot->pNetRoot->Flags,NETROOT_FLAG_DFS_AWARE_NETROOT) &&
|
|
(RxContext->Create.NtCreateParameters.DfsContext == UIntToPtr(DFS_OPEN_CONTEXT))) {
|
|
SetFlag(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_TURNON_DFS_FLAG);
|
|
}
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
goto UNWIND;
|
|
}
|
|
|
|
//
|
|
// Allocate the SmbBuffer
|
|
//
|
|
|
|
if (SmbBuffer == NULL) {
|
|
SmbBuffer = (PCHAR)RxAllocatePoolWithTag(
|
|
PagedPool,
|
|
OrdinaryExchange->SmbBufSize +
|
|
TRANSPORT_HEADER_SIZE,
|
|
'BMSx' );
|
|
}
|
|
|
|
if ( SmbBuffer == NULL ) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto UNWIND;
|
|
}
|
|
|
|
RxDbgTrace(0, Dbg, (" smbbuf=%08lx,stfstate=%08lx\n",SmbBuffer,StufferState));
|
|
|
|
StufferState->ActualBufferBase = SmbBuffer;
|
|
|
|
(PBYTE) SmbBuffer += TRANSPORT_HEADER_SIZE;
|
|
|
|
StufferState->BufferBase = SmbBuffer;
|
|
StufferState->BufferLimit = SmbBuffer + OrdinaryExchange->SmbBufSize;
|
|
|
|
//
|
|
// Init the HeaderMdl
|
|
//
|
|
|
|
HeaderFullMdl = StufferState->HeaderMdl = &OrdinaryExchange->HeaderMdl.Mdl;
|
|
RxInitializeHeaderMdl(HeaderFullMdl,SmbBuffer, OrdinaryExchange->SmbBufSize);
|
|
|
|
RxDbgTrace(
|
|
0,
|
|
Dbg,
|
|
(" --> smbbufsize %08lx, mdllength %08lx\n",
|
|
OrdinaryExchange->SmbBufSize,
|
|
MmGetMdlByteCount(HeaderFullMdl)));
|
|
|
|
//finally, lock down the smbbuf taking different paths according to whether
|
|
// we are must-succeed or not
|
|
|
|
ASSERT( !RxMdlIsLocked(HeaderFullMdl) );
|
|
ASSERT( HeaderFullMdl->Next == NULL );
|
|
|
|
RxDbgTrace( 0, Dbg, (" --> LOCKING %08lx\n",HeaderFullMdl));
|
|
|
|
RxProbeAndLockHeaderPages(
|
|
HeaderFullMdl,
|
|
KernelMode,
|
|
IoModifyAccess,
|
|
Status );
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
RxDbgTrace( 0, Dbg, (" --> LOCKING FAILED\n"));
|
|
goto UNWIND;
|
|
}
|
|
|
|
SetFlag(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_OE_HDR_LOCKED);
|
|
|
|
if (MmGetSystemAddressForMdlSafe(HeaderFullMdl,LowPagePriority) == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto UNWIND;
|
|
}
|
|
|
|
//
|
|
// No initialization is required for the partial...just set the pointer
|
|
|
|
StufferState->HeaderPartialMdl = &OrdinaryExchange->HeaderPartialMdl.Mdl;
|
|
|
|
RxDbgTrace( -1, Dbg, (" --> exiting w!\n") );
|
|
|
|
*OrdinaryExchangePtr = OrdinaryExchange;
|
|
return Status;
|
|
|
|
|
|
UNWIND:
|
|
RxDbgTrace( -1, Dbg, (" --> exiting w/o!\n") );
|
|
|
|
if (OrdinaryExchange != NULL ) {
|
|
SmbPseFinalizeOrdinaryExchange( OrdinaryExchange );
|
|
}
|
|
|
|
*OrdinaryExchangePtr = NULL;
|
|
return Status;
|
|
|
|
} // SmbPseCreateOrdinaryExchange
|
|
|
|
|
|
|
|
#if DBG
|
|
ULONG MRxSmbFinalizeStfStateTraceLevel = 1200;
|
|
#define FINALIZESS_LEVEL MRxSmbFinalizeStfStateTraceLevel
|
|
#define FINALIZE_TRACKING_SETUP() \
|
|
struct { \
|
|
ULONG marker1; \
|
|
ULONG finalstate; \
|
|
ULONG marker2; \
|
|
} Tracking = {'ereh',0,'ereh'};
|
|
#define FINALIZE_TRACKING(x) {\
|
|
Tracking.finalstate |= x; \
|
|
}
|
|
|
|
#define FINALIZE_TRACE(x) SmbPseFinalizeOETrace(x,Tracking.finalstate)
|
|
VOID
|
|
SmbPseFinalizeOETrace(PSZ text,ULONG finalstate)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
RxDbgTraceLV(0, Dbg, FINALIZESS_LEVEL,
|
|
("MRxSmbFinalizeSmbStufferState --> %s(%08lx)\n",text,finalstate));
|
|
}
|
|
#else
|
|
#define FINALIZE_TRACKING_SETUP()
|
|
#define FINALIZE_TRACKING(x)
|
|
#define FINALIZE_TRACE(x)
|
|
#endif
|
|
|
|
BOOLEAN
|
|
SmbPseFinalizeOrdinaryExchange (
|
|
IN OUT PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This finalizes an OE.
|
|
|
|
Arguments:
|
|
|
|
OrdinaryExchange - pointer to the OE to be dismantled.
|
|
|
|
Return Value:
|
|
|
|
TRUE if finalization occurs otherwise FALSE.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
PMRXSMB_RX_CONTEXT pMRxSmbContext;
|
|
PSMBSTUFFER_BUFFER_STATE StufferState;
|
|
LONG result;
|
|
ULONG OrdinaryExchangeFlags = OrdinaryExchange->Flags;
|
|
|
|
FINALIZE_TRACKING_SETUP()
|
|
|
|
PAGED_CODE();
|
|
|
|
SmbPseOEAssertConsistentLinkageFromOEwithFlags(
|
|
"SmbPseFinalizeOrdinaryExchange:",
|
|
OECHKLINKAGE_FLAG_NO_REQPCKT_CHECK);
|
|
|
|
StufferState = &OrdinaryExchange->AssociatedStufferState;
|
|
|
|
pMRxSmbContext = MRxSmbGetMinirdrContext(StufferState->RxContext);
|
|
|
|
RxDbgTraceLV(+1, Dbg, 1000, ("MRxSmbFinalizeSmbStufferState\n"));
|
|
|
|
result = SmbCeDereferenceExchange(&OrdinaryExchange->Exchange);
|
|
|
|
if ( result != 0 ) {
|
|
RxDbgTraceLV(
|
|
-1,
|
|
Dbg,
|
|
1000,
|
|
("MRxSmbFinalizeSmbStufferState -- returning w/o finalizing (%d)\n",
|
|
result));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#if 0
|
|
RxLog((">>>OE %lx %lx %lx %lx %lx",
|
|
OrdinaryExchange,
|
|
OrdinaryExchange->DataPartialMdl,
|
|
StufferState->HeaderPartialMdl,
|
|
StufferState->HeaderMdl,
|
|
OrdinaryExchange->Flags
|
|
));
|
|
#endif
|
|
|
|
FINALIZE_TRACKING( 0x10000000 );
|
|
FINALIZE_TRACE("ready to freedatapartial");
|
|
|
|
if (OrdinaryExchange->CopyDataPendingOperations != 0 ||
|
|
OrdinaryExchange->SendCompletePendingOperations != 0) {
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
SmbPseVerifyDataPartialAllocationPerFlags(OrdinaryExchange);
|
|
|
|
if ( OrdinaryExchange->DataPartialMdl ) {
|
|
if (!FlagOn(OrdinaryExchangeFlags, SMBPSE_OE_FLAG_MUST_SUCCEED_ALLOCATED_SMBBUF)) {
|
|
IoFreeMdl( OrdinaryExchange->DataPartialMdl );
|
|
FINALIZE_TRACKING( 0x8000000 );
|
|
}
|
|
}
|
|
|
|
if (FlagOn(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_OE_HDR_LOCKED)) {
|
|
RxUnlockHeaderPages(StufferState->HeaderMdl);
|
|
ClearFlag(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_OE_HDR_LOCKED);
|
|
MmPrepareMdlForReuse( StufferState->HeaderMdl );
|
|
FINALIZE_TRACKING( 0x4000000 );
|
|
}
|
|
|
|
FINALIZE_TRACE("ready to uninit hdr partial");
|
|
|
|
if (FlagOn(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_OE_HDR_PARTIAL_INITIALIZED)) {
|
|
MmPrepareMdlForReuse( StufferState->HeaderPartialMdl ); //no harm in calling this multiple times
|
|
FINALIZE_TRACKING( 0x300000 );
|
|
} else {
|
|
FINALIZE_TRACKING( 0xf00000 );
|
|
}
|
|
|
|
if (!FlagOn(OrdinaryExchangeFlags, SMBPSE_OE_FLAG_MUST_SUCCEED_ALLOCATED_SMBBUF)) {
|
|
FINALIZE_TRACE("ready to freepool actualbuffer");
|
|
if ( StufferState->ActualBufferBase != NULL ) {
|
|
|
|
RxFreePool( StufferState->ActualBufferBase );
|
|
|
|
FINALIZE_TRACKING( 0x5000 );
|
|
} else {
|
|
FINALIZE_TRACKING( 0xf000 );
|
|
}
|
|
}
|
|
|
|
if ( StufferState->RxContext != NULL ) {
|
|
//get rid of the reference on the RxContext....if i'm the last guy this will finalize
|
|
RxDereferenceAndDeleteRxContext( StufferState->RxContext );//CODE.IMPROVEMENT Capture rxcontext earlier
|
|
FINALIZE_TRACKING( 0x600 );
|
|
} else {
|
|
FINALIZE_TRACKING( 0xf00 );
|
|
}
|
|
|
|
FINALIZE_TRACE("ready to discard exchange");
|
|
SmbCeDiscardExchange(OrdinaryExchange);
|
|
FINALIZE_TRACKING( 0x2000000 );
|
|
|
|
FINALIZE_TRACKING( 0x8 );
|
|
RxDbgTraceLV(-1, Dbg, 1000, ("MRxSmbFinalizeSmbStufferState --> exit finalstate=%x\n",Tracking.finalstate));
|
|
return(TRUE);
|
|
|
|
} // MRxSmbFinalizeSmbStufferState
|
|
|
|
NTSTATUS
|
|
SmbPseExchangeFinalize_default(
|
|
IN OUT PSMB_EXCHANGE pExchange,
|
|
OUT BOOLEAN *pPostFinalize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
pExchange - the exchange instance
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
|
|
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange =
|
|
(PSMB_PSE_ORDINARY_EXCHANGE)pExchange;
|
|
PRX_CONTEXT RxContext = OrdinaryExchange->RxContext;
|
|
|
|
UPDATE_OE_HISTORY_WITH_STATUS('ff');
|
|
SmbPseOEAssertConsistentLinkageFromOE("SmbPseExchangeFinalize_default: ");
|
|
|
|
if (OrdinaryExchange->SmbStatus != STATUS_SUCCESS) {
|
|
OrdinaryExchange->Status = OrdinaryExchange->SmbStatus;
|
|
}
|
|
|
|
if (OrdinaryExchange->AsyncResumptionRoutine != NULL) {
|
|
NTSTATUS PostStatus;
|
|
RxDbgTraceLV(0, Dbg, 1000, ("Resume with post-to-async\n"));
|
|
SetFlag(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_OE_AWAITING_DISPATCH);
|
|
|
|
IF_DEBUG {
|
|
//fill the workqueue structure with deadbeef....all the better to diagnose
|
|
//a failed post
|
|
ULONG i;
|
|
for (i=0;i+sizeof(ULONG)-1<sizeof(OrdinaryExchange->WorkQueueItem);i+=sizeof(ULONG)) {
|
|
//*((PULONG)(((PBYTE)&OrdinaryExchange->WorkQueueItem)+i)) = 0xdeadbeef;
|
|
PBYTE BytePtr = ((PBYTE)&OrdinaryExchange->WorkQueueItem)+i;
|
|
PULONG UlongPtr = (PULONG)BytePtr;
|
|
*UlongPtr = 0xdeadbeef;
|
|
}
|
|
}
|
|
|
|
PostStatus = RxPostToWorkerThread(
|
|
MRxSmbDeviceObject,
|
|
CriticalWorkQueue,
|
|
&OrdinaryExchange->WorkQueueItem,
|
|
SmbPseContinueOrdinaryExchange,
|
|
OrdinaryExchange);
|
|
|
|
ASSERT(PostStatus == STATUS_SUCCESS);
|
|
} else {
|
|
RxDbgTraceLV(0, Dbg, 1000, ("sync resume\n"));
|
|
KeSetEvent(OrdinaryExchange->pSmbCeSynchronizationEvent, 0, FALSE);
|
|
}
|
|
|
|
*pPostFinalize = FALSE;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbPseExchangeSendCallbackHandler_default(
|
|
IN PSMB_EXCHANGE pExchange,
|
|
IN PMDL pXmitBuffer,
|
|
IN NTSTATUS SendCompletionStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the send call back indication handling routine for ordinary
|
|
exchanges.
|
|
|
|
Arguments:
|
|
|
|
pExchange - the exchange instance
|
|
pXmitBuffer - pointer to the transmit buffer MDL
|
|
BytesSent - number of bytes transmitted
|
|
SendCompletionStatus - status for the send
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange =
|
|
(PSMB_PSE_ORDINARY_EXCHANGE)pExchange;
|
|
|
|
SmbPseOEAssertConsistentLinkageFromOE("SmbPseExchangeSendCallbackHandler_default: ");
|
|
UPDATE_OE_HISTORY_WITH_STATUS('cs');
|
|
|
|
OrdinaryExchange->SendCompletionStatus = SendCompletionStatus;
|
|
|
|
if (!NT_SUCCESS(SendCompletionStatus)) {
|
|
//sometimes we use exchange-status, sometimes exchange->smbstatus
|
|
//set them both
|
|
pExchange->Status = SendCompletionStatus;
|
|
pExchange->SmbStatus = SendCompletionStatus;
|
|
}
|
|
|
|
SmbPseDbgRunMdlChain(
|
|
OrdinaryExchange->AssociatedStufferState.HeaderPartialMdl,
|
|
OrdinaryExchange->SaveLengthForDebug,
|
|
OrdinaryExchange,
|
|
"SmbPseExchangeSendCallbackHandler_default");
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // SmbPseExchangeSendCallbackHandler_default
|
|
|
|
NTSTATUS
|
|
SmbPseExchangeStart_default(
|
|
IN PSMB_EXCHANGE pExchange
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the start routine for ordinary exchanges. irght now this is just a simple wrapper.
|
|
|
|
Arguments:
|
|
|
|
pExchange - the exchange instance NOT an Ordinary Exchange
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange =
|
|
(PSMB_PSE_ORDINARY_EXCHANGE)pExchange;
|
|
|
|
PAGED_CODE();
|
|
|
|
return OrdinaryExchange->StartRoutine(
|
|
(PSMB_PSE_ORDINARY_EXCHANGE)pExchange,
|
|
pExchange->RxContext);
|
|
|
|
} // SmbPseExchangeStart_default
|
|
|
|
|
|
NTSTATUS
|
|
SmbPseExchangeCopyDataHandler_default(
|
|
IN PSMB_EXCHANGE pExchange,
|
|
IN PMDL pCopyDataBuffer,
|
|
IN ULONG CopyDataSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the copy data handling routine for ordinary exchanges.
|
|
|
|
Arguments:
|
|
|
|
pExchange - the exchange instance
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange =
|
|
(PSMB_PSE_ORDINARY_EXCHANGE)pExchange;
|
|
|
|
SmbPseOEAssertConsistentLinkageFromOE("SmbPseExchangeCopyDataHandler_default: ");
|
|
UPDATE_OE_HISTORY_WITH_STATUS('dd');
|
|
|
|
OrdinaryExchange->MessageLength = CopyDataSize;
|
|
pExchange->Status = STATUS_MORE_PROCESSING_REQUIRED;
|
|
|
|
return STATUS_SUCCESS;
|
|
} // SmbPseExchangeCopyDataHandler_default
|
|
|
|
NTSTATUS
|
|
SmbPseExchangeReceive_default(
|
|
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 receive indication handling routine for ordinary 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 - pointer to the data buffer
|
|
|
|
pDataBufferPointer - pointer to the buffer Mdl into which the remaining
|
|
data is to be copied.
|
|
|
|
pDataSize - the buffer size.
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
|
|
This routine is called at DPC level directly from the tdi receive event
|
|
handler. BUT, it is also called at task time from SmbPseContinueOrdinaryExchange.
|
|
Often, we cannot complete processing from DPClevel because fileobjects, fcbs,
|
|
srvopens, and fobx are pageable and not locked.
|
|
|
|
--*/
|
|
{
|
|
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange =
|
|
(PSMB_PSE_ORDINARY_EXCHANGE)pExchange;
|
|
PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
|
|
PRX_CONTEXT RxContext = OrdinaryExchange->RxContext;
|
|
|
|
NTSTATUS SmbStatus;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PGENERIC_ANDX CommandState;
|
|
UCHAR Command;
|
|
ULONG CopyBufferLength;
|
|
BOOLEAN ThisIsAReenter = BooleanFlagOn(OrdinaryExchange->Flags,
|
|
SMBPSE_OE_FLAG_HEADER_ALREADY_PARSED);
|
|
PLOWIO_CONTEXT LowIoContext;
|
|
ULONG ByteCount;
|
|
ULONG Remain;
|
|
PSMB_PSE_OE_READWRITE rw = &OrdinaryExchange->ReadWrite;
|
|
PCHAR startVa;
|
|
|
|
SmbPseOEAssertConsistentLinkage("SmbPseExchangeReceive_default: ");
|
|
UPDATE_OE_HISTORY_WITH_STATUS(ThisIsAReenter?'00':'01');
|
|
|
|
RxDbgTrace (0, Dbg, ("SmbPseExchangeReceive_default av/ind=%08lx/%08lx\n",
|
|
BytesAvailable,BytesIndicated)
|
|
);
|
|
RxDbgTrace (0, Dbg, (" -->headermdl %08lx\n",StufferState->HeaderMdl));
|
|
ASSERT_ORDINARY_EXCHANGE( OrdinaryExchange );
|
|
|
|
CommandState = &OrdinaryExchange->ParseResumeState;
|
|
|
|
if ( !ThisIsAReenter ) {
|
|
|
|
OrdinaryExchange->BytesIndicatedCopy = BytesIndicated;
|
|
OrdinaryExchange->BytesAvailableCopy = BytesAvailable;
|
|
|
|
pExchange->Status = SmbCeParseSmbHeader(
|
|
pExchange,
|
|
pSmbHeader,
|
|
CommandState,
|
|
&OrdinaryExchange->SmbStatus,
|
|
BytesAvailable,
|
|
BytesIndicated,
|
|
pBytesTaken);
|
|
|
|
UPDATE_OE_HISTORY_WITH_STATUS('22');
|
|
|
|
if ( pExchange->Status == STATUS_MORE_PROCESSING_REQUIRED) {
|
|
goto COPY_FOR_RESUME;
|
|
}
|
|
|
|
if ( (pExchange->Status != STATUS_SUCCESS) ||
|
|
((Command = OrdinaryExchange->ParseResumeState.AndXCommand) == SMB_COM_NO_ANDX_COMMAND) ) {
|
|
goto FINALLY;
|
|
}
|
|
|
|
if (Command == SMB_COM_WRITE_ANDX) {
|
|
if (!FlagOn(pSmbHeader->Flags2,SMB_FLAGS2_COMPRESSED)) {
|
|
if (OrdinaryExchange->ReadWrite.CompressedRequestInProgress) {
|
|
OrdinaryExchange->ReadWrite.CompressedReadOrWrite = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
SetFlag(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_HEADER_ALREADY_PARSED);
|
|
} else {
|
|
|
|
OrdinaryExchange->Status = OrdinaryExchange->SmbStatus;
|
|
|
|
RxDbgTrace (0, Dbg, (" -->this is a reenter\n"));
|
|
|
|
Command = CommandState->AndXCommand;
|
|
}
|
|
|
|
SmbStatus = OrdinaryExchange->SmbStatus;
|
|
|
|
if ( (SmbStatus!=RX_MAP_STATUS(SUCCESS)) ) {
|
|
RxDbgTrace (0, Dbg, (" STATUS NOT SUCCESS = %08lx\n", SmbStatus));
|
|
}
|
|
|
|
for ( ; Command != SMB_COM_NO_ANDX_COMMAND ; ) {
|
|
PSMBPSE_RECEIVE_MODEL_PARAMETERS ReceiveModelParams = &SmbPseReceiveModelParameters[Command];
|
|
ULONG ReceiveModelParamsFlags;
|
|
UCHAR mappedCommand = Command;
|
|
PCHAR Response = (PCHAR)pSmbHeader + SmbGetUshort(&CommandState->AndXOffset);
|
|
|
|
if( Response > (PCHAR)pSmbHeader + BytesAvailable )
|
|
{
|
|
// Invalid Command
|
|
*pBytesTaken = BytesAvailable;
|
|
*pDataBufferPointer = NULL;
|
|
*pDataSize = 0;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
pExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
|
|
goto FINALLY;
|
|
}
|
|
|
|
OrdinaryExchange->LastSmbCommand = Command; //this is used to multiplex in finish routines
|
|
UPDATE_OE_HISTORY_WITH_STATUS('88');
|
|
|
|
//
|
|
// Case on the Smb Command Type
|
|
//
|
|
|
|
ReceiveModelParamsFlags = ReceiveModelParams->Flags;
|
|
if (ReceiveModelParamsFlags!=0) {
|
|
|
|
//map this onto read_andx....which is the arm of the switch that implements the model
|
|
mappedCommand = SMB_COM_READ_ANDX;
|
|
|
|
} else {
|
|
|
|
//
|
|
// If there's a continuation, then copy&post. it used to always do this.
|
|
// now, we're going to do it unless the command is modeled.
|
|
// the modeling code will take care of correctly deciding to post/nopost.
|
|
//
|
|
|
|
if ( (OrdinaryExchange->AsyncResumptionRoutine != NULL) &&
|
|
!ThisIsAReenter) {
|
|
goto COPY_FOR_RESUME;
|
|
}
|
|
|
|
}
|
|
|
|
switch (mappedCommand) {
|
|
case SMB_COM_READ_ANDX:
|
|
{
|
|
NTSTATUS FinishStatus = RX_MAP_STATUS(SUCCESS);
|
|
NTSTATUS FinalStatus = RX_MAP_STATUS(SUCCESS);
|
|
BOOLEAN ThisIsAnAndX = BooleanFlagOn(ReceiveModelParamsFlags,SMBPSE_RMP_THIS_IS_ANDX);
|
|
BOOLEAN ThisWouldBeMyError = (IM_THE_LAST_GUY || !ThisIsAnAndX);
|
|
|
|
RxDbgTrace( 0, Dbg, (" *(ind) %s, smbstatus=%08lx\n",ReceiveModelParams->IndicationString,SmbStatus) );
|
|
|
|
IF_DEBUG {
|
|
BOOLEAN BadType = FALSE;
|
|
DbgDoit(BadType = (OrdinaryExchange->OEType < ReceiveModelParams->LowType)
|
|
|| (OrdinaryExchange->OEType > ReceiveModelParams->HighType) );
|
|
if (BadType) {
|
|
DbgPrint("Bad OEType....%u,Cmd=%02lx,Exch=%08lx\n",OrdinaryExchange->OEType,Command,OrdinaryExchange);
|
|
ASSERT(!"proceed???");
|
|
}
|
|
}
|
|
|
|
// If this is an error and it's an error for this guy of the AndX
|
|
// chain then finishup If it's a warning tho, continue according
|
|
// to the Flags
|
|
|
|
if ( NT_ERROR(SmbStatus) && ThisWouldBeMyError ) {
|
|
|
|
SmbPseDiscardProtocol( SmbStatus );
|
|
RxDbgTrace( 0, Dbg, ("--->discard1\n"));
|
|
goto FINALLY;
|
|
|
|
} else if ( (SmbStatus != RX_MAP_STATUS(SUCCESS)) && ThisWouldBeMyError ) {
|
|
|
|
if (!FlagOn(ReceiveModelParamsFlags,SMBPSE_RMP_WARNINGS_OK)) {
|
|
SmbPseDiscardProtocol(SmbStatus);
|
|
RxDbgTrace( 0, Dbg, ("--->discard1\n"));
|
|
goto FINALLY;
|
|
} else {
|
|
FinalStatus = SmbStatus;
|
|
}
|
|
|
|
}
|
|
|
|
// if there's no nocopy handler then do things the old way
|
|
|
|
if (!FlagOn(ReceiveModelParamsFlags,SMBPSE_RMP_NOCOPY_HANDLER)) {
|
|
// TEMPORARY!!!!!!
|
|
// If there's a continuation, then copy&post. it used to always do this. now, we're
|
|
// going to do it unless the command is modeled. the modeling code will take care of
|
|
// correctly deciding to post/nopost.
|
|
//
|
|
|
|
if ((OrdinaryExchange->AsyncResumptionRoutine != NULL) &&
|
|
!ThisIsAReenter ) {
|
|
goto COPY_FOR_RESUME;
|
|
}
|
|
|
|
|
|
//eventually, we'll finish from here but for now copy
|
|
//CODE.IMPROVEMENT.ASHAMED....this is really mandatory.......
|
|
if (RxShouldPostCompletion()) {
|
|
goto COPY_FOR_RESUME;
|
|
}
|
|
|
|
if (ReceiveModelParams->ReceiveHandlerToken < SMBPSE_RECEIVE_HANDLER_TOKEN_MAXIMUM){
|
|
PSMBPSE_RECEIVE_HANDLER ReceiveHandler = SmbPseReceiveHandlers[ReceiveModelParams->ReceiveHandlerToken];
|
|
FinishStatus = ReceiveHandler( OrdinaryExchange, Response);
|
|
}
|
|
} else {
|
|
PSMBPSE_NOCOPY_RECEIVE_HANDLER NoCopyReceiveHandler =
|
|
(PSMBPSE_NOCOPY_RECEIVE_HANDLER)(SmbPseReceiveHandlers[ReceiveModelParams->ReceiveHandlerToken]);
|
|
UCHAR Action;
|
|
|
|
OrdinaryExchange->NoCopyFinalStatus = FinalStatus;
|
|
Action = NoCopyReceiveHandler(
|
|
OrdinaryExchange,
|
|
BytesIndicated,
|
|
BytesAvailable,
|
|
pBytesTaken,
|
|
pSmbHeader,
|
|
pDataBufferPointer,
|
|
pDataSize,
|
|
#if DBG
|
|
ThisIsAReenter,
|
|
#endif
|
|
Response );
|
|
|
|
switch(Action) {
|
|
case SMBPSE_NOCOPYACTION_NORMALFINISH:
|
|
NOTHING;
|
|
break;
|
|
|
|
case SMBPSE_NOCOPYACTION_MDLFINISH:
|
|
Status = STATUS_MORE_PROCESSING_REQUIRED;
|
|
//note that whatever does this must be the last command in the
|
|
// packet unless we make continueOE more complicated
|
|
goto FINALLY;
|
|
|
|
case SMBPSE_NOCOPYACTION_COPY_FOR_RESUME:
|
|
goto COPY_FOR_RESUME;
|
|
|
|
case SMBPSE_NOCOPYACTION_DISCARD:
|
|
*pBytesTaken = BytesAvailable;
|
|
RxDbgTrace( 0, Dbg, ("--->discardX\n"));
|
|
goto FINALLY;
|
|
}
|
|
}
|
|
|
|
pExchange->Status = (FinishStatus==RX_MAP_STATUS(SUCCESS))
|
|
? FinalStatus : FinishStatus;
|
|
|
|
if (!ThisIsAnAndX) {
|
|
Response = (PCHAR)&NullGenericAndX;
|
|
}
|
|
|
|
}//this corresponds to the top level of the switch
|
|
break;
|
|
|
|
default:
|
|
{
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
|
|
|
|
RxDbgTrace( 0, Dbg, (" *(ind) Unimplemented cmd=%02lx,wct=%02lx\n",
|
|
Command,*Response) );
|
|
|
|
|
|
SmbCeTransportDisconnectIndicated(pServerEntry);
|
|
*pBytesTaken = BytesAvailable;
|
|
*pDataBufferPointer = NULL;
|
|
*pDataSize = 0;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
pExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
|
|
goto FINALLY;
|
|
}
|
|
}
|
|
|
|
CommandState = (PGENERIC_ANDX)Response;
|
|
Command = CommandState->AndXCommand;
|
|
}
|
|
|
|
//
|
|
// If we get here then we're done.
|
|
// Make everyone happy by taking all the bytes.
|
|
//
|
|
//CODE.IMPROVEMENT: it is not clear to me that this is enough. some servers may send extra bytes
|
|
// on the end.
|
|
//
|
|
|
|
*pBytesTaken = BytesAvailable;
|
|
goto FINALLY;
|
|
|
|
|
|
COPY_FOR_RESUME:
|
|
//CODE.IMPROVEMENT even if we are taking by copy (as opposed to tail-MDL
|
|
// which is how reads should work) we shouldn't copy the whole packet -
|
|
// just the residue. of course, this is really only an issue when we have
|
|
// significant andXing.
|
|
|
|
CopyBufferLength = MmGetMdlByteCount(StufferState->HeaderMdl);
|
|
|
|
ASSERT( BytesAvailable <= CopyBufferLength );
|
|
|
|
if (!FlagOn(ReceiveFlags,TDI_RECEIVE_ENTIRE_MESSAGE) ||
|
|
(BytesAvailable > BytesIndicated) ||
|
|
(BytesAvailable > 127)) {
|
|
|
|
RxDbgTrace( 0, Dbg, ("Taking data through MDL\n") );
|
|
// Pass an MDL back in for copying the data
|
|
*pDataBufferPointer = StufferState->HeaderMdl;
|
|
*pDataSize = CopyBufferLength;
|
|
*pBytesTaken = 0;
|
|
Status = STATUS_MORE_PROCESSING_REQUIRED;
|
|
|
|
} else {
|
|
|
|
// Copy the data and resume the exchange
|
|
ASSERT( BytesAvailable == BytesIndicated );
|
|
RxDbgTrace( 0, Dbg, ("Taking data through copying\n") );
|
|
*pBytesTaken = OrdinaryExchange->MessageLength = BytesAvailable;
|
|
|
|
RtlCopyMemory(StufferState->BufferBase,
|
|
pSmbHeader,BytesIndicated);
|
|
|
|
ASSERT(SmbGetUlong((PULONG)pSmbHeader->Protocol) == (ULONG)SMB_HEADER_PROTOCOL);
|
|
|
|
pExchange->Status = RX_MAP_STATUS(MORE_PROCESSING_REQUIRED);
|
|
}
|
|
|
|
if (ThisIsAReenter) {
|
|
pExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
|
|
}
|
|
|
|
FINALLY:
|
|
OrdinaryExchange->ParseResumeState = *CommandState;
|
|
UPDATE_OE_HISTORY_WITH_STATUS('99');
|
|
return Status;
|
|
|
|
} // SmbPseExchangeReceive_default
|
|
|
|
|
|
#define SmbPseRIStringsBufferSize 500
|
|
CHAR SmbPseReceiveIndicationStringsBuffer[SmbPseRIStringsBufferSize];
|
|
ULONG SmbPseRIStringsBufferUsed = 0;
|
|
|
|
VOID
|
|
__SmbPseRMTableEntry(
|
|
UCHAR SmbCommand,
|
|
UCHAR Flags,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN ReceiveHandlerToken,
|
|
PSMBPSE_RECEIVE_HANDLER ReceiveHandler
|
|
#if DBG
|
|
,
|
|
PBYTE IndicationString,
|
|
SMB_PSE_ORDINARY_EXCHANGE_TYPE LowType,
|
|
SMB_PSE_ORDINARY_EXCHANGE_TYPE HighType
|
|
#endif
|
|
)
|
|
{
|
|
PSMBPSE_RECEIVE_MODEL_PARAMETERS r = &SmbPseReceiveModelParameters[SmbCommand];
|
|
#if DBG
|
|
ULONG ISlength = strlen(IndicationString)+1;
|
|
#endif
|
|
|
|
PAGED_CODE();
|
|
|
|
r->Flags = SMBPSE_RMP_MODELED | Flags;
|
|
r->ReceiveHandlerToken = (UCHAR)ReceiveHandlerToken;
|
|
if (ReceiveHandlerToken < SMBPSE_RECEIVE_HANDLER_TOKEN_MAXIMUM){
|
|
ASSERT((SmbPseReceiveHandlers[ReceiveHandlerToken] == ReceiveHandler)
|
|
|| (SmbPseReceiveHandlers[ReceiveHandlerToken] == NULL));
|
|
SmbPseReceiveHandlers[ReceiveHandlerToken] = ReceiveHandler;
|
|
}
|
|
|
|
#if DBG
|
|
r->ReceiveHandler = ReceiveHandler;
|
|
r->LowType = LowType;
|
|
r->HighType = HighType;
|
|
if (SmbPseRIStringsBufferUsed+ISlength<=SmbPseRIStringsBufferSize) {
|
|
r->IndicationString = &SmbPseReceiveIndicationStringsBuffer[SmbPseRIStringsBufferUsed];
|
|
RtlCopyMemory(r->IndicationString,IndicationString,ISlength);
|
|
} else {
|
|
if (SmbPseRIStringsBufferUsed<SmbPseRIStringsBufferSize) {
|
|
DbgPrint("Overflowing the indicationstringarray...%s\n",IndicationString);
|
|
ASSERT(!"fix it please");
|
|
}
|
|
r->IndicationString = &SmbPseReceiveIndicationStringsBuffer[SmbPseRIStringsBufferUsed];
|
|
}
|
|
SmbPseRIStringsBufferUsed += ISlength;
|
|
#endif
|
|
}
|
|
#if DBG
|
|
#define SmbPseRMTableEntry(__smbcommand,b,c,token,__rcv,flags) \
|
|
__SmbPseRMTableEntry(SMB_COM_##__smbcommand,flags,token,__rcv \
|
|
,#__smbcommand,b,c)
|
|
#else
|
|
#define SmbPseRMTableEntry(__smbcommand,b,c,token,__rcv,flags) \
|
|
__SmbPseRMTableEntry(SMB_COM_##__smbcommand,flags,token,__rcv \
|
|
)
|
|
#endif
|
|
|
|
|
|
VOID
|
|
SmbPseInitializeTables(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes tables that are used at various points by the
|
|
smbpse mechanisms. The must succeed structure(s) is(are) also initialized.
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
|
|
PAGED_CODE();
|
|
|
|
for (i=0;i<256;i++) {
|
|
SmbPseReceiveModelParameters[i].Flags = 0;
|
|
SmbPseReceiveModelParameters[i].ReceiveHandlerToken =
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_MAXIMUM;
|
|
}
|
|
|
|
for (i=0;i<SMBPSE_RECEIVE_HANDLER_TOKEN_MAXIMUM;i++) {
|
|
SmbPseReceiveHandlers[i] = NULL;
|
|
}
|
|
|
|
SmbPseRMTableEntry(
|
|
READ_ANDX,
|
|
SMBPSE_OETYPE_READ,
|
|
SMBPSE_OETYPE_READ,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_READ_ANDX_HANDLER,
|
|
MRxSmbReceiveHandler_Read_NoCopy,
|
|
SMBPSE_RMP_THIS_IS_ANDX|SMBPSE_RMP_WARNINGS_OK|SMBPSE_RMP_NOCOPY_HANDLER);
|
|
|
|
SmbPseRMTableEntry(
|
|
READ,
|
|
SMBPSE_OETYPE_READ,
|
|
SMBPSE_OETYPE_READ,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_READ_ANDX_HANDLER,
|
|
MRxSmbReceiveHandler_Read_NoCopy,
|
|
SMBPSE_RMP_WARNINGS_OK|SMBPSE_RMP_NOCOPY_HANDLER);
|
|
|
|
SmbPseRMTableEntry(
|
|
WRITE_ANDX,
|
|
SMBPSE_OETYPE_WRITE,
|
|
SMBPSE_OETYPE_EXTEND_WRITE,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_WRITE_ANDX_HANDLER,
|
|
MRxSmbReceiveHandler_WriteAndX,
|
|
SMBPSE_RMP_THIS_IS_ANDX);
|
|
|
|
SmbPseRMTableEntry(
|
|
WRITE,
|
|
SMBPSE_OETYPE_WRITE,
|
|
SMBPSE_OETYPE_CORETRUNCATE,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_WRITE_HANDLER,
|
|
MRxSmbReceiveHandler_CoreWrite,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
WRITE_PRINT_FILE,
|
|
SMBPSE_OETYPE_WRITE,
|
|
SMBPSE_OETYPE_WRITE,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_WRITE_PRINTFILE_HANDLER,
|
|
MRxSmbReceiveHandler_WritePrintFile,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
LOCKING_ANDX,
|
|
SMBPSE_OETYPE_LOCKS,
|
|
SMBPSE_OETYPE_ASSERTBUFFEREDLOCKS,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_LOCKING_ANDX_HANDLER,
|
|
MRxSmbReceiveHandler_LockingAndX,
|
|
SMBPSE_RMP_THIS_IS_ANDX);
|
|
|
|
SmbPseRMTableEntry(
|
|
UNLOCK_BYTE_RANGE,
|
|
SMBPSE_OETYPE_LOCKS,
|
|
SMBPSE_OETYPE_LOCKS,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_MAXIMUM+1,
|
|
NULL,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
LOCK_BYTE_RANGE,
|
|
SMBPSE_OETYPE_LOCKS,
|
|
SMBPSE_OETYPE_LOCKS,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_MAXIMUM+1,
|
|
NULL,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
OPEN_PRINT_FILE,
|
|
SMBPSE_OETYPE_CREATEPRINTFILE,
|
|
SMBPSE_OETYPE_CREATEPRINTFILE,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_OPEN_PRINTFILE_HANDLER,
|
|
MRxSmbReceiveHandler_OpenPrintFile,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
QUERY_INFORMATION2,
|
|
SMBPSE_OETYPE_GFA,
|
|
SMBPSE_OETYPE_GFA,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_GFA_HANDLER,
|
|
MRxSmbReceiveHandler_GetFileAttributes,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
CLOSE_PRINT_FILE,
|
|
SMBPSE_OETYPE_CLOSE,
|
|
SMBPSE_OETYPE_CLOSE,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_CLOSE_HANDLER,
|
|
MRxSmbReceiveHandler_Close,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
NT_CREATE_ANDX,
|
|
SMBPSE_OETYPE_LATENT_HEADEROPS,
|
|
SMBPSE_OETYPE_CREATE,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_NTCREATE_ANDX_HANDLER,
|
|
MRxSmbReceiveHandler_NTCreateAndX,
|
|
SMBPSE_RMP_THIS_IS_ANDX);
|
|
|
|
SmbPseRMTableEntry(
|
|
OPEN_ANDX,
|
|
SMBPSE_OETYPE_LATENT_HEADEROPS,
|
|
SMBPSE_OETYPE_CREATE,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_OPEN_ANDX_HANDLER,
|
|
MRxSmbReceiveHandler_OpenAndX,
|
|
SMBPSE_RMP_THIS_IS_ANDX);
|
|
|
|
SmbPseRMTableEntry(
|
|
OPEN,
|
|
SMBPSE_OETYPE_COREOPEN,
|
|
SMBPSE_OETYPE_COREOPEN,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_OPEN_HANDLER,
|
|
MRxSmbReceiveHandler_CoreOpen,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
CREATE,
|
|
SMBPSE_OETYPE_CORECREATE,
|
|
SMBPSE_OETYPE_CORECREATE,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_CREATE_HANDLER,
|
|
MRxSmbReceiveHandler_CoreCreate,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
CREATE_NEW,
|
|
SMBPSE_OETYPE_CORECREATE,
|
|
SMBPSE_OETYPE_CORECREATE,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_CREATE_HANDLER,
|
|
MRxSmbReceiveHandler_CoreCreate,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
CLOSE,
|
|
SMBPSE_OETYPE_CLOSE,
|
|
SMBPSE_OETYPE_CLOSEAFTERCORECREATE,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_CLOSE_HANDLER,
|
|
MRxSmbReceiveHandler_Close,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
QUERY_INFORMATION,
|
|
0,
|
|
SMBPSE_OETYPE_MAXIMUM,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_GFA_HANDLER,
|
|
MRxSmbReceiveHandler_GetFileAttributes,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
TRANSACTION2,
|
|
SMBPSE_OETYPE_T2_FOR_NT_FILE_ALLOCATION_INFO,
|
|
SMBPSE_OETYPE_T2_FOR_LANMAN_VOLUMELABEL_INFO,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_TRANS2_ANDX_HANDLER,
|
|
MRxSmbReceiveHandler_Transact2,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
TRANSACTION2_SECONDARY,
|
|
SMBPSE_OETYPE_T2_FOR_NT_FILE_ALLOCATION_INFO,
|
|
SMBPSE_OETYPE_T2_FOR_LANMAN_VOLUMELABEL_INFO,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_TRANS2_ANDX_HANDLER,
|
|
MRxSmbReceiveHandler_Transact2,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
SEARCH,
|
|
SMBPSE_OETYPE_COREQUERYLABEL,
|
|
SMBPSE_OETYPE_CORESEARCHFORCHECKEMPTY,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_SEARCH_HANDLER,
|
|
MRxSmbReceiveHandler_Search,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
QUERY_INFORMATION_DISK,
|
|
SMBPSE_OETYPE_COREQUERYDISKATTRIBUTES,
|
|
SMBPSE_OETYPE_COREQUERYDISKATTRIBUTES,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_QUERYDISKINFO_HANDLER,
|
|
MRxSmbReceiveHandler_QueryDiskInfo,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
DELETE,
|
|
SMBPSE_OETYPE_DELETEFORSUPERSEDEORCLOSE,
|
|
SMBPSE_OETYPE_DELETE_FOR_RENAME,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_MAXIMUM+1,
|
|
NULL,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
DELETE_DIRECTORY,
|
|
SMBPSE_OETYPE_DELETEFORSUPERSEDEORCLOSE,
|
|
SMBPSE_OETYPE_DELETEFORSUPERSEDEORCLOSE,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_MAXIMUM+1,
|
|
NULL,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
CHECK_DIRECTORY,
|
|
SMBPSE_OETYPE_CORECHECKDIRECTORY,
|
|
SMBPSE_OETYPE_CORECHECKDIRECTORY,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_MAXIMUM+1,
|
|
NULL,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
SET_INFORMATION,
|
|
SMBPSE_OETYPE_SFA,
|
|
SMBPSE_OETYPE_SFA,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_MAXIMUM+1,
|
|
NULL,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
SET_INFORMATION2,
|
|
SMBPSE_OETYPE_SFA2,
|
|
SMBPSE_OETYPE_SFA2,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_MAXIMUM+1,
|
|
NULL,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
CREATE_DIRECTORY,
|
|
SMBPSE_OETYPE_CORECREATEDIRECTORY,
|
|
SMBPSE_OETYPE_CORECREATEDIRECTORY,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_MAXIMUM+1,
|
|
NULL,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
FLUSH,
|
|
SMBPSE_OETYPE_FLUSH,
|
|
SMBPSE_OETYPE_FLUSH,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_MAXIMUM+1,
|
|
NULL,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
FIND_CLOSE2,
|
|
SMBPSE_OETYPE_FINDCLOSE,
|
|
SMBPSE_OETYPE_FINDCLOSE,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_MAXIMUM+1,
|
|
NULL,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
RENAME,
|
|
SMBPSE_OETYPE_RENAME,
|
|
SMBPSE_OETYPE_RENAME,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_MAXIMUM+1,
|
|
NULL,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
NT_RENAME,
|
|
SMBPSE_OETYPE_RENAME,
|
|
SMBPSE_OETYPE_RENAME,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_MAXIMUM+1,
|
|
NULL,
|
|
0);
|
|
|
|
SmbPseRMTableEntry(
|
|
IOCTL,
|
|
SMBPSE_OETYPE_IOCTL,
|
|
SMBPSE_OETYPE_IOCTL,
|
|
SMBPSE_RECEIVE_HANDLER_TOKEN_IOCTL_HANDLER,
|
|
MRxSmbReceiveHandler_Ioctl,
|
|
0);
|
|
}
|
|
|
|
|
|
#ifdef WIN9X
|
|
|
|
NTSTATUS
|
|
MRxSmbQueryDosVolumeInformation(
|
|
IN OUT PRX_CONTEXT RxContext,
|
|
IN OUT PVOID pBuffer,
|
|
IN OUT PULONG pBufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine queries the volume information
|
|
|
|
Arguments:
|
|
|
|
pRxContext - the RDBSS context
|
|
|
|
FsInformationClass - the kind of Fs information desired.
|
|
|
|
pBuffer - the buffer for copying the information
|
|
|
|
pBufferLength - the buffer length ( set to buffer length on input and set
|
|
to the remaining length on output)
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
|
|
PAGED_CODE();
|
|
|
|
TURN_BACK_ASYNCHRONOUS_OPERATIONS();
|
|
return MRxSmbVolumeInformation(RxContext, 0, pBuffer, pBufferLength);
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifndef RX_NO_DBGFIELD_HLPRS
|
|
|
|
#define DECLARE_FIELD_HLPR(x) ULONG SmbPseOeField_##x = FIELD_OFFSET(SMB_PSE_ORDINARY_EXCHANGE,x);
|
|
#define DECLARE_FIELD_HLPR2(x,y) ULONG SmbPseOeField_##x##y = FIELD_OFFSET(SMB_PSE_ORDINARY_EXCHANGE,x.y);
|
|
|
|
DECLARE_FIELD_HLPR(RxContext);
|
|
DECLARE_FIELD_HLPR(ReferenceCount);
|
|
DECLARE_FIELD_HLPR(AssociatedStufferState);
|
|
DECLARE_FIELD_HLPR(Flags);
|
|
DECLARE_FIELD_HLPR(ReadWrite);
|
|
DECLARE_FIELD_HLPR(Transact2);
|
|
DECLARE_FIELD_HLPR2(Create,FileInfo);
|
|
DECLARE_FIELD_HLPR2(Create,smbSrvOpen);
|
|
DECLARE_FIELD_HLPR2(ReadWrite,RemainingByteCount);
|
|
DECLARE_FIELD_HLPR2(Info,FileInfo);
|
|
DECLARE_FIELD_HLPR2(Info,Buffer);
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|