2025-04-27 07:49:33 -04:00

1759 lines
63 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++ 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.
--*/
#include "precomp.h"
#pragma hdrstop
RXDT_DefineCategory(SMBPSE);
#define Dbg (DEBUG_TRACE_SMBPSE)
typedef struct _SMBPSE_VESTIGIAL_SMBBUF {
NT_SMB_HEADER Header;
union {
REQ_WRITE Write;
REQ_NT_WRITE_ANDX WriteAndX;
REQ_FLUSH Flush;
struct {
REQ_LOCKING_ANDX LockingAndX;
NTLOCKING_ANDX_RANGE Locks[20];
};
REQ_FIND_CLOSE2 FindClose;
REQ_CLOSE Close;
};
ULONG Pad;
} SMBPSE_VESTIGIAL_SMBBUF;
typedef struct _SMBPSE_MUST_SUCCEEED_CONTEXT {
struct {
LIST_ENTRY ExchangeListEntry;
union {
SMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange;
};
};
SMBPSE_VESTIGIAL_SMBBUF SmbBuf;
struct {
union {
MDL;
MDL Mdl;
};
ULONG Pages[2];
} DataPartialMdl;
} SMBPSE_MUST_SUCCEEED_CONTEXT, *PSMBPSE_MUST_SUCCEEED_CONTEXT;
BOOLEAN MRxSmbEntryPointIsMustSucceedable[SMBPSE_OE_FROM_MAXIMUM];
typedef enum {
SmbPseMustSucceed = 0,
SmbPseMustSucceedMaximum
};
RX_MUSTSUCCEED_DESCRIPTOR SmbPseMustSucceedDescriptor[SmbPseMustSucceedMaximum];
SMBPSE_MUST_SUCCEEED_CONTEXT SmbPseMustSucceedContext[SmbPseMustSucceedMaximum];
#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, // The exchange instance
IN ULONG BytesIndicated,
IN ULONG BytesAvailable,
OUT ULONG *pBytesTaken,
IN PSMB_HEADER pSmbHeader,
OUT PMDL *pDataBufferPointer,
OUT PULONG pDataSize);
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
};
//
// External declarations
//
#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;
PMRXIFS_RX_CONTEXT pMRxSmbContext;
PSMB_EXCHANGE Exchange = &OrdinaryExchange->Exchange;
pMRxSmbContext = MRxSmbGetMinirdrContext(RxContext);
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( pMRxSmbContext->pExchange == Exchange );
P__ASSERT( pMRxSmbContext->pStufferState == StufferState );
P__ASSERT( Exchange == StufferState->Exchange);
P__ASSERT( StufferState->RxContext == RxContext );
if(StufferState->HeaderMdl!=NULL){
P__ASSERT( !RxMdlIsPartial(StufferState->HeaderMdl) );
}
if (!FlagOn(Flags,OECHKLINKAGE_FLAG_NO_REQPCKT_CHECK)) {
P__ASSERT( OrdinaryExchange->RxContextCapturedRequestPacket == RxContext->CurrentIrp);
}
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;
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))
NTSTATUS
SmbPseContinueOrdinaryExchange(
IN OUT PRX_CONTEXT RxContext
)
/*++
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:
RXSTATUS - The return status for the operation
Notes:
--*/
{
NTSTATUS Status;
PMRXIFS_RX_CONTEXT pMRxSmbContext = MRxSmbGetMinirdrContext(RxContext);
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange =
(PSMB_PSE_ORDINARY_EXCHANGE)(pMRxSmbContext->pExchange);
RxCaptureFobx;
//PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange;
PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
PMDL SubmitMdl, HeaderFullMdl;
RxDbgTrace(+1, Dbg, ("SmbPseContinueOrdinaryExchange entering........OE=%08lx\n",OrdinaryExchange));
ClearFlag(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_OE_AWAITING_DISPATCH);
SmbPseOEAssertConsistentLinkageFromOE("SmbPseContinueOrdinaryExchange:");
Status = Exchange->Status;
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));
__RETRY_FINISH_ROUTINE__:
if ( OrdinaryExchange->FinishRoutine != NULL ) {
if ( Status == STATUS_MORE_PROCESSING_REQUIRED ){
Exchange->Status = STATUS_SUCCESS;
}
Status = OrdinaryExchange->FinishRoutine( OrdinaryExchange );
UPDATE_OE_HISTORY_WITH_STATUS('1c');
Exchange->Status = Status;
OrdinaryExchange->FinishRoutine = NULL;
} else 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)
));
if (Status==STATUS_SUCCESS) {
Status = Exchange->Status;
UPDATE_OE_HISTORY_WITH_STATUS('2c');
} else {
UPDATE_OE_HISTORY_WITH_STATUS('dd');
}
ASSERT( BytesTaken==MessageLength );
ASSERT( ( DataBufferPointer==NULL ) && ( DataSize == 0 ) );
ASSERT( Status != STATUS_MORE_PROCESSING_REQUIRED );
// after calling the receive routine again, we may NOW have a finish routine!
if ( OrdinaryExchange->FinishRoutine != NULL ) {
goto __RETRY_FINISH_ROUTINE__;
}
} else {
NOTHING;
}
if ( OrdinaryExchange->Continuation ) {
//call the continuation is it's async
//Exchange->SmbStatus = Status; //this is where read/write/locks pick up the status
Status = OrdinaryExchange->Continuation( 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:
RXSTATUS - The return status for the operation
Notes:
--*/
{
NTSTATUS Status;
RxCaptureFobx;
PMRXIFS_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;
RxDbgTrace(+1, Dbg, ("SmbPseOrdinaryExchange entering.......OE=%08lx\n",OrdinaryExchange));
SmbPseOEAssertConsistentLinkageFromOE("SmbPseOrdinaryExchange:");
OrdinaryExchange->OEType = OEType;
StufferState = &OrdinaryExchange->AssociatedStufferState;
KeInitializeEvent( &RxContext->SyncEvent,
NotificationEvent,
FALSE );
HeaderFullMdl = StufferState->HeaderMdl;
ASSERT( HeaderFullMdl != NULL );
SmbLength = StufferState->CurrentPosition - StufferState->BufferBase;
SubmitMdl = StufferState->HeaderPartialMdl;
if (SubmitMdl == NULL) {
RxDbgTrace(0,Dbg,("SmbPseOE allocating hdr partial\n"));
SubmitMdl = StufferState->HeaderPartialMdl = RxAllocateMdl( StufferState->BufferBase,
MmGetMdlByteCount(StufferState->HeaderMdl) );
if (SubmitMdl==NULL) {
RxDbgTrace(0,Dbg,("SmbPseOE cant get partial for submit mdl\n"));
Status = STATUS_INSUFFICIENT_RESOURCES;
goto FINALLY;
}
}
ASSERT(RxMdlIsOwned(SubmitMdl));
IoBuildPartialMdl( 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;
}
#if DBG
SmbPseDbgRunMdlChain(SubmitMdl,SmbLength,OrdinaryExchange,"SmbPseOrdinaryExchange(before)");
OrdinaryExchange->SaveDataMdlForDebug = SubmitMdl->Next;
OrdinaryExchange->SaveLengthForDebug = SmbLength;
if (OrdinaryExchange->RxContextCapturedRequestPacket != NULL) {
OrdinaryExchange->SaveIrpMdlForDebug = OrdinaryExchange->RxContextCapturedRequestPacket->MdlAddress;
}
#endif
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->Continuation;
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);
}
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 = MRxIfsGetSrvOpenExtension(SrvOpen);
if (smbSrvOpen->Version == OrdinaryExchange->SmbCeContext.pServerEntry->Server.Version) {
Status = STATUS_SUCCESS;
} else {
DbgPrint("HANDLE VERSION MISMATCH!!!!");
Exchange->SmbStatus = Status = STATUS_INVALID_HANDLE;
}
IF_DEBUG {
PSMB_HEADER pSmbHeader = (PSMB_HEADER)MmGetSystemAddressForMdl(SubmitMdl);
USHORT 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 {
ASSERT(SmbLength <= OrdinaryExchange->SmbCeContext.pServerEntry->Server.MaximumBufferSize);
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');
RxWaitSync( RxContext );
ASSERT(RxMdlIsOwned(SubmitMdl));
} else {
RxDbgTrace (0, Dbg, (" -->Status after transceive %08lx\n",Status));
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: ");
Status = SmbPseContinueOrdinaryExchange( RxContext );
UPDATE_OE_HISTORY_WITH_STATUS('9o');
FINALLY:
RxDbgTrace(-1, Dbg, ("SmbPseOrdinaryExchange returning %08lx.\n", Status));
return(Status);
} // SmbPseOrdinaryExchange
//#define MRXSMB_TEST_MUST_SUCCEED
#ifdef MRXSMB_TEST_MUST_SUCCEED
ULONG MRxSmbAllocatedMustSucceedExchange;
ULONG MRxSmbAllocatedMustSucceedSmbBuf;
#define MSFAILPAT ((0x3f)<<2)
#define FAIL_XXX_ALLOCATE() (FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED) \
&&((RxContext->SerialNumber&MSFAILPAT)==MSFAILPAT) \
&&((MRxSmbEntryPointIsMustSucceedable[EntryPoint])) )
#define FAIL_EXCHANGE_ALLOCATE() ( FAIL_XXX_ALLOCATE() && (RxContext->SerialNumber&2) )
#define FAIL_SMBBUF_ALLOCATE() ( FAIL_XXX_ALLOCATE() && (RxContext->SerialNumber&1) )
#define COUNT_MUST_SUCCEED_EXCHANGE_ALLOCATED() {MRxSmbAllocatedMustSucceedExchange++;}
#define COUNT_MUST_SUCCEED_SMBBUF_ALLOCATED() {MRxSmbAllocatedMustSucceedSmbBuf++;}
#define MUST_SUCCEED_ASSERT(x) {ASSERT(x);}
#else
#define FAIL_EXCHANGE_ALLOCATE() (FALSE)
#define FAIL_SMBBUF_ALLOCATE() (FALSE)
#define COUNT_MUST_SUCCEED_EXCHANGE_ALLOCATED() {NOTHING;}
#define COUNT_MUST_SUCCEED_SMBBUF_ALLOCATED() {NOTHING;}
#define MUST_SUCCEED_ASSERT(x) {NOTHING;}
#endif
PSMB_PSE_ORDINARY_EXCHANGE
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 PSMB_EXCHANGE_DISPATCH_VECTOR DispatchVector
)
/*++
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:
--*/
{
PMRXIFS_RX_CONTEXT pMRxSmbContext = MRxSmbGetMinirdrContext(RxContext);
PSMBSTUFFER_BUFFER_STATE StufferState = NULL;
PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange = NULL;
PSMBPSE_MUST_SUCCEEED_CONTEXT MustSucceedContext = NULL;
PCHAR SmbBuffer = NULL;
PMDL HeaderFullMdl = NULL;
NTSTATUS Status;
RxCaptureFobx;
RxDbgTrace( +1, Dbg, ("MRxSmbCreateSmbStufferState\n") );
if (!FAIL_EXCHANGE_ALLOCATE()) {
OrdinaryExchange = (PSMB_PSE_ORDINARY_EXCHANGE)SmbMmAllocateExchange(ORDINARY_EXCHANGE,NULL);
}
//we rely on the fact that SmbMmAllocate Zeros the exchange.............
if ( OrdinaryExchange == NULL ) {
//ASSERT(!"must-succeed");
if (!FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED)
|| !MRxSmbEntryPointIsMustSucceedable[EntryPoint]) {
RxDbgTrace( 0, Dbg, (" --> Couldn't get the exchange!\n") );
MUST_SUCCEED_ASSERT(!"failing the exchange");
return NULL;
}
MustSucceedContext = RxAcquireMustSucceedStructure(&SmbPseMustSucceedDescriptor[SmbPseMustSucceed]);
COUNT_MUST_SUCCEED_EXCHANGE_ALLOCATED();
OrdinaryExchange = (PSMB_PSE_ORDINARY_EXCHANGE)SmbMmAllocateExchange(ORDINARY_EXCHANGE,
&MustSucceedContext->ExchangeListEntry);
SetFlag( OrdinaryExchange->Flags, SMBPSE_OE_FLAG_MUST_SUCCEED_ALLOCATED_OE );
SetFlag( OrdinaryExchange->Flags, SMBPSE_OE_FLAG_MUST_SUCCEED_ALLOCATED_SMBBUF );
SmbBuffer = (PBYTE)&MustSucceedContext->SmbBuf;
OrdinaryExchange->SmbBufSize = sizeof(SMBPSE_VESTIGIAL_SMBBUF);
}
StufferState = &OrdinaryExchange->AssociatedStufferState;
StufferState->NodeTypeCode = SMB_NTC_STUFFERSTATE;
StufferState->NodeByteSize = sizeof(SMBSTUFFER_BUFFER_STATE);
StufferState->Exchange = &OrdinaryExchange->Exchange;
DbgDoit(OrdinaryExchange->SerialNumber = RxContext->SerialNumber);
//
// Initialize the exchange packet
//
SmbCeInitializeExchange( &StufferState->Exchange,
(PMRX_V_NET_ROOT)VNetRoot,
ORDINARY_EXCHANGE,
&SmbPseOEDispatch);
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)) {
SetFlag(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_TURNON_DFS_FLAG);
}
//
// Allocate the SmbBuffer
//
if ( (SmbBuffer == NULL) && !FAIL_SMBBUF_ALLOCATE() ) {
SmbBuffer = (PCHAR)RxAllocatePoolWithTag( PagedPool,OrdinaryExchange->SmbBufSize,'BMSx' );
}
if ( SmbBuffer == NULL ) {
if (!FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED)
|| !MRxSmbEntryPointIsMustSucceedable[EntryPoint]) {
RxDbgTrace( 0, Dbg, (" --> Couldn't get the smb buf!\n") );
MUST_SUCCEED_ASSERT(!"failed the smbbuf");
goto UNWIND;
}
MustSucceedContext = RxAcquireMustSucceedStructure(&SmbPseMustSucceedDescriptor[SmbPseMustSucceed]);
COUNT_MUST_SUCCEED_SMBBUF_ALLOCATED();
SetFlag( OrdinaryExchange->Flags, SMBPSE_OE_FLAG_MUST_SUCCEED_ALLOCATED_SMBBUF );
SmbBuffer = (PBYTE)&MustSucceedContext->SmbBuf;
OrdinaryExchange->SmbBufSize = sizeof(SMBPSE_VESTIGIAL_SMBBUF);
}
RxDbgTrace(0, Dbg, (" smbbuf=%08lx,stfstate=%08lx\n",SmbBuffer,StufferState));
StufferState->ActualBufferBase = SmbBuffer;
StufferState->BufferBase = SmbBuffer;
StufferState->BufferLimit = SmbBuffer + OrdinaryExchange->SmbBufSize;
//
// Init the HeaderMdl
//
HeaderFullMdl = StufferState->HeaderMdl = &OrdinaryExchange->HeaderMdl.Mdl;
MmInitializeMdl(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 );
if (MustSucceedContext==NULL) {
RxDbgTrace( 0, Dbg, (" --> LOCKING %08lx\n",HeaderFullMdl));
RxProbeAndLockPages( HeaderFullMdl,
KernelMode,
IoModifyAccess,
Status );
if (Status != STATUS_SUCCESS) {
RxDbgTrace( 0, Dbg, (" --> LOCKING FAILED\n"));
MUST_SUCCEED_ASSERT(!"LockingFailed");
goto UNWIND;
}
SetFlag(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_OE_HDR_LOCKED);
MmGetSystemAddressForMdl(HeaderFullMdl); //and map!
} else {
RxDbgTrace( 0, Dbg, (" --> LOCKING %08lx\n",HeaderFullMdl));
MmBuildMdlForNonPagedPool(HeaderFullMdl);
//also set up the data partial
OrdinaryExchange->DataPartialMdl = &MustSucceedContext->DataPartialMdl.Mdl;
}
//
// No initialization is required for the partial...just set the pointer
StufferState->HeaderPartialMdl = &OrdinaryExchange->HeaderPartialMdl.Mdl;
RxDbgTrace( -1, Dbg, (" --> exiting w!\n") );
return(OrdinaryExchange);
UNWIND:
RxDbgTrace( -1, Dbg, (" --> exiting w/o!\n") );
MUST_SUCCEED_ASSERT(!"Finalizing on the way out");
SmbPseFinalizeOrdinaryExchange( OrdinaryExchange );
return(NULL);
} // MRxSmbCreateSmbStufferState
#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)
{
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:
--*/
{
PMRXIFS_RX_CONTEXT pMRxSmbContext;
PSMBSTUFFER_BUFFER_STATE StufferState;
LONG result;
ULONG OrdinaryExchangeFlags = OrdinaryExchange->Flags;
ULONG ThisIsMustSucceedAllocated =
OrdinaryExchangeFlags & (SMBPSE_OE_FLAG_MUST_SUCCEED_ALLOCATED_SMBBUF
|SMBPSE_OE_FLAG_MUST_SUCCEED_ALLOCATED_OE);
FINALIZE_TRACKING_SETUP()
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;
}
RxLog((">>>OE %lx %lx %lx %lx %lx",
OrdinaryExchange,
OrdinaryExchange->DataPartialMdl,
StufferState->HeaderPartialMdl,
StufferState->HeaderMdl,
OrdinaryExchange->Flags
));
FINALIZE_TRACKING( 0x10000000 );
FINALIZE_TRACE("ready to freedatapartial");
if(FlagOn(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_SMBBUF_IS_A_MDL)){
MmPrepareMdlForReuse((PMDL)(OrdinaryExchange->AssociatedStufferState.BufferBase));
}
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)) {
MmUnlockPages(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 ) {
ASSERT( pMRxSmbContext->pExchange == &OrdinaryExchange->Exchange );
ASSERT( pMRxSmbContext->pStufferState == StufferState );
//get rid of the reference on the RxContext....if i'm the last guy this will finalize
RxDereferenceAndDeleteRxContext( StufferState->RxContext );
FINALIZE_TRACKING( 0x600 );
} else {
FINALIZE_TRACKING( 0xf00 );
}
FINALIZE_TRACE("ready to discard exchange");
SmbCeDiscardExchange(OrdinaryExchange);
FINALIZE_TRACKING( 0x2000000 );
if (ThisIsMustSucceedAllocated) {
RxReleaseMustSucceedStructure(&SmbPseMustSucceedDescriptor[SmbPseMustSucceed]);
}
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->Continuation!=NULL) {
NTSTATUS PostStatus;
RxDbgTraceLV(0, Dbg, 1000, ("Resume with post-to-async\n"));
//SetFlag(RxContext->Flags,RX_CONTEXT_FLAG_NO_COMPLETE_FROM_FSP);
//RxFsdPostRequestWithResume(RxContext,SmbPseContinueOrdinaryExchange);SMBPSE_OE_FLAG_OE_AWAITING_DISPATCH
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(MRxIfsDeviceObject,
CriticalWorkQueue,
//&OrdinaryExchange->WorkQueueItemForOE,
&OrdinaryExchange->WorkQueueItem,
SmbPseContinueOrdinaryExchange,
RxContext);
ASSERT(PostStatus == STATUS_SUCCESS);
} else {
RxDbgTraceLV(0, Dbg, 1000, ("sync resume\n"));
RxSignalSynchronousWaiter(RxContext);
}
*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');
if (!NT_SUCCESS(SendCompletionStatus)) {
pExchange->Status = 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;
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
)
/*++
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 ) {
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) ){
RxLog(("OErcv errorstatus %lx %lx %lx",pExchange->Status,RxContext,OrdinaryExchange));
}
if ( (pExchange->Status != STATUS_SUCCESS) ||
( (Command = OrdinaryExchange->ParseResumeState.AndXCommand) == SMB_COM_NO_ANDX_COMMAND) ) {
goto FINALLY;
}
SetFlag(OrdinaryExchange->Flags,SMBPSE_OE_FLAG_HEADER_ALREADY_PARSED);
} else {
RxDbgTrace (0, Dbg, (" -->this is a reenter\n"));
Command = CommandState->AndXCommand;
}
SmbStatus = OrdinaryExchange->SmbStatus;
if ( (SmbStatus!=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);
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->Continuation != NULL) && !ThisIsAReenter ) {
goto COPY_FOR_RESUME;
}
}
switch (mappedCommand) {
case SMB_COM_READ_ANDX:{
NTSTATUS FinishStatus = STATUS_SUCCESS;
NTSTATUS FinalStatus = 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 != 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->Continuation != NULL) && !ThisIsAReenter ) {
goto COPY_FOR_RESUME;
}
//eventually, we'll finish from here but for now copy
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:
SmbPseDiscardProtocol( FinishStatus );
RxDbgTrace( 0, Dbg, ("--->discardX\n"));
goto FINALLY;
}
}
pExchange->Status = (FinishStatus==STATUS_SUCCESS)
?FinalStatus:FinishStatus;
if (!ThisIsAnAndX) {
Response = (PCHAR)&NullGenericAndX;
}
}//this corresponds to the top level of the switch
break;
default:
ASSERT( !"taking a command that's not implemented" );
RxDbgTrace( 0, Dbg, (" *(ind) Unimplemented cmd=%02lx,wct=%02lx\n",
Command,*Response) );
pExchange->Status = STATUS_NOT_IMPLEMENTED;
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.
//
*pBytesTaken = BytesAvailable;
goto FINALLY;
COPY_FOR_RESUME:
ASSERT( !ThisIsAReenter );
// 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 ( (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);
pExchange->Status = STATUS_MORE_PROCESSING_REQUIRED;
}
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
//DbgDoit(DbgPrint("RMT %x %s\n",SmbCommand,IndicationString););
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;
for (i=SmbPseMustSucceed;i<SmbPseMustSucceedMaximum;i++) {
RxInitializeMustSucceedStructureDescriptor(
&SmbPseMustSucceedDescriptor[i],
(PVOID)(&SmbPseMustSucceedContext[i]));
}
for (i=0;i<SMBPSE_OE_FROM_MAXIMUM;i++) {
MRxSmbEntryPointIsMustSucceedable[i] = FALSE;
}
MRxSmbEntryPointIsMustSucceedable[SMBPSE_OE_FROM_WRITE] = TRUE;
MRxSmbEntryPointIsMustSucceedable[SMBPSE_OE_FROM_EXTENDFILEFORCACHEING] = FALSE;
MRxSmbEntryPointIsMustSucceedable[SMBPSE_OE_FROM_FLUSH] = TRUE;
MRxSmbEntryPointIsMustSucceedable[SMBPSE_OE_FROM_LOCKS] = TRUE;
MRxSmbEntryPointIsMustSucceedable[SMBPSE_OE_FROM_ASSERTBUFFEREDLOCKS] = TRUE;
MRxSmbEntryPointIsMustSucceedable[SMBPSE_OE_FROM_CLOSESRVCALL] = TRUE;
MRxSmbEntryPointIsMustSucceedable[SMBPSE_OE_FROM_CLEANUPFOBX] = TRUE;
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;
}
// egb
// 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);
// egb
// 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); //SMBPSE_RMP_THIS_IS_ANDX);
// egb
//
// 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);
//
// egb
//
// SmbPseRMTableEntry( OPEN_PRINT_FILE,SMBPSE_OETYPE_CREATEPRINTFILE,SMBPSE_OETYPE_CREATEPRINTFILE,
// SMBPSE_RECEIVE_HANDLER_TOKEN_OPEN_PRINTFILE_HANDLER,MRxSmbReceiveHandler_OpenPrintFile,
// 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);
//
// e g b
//
// 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);
//
// egb
// 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_DELETEFORSUPERSEDEORCLOSE,
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( 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);
}
#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