/*++ BUILD Version: 0009    // Increment this if a change has global effects

Copyright (c) 1987-1993  Microsoft Corporation

Module Name:

    smbcxchng.h

Abstract:

    This is the include file that defines all constants and types for
    SMB exchange implementation.

Author:

    Balan Sethu Raman (SethuR) 06-Feb-95    Created

--*/

#ifndef _TRANSACT_H_
#define _TRANSACT_H_

typedef enum _TRANSACT_EXCHANGE_STATE_ {
   TRANSACT_EXCHANGE_START,
   TRANSACT_EXCHANGE_ERROR,
   TRANSACT_EXCHANGE_SUCCESS,
   TRANSACT_EXCHANGE_TRANSMITTED_PRIMARY_REQUEST,
   TRANSACT_EXCHANGE_RECEIVED_INTERIM_RESPONSE,
   TRANSACT_EXCHANGE_TRANSMITTED_SECONDARY_REQUESTS,
   TRANSACT_EXCHANGE_RECEIVED_PRIMARY_RESPONSE
} TRANSACT_EXCHANGE_STATE, *PTRANSACT_EXCHANGE_STATE;

typedef struct _SMB_TRANSACTION_RESUMPTION_CONTEXT{
    struct _SMB_TRANSACT_EXCHANGE *pTransactExchange;
    SMBCE_RESUMPTION_CONTEXT SmbCeResumptionContext;
    ULONG SetupBytesReceived;
    ULONG DataBytesReceived;
    ULONG ParameterBytesReceived;
    NTSTATUS FinalStatusFromServer;
    ULONG ServerVersion;
} SMB_TRANSACTION_RESUMPTION_CONTEXT, *PSMB_TRANSACTION_RESUMPTION_CONTEXT;

#define TRAILING_BYTES_BUFFERSIZE 8
typedef struct _SMB_TRANSACT_EXCHANGE {
    SMB_EXCHANGE;

    TRANSACT_EXCHANGE_STATE State;

    // Client supplied parameters for the transact exchange
    //PRX_CONTEXT             RxContext;
    PMDL            pSendDataMdl;
    ULONG                   SendDataBufferSize;
    ULONG                   DataBytesSent;
    PMDL            pReceiveDataMdl;
    ULONG                   ReceiveDataBufferSize;
    ULONG                   DataBytesReceived;
    PMDL            pSendParamMdl; //used if we cannot subsume
    PVOID                   pSendParamBuffer;
    ULONG                   SendParamBufferSize;
    ULONG                   ParamBytesSent;
    PMDL            pReceiveParamMdl;
    ULONG                   ReceiveParamBufferSize;
    ULONG                   ParamBytesReceived;
    PVOID                   pSendSetupMdl;
    ULONG                   SendSetupBufferSize;
    PMDL            pReceiveSetupMdl;
    ULONG                   ReceiveSetupBufferSize;
    ULONG                   SetupBytesReceived;

    // Transact exchange intrinsic fields
    ULONG                     PrimaryRequestSmbSize;
    PVOID                     pActualPrimaryRequestSmbHeader;     // Original buffer allocated
    PSMB_HEADER               pPrimaryRequestSmbHeader;           // Start of header
    ULONG                     ParameterBytesSeen;
    ULONG                     DataBytesSeen;
    LONG                      PendingCopyRequests;    //CODE.IMPROVEMENT this field is useless
    BOOLEAN                   fParamsSubsumedInPrimaryRequest;
    UCHAR                     TransactSmbCommand;
    USHORT                    Flags;
    USHORT                    NtTransactFunction;
    SMB_FILE_ID               Fid;           //CODE.IMPROVEMENT is this used?
    ULONG                     TransactionNameLength;
    ULONG                     MaximumTransmitSmbBufferSize;
                                 //used to cache value and also to force
                                 //smaller value for testing
    PSMB_TRANSACTION_RESUMPTION_CONTEXT pResumptionContext;

    struct {
        MDL  TrailingBytesMdl;
        ULONG Pages[3]; //you need 2...one pad; this must cover an smbbuf
    };
    NTSTATUS SaveTheRealStatus;
    PVOID    DiscardBuffer;
    struct {
        ULONG Bytes[TRAILING_BYTES_BUFFERSIZE/sizeof(ULONG)];
    } TrailingBytesBuffer;
} SMB_TRANSACT_EXCHANGE, *PSMB_TRANSACT_EXCHANGE;

typedef struct SMB_TRANSACTION_PARAMETERS {
   USHORT Flags;
   USHORT SetupLength;      // the steup buffer length
   union {
      PVOID pSetup;         // the setup buffer
      PMDL  pSetupMdl;      // the MDL version of the buffer
   };
   ULONG ParamLength;
   PVOID pParam;            //you need the bufptr is you're subsuming
   PMDL  pParamMdl;         //you need the MDL is you can't subsume
   PMDL  pDataMdl;          // the data buffer
   ULONG DataLength;        // this is total length...not the length
                            // of the 1st mdl in the chain
} SMB_TRANSACTION_PARAMETERS, *PSMB_TRANSACTION_PARAMETERS;

typedef SMB_TRANSACTION_PARAMETERS          SMB_TRANSACTION_SEND_PARAMETERS;
typedef SMB_TRANSACTION_SEND_PARAMETERS*    PSMB_TRANSACTION_SEND_PARAMETERS;
typedef SMB_TRANSACTION_PARAMETERS          SMB_TRANSACTION_RECEIVE_PARAMETERS;
typedef SMB_TRANSACTION_RECEIVE_PARAMETERS* PSMB_TRANSACTION_RECEIVE_PARAMETERS;

#define SMBCE_DEFAULT_TRANSACTION_TIMEOUT (0xffffffff)
#define SMBCE_TRANSACTION_TIMEOUT_NOT_USED (0x0)

typedef struct SMB_TRANSACTION_OPTIONS {
   USHORT     NtTransactFunction;
   USHORT     Flags;
   PUNICODE_STRING pTransactionName;
   ULONG      TimeoutIntervalInMilliSeconds;
   ULONG      MaximumTransmitSmbBufferSize;
} SMB_TRANSACTION_OPTIONS, *PSMB_TRANSACTION_OPTIONS;

#define DEFAULT_TRANSACTION_OPTIONS {0,0,NULL,SMBCE_TRANSACTION_TIMEOUT_NOT_USED,0xffff}
extern SMB_TRANSACTION_OPTIONS RxDefaultTransactionOptions;

#define TRANSACTION_SEND_PARAMETERS_FLAG    (0x1)
#define TRANSACTION_RECEIVE_PARAMETERS_FLAG (0x2)

// xact and xact_options have the same flags so we have to be careful to strip off these bits
// when we format up the smb ( the flags field is a USHORT)
#define SMB_XACT_FLAGS_REPARSE                      (0x8000)
#define SMB_XACT_FLAGS_FID_NOT_NEEDED               (0x4000)
#define SMB_XACT_FLAGS_CALLERS_SENDDATAMDL          (0x2000)
#define SMB_XACT_FLAGS_TID_FOR_FID                  (0x1000)
#define SMB_XACT_FLAGS_MAILSLOT_OPERATION           (0x0800)
#define SMB_XACT_FLAGS_INDEFINITE_DELAY_IN_RESPONSE (0x0400)
#define SMB_XACT_FLAGS_DFS_AWARE                    (0x0200)
#define SMB_XACT_FLAGS_ASYNCHRONOUS                 (0x0100)
//#define SMB_XACT_FLAGS_COPY_ON_ERROR                (0x080)

#define SMB_XACT_INTERNAL_FLAGS_MASK               \
            ( SMB_XACT_FLAGS_REPARSE               \
              | SMB_XACT_FLAGS_FID_NOT_NEEDED      \
              | SMB_XACT_FLAGS_CALLERS_SENDDATAMDL \
              | SMB_XACT_FLAGS_TID_FOR_FID         \
              | SMB_XACT_FLAGS_MAILSLOT_OPERATION  \
              | SMB_XACT_FLAGS_INDEFINITE_DELAY_IN_RESPONSE \
              | SMB_XACT_FLAGS_DFS_AWARE                    \
              | SMB_XACT_FLAGS_ASYNCHRONOUS                 \
            )
#if 0
//CODE.IMROVEMENT.POSTPDC the constant SMB_TRANSACTION_VALID_FLAGS should be
//in smb.h. SMB_TRANSACTION_RECONNECTING and SMB_TRANSACTION_DFSFILE should NOT
//be in SMB.h. here is what's there now
#define SMB_TRANSACTION_DISCONNECT 1
#define SMB_TRANSACTION_NO_RESPONSE 2
#define SMB_TRANSACTION_RECONNECTING 4
#define SMB_TRANSACTION_DFSFILE 8
#endif

#define SMB_TRANSACTION_VALID_FLAGS (\
        SMB_TRANSACTION_DISCONNECT   \
     |  SMB_TRANSACTION_NO_RESPONSE  \
   )

#if ((SMB_XACT_INTERNAL_FLAGS_MASK & SMB_TRANSACTION_VALID_FLAGS) != 0)
#error SMB_XACT_INTERNAL_FLAGS_MASK has overrun the transact flags
#endif

extern NTSTATUS
SmbCeInitializeTransactionParameters(
   PVOID  pSetup,
   USHORT SetupLength,
   PVOID  pParam,
   ULONG  ParamLength,
   PVOID  pData,
   ULONG  DataLength,
   PSMB_TRANSACTION_PARAMETERS pTransactionParameters);

#define SmbCeProvideTransactionDataAsMdl(pTransactionParameters,pMdl,Length) { \
          ASSERT( (pTransactionParameters)->DataLength == 0 );                   \
          ASSERT( (pTransactionParameters)->pDataMdl == NULL );                  \
          ASSERT( FlagOn((pTransactionParameters)->Flags,TRANSACTION_SEND_PARAMETERS_FLAG) ); \
          (pTransactionParameters)->DataLength = Length;                         \
          (pTransactionParameters)->pDataMdl = pMdl;                             \
          (pTransactionParameters)->Flags |= SMB_XACT_FLAGS_CALLERS_SENDDATAMDL;    \
  }

extern VOID
SmbCeUninitializeTransactionParameters(
   PSMB_TRANSACTION_PARAMETERS pTransactionParameters);

extern VOID
SmbCeDiscardTransactExchange(PSMB_TRANSACT_EXCHANGE pTransactExchange);

INLINE NTSTATUS
SmbCeInitializeTransactionSendParameters(
      PVOID  pSetup,
      USHORT SetupLength,
      PVOID  pParam,
      ULONG  ParamLength,
      PVOID  pData,
      ULONG  DataLength,
      PSMB_TRANSACTION_SEND_PARAMETERS pSendParameters)
{
   ((PSMB_TRANSACTION_PARAMETERS)pSendParameters)->Flags = TRANSACTION_SEND_PARAMETERS_FLAG;
   return SmbCeInitializeTransactionParameters(
                pSetup,SetupLength,pParam,ParamLength,pData,DataLength,pSendParameters);

}

INLINE NTSTATUS
SmbCeInitializeTransactionReceiveParameters(
      PVOID  pSetup,
      USHORT SetupLength,
      PVOID  pParam,
      ULONG  ParamLength,
      PVOID  pData,
      ULONG  DataLength,
      PSMB_TRANSACTION_RECEIVE_PARAMETERS pReceiveParameters)
{
   ((PSMB_TRANSACTION_PARAMETERS)pReceiveParameters)->Flags = TRANSACTION_RECEIVE_PARAMETERS_FLAG;
   return SmbCeInitializeTransactionParameters(
                pSetup,SetupLength,pParam,ParamLength,pData,DataLength,pReceiveParameters);

}

#define SmbCeUninitializeTransactionSendParameters(pSendParameters)  \
        ASSERT((pSendParameters)->Flags & TRANSACTION_SEND_PARAMETERS_FLAG); \
        SmbCeUninitializeTransactionParameters(pSendParameters);

#define SmbCeUninitializeTransactionReceiveParameters(pReceiveParameters)  \
        ASSERT((pReceiveParameters)->Flags & TRANSACTION_RECEIVE_PARAMETERS_FLAG); \
        SmbCeUninitializeTransactionParameters(pReceiveParameters)

INLINE VOID
SmbCeInitializeTransactionResumptionContext(
   PSMB_TRANSACTION_RESUMPTION_CONTEXT ptResumptionContext)
{
   SmbCeInitializeResumptionContext(&(ptResumptionContext)->SmbCeResumptionContext);
   ptResumptionContext->SetupBytesReceived = 0;
   ptResumptionContext->DataBytesReceived = 0;
   ptResumptionContext->ParameterBytesReceived = 0;
   ptResumptionContext->FinalStatusFromServer = (STATUS_SUCCESS);
}

INLINE VOID
SmbCeInitializeAsynchronousTransactionResumptionContext(
   PSMB_TRANSACTION_RESUMPTION_CONTEXT ptResumptionContext,
   PRX_WORKERTHREAD_ROUTINE            pResumptionRoutine,
   PVOID                               pResumptionRoutineParam)
{
   SmbCeInitializeAsynchronousResumptionContext(
        &ptResumptionContext->SmbCeResumptionContext,
        pResumptionRoutine,
        pResumptionRoutineParam);

   ptResumptionContext->SetupBytesReceived     = 0;
   ptResumptionContext->DataBytesReceived      = 0;
   ptResumptionContext->ParameterBytesReceived = 0;
   ptResumptionContext->FinalStatusFromServer  = (STATUS_SUCCESS);
}

INLINE VOID
SmbCeWaitOnTransactionResumptionContext(
   PSMB_TRANSACTION_RESUMPTION_CONTEXT pTransactionResumptionContext)
{
   SmbCeSuspend(&pTransactionResumptionContext->SmbCeResumptionContext);
}


extern UNICODE_STRING s_NamedPipeTransactionName;
extern UNICODE_STRING s_MailSlotTransactionName;

extern NTSTATUS
SmbCeSubmitTransactionRequest(
   PRX_CONTEXT                 RxContext,
   PSMB_TRANSACTION_OPTIONS    pOptions,
   PSMB_TRANSACTION_PARAMETERS pSendParameters,
   PSMB_TRANSACTION_PARAMETERS pReceiveParameters,
   PSMB_TRANSACTION_RESUMPTION_CONTEXT   pResumptionContext );

extern NTSTATUS
_SmbCeTransact(
   PRX_CONTEXT                         RxContext,
   PSMB_TRANSACTION_OPTIONS            pOptions,
   PVOID                               pInputSetupBuffer,
   ULONG                               InputSetupBufferlength,
   PVOID                               pOutputSetupBuffer,
   ULONG                               OutputSetupBufferLength,
   PVOID                               pInputParamBuffer,
   ULONG                               InputParamBufferLength,
   PVOID                               pOutputParamBuffer,
   ULONG                               OutputParamBufferLength,
   PVOID                               pInputDataBuffer,
   ULONG                               InputDataBufferLength,
   PVOID                               pOutputDataBuffer,
   ULONG                               OutputDataBufferLength,
   PSMB_TRANSACTION_RESUMPTION_CONTEXT pResumptionContext);


INLINE NTSTATUS
SmbCeTransact(
   PRX_CONTEXT                         RxContext,
   PSMB_TRANSACTION_OPTIONS            pOptions,
   PVOID                               pInputSetupBuffer,
   ULONG                               InputSetupBufferlength,
   PVOID                               pOutputSetupBuffer,
   ULONG                               OutputSetupBufferLength,
   PVOID                               pInputParamBuffer,
   ULONG                               InputParamBufferLength,
   PVOID                               pOutputParamBuffer,
   ULONG                               OutputParamBufferLength,
   PVOID                               pInputDataBuffer,
   ULONG                               InputDataBufferLength,
   PVOID                               pOutputDataBuffer,
   ULONG                               OutputDataBufferLength,
   PSMB_TRANSACTION_RESUMPTION_CONTEXT pResumptionContext)
{
   SmbCeInitializeTransactionResumptionContext(pResumptionContext);

   return _SmbCeTransact(
               RxContext,
               pOptions,
               pInputSetupBuffer,
               InputSetupBufferlength,
               pOutputSetupBuffer,
               OutputSetupBufferLength,
               pInputParamBuffer,
               InputParamBufferLength,
               pOutputParamBuffer,
               OutputParamBufferLength,
               pInputDataBuffer,
               InputDataBufferLength,
               pOutputDataBuffer,
               OutputDataBufferLength,
               pResumptionContext);
}

INLINE NTSTATUS
SmbCeAsynchronousTransact(
   PRX_CONTEXT                         RxContext,
   PSMB_TRANSACTION_OPTIONS            pOptions,
   PVOID                               pInputSetupBuffer,
   ULONG                               InputSetupBufferlength,
   PVOID                               pOutputSetupBuffer,
   ULONG                               OutputSetupBufferLength,
   PVOID                               pInputParamBuffer,
   ULONG                               InputParamBufferLength,
   PVOID                               pOutputParamBuffer,
   ULONG                               OutputParamBufferLength,
   PVOID                               pInputDataBuffer,
   ULONG                               InputDataBufferLength,
   PVOID                               pOutputDataBuffer,
   ULONG                               OutputDataBufferLength,
   PSMB_TRANSACTION_RESUMPTION_CONTEXT pResumptionContext)
{
    pOptions->Flags |= SMB_XACT_FLAGS_ASYNCHRONOUS;
    return _SmbCeTransact(
               RxContext,
               pOptions,
               pInputSetupBuffer,
               InputSetupBufferlength,
               pOutputSetupBuffer,
               OutputSetupBufferLength,
               pInputParamBuffer,
               InputParamBufferLength,
               pOutputParamBuffer,
               OutputParamBufferLength,
               pInputDataBuffer,
               InputDataBufferLength,
               pOutputDataBuffer,
               OutputDataBufferLength,
               pResumptionContext);
}

#endif // _TRANSACT_H_

