/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    SmbPse.h

Abstract:

    This module defines the types and functions related to the SMB protocol
    selection engine: the component that translates minirdr calldowns into
    SMBs.

Revision History:

--*/

#ifndef _SMBPSE_H_
#define _SMBPSE_H_

IMPORTANT_STRUCTURE(SMB_PSE_ORDINARY_EXCHANGE);

//CODE.IMPROVEMENT is this the right place for this?
#define StorageType(co) ((co) & FILE_STORAGE_TYPE_MASK)
#define StorageFlag(co) ((co) & FILE_STORAGE_TYPE_SPECIFIED)
#define IsStorageTypeSpecified(co)  (StorageFlag(co) == FILE_STORAGE_TYPE_SPECIFIED)

#define MustBeDirectory(co) ((co) & FILE_DIRECTORY_FILE)
#define MustBeFile(co)      ((co) & FILE_NON_DIRECTORY_FILE)

//CODE.IMPROVEMENT The following should get fixed - use Tom's literal!
#define CLUSTER_SIZE 0x1000

//CODE.IMPROVEMENT.STACKSPACE we could save a dword of stack space
//                            by not passing rxcontext
//                 and by retrieving it from ordinaryexchange
#define SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE \
    PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange, \
    PRX_CONTEXT RxContext

//CODE.IMPROVEMENT this is not used consistently. in particular, it is not used in the OE start wrapper
//                 in order to not have any extra variables on the stack....a good idea but it breaks
//                 this encapsulation. on a risc machine, they would be in registers anyway. so, it makes
//                 sense to put in a comment there (and maybe the x86-specific code.......)
#define SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS \
    OrdinaryExchange,RxContext

#if DBG
#define OECHKLINKAGE_FLAG_NO_REQPCKT_CHECK 0x00000001

VOID
__SmbPseOEAssertConsistentLinkage(
    PSZ MsgPrefix,
    PSZ File,
    unsigned Line,
    PRX_CONTEXT RxContext,
    PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
    PSMBSTUFFER_BUFFER_STATE StufferState,
    ULONG Flags
    );
#define SmbPseOEAssertConsistentLinkage(a) {\
   __SmbPseOEAssertConsistentLinkage(a,__FILE__,__LINE__,RxContext,OrdinaryExchange,StufferState,0);\
   }
#define SmbPseOEAssertConsistentLinkageFromOE(a) {\
    ASSERT_ORDINARY_EXCHANGE(OrdinaryExchange);                        \
   __SmbPseOEAssertConsistentLinkage(a,__FILE__,__LINE__,              \
                                     OrdinaryExchange->RxContext,      \
                                     OrdinaryExchange,                 \
                                     &OrdinaryExchange->AssociatedStufferState,0);  \
   }
#define SmbPseOEAssertConsistentLinkageFromOEwithFlags(a,FLAGS) {\
    ASSERT_ORDINARY_EXCHANGE(OrdinaryExchange);                        \
   __SmbPseOEAssertConsistentLinkage(a,__FILE__,__LINE__,              \
                                     OrdinaryExchange->RxContext,      \
                                     OrdinaryExchange,                 \
                                     &OrdinaryExchange->AssociatedStufferState,FLAGS);  \
   }
#else
#define SmbPseOEAssertConsistentLinkage(a) {NOTHING;}
#define SmbPseOEAssertConsistentLinkageFromOE(a) {NOTHING;}
#define SmbPseOEAssertConsistentLinkageFromOEwithFlags(a,b) {NOTHING;}
#endif

typedef
NTSTATUS
(*PSMB_PSE_OE_START_ROUTINE) (
    SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
    );

typedef
NTSTATUS
(*PSMB_PSE_CONTINUATION_ROUTINE) (
    PSMB_PSE_ORDINARY_EXCHANGE
    );

#define SMBPSE_OE_HISTORY_SIZE 32
typedef struct _SMBPSE_HISTORY {
    ULONG Next;
    ULONG Submits; //could be shortened....
    struct {
        ULONG Longs[2];
    } Markers[SMBPSE_OE_HISTORY_SIZE];
} SMBPSE_HISTORY;

#if DBG
VOID SmbPseUpdateOEHistory(
    PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
    ULONG Tag1,
    ULONG Tag2
    );
#define UPDATE_OE_HISTORY_LONG(a) {SmbPseUpdateOEHistory(OrdinaryExchange,a,0);}
#define UPDATE_OE_HISTORY_2SHORTS(a,b) {SmbPseUpdateOEHistory(OrdinaryExchange,a,b);}
#else
#define UPDATE_OE_HISTORY_LONG(a)
#define UPDATE_OE_HISTORY_2SHORTS(a,b)
#endif //if DBG


typedef enum _SMB_PSE_ORDINARY_EXCHANGE_TYPE {
    SMBPSE_OETYPE_LATENT_HEADEROPS,
    SMBPSE_OETYPE_CREATE,
    SMBPSE_OETYPE_COREOPEN,
//    SMBPSE_OETYPE_CLEANUP,
    SMBPSE_OETYPE_FINDCLOSE,
    SMBPSE_OETYPE_READ,
    SMBPSE_OETYPE_WRITE, SMBPSE_OETYPE_EXTEND_WRITE, SMBPSE_OETYPE_CORETRUNCATE,
    SMBPSE_OETYPE_LOCKS, SMBPSE_OETYPE_ASSERTBUFFEREDLOCKS,
    SMBPSE_OETYPE_FLUSH,
    SMBPSE_OETYPE_CLOSE, SMBPSE_OETYPE_CLOSEAFTERCORECREATE,
    //SMBPSE_OETYPE_SEARCH,
    SMBPSE_OETYPE_RENAME,
    SMBPSE_OETYPE_T2_FOR_NT_FILE_ALLOCATION_INFO,  //MUST BE FIRST T2
    SMBPSE_OETYPE_T2_FOR_NT_DISKATTRIBUTES_INFO,
    SMBPSE_OETYPE_T2_FOR_ONE_FILE_DIRCTRL,
    SMBPSE_OETYPE_T2_FOR_LANMAN_DISKATTRIBUTES_INFO,
    SMBPSE_OETYPE_T2_FOR_LANMAN_VOLUMELABEL_INFO,  //MUST BE LAST T2
    SMBPSE_OETYPE_GFA,
//    SMBPSE_OETYPE_GFA2,
    SMBPSE_OETYPE_COREINFO,
    SMBPSE_OETYPE_CORECREATE,
    SMBPSE_OETYPE_DELETEFORSUPERSEDEORCLOSE, SMBPSE_OETYPE_DELETE_FOR_RENAME,
    SMBPSE_OETYPE_CORECREATEDIRECTORY,
    SMBPSE_OETYPE_CORECHECKDIRECTORY,
    SMBPSE_OETYPE_SFA,
    SMBPSE_OETYPE_SFA2,
    SMBPSE_OETYPE_COREQUERYLABEL, SMBPSE_OETYPE_CORESEARCH, SMBPSE_OETYPE_CORESEARCHFORCHECKEMPTY,
    SMBPSE_OETYPE_COREQUERYDISKATTRIBUTES,
    SMBPSE_OETYPE_CREATEPRINTFILE,
    SMBPSE_OETYPE_IOCTL,
    SMBPSE_OETYPE_MAXIMUM
} SMB_PSE_ORDINARY_EXCHANGE_TYPE;

typedef enum _SMB_PSE_ORDINARY_EXCHANGE_ENTRYPOINTS {
    SMBPSE_OE_FROM_QUERYDIRECTORY,
    SMBPSE_OE_FROM_QUERYFILEINFO,
    SMBPSE_OE_FROM_SETFILEINFO,
    SMBPSE_OE_FROM_QUERYVOLUMEINFO,
    SMBPSE_OE_FROM_EXTENDFILEFORCACHEING,
    SMBPSE_OE_FROM_LOCKS,
    SMBPSE_OE_FROM_FLUSH,
    SMBPSE_OE_FROM_ASSERTBUFFEREDLOCKS,
    SMBPSE_OE_FROM_CLEANUPFOBX,
    SMBPSE_OE_FROM_CLOSESRVCALL,
    SMBPSE_OE_FROM_CLOSECOPYCHUNKSRVCALL,
    SMBPSE_OE_FROM_GETFILEINFOFORCSHADOW,
    SMBPSE_OE_FROM_CREATE,
    SMBPSE_OE_FROM_RENAME,
    SMBPSE_OE_FROM_READ,
    SMBPSE_OE_FROM_WRITE,
    SMBPSE_OE_FROM_FAKESETDELETEDISPOSITION,
    SMBPSE_OE_FROM_GETPRINTJOBID,
    SMBPSE_OE_FROM_MAXIMUM
} SMB_PSE_ORDINARY_EXCHANGE_ENTRYPOINTS;

#define SMBPSE_DEFINE_OE_FLAG(a,c) RX_DEFINE_FLAG(SMBPSE_OE_FLAG_##a,c,0xffff)

typedef enum {
    SMBPSE_DEFINE_OE_FLAG(HEADER_ALREADY_PARSED, 0)
    SMBPSE_DEFINE_OE_FLAG(OE_ALREADY_RESUMED, 1)
    SMBPSE_DEFINE_OE_FLAG(VALIDATE_FID, 2)
    SMBPSE_DEFINE_OE_FLAG(OE_HDR_PARTIAL_INITIALIZED, 3)
    SMBPSE_DEFINE_OE_FLAG(OE_ALLOCATED_DATA_PARTIAL, 4)
    SMBPSE_DEFINE_OE_FLAG(OE_HDR_LOCKED, 5)
    //SMBPSE_DEFINE_OE_FLAG(SMBBUF_IS_A_MDL, 6)
    SMBPSE_DEFINE_OE_FLAG(NO_RESPONSE_EXPECTED, 7)
    SMBPSE_DEFINE_OE_FLAG(MUST_SUCCEED_ALLOCATED_OE, 8)
    SMBPSE_DEFINE_OE_FLAG(MUST_SUCCEED_ALLOCATED_SMBBUF, 9)
    SMBPSE_DEFINE_OE_FLAG(OE_AWAITING_DISPATCH, 10)
    SMBPSE_DEFINE_OE_FLAG(TURNON_DFS_FLAG, 11)
    //SMBPSE_DEFINE_OE_FLAG(NETROOT_GOOD, 15)
} SMBPSE_OE_FLAGS;

typedef enum _SMB_PSE_OE_INNERIO_STATE {
    SmbPseOEInnerIoStates_Initial = 0,
    SmbPseOEInnerIoStates_ReadyToSend,
    SmbPseOEInnerIoStates_OperationOutstanding,
    SmbPseOEInnerIoStates_OperationCompleted
} SMB_PSE_OE_INNERIO_STATE;

typedef enum _SMB_PSE_OE_READWRITE_STATE {
    SmbPseOEReadWriteIoStates_Initial = 0,
    SmbPseOEReadWriteIoStates_OperationOutstanding,
    SmbPseOEReadWriteIoStates_OperationCompleted,
    SmbPseOEReadWriteIoStates_OperationAbandoned
} SMB_PSE_OE_READWRITE_STATE;


#define MAX_PAGES_SPANNED_BY_PARTIAL_DATA_MDL (20)
#define MAX_PAGES_SPANNED_BY_PARTIAL_EXCHANGE_MDL (2)

#define MAX_PARTIAL_DATA_MDL_BUFFER_SIZE    \
    (MAX_PAGES_SPANNED_BY_PARTIAL_DATA_MDL * PAGE_SIZE)

#define MAX_PARTIAL_EXCHANGE_MDL_BUFFER_SIZE \
    (MAX_PAGES_SPANNED_BY_PARTIAL_EXCHANGE_MDL * PAGE_SIZE)

extern FAST_MUTEX MRxSmbReadWriteMutex;

typedef struct _SMB_PSE_OE_READWRITE {
    union {
    	PBYTE UserBufferBase;
    	PLOWIO_LOCK_LIST LockList;
    };

    ULONG         RemainingByteCount;
    ULONG         ThisBytesRequested;
    ULONG         ThisByteCount;
    ULONG         ThisBufferOffset;
    LARGE_INTEGER ByteOffsetAsLI;
    ULONG         BytesReturned;

    BOOLEAN PartialExchangeMdlInUse;
    BOOLEAN PartialDataMdlInUse;
    BOOLEAN CompressedRequestInProgress;
    BOOLEAN CompressedReadOrWrite;
    BOOLEAN WriteToTheEnd;
    BOOLEAN ReadWriteFinalized;

    ULONG   CompressedDataInfoLength;
    PBYTE   pCompressedDataBuffer;

    ULONG   UserBufferPortionLength;
    ULONG   ExchangeBufferPortionLength;

    union {
        MDL                   PartialDataMdl;
        COMPRESSED_DATA_INFO  CompressedDataInfo;
        BYTE    ByteBuffer1[
                    sizeof(MDL) +
                    sizeof(ULONG) * MAX_PAGES_SPANNED_BY_PARTIAL_DATA_MDL];
    };

    union {
        MDL     PartialExchangeMdl;
        BYTE    PartialExchangeMdlBuffer[
                    sizeof(MDL) +
                    sizeof(ULONG) * MAX_PAGES_SPANNED_BY_PARTIAL_EXCHANGE_MDL];
    };

    ULONG      TotalNumOfSections;
    ULONG      NumOfOutstandingOperations;
    ULONG      MaximumBufferSize;
    ULONG      CurrentSection;
    ULONG      RefCount;
    KEVENT     CompletionEvent;
    NTSTATUS   CompletionStatus;
    SMBFCB_HOLDING_STATE SmbFcbHoldingState;
    SMB_PSE_OE_READWRITE_STATE SectionState[];
} SMB_PSE_OE_READWRITE, *PSMB_PSE_OE_READWRITE;

#define OE_RW_FLAG_SUCCESS_IN_COPYHANDLER (0x01)
#define OE_RW_FLAG_REDUCE_RETURNCOUNT     (0x20) //used in pipewrites to track rawmode
#define OE_RW_FLAG_SUBSEQUENT_OPERATION   (0x40) //used in pipewrites to distinguish the first
#define OE_RW_FLAG_MSGMODE_PIPE_OPERATION (0x80) //MAX VALUE, it's just a byte.....


#define SMB_PSE_OE_HDR_MDL_PAGES (2 + (ADDRESS_AND_SIZE_TO_SPAN_PAGES( (ULONG) 0, MAXIMUM_SMB_BUFFER_SIZE )))

typedef struct _SMB_PSE_ORDINARY_EXCHANGE{
   union {
       SMB_EXCHANGE  Exchange;
       SMB_EXCHANGE;
   };
   SMB_PSE_ORDINARY_EXCHANGE_TYPE OEType;
   SMB_PSE_ORDINARY_EXCHANGE_ENTRYPOINTS EntryPoint;
   ULONG SmbBufSize;
   ULONG StartEntryCount;
   PMDL  DataPartialMdl;
   USHORT Flags;
   UCHAR  OpSpecificFlags;
   UCHAR  OpSpecificState;
   UCHAR  LastSmbCommand;
   ULONG  SendOptions;
   GENERIC_ANDX ParseResumeState;
   NTSTATUS NoCopyFinalStatus;
   NTSTATUS SendCompletionStatus;
   ULONG MessageLength;
   SMBFCB_HOLDING_STATE SmbFcbHoldingState; //plenty of pad....only 2 bits used

   PSMB_PSE_OE_START_ROUTINE        AsyncResumptionRoutine;
   PSMB_PSE_OE_START_ROUTINE        StartRoutine;
   PSMB_PSE_CONTINUATION_ROUTINE    ContinuationRoutine;

   union {
       struct {
           SMBPSE_FILEINFO_BUNDLE FileInfo;
           PMRX_SMB_SRV_OPEN smbSrvOpen;
           RX_FILE_TYPE StorageTypeFromGFA;
           ///DO NOT CHANGE ABOVE HERE UNLESS YOU CHANGE THE INFO ARM AS WELL
           MRXSMB_CREATE_PARAMETERS SmbCp;
           BOOLEAN MustRegainExclusiveResource;
           BOOLEAN CreateWithEasSidsOrLongName;
           ULONG FidReturnedFromCreate;
           ULONG FidReturnedFromOpen;
           ULONG FileSizeReturnedFromOpen;
           BOOLEAN FileWasCreated;
           BOOLEAN FileWasTruncated;
           //UNICODE_STRING PathNameForCoreOperation;
       } Create;
       SMB_PSE_OE_READWRITE ReadWrite;    //also used for locks
       struct {
           SMBPSE_FILEINFO_BUNDLE FileInfo;
           PMRX_SMB_SRV_OPEN smbSrvOpen;
           RX_FILE_TYPE StorageTypeFromGFA;
           ///DO NOT CHANGE ABOVE HERE UNLESS YOU CHANGE THE CREATE ARM AS WELL
    	   PVOID Buffer;
    	   PULONG pBufferLength;
           ULONG InfoClass;
           union {
               struct {
                   UCHAR CoreLabel[13];    //right from smb.h
               } QFSVolInfo;
               struct {
                   ULONG CountRemaining;
                   ULONG CountRemainingInSmbbuf;
                   PSMB_DIRECTORY_INFORMATION NextDirInfo;
                   //there should be a union here
                   PSMB_RESUME_KEY EmptyCheckResumeKey;
                   SMB_RESUME_KEY EmptyCheckResumeKeyBuffer;
               } CoreSearch;
           };
       } Info;
       struct {
           LARGE_INTEGER AllocationSize;
       } Transact2;
       struct {
           PUCHAR PtrToLockType;   //this must be here because the beginning of the
                                   //lockstart code sets the locklist to zero which will be this
                                   //CODE.IMPROVEMENT.ASHAMED fix this up so that assert locks uses readwrite
           PMRX_SRV_OPEN SrvOpen;
           PRX_LOCK_ENUMERATOR LockEnumerator;
           PVOID ContinuationHandle;
           ULONG NumberOfLocksPlaced;
           LARGE_INTEGER NextLockOffset;
           LARGE_INTEGER NextLockRange;
           BOOLEAN NextLockIsExclusive;
           BOOLEAN LockAreaNonEmpty;
           BOOLEAN EndOfListReached;
       } AssertLocks;
   } ;
   
   PSMB_PSE_OE_READWRITE GlobalReadWrite;

   PUNICODE_STRING   pPathArgument1;  // Unicode path
   union {
       PUNICODE_STRING   pPathArgument2;  // secondary unicode path
       PVOID             Find32WithinSmbbuf;
   };
   PSMBSTUFFER_BUFFER_STATE StufferStateDbgPtr; //this is just for the debugger....get rid of it
   SMBSTUFFER_BUFFER_STATE AssociatedStufferState;
   struct {
       union {
           MDL;
           MDL Mdl;
       };
       ULONG Pages2[SMB_PSE_OE_HDR_MDL_PAGES];
   } HeaderMdl;
   struct {
       union {
           MDL;
           MDL Mdl;
       };
       ULONG Pages2[SMB_PSE_OE_HDR_MDL_PAGES];
   } HeaderPartialMdl;
//#if DBG      CODE.IMPROVEMENT we should get rid of what we don't really, really need
   ULONG SerialNumber;
   SMBPSE_HISTORY History;
   PIRP RxContextCapturedRequestPacket;
   PMDL  SaveDataMdlForDebug;
   ULONG SaveLengthForDebug;
   PMDL  SaveIrpMdlForDebug;
//#endif
   ULONG BytesAvailableCopy;
   ULONG BytesIndicatedCopy;
} SMB_PSE_ORDINARY_EXCHANGE, *PSMB_PSE_ORDINARY_EXCHANGE;

// CODE.IMPROVEMENT actually, we have to get rid of a message...we need to know the length in the long term
// in the short term this will be okay. i think that what i really have to do is to return error_discard
// or something like that
#define SmbPseDiscardProtocol(__STATUS__) { \
    *pBytesTaken = BytesAvailable; \
    pExchange->Status = (__STATUS__); \
}

NTSTATUS
SmbPseOrdinaryExchange(
    SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE,
    IN SMB_PSE_ORDINARY_EXCHANGE_TYPE OEType
    );

NTSTATUS
SmbPseResumeOrdinaryExchange(
    IN OUT PRX_CONTEXT RxContext
    );

#define ASSERT_ORDINARY_EXCHANGE(__p) ASSERT(NodeType(__p)==SMB_EXCHANGE_NTC(ORDINARY_EXCHANGE))


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
    );
#define SmbPseCreateOrdinaryExchange(__rxcontext,__vnetroot,__entrypoint,__start,__ordinaryexchangeptr) \
      __SmbPseCreateOrdinaryExchange(__rxcontext,__vnetroot,__entrypoint,__start,NULL,__ordinaryexchangeptr)

BOOLEAN
SmbPseFinalizeOrdinaryExchange (
    IN OUT PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange
    );

#define SmbPseInitiateOrdinaryExchange(OrdinaryExchange) (SmbCeInitiateExchange(&OrdinaryExchange->Exchange))

// this macro is used to do the async completion for read/write/locks. Note that the call to lowiocompletion
// will try to complete the irp thereby freeing the user's mdl. so, we better get rid of the partial first.
// we use this macro so that there will be only one version of this code. when we combine start routines,
// this will be un macroed
#define SmbPseAsyncCompletionIfNecessary(OE,RXCONTEXT) {                           \
    if (StartEntryCount>1) {                                                       \
    	BOOLEAN FinalizationComplete;                                              \
        if (FALSE) {DbgBreakPoint(); }                                             \
    	if ( (OE)->DataPartialMdl ) {                                              \
            if (FlagOn((OE)->Flags, SMBPSE_OE_FLAG_MUST_SUCCEED_ALLOCATED_SMBBUF)){\
                MmPrepareMdlForReuse((OE)->DataPartialMdl);                        \
            } else {                                                               \
        	    IoFreeMdl((OE)->DataPartialMdl);                                   \
        	    (OE)->DataPartialMdl = NULL;                                       \
        	    ClearFlag((OE)->Flags,SMBPSE_OE_FLAG_OE_ALLOCATED_DATA_PARTIAL);   \
            }                                                                      \
    	}                                                                          \
    	(RXCONTEXT)->StoredStatus = Status;                                        \
    	                                                                           \
        RxLowIoCompletion((RXCONTEXT));                                            \
    	FinalizationComplete = SmbPseFinalizeOrdinaryExchange((OE));               \
    	ASSERT(!FinalizationComplete);                                             \
        Status = STATUS_PENDING;                                                   \
    }}


/* ------------------------------------------
   ------------------------------------------
   Receive Handler Stuff
   ------------------------------------------
   ------------------------------------------
*/

VOID
SmbPseInitializeTables(
    void
    );

typedef
NTSTATUS
(*PSMBPSE_RECEIVE_HANDLER) (
      PSMB_PSE_ORDINARY_EXCHANGE   OrdinaryExchange,
      PBYTE                        Response
    );


//boy, talk about a load of arguments
typedef
UCHAR
(*PSMBPSE_NOCOPY_RECEIVE_HANDLER) (
    IN OUT  PSMB_PSE_ORDINARY_EXCHANGE   OrdinaryExchange,
    IN  ULONG       BytesIndicated,
    IN  ULONG       BytesAvailable,
    OUT ULONG       *pBytesTaken,
    IN  PSMB_HEADER pSmbHeader,
    OUT PMDL        *pDataBufferPointer,
    OUT PULONG      pDataSize,
#if DBG
    IN  UCHAR       ThisIsAReenter,
#endif
    IN  PBYTE       Response
    );
#define SMBPSE_NOCOPYACTION_NORMALFINISH  0x00
#define SMBPSE_NOCOPYACTION_MDLFINISH     0x01
#define SMBPSE_NOCOPYACTION_DISCARD 0x02
#define SMBPSE_NOCOPYACTION_COPY_FOR_RESUME 0x03


#define SMBPSE_RMP_MODELED        (0x00000001)
#define SMBPSE_RMP_THIS_IS_ANDX   (0x00000002)
#define SMBPSE_RMP_WARNINGS_OK    (0x00000004)
#define SMBPSE_RMP_NOCOPY_HANDLER (0x00000008)

typedef enum _SMBPSE_RECEIVE_HANDLER_TOKEN {
    SMBPSE_RECEIVE_HANDLER_TOKEN_READ_ANDX_HANDLER = 0,
    SMBPSE_RECEIVE_HANDLER_TOKEN_READ_HANDLER,
    SMBPSE_RECEIVE_HANDLER_TOKEN_WRITE_ANDX_HANDLER,
    SMBPSE_RECEIVE_HANDLER_TOKEN_WRITE_HANDLER,
    SMBPSE_RECEIVE_HANDLER_TOKEN_LOCKING_ANDX_HANDLER,
    SMBPSE_RECEIVE_HANDLER_TOKEN_OPEN_PRINTFILE_HANDLER,
    SMBPSE_RECEIVE_HANDLER_TOKEN_WRITE_PRINTFILE_HANDLER,
    SMBPSE_RECEIVE_HANDLER_TOKEN_CLOSE_HANDLER,  //also close_print_file
    SMBPSE_RECEIVE_HANDLER_TOKEN_NTCREATE_ANDX_HANDLER,
    SMBPSE_RECEIVE_HANDLER_TOKEN_OPEN_ANDX_HANDLER,
    SMBPSE_RECEIVE_HANDLER_TOKEN_CREATE_HANDLER,  //also create_new
    SMBPSE_RECEIVE_HANDLER_TOKEN_OPEN_HANDLER,
    SMBPSE_RECEIVE_HANDLER_TOKEN_TRANS2_ANDX_HANDLER,
    SMBPSE_RECEIVE_HANDLER_TOKEN_GFA_HANDLER,
    SMBPSE_RECEIVE_HANDLER_TOKEN_SEARCH_HANDLER,
    SMBPSE_RECEIVE_HANDLER_TOKEN_QUERYDISKINFO_HANDLER,
    SMBPSE_RECEIVE_HANDLER_TOKEN_IOCTL_HANDLER,
    SMBPSE_RECEIVE_HANDLER_TOKEN_MAXIMUM
} SMBPSE_RECEIVE_HANDLER_TOKEN;

PSMBPSE_RECEIVE_HANDLER SmbPseReceiveHandlers[SMBPSE_RECEIVE_HANDLER_TOKEN_MAXIMUM];
typedef struct _SMBPSE_RECEIVE_MODEL_PARAMETERS {
    UCHAR Flags;
    UCHAR ReceiveHandlerToken;
#if DBG
    USHORT Dummy;
    PSMBPSE_RECEIVE_HANDLER ReceiveHandler;
    PBYTE IndicationString;
    SMB_PSE_ORDINARY_EXCHANGE_TYPE LowType,HighType;
#endif
} SMBPSE_RECEIVE_MODEL_PARAMETERS, *PSMBPSE_RECEIVE_MODEL_PARAMETERS;

SMBPSE_RECEIVE_MODEL_PARAMETERS SmbPseReceiveModelParameters[256]; //there are 256 possible smbs


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]; //CODE.IMPROVEMENT.ASHAMED see locks.c
        };
        REQ_FIND_CLOSE2 FindClose;
        REQ_CLOSE Close;
    };
    ULONG Pad;
} SMBPSE_VESTIGIAL_SMBBUF;


// Finishing routines - these are all cast into the correct procedure type
//                      so that the response will already have the correct SMB format
//                      on entry to the routine

//CODE.IMPROVEMENT the names of these routines should be changed from FinishX to X_Handler
//CODE.IMPROVEMENT also, any routine that doesn't retrieve data should be changed over to a nocopy handler

NTSTATUS
MRxSmbFinishNTCreateAndX (
      IN OUT PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
      IN     PRESP_NT_CREATE_ANDX        Response
      );
#define MRxSmbReceiveHandler_NTCreateAndX ((PSMBPSE_RECEIVE_HANDLER)MRxSmbFinishNTCreateAndX)

NTSTATUS
MRxSmbFinishOpenAndX (
      IN OUT PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
      IN     PRESP_OPEN_ANDX             Response
      );
#define MRxSmbReceiveHandler_OpenAndX ((PSMBPSE_RECEIVE_HANDLER)MRxSmbFinishOpenAndX)

NTSTATUS
MRxSmbFinishClose (
      IN OUT PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
      IN     PRESP_CLOSE                 Response
      );
//use the close finsh routine for closeprintfile as well
#define MRxSmbReceiveHandler_Close ((PSMBPSE_RECEIVE_HANDLER)MRxSmbFinishClose)

NTSTATUS
MRxSmbFinishGFA (
      IN OUT PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
      IN     PVOID                       Response
      );
#define MRxSmbReceiveHandler_GetFileAttributes ((PSMBPSE_RECEIVE_HANDLER)MRxSmbFinishGFA)

NTSTATUS
MRxSmbFinishTransaction2 (
      IN OUT PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
      IN     PRESP_TRANSACTION           Response
      );
#define MRxSmbReceiveHandler_Transact2 ((PSMBPSE_RECEIVE_HANDLER)MRxSmbFinishTransaction2)

NTSTATUS
MRxSmbFinishCoreOpen (
      IN OUT PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
      IN     PRESP_OPEN                  Response
      );
#define MRxSmbReceiveHandler_CoreOpen ((PSMBPSE_RECEIVE_HANDLER)MRxSmbFinishCoreOpen)

NTSTATUS
MRxSmbFinishCoreCreate (
      IN OUT PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
      IN     PRESP_CREATE                Response
      );
#define MRxSmbReceiveHandler_CoreCreate ((PSMBPSE_RECEIVE_HANDLER)MRxSmbFinishCoreCreate)

NTSTATUS
MRxSmbFinishCoreIoCtl(
      PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
      PRESP_IOCTL                 Response
      );
#define MRxSmbReceiveHandler_Ioctl ((PSMBPSE_RECEIVE_HANDLER)MRxSmbFinishCoreIoCtl)

//NTSTATUS
//MRxSmbFinishRead (
//      IN OUT PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
//      IN     PRESP_READ_ANDX             Response
//      );
//#define MRxSmbReceiveHandler_ReadAndX ((PSMBPSE_RECEIVE_HANDLER)MRxSmbFinishRead)

//NTSTATUS
//MRxSmbFinishCoreRead (
//      IN OUT PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
//      IN     PRESP_READ                  Response
//      );
//#define MRxSmbReceiveHandler_CoreRead ((PSMBPSE_RECEIVE_HANDLER)MRxSmbFinishCoreRead)

UCHAR
MRxSmbReadHandler_NoCopy (
    IN OUT  PSMB_PSE_ORDINARY_EXCHANGE   OrdinaryExchange,
    IN  ULONG       BytesIndicated,
    IN  ULONG       BytesAvailable,
    OUT ULONG       *pBytesTaken,
    IN  PSMB_HEADER pSmbHeader,
    OUT PMDL        *pDataBufferPointer,
    OUT PULONG      pDataSize,
#if DBG
    IN  UCHAR       ThisIsAReenter,
#endif
    IN  PRESP_READ_ANDX       Response
    );
#define MRxSmbReceiveHandler_Read_NoCopy ((PSMBPSE_RECEIVE_HANDLER)MRxSmbReadHandler_NoCopy)

NTSTATUS
MRxSmbFinishCreatePrintFile (
      IN OUT PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
      IN     PRESP_OPEN_PRINT_FILE       Response
      );
#define MRxSmbReceiveHandler_OpenPrintFile ((PSMBPSE_RECEIVE_HANDLER)MRxSmbFinishCreatePrintFile)

NTSTATUS
MRxSmbFinishWrite (
      IN OUT PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
      IN     PBYTE                       Response
      );

#define MRxSmbReceiveHandler_WritePrintFile ((PSMBPSE_RECEIVE_HANDLER)MRxSmbFinishWrite)
#define MRxSmbReceiveHandler_WriteAndX ((PSMBPSE_RECEIVE_HANDLER)MRxSmbFinishWrite)
#define MRxSmbReceiveHandler_CoreWrite ((PSMBPSE_RECEIVE_HANDLER)MRxSmbFinishWrite)

NTSTATUS
MRxSmbFinishLocks (
      IN OUT PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
      IN     PRESP_LOCKING_ANDX          Response
      );
#define MRxSmbReceiveHandler_LockingAndX ((PSMBPSE_RECEIVE_HANDLER)MRxSmbFinishLocks)

#if 0
NTSTATUS
MRxSmbFinishFlush (
      IN OUT PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
      IN     PRESP_FLUSH                 Response
      );
#endif //if 0

NTSTATUS
MRxSmbFinishSearch (
      PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
      PRESP_SEARCH                Response
      );
#define MRxSmbReceiveHandler_Search ((PSMBPSE_RECEIVE_HANDLER)MRxSmbFinishSearch)
NTSTATUS
MRxSmbFinishQueryDiskInfo (
      PSMB_PSE_ORDINARY_EXCHANGE   OrdinaryExchange,
      PRESP_QUERY_INFORMATION_DISK Response
      );
#define MRxSmbReceiveHandler_QueryDiskInfo ((PSMBPSE_RECEIVE_HANDLER)MRxSmbFinishQueryDiskInfo)


//CODE.IMPROVEMENT.ASHAMED it would be so much better if
//    __MRxSmbSimpleSyncTransact2were divided into two routines.....one for
//    building and another for submitting. it would save some stack space.
typedef
NTSTATUS
(*PSMB_PSE_OE_T2_FIXUP_ROUTINE) (
    PSMB_PSE_ORDINARY_EXCHANGE
    );

NTSTATUS
__MRxSmbSimpleSyncTransact2(
    SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE,
    IN SMB_PSE_ORDINARY_EXCHANGE_TYPE OEType,
    IN ULONG TransactSetupCode,
    IN PVOID Params,
    IN ULONG ParamsLength,
    IN PVOID Data,
    IN ULONG DataLength,
    IN PSMB_PSE_OE_T2_FIXUP_ROUTINE FixupRoutine
    );
#define MRxSmbSimpleSyncTransact2(a,b,c,d,e,f,g) \
    __MRxSmbSimpleSyncTransact2(a,b,c,d,e,f,g,NULL);

NTSTATUS
MRxSmbDeferredCreate (
      IN OUT PRX_CONTEXT RxContext
      );
NTSTATUS
MRxSmbConstructDeferredOpenContext (
      IN OUT PRX_CONTEXT RxContext
      );

//downlevel stuff....
NTSTATUS
MRxSmbPseudoOpenTailFromGFAResponse (
      PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange
      );

NTSTATUS
MRxSmbPseudoOpenTailFromFakeGFAResponse (
      PSMB_PSE_ORDINARY_EXCHANGE  OrdinaryExchange,
      RX_FILE_TYPE StorageType         //CODE.IMPROVEMENT this should be a RDBSS_STORAGE_TYPE
      );

NTSTATUS
MRxSmbCoreTruncate(
    SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE,
    ULONG Fid,
    ULONG FileTruncationPoint
    );

NTSTATUS
MRxSmbCoreInformation(
      IN OUT PRX_CONTEXT          RxContext,
      IN     ULONG                InformationClass,
      IN OUT PVOID                pBuffer,
      IN OUT PULONG               pBufferLength,
      IN     SMB_PSE_ORDINARY_EXCHANGE_ENTRYPOINTS EntryPoint
      );

ULONG
MRxSmbMapSmbAttributes (
    IN USHORT SmbAttribs
    );

USHORT
MRxSmbMapDisposition (
    IN ULONG Disposition
    );

USHORT
MRxSmbMapShareAccess (
    IN USHORT ShareAccess
    );

USHORT
MRxSmbMapDesiredAccess (
    IN ULONG DesiredAccess
    );

USHORT
MRxSmbMapFileAttributes (
    IN ULONG FileAttributes
    );

ULONG
MRxSmbUnmapDisposition (
    IN USHORT SmbDisposition,
    IN ULONG Disposition
    );

LARGE_INTEGER
MRxSmbConvertSmbTimeToTime (
    //IN PSMB_EXCHANGE Exchange OPTIONAL,
    IN PSMBCE_SERVER Server OPTIONAL,
    IN SMB_TIME Time,
    IN SMB_DATE Date
    );


BOOLEAN
MRxSmbConvertTimeToSmbTime (
    IN PLARGE_INTEGER InputTime,
    IN PSMB_EXCHANGE Exchange OPTIONAL,
    OUT PSMB_TIME Time,
    OUT PSMB_DATE Date
    );


BOOLEAN
MRxSmbTimeToSecondsSince1970 (
    IN PLARGE_INTEGER CurrentTime,
    IN PSMBCE_SERVER Server OPTIONAL,
    OUT PULONG SecondsSince1970
    );

VOID
MRxSmbSecondsSince1970ToTime (
    IN ULONG SecondsSince1970,
    IN PSMBCE_SERVER Server OPTIONAL,
    OUT PLARGE_INTEGER CurrentTime
    );


VOID
MRxSmbResumeAsyncReadWriteRequests(
    PRX_CONTEXT RxContext);

#endif // _SMBPSE_H_

