832 lines
30 KiB
C
832 lines
30 KiB
C
/*++ 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
|
|
|
|
Notes:
|
|
|
|
An exchange is the core abstarction on which the SMB connection engine and
|
|
the mini RDR are implemented. It encapsulates the notion of sending an SMB to
|
|
the server and receiving the associated response, i.e, exchanging an SMB and
|
|
hence the name.
|
|
|
|
The exchange of an SMB with the server involves the following steps ....
|
|
|
|
1) Submitting the formatted SMB buffer for transmission.
|
|
2) Processing a send complete indication which ensures that at the
|
|
transport level the SMB has been sent to the server.
|
|
3) Processing the receive indication which contains all/part of the
|
|
response sent by the server.
|
|
4) Copying additional data not indicated by the transport
|
|
|
|
There are a number of variations on this theme. For example there are certain
|
|
SMB's for which no response is expected, e.g., write mailslots and there are
|
|
certain SMB's which are inherently multi part in nature, TRANSACT smb's.
|
|
|
|
In addition the steps outlined above will not always happen in that order. The
|
|
precise sequence of events is dictated by the underlying transport chosen and
|
|
the network conditions. It is this dependency that makes the implementation
|
|
of exchanges challenging.
|
|
|
|
The two primary goals that the current implementation was designed for are (1)
|
|
performance and (2) encapsulation of transport dependencies. Goal(1) is
|
|
important because this constitutes an integral part of the code path for
|
|
exchanging any packet with the server. Goal (2) is important to ensure
|
|
customization of the Rdr for different transports. This encapsulation provides
|
|
a convenient vehicle for isolating SMB protocol level decisions from transport
|
|
level decisons as much as possible.
|
|
|
|
In addition the following goals were used to guide the implementation process ...
|
|
|
|
1) The exchange implementation must be able to handle asynchronous
|
|
operations and synchronous operations well. The trade offs were made in
|
|
favour of asynchronous operations as and when required.
|
|
|
|
2) Sufficient infrastructure support must be provided so as to ease the
|
|
implementation of different flavours of exchanges.
|
|
|
|
The SMB_EXCHANGE consists of a dispatch vector with the following functions
|
|
|
|
1) Start -- to initiate the exchange
|
|
2) Receive -- to handle response indications from the server
|
|
3) CopyDataHandler -- to handle portions of the response not indicated
|
|
4) SendCompletionHandler -- to handle send complete indications from the transport.
|
|
5) QuiescentStateHandler -- to handle transitions to a quiescent state, i.e., no
|
|
SMB connection engine operations are outstanding.
|
|
|
|
Most kinds of exchange use the QuiescentStateHandler to finalize the
|
|
operation and discard the exchange. However, certain kinds of exchanges
|
|
which implement the notion of a macro exchange, i.e., exchange multiple
|
|
SMB's use this to delineate different phases of the multiple exchange,
|
|
e.g., ORDINARY_EXCHANGE which implements most file io operations.
|
|
|
|
In addition to the dispatch vector the vanilla exchange consists of state
|
|
information to record the current state of the exchange, sufficient context
|
|
for resumption and context for handling SMB protocol related operations. The
|
|
SMB protocol requires that each SMB sent to the server be stamped with a MID
|
|
( multiplex id. ) in order to distinguish between concurrent SMB exchanges.
|
|
The connection engine provides this service.
|
|
|
|
The exchange also encapsulates a SMBCE_EXCHANGE_CONTEXT instance which
|
|
encapsulates all the information required for building a SMB_HEADER.
|
|
|
|
--*/
|
|
|
|
#ifndef _SMBXCHNG_H_
|
|
#define _SMBXCHNG_H_
|
|
|
|
typedef enum _SMBCE_STATE_ {
|
|
SMBCE_START_IN_PROGRESS,
|
|
SMBCE_STARTED,
|
|
SMBCE_STOP_IN_PROGRESS,
|
|
SMBCE_STOPPED
|
|
} SMBCE_STATE, *PSMBCE_STATE;
|
|
|
|
typedef struct _SMBCE_STARTSTOP_CONTEXT_ {
|
|
SMBCE_STATE State;
|
|
LONG ActiveExchanges;
|
|
KEVENT StopEvent;
|
|
PKEVENT pServerEntryTearDownEvent;
|
|
LIST_ENTRY SessionSetupRequests;
|
|
} SMBCE_STARTSTOP_CONTEXT, *PSMBCE_STARTSTOP_CONTEXT;
|
|
|
|
extern SMBCE_STARTSTOP_CONTEXT SmbCeStartStopContext;
|
|
|
|
//
|
|
// SMB_PROTOCOL_EXCHANGE dispatch vector function prototypes ..
|
|
//
|
|
|
|
// the initiator or the start routine
|
|
typedef
|
|
NTSTATUS
|
|
(*PSMB_EXCHANGE_START)(
|
|
IN struct _SMB_EXCHANGE *pExchange);
|
|
|
|
// The SMB receive handler
|
|
typedef
|
|
NTSTATUS
|
|
(*PSMB_EXCHANGE_IND_RECEIVE)(
|
|
IN struct _SMB_EXCHANGE *pExchange, // The exchange instance
|
|
IN ULONG BytesIndicated,
|
|
IN ULONG BytesAvailable,
|
|
OUT ULONG *BytesTaken,
|
|
IN PSMB_HEADER pSmbHeader,
|
|
OUT PMDL *pDataBufferPointer, // buffer to copy unindicated data
|
|
OUT PULONG pDataSize, // buffer size
|
|
IN ULONG ReceiveFlags
|
|
);
|
|
|
|
// the SMB xmit callback
|
|
typedef
|
|
NTSTATUS
|
|
(*PSMB_EXCHANGE_IND_SEND_CALLBACK)(
|
|
IN struct _SMB_EXCHANGE *pExchange, // The exchange instance
|
|
IN PMDL pDataBuffer,
|
|
IN NTSTATUS SendCompletionStatus
|
|
);
|
|
|
|
// the copy data callback for fetching large data
|
|
typedef
|
|
NTSTATUS
|
|
(*PSMB_EXCHANGE_IND_COPY_DATA_CALLBACK)(
|
|
IN struct _SMB_EXCHANGE *pExchange, // the exchange instance
|
|
IN PMDL pCopyDataBuffer, // the buffer
|
|
IN ULONG CopyDataSize // amount of data copied
|
|
);
|
|
|
|
// the finalization routine
|
|
// This particular routine has a signature that is NT specific the IRQL
|
|
// parameter that is passed in and the notion of posting. This helps consolidate
|
|
// the NT transport driver model of indications at DPC level in SmbCeFinalizeExchange.
|
|
// On WIN95 the lease restrictive value of IRQL can be passed in.
|
|
|
|
typedef
|
|
NTSTATUS
|
|
(*PSMB_EXCHANGE_FINALIZE)(
|
|
IN OUT struct _SMB_EXCHANGE *pExchange,
|
|
OUT BOOLEAN *pPostRequest);
|
|
|
|
typedef
|
|
NTSTATUS
|
|
(*PSMB_EXCHANGE_IND_ASSOCIATED_EXCHANGES_COMPLETION)(
|
|
IN OUT struct _SMB_EXCHANGE *pExchange,
|
|
OUT BOOLEAN *pPostRequest);
|
|
|
|
// The Exchange dispatch vector definition
|
|
|
|
typedef struct _SMB_EXCHANGE_DISPATCH_VECTOR_ {
|
|
PSMB_EXCHANGE_START Start;
|
|
PSMB_EXCHANGE_IND_RECEIVE Receive;
|
|
PSMB_EXCHANGE_IND_COPY_DATA_CALLBACK CopyDataHandler;
|
|
PSMB_EXCHANGE_IND_SEND_CALLBACK SendCompletionHandler;
|
|
PSMB_EXCHANGE_FINALIZE Finalize;
|
|
PSMB_EXCHANGE_IND_ASSOCIATED_EXCHANGES_COMPLETION AssociatedExchangesCompletionHandler;
|
|
} SMB_EXCHANGE_DISPATCH_VECTOR, *PSMB_EXCHANGE_DISPATCH_VECTOR;
|
|
|
|
// An enumerated type listing the type of exchanges
|
|
|
|
typedef enum _SMB_EXCHANGE_TYPE_ {
|
|
CONSTRUCT_NETROOT_EXCHANGE,
|
|
ORDINARY_EXCHANGE,
|
|
TRANSACT_EXCHANGE,
|
|
EXTENDED_SESSION_SETUP_EXCHANGE,
|
|
ADMIN_EXCHANGE,
|
|
SENTINEL_EXCHANGE
|
|
} SMB_EXCHANGE_TYPE, *PSMB_EXCHANGE_TYPE;
|
|
|
|
// known exchange type dispatch vectors
|
|
|
|
extern SMB_EXCHANGE_DISPATCH_VECTOR ConstructNetRootExchangeDispatch;
|
|
extern SMB_EXCHANGE_DISPATCH_VECTOR OrdinaryExchangeDispatch;
|
|
extern SMB_EXCHANGE_DISPATCH_VECTOR TransactExchangeDispatch;
|
|
|
|
// The various states of the exchange. Each exchange transitions from
|
|
// the SMBCE_EXCHANGE_INITIALIZATION_START to SMBCE_EXCHANGE_INITIATED or
|
|
// SMBCE_EXCHANGE_ABORTED state.
|
|
|
|
typedef enum _SMBCE_EXCHANGE_STATE_ {
|
|
SMBCE_EXCHANGE_INITIALIZATION_START,
|
|
SMBCE_EXCHANGE_SERVER_INITIALIZED,
|
|
SMBCE_EXCHANGE_SESSION_INITIALIZED,
|
|
SMBCE_EXCHANGE_NETROOT_INITIALIZED,
|
|
SMBCE_EXCHANGE_SECURITYBUFFER_INITIALIZED,
|
|
SMBCE_EXCHANGE_INITIATED,
|
|
SMBCE_EXCHANGE_ABORTED
|
|
} SMBCE_EXCHANGE_STATE, *PSMBCE_EXCHANGE_STATE;
|
|
|
|
// The exchange encapsulates the transport information from the clients. The
|
|
// Exchange engine is sandwiched between the protocol selection engine in the
|
|
// mini redirector on one side and the various transports on the other side.
|
|
// The transport information encapsulates the various categories of transport
|
|
// the exchange engine understands.
|
|
|
|
typedef struct SMBCE_EXCHANGE_TRANSPORT_INFORMATION {
|
|
union {
|
|
struct {
|
|
struct _SMBCE_VC *pVc;
|
|
} Vcs;
|
|
struct {
|
|
ULONG Dummy;
|
|
} Datagrams;
|
|
struct {
|
|
ULONG Dummy;
|
|
} Hybrid;
|
|
};
|
|
} SMBCE_EXCHANGE_TRANSPORT_CONTEXT,
|
|
*PSMBCE_EXCHANGE_TRANSPORT_CONTEXT;
|
|
|
|
typedef struct _SMBCE_EXCHANGE_CONTEXT_ {
|
|
PMRX_V_NET_ROOT pVNetRoot;
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
|
PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
|
|
SMBCE_EXCHANGE_TRANSPORT_CONTEXT TransportContext;
|
|
} SMBCE_EXCHANGE_CONTEXT,*PSMBCE_EXCHANGE_CONTEXT;
|
|
|
|
//
|
|
// Similar to the subclassing of SMB net roots the SMB_EXCHANGE will be subclassed
|
|
// further to deal with various types of SMB exchanges. SMB exchanges can be roughly
|
|
// classified into the following types based on the interactions involved ...
|
|
//
|
|
// The SMB's that need to be exchanged need to be augmented with some admin SMB's which
|
|
// are required for the maintenance of SMB's in the connection engine.
|
|
|
|
#define SMBCE_EXCHANGE_MID_VALID (0x00000001)
|
|
#define SMBCE_EXCHANGE_REUSE_MID (0x00000002)
|
|
#define SMBCE_EXCHANGE_RETAIN_MID (SMBCE_EXCHANGE_REUSE_MID)
|
|
#define SMBCE_EXCHANGE_MULTIPLE_SENDS_POSSIBLE (0x00000004)
|
|
#define SMBCE_EXCHANGE_FINALIZED (0x00000008)
|
|
|
|
#define SMBCE_EXCHANGE_ATTEMPT_RECONNECTS (0x00000010)
|
|
#define SMBCE_EXCHANGE_INDEFINITE_DELAY_IN_RESPONSE (0x00000020)
|
|
#define SMBCE_EXCHANGE_MAILSLOT_OPERATION (0x00000040)
|
|
|
|
#define SMBCE_EXCHANGE_SESSION_CONSTRUCTOR (0x00000100)
|
|
#define SMBCE_EXCHANGE_NETROOT_CONSTRUCTOR (0x00000200)
|
|
#define SMBCE_EXCHANGE_NOT_FROM_POOL (0x00000800)
|
|
|
|
#define SMBCE_EXCHANGE_TIMED_RECEIVE_OPERATION (0x00001000)
|
|
#define SMBCE_EXCHANGE_TIMEDOUT (0x00002000)
|
|
#define SMBCE_EXCHANGE_FULL_PROCESSID_SPECIFIED (0x00004000)
|
|
#define SMBCE_EXCHANGE_SMBCE_STOPPED (0x00008000)
|
|
|
|
#define SMBCE_EXCHANGE_SIGNATURE_BUFFER_ALLOCATED (0x01000000)
|
|
#define SMBCE_EXCHANGE_DEBUG_SYSCACHE (0x02000000)
|
|
|
|
#define SMBCE_ASSOCIATED_EXCHANGE (0x80000000)
|
|
#define SMBCE_ASSOCIATED_EXCHANGES_COMPLETION_HANDLER_ACTIVATED (0x40000000)
|
|
|
|
#define SMBCE_EXCHANGE_FLAGS_TO_PRESERVE (SMBCE_EXCHANGE_NOT_FROM_POOL)
|
|
|
|
#define SMBCE_OPLOCK_RESPONSE_MID (0xffff)
|
|
#define SMBCE_MAILSLOT_OPERATION_MID (0xffff)
|
|
#define SMBCE_ECHO_PROBE_MID (0xfffe)
|
|
|
|
//
|
|
// The cancellation status is defined as a PVOID instead of a BOOLEAN to allow
|
|
// us the use of Interlocked manipulation instructions
|
|
// There are only two states SMBCE_EXCHANGE_CANCELLED, SMBCE_EXCHANGE_ACTIVE
|
|
//
|
|
|
|
#define SMBCE_EXCHANGE_CANCELLED (0xcccccccc)
|
|
#define SMBCE_EXCHANGE_NOT_CANCELLED (0xaaaaaaaa)
|
|
|
|
// The Exchange definition
|
|
|
|
typedef struct _SMB_EXCHANGE {
|
|
union {
|
|
UCHAR Type;
|
|
struct {
|
|
NODE_TYPE_CODE NodeTypeCode; // node type.
|
|
NODE_BYTE_SIZE NodeByteSize; // node size.
|
|
LONG ReferenceCount;
|
|
};
|
|
};
|
|
|
|
LIST_ENTRY SmbMmInUseListEntry;
|
|
|
|
PRX_CONTEXT RxContext; //use of these two fields is advisory
|
|
PVOID LastExecutingThread; //OE and Xact will use them
|
|
|
|
union {
|
|
NTSTATUS SmbStatus;
|
|
PMRX_SMB_SRV_OPEN SmbSrvOpen;
|
|
};
|
|
NTSTATUS Status;
|
|
|
|
ULONG ServerVersion;
|
|
SMB_EXCHANGE_ID Id;
|
|
|
|
USHORT SmbCeState;
|
|
|
|
USHORT MidCookie;
|
|
SMB_MPX_ID Mid;
|
|
|
|
LONG CancellationStatus;
|
|
|
|
ULONG SmbCeFlags;
|
|
SMBCE_EXCHANGE_CONTEXT SmbCeContext;
|
|
|
|
LONG SendCompletePendingOperations;
|
|
LONG CopyDataPendingOperations;
|
|
LONG ReceivePendingOperations;
|
|
LONG LocalPendingOperations;
|
|
|
|
PKEVENT pSmbCeSynchronizationEvent;
|
|
|
|
LIST_ENTRY ExchangeList;
|
|
LARGE_INTEGER ExpiryTime;
|
|
|
|
PSMB_EXCHANGE_DISPATCH_VECTOR pDispatchVector;
|
|
|
|
union {
|
|
struct {
|
|
struct _SMB_EXCHANGE *pMasterExchange;
|
|
SINGLE_LIST_ENTRY NextAssociatedExchange;
|
|
} Associated;
|
|
struct {
|
|
SINGLE_LIST_ENTRY AssociatedExchangesToBeFinalized;
|
|
LONG PendingAssociatedExchanges;
|
|
} Master;
|
|
};
|
|
|
|
RX_WORK_QUEUE_ITEM WorkQueueItem;
|
|
|
|
PVOID BufferForServerResponse; //For Security Signature verification
|
|
PMDL MdlForServerResponse; //temporarily hold the entire message for security
|
|
//signature checking.
|
|
ULONG SmbSecuritySignatureIndex;
|
|
ULONG ExchangeTransportInitialized;
|
|
NTSTATUS SessionSetupStatus;
|
|
BOOLEAN IsOffLineFile;
|
|
BOOLEAN IsSecuritySignatureEnabled;
|
|
BOOLEAN SecuritySignatureReturned;
|
|
UCHAR SmbCommand;
|
|
LIST_ENTRY CancelledList;
|
|
} SMB_EXCHANGE, *PSMB_EXCHANGE;
|
|
|
|
|
|
INLINE PSMBCEDB_SERVER_ENTRY
|
|
SmbCeGetExchangeServerEntry(PVOID pExchange)
|
|
{
|
|
PSMB_EXCHANGE pSmbExchange = (PSMB_EXCHANGE)pExchange;
|
|
|
|
ASSERT(pSmbExchange->SmbCeContext.pServerEntry != NULL);
|
|
|
|
return pSmbExchange->SmbCeContext.pServerEntry;
|
|
}
|
|
|
|
INLINE PSMBCE_SERVER
|
|
SmbCeGetExchangeServer(PVOID pExchange)
|
|
{
|
|
PSMB_EXCHANGE pSmbExchange = (PSMB_EXCHANGE)pExchange;
|
|
|
|
return &(pSmbExchange->SmbCeContext.pServerEntry->Server);
|
|
}
|
|
|
|
INLINE PSMBCEDB_SESSION_ENTRY
|
|
SmbCeGetExchangeSessionEntry(PVOID pExchange)
|
|
{
|
|
PSMB_EXCHANGE pSmbExchange = (PSMB_EXCHANGE)pExchange;
|
|
|
|
if (pSmbExchange->SmbCeContext.pVNetRootContext != NULL) {
|
|
return pSmbExchange->SmbCeContext.pVNetRootContext->pSessionEntry;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
INLINE PSMBCE_SESSION
|
|
SmbCeGetExchangeSession(PVOID pExchange)
|
|
{
|
|
PSMB_EXCHANGE pSmbExchange = (PSMB_EXCHANGE)pExchange;
|
|
|
|
if (pSmbExchange->SmbCeContext.pVNetRootContext != NULL) {
|
|
return &(pSmbExchange->SmbCeContext.pVNetRootContext->pSessionEntry->Session);
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
INLINE PSMBCEDB_NET_ROOT_ENTRY
|
|
SmbCeGetExchangeNetRootEntry(PVOID pExchange)
|
|
{
|
|
PSMB_EXCHANGE pSmbExchange = (PSMB_EXCHANGE)pExchange;
|
|
|
|
if (pSmbExchange->SmbCeContext.pVNetRootContext != NULL) {
|
|
return pSmbExchange->SmbCeContext.pVNetRootContext->pNetRootEntry;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
INLINE PSMBCE_NET_ROOT
|
|
SmbCeGetExchangeNetRoot(PVOID pExchange)
|
|
{
|
|
PSMB_EXCHANGE pSmbExchange = (PSMB_EXCHANGE)pExchange;
|
|
|
|
if (pSmbExchange->SmbCeContext.pVNetRootContext != NULL) {
|
|
return &(pSmbExchange->SmbCeContext.pVNetRootContext->pNetRootEntry->NetRoot);
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
INLINE PMRX_V_NET_ROOT
|
|
SmbCeGetExchangeVNetRoot(PVOID pExchange)
|
|
{
|
|
PSMB_EXCHANGE pSmbExchange = (PSMB_EXCHANGE)pExchange;
|
|
|
|
return pSmbExchange->SmbCeContext.pVNetRoot;
|
|
}
|
|
|
|
INLINE PSMBCE_V_NET_ROOT_CONTEXT
|
|
SmbCeGetExchangeVNetRootContext(PVOID pExchange)
|
|
{
|
|
PSMB_EXCHANGE pSmbExchange = (PSMB_EXCHANGE)pExchange;
|
|
|
|
return pSmbExchange->SmbCeContext.pVNetRootContext;
|
|
}
|
|
|
|
extern ULONG SmbCeTraceExchangeReferenceCount;
|
|
|
|
// The following functions ( inline, macros and otherwise ) are defined
|
|
// to manipulate the exchanges
|
|
|
|
// The reset exchange macro provides a mechanism for forcing the exchange
|
|
// instance to a well known start state. This is used by the protocol
|
|
// selection engine to transceive different SMB's. A note of caution --
|
|
// ensure that the conditions are O.K for initialization. There is no well
|
|
// known mechanism in the exchange engine to prevent overwriting an
|
|
// exchange instance while in use.
|
|
|
|
#define SmbCeResetExchange(pExchange) \
|
|
(pExchange)->SmbCeFlags &= ~SMBCE_EXCHANGE_FINALIZED; \
|
|
(pExchange)->ReceivePendingOperations = 0; \
|
|
(pExchange)->CopyDataPendingOperations = 0; \
|
|
(pExchange)->SendCompletePendingOperations = 0; \
|
|
(pExchange)->LocalPendingOperations = 0; \
|
|
(pExchange)->Status = STATUS_SUCCESS; \
|
|
(pExchange)->SmbStatus = STATUS_SUCCESS
|
|
|
|
// The following macros provide a mechanism for referencing and dereferencing
|
|
// the exchange. The reference count provides a mechanism for detecting
|
|
// when an exchange instance can be safely discarded. The reference count
|
|
// differs from the pending operations count maintained in the exchange
|
|
// which are used to detect when a quiescent state is reached.
|
|
|
|
#define SmbCeReferenceExchange(pExchange) \
|
|
InterlockedIncrement(&(pExchange)->ReferenceCount); \
|
|
if (SmbCeTraceExchangeReferenceCount) { \
|
|
DbgPrint("Reference Exchange %lx Type(%ld) %s %ld %ld\n", \
|
|
(pExchange), \
|
|
(pExchange)->Type, \
|
|
__FILE__, \
|
|
__LINE__, \
|
|
(pExchange)->ReferenceCount); \
|
|
}
|
|
|
|
#define SmbCeDereferenceExchange(pExchange) \
|
|
InterlockedDecrement(&(pExchange)->ReferenceCount); \
|
|
if (SmbCeTraceExchangeReferenceCount) { \
|
|
DbgPrint("Dereference Exchange %lx Type(%ld) %s %ld %ld\n", \
|
|
(pExchange), \
|
|
(pExchange)->Type, \
|
|
__FILE__, \
|
|
__LINE__, \
|
|
(pExchange)->ReferenceCount); \
|
|
}
|
|
|
|
|
|
#define SmbCeDereferenceAndDiscardExchange(pExchange) \
|
|
if (InterlockedDecrement(&(pExchange)->ReferenceCount) == 0) { \
|
|
SmbCeDiscardExchange(pExchange); \
|
|
} \
|
|
if (SmbCeTraceExchangeReferenceCount) { \
|
|
DbgPrint("Dereference Exchange %lx Type(%ld) %s %ld %ld\n", \
|
|
(pExchange), \
|
|
(pExchange)->Type, \
|
|
__FILE__, \
|
|
__LINE__, \
|
|
(pExchange)->ReferenceCount); \
|
|
}
|
|
|
|
// Macros to hide the syntactic details of dereferencing and calling a
|
|
// routine in a dispatch vector. These macros are purely intended for
|
|
// use in the connection engine only and is not meant for use by
|
|
// other modules.
|
|
|
|
#define SMB_EXCHANGE_DISPATCH(pExchange,Routine,Arguments) \
|
|
(*((pExchange)->pDispatchVector->Routine))##Arguments
|
|
|
|
#define SMB_EXCHANGE_POST(pExchange,Routine) \
|
|
RxPostToWorkerThread(&(pExchange)->WorkItem.WorkQueueItem, \
|
|
(pExchange)->pDispatchVector->Routine, \
|
|
(pExchange))
|
|
|
|
// The following enum type defines the result of invoking the finalization routine
|
|
// on an exchange instance.
|
|
|
|
typedef enum _SMBCE_EXCHANGE_STATUS_ {
|
|
SmbCeExchangeAlreadyFinalized,
|
|
SmbCeExchangeFinalized,
|
|
SmbCeExchangeNotFinalized
|
|
} SMBCE_EXCHANGE_STATUS, *PSMBCE_EXCHANGE_STATUS;
|
|
|
|
// The pending operations associated with an exchange are classified into four kinds
|
|
// Receive operations, Copy Data Operations, Send Complete and Local operations.
|
|
// These need to be incremented under the protection of a spinlock. However they
|
|
// are decremented in the absence of a spinlock ( with the respective assert ).
|
|
|
|
|
|
#define SMBCE_LOCAL_OPERATION 0x1
|
|
#define SMBCE_SEND_COMPLETE_OPERATION 0x2
|
|
#define SMBCE_COPY_DATA_OPERATION 0x4
|
|
#define SMBCE_RECEIVE_OPERATION 0x8
|
|
|
|
extern NTSTATUS
|
|
SmbCeIncrementPendingOperations(
|
|
PSMB_EXCHANGE pExchange,
|
|
ULONG PendingOperationsMask,
|
|
PVOID FileName,
|
|
ULONG FileLine);
|
|
|
|
extern NTSTATUS
|
|
SmbCeDecrementPendingOperations(
|
|
PSMB_EXCHANGE pExchange,
|
|
ULONG PendingOperationsMask,
|
|
PVOID FileName,
|
|
ULONG FileLine);
|
|
|
|
extern SMBCE_EXCHANGE_STATUS
|
|
SmbCeDecrementPendingOperationsAndFinalize(
|
|
PSMB_EXCHANGE pExchange,
|
|
ULONG PendingOperationsMask,
|
|
PVOID FileName,
|
|
ULONG FileLine);
|
|
|
|
// the pending operations increment routines
|
|
|
|
#define SmbCeIncrementPendingReceiveOperations(pExchange) \
|
|
SmbCeIncrementPendingOperations(pExchange,(SMBCE_RECEIVE_OPERATION),__FILE__,__LINE__)
|
|
|
|
#define SmbCeIncrementPendingSendCompleteOperations(pExchange) \
|
|
SmbCeIncrementPendingOperations(pExchange,(SMBCE_SEND_COMPLETE_OPERATION),__FILE__,__LINE__)
|
|
|
|
#define SmbCeIncrementPendingCopyDataOperations(pExchange) \
|
|
SmbCeIncrementPendingOperations(pExchange,(SMBCE_COPY_DATA_OPERATION),__FILE__,__LINE__)
|
|
|
|
#define SmbCeIncrementPendingLocalOperations(pExchange) \
|
|
SmbCeIncrementPendingOperations(pExchange,(SMBCE_LOCAL_OPERATION),__FILE__,__LINE__)
|
|
|
|
// The pending operations decrement routines
|
|
// Note the special casing of ReceivePendingOperations since it is the only one
|
|
// that can be forced by a disconnect indication. There are two variations in
|
|
// the decrement macros. The first flavour is to be used when it can be
|
|
// guaranteed that the decrement operation will not lead to the finalization
|
|
// of the exchange and the second is to be used when we cannot ensure the criterion
|
|
// for the first. The difference between the two is that it eliminates
|
|
// acquisition/release of a spinlock.
|
|
|
|
#define SmbCeDecrementPendingReceiveOperations(pExchange) \
|
|
SmbCeDecrementPendingOperations(pExchange,(SMBCE_RECEIVE_OPERATION),__FILE__,__LINE__)
|
|
|
|
#define SmbCeDecrementPendingSendCompleteOperations(pExchange) \
|
|
SmbCeDecrementPendingOperations(pExchange,(SMBCE_SEND_COMPLETE_OPERATION),__FILE__,__LINE__)
|
|
|
|
#define SmbCeDecrementPendingCopyDataOperations(pExchange) \
|
|
SmbCeDecrementPendingOperations(pExchange,(SMBCE_COPY_DATA_OPERATION),__FILE__,__LINE__)
|
|
|
|
#define SmbCeDecrementPendingLocalOperations(pExchange) \
|
|
SmbCeDecrementPendingOperations(pExchange,(SMBCE_LOCAL_OPERATION),__FILE__,__LINE__)
|
|
|
|
// The pending operations decrement routines
|
|
|
|
#define SmbCeDecrementPendingReceiveOperationsAndFinalize(pExchange) \
|
|
SmbCeDecrementPendingOperationsAndFinalize(pExchange,(SMBCE_RECEIVE_OPERATION),__FILE__,__LINE__)
|
|
|
|
#define SmbCeDecrementPendingSendCompleteOperationsAndFinalize(pExchange) \
|
|
SmbCeDecrementPendingOperationsAndFinalize(pExchange,(SMBCE_SEND_COMPLETE_OPERATION),__FILE__,__LINE__)
|
|
|
|
#define SmbCeDecrementPendingCopyDataOperationsAndFinalize(pExchange) \
|
|
SmbCeDecrementPendingOperationsAndFinalize(pExchange,(SMBCE_COPY_DATA_OPERATION),__FILE__,__LINE__)
|
|
|
|
#define SmbCeDecrementPendingLocalOperationsAndFinalize(pExchange) \
|
|
SmbCeDecrementPendingOperationsAndFinalize(pExchange,(SMBCE_LOCAL_OPERATION),__FILE__,__LINE__)
|
|
|
|
//
|
|
// This is the pid that will be used by the rdr; rdr1 used 0xcafe.
|
|
// only this pid is ever sent except for nt<-->nt creates. in these cases,
|
|
// we have to send the full 32bit process id for RPC. actually, we only have to do
|
|
// for pipes but we do it all the time instead.
|
|
//
|
|
|
|
#define MRXSMB_PROCESS_ID (0xfeff)
|
|
|
|
INLINE VOID
|
|
SmbCeSetFullProcessIdInHeader(
|
|
PSMB_EXCHANGE pExchange,
|
|
ULONG ProcessId,
|
|
PNT_SMB_HEADER pNtSmbHeader)
|
|
{
|
|
pExchange->SmbCeFlags |= SMBCE_EXCHANGE_FULL_PROCESSID_SPECIFIED;
|
|
SmbPutUshort(&pNtSmbHeader->Pid, (USHORT)((ProcessId) & 0xFFFF));
|
|
SmbPutUshort(&pNtSmbHeader->PidHigh, (USHORT)((ProcessId) >> 16));
|
|
}
|
|
|
|
// The exchange engine API, for creation and manipulation of exchange instances
|
|
|
|
// Initialization/Creation of an exchange instance
|
|
|
|
extern NTSTATUS
|
|
SmbCepInitializeExchange(
|
|
PSMB_EXCHANGE *pExchangePointer,
|
|
PRX_CONTEXT pRxContext,
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry,
|
|
PMRX_V_NET_ROOT pVNetRoot,
|
|
SMB_EXCHANGE_TYPE ExchangeType,
|
|
PSMB_EXCHANGE_DISPATCH_VECTOR pDispatchVector);
|
|
|
|
|
|
INLINE NTSTATUS
|
|
SmbCeInitializeExchange(
|
|
PSMB_EXCHANGE *pExchangePointer,
|
|
PRX_CONTEXT pRxContext,
|
|
PMRX_V_NET_ROOT pVNetRoot,
|
|
SMB_EXCHANGE_TYPE ExchangeType,
|
|
PSMB_EXCHANGE_DISPATCH_VECTOR pDispatchVector)
|
|
{
|
|
return SmbCepInitializeExchange(
|
|
pExchangePointer,
|
|
pRxContext,
|
|
NULL,
|
|
pVNetRoot,
|
|
ExchangeType,
|
|
pDispatchVector);
|
|
}
|
|
|
|
INLINE NTSTATUS
|
|
SmbCeInitializeExchange2(
|
|
PSMB_EXCHANGE *pExchangePointer,
|
|
PRX_CONTEXT pRxContext,
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry,
|
|
SMB_EXCHANGE_TYPE ExchangeType,
|
|
PSMB_EXCHANGE_DISPATCH_VECTOR pDispatchVector)
|
|
{
|
|
return SmbCepInitializeExchange(
|
|
pExchangePointer,
|
|
pRxContext,
|
|
pServerEntry,
|
|
NULL,
|
|
ExchangeType,
|
|
pDispatchVector);
|
|
}
|
|
|
|
|
|
extern NTSTATUS
|
|
SmbCeInitializeAssociatedExchange(
|
|
PSMB_EXCHANGE *pAssociatedExchangePointer,
|
|
PSMB_EXCHANGE pMasterExchange,
|
|
SMB_EXCHANGE_TYPE Type,
|
|
PSMB_EXCHANGE_DISPATCH_VECTOR pDispatchVector);
|
|
|
|
// converting one type of exchange to another
|
|
|
|
extern NTSTATUS
|
|
SmbCeTransformExchange(
|
|
PSMB_EXCHANGE pExchange,
|
|
SMB_EXCHANGE_TYPE NewType,
|
|
PSMB_EXCHANGE_DISPATCH_VECTOR pDispatchVector);
|
|
|
|
// Initiating an exchange
|
|
|
|
extern NTSTATUS
|
|
SmbCeInitiateExchange(PSMB_EXCHANGE pExchange);
|
|
|
|
extern NTSTATUS
|
|
SmbCeInitiateAssociatedExchange(
|
|
PSMB_EXCHANGE pAssociatedExchange,
|
|
BOOLEAN EnableCompletionHandlerInMasterExchange);
|
|
|
|
// Resuming an exchange
|
|
|
|
extern NTSTATUS
|
|
SmbCeResumeExchange(PSMB_EXCHANGE pExchange);
|
|
|
|
// aborting an initiated exchange
|
|
|
|
extern NTSTATUS
|
|
SmbCeAbortExchange(PSMB_EXCHANGE pExchange);
|
|
|
|
// discarding an exchnge instance
|
|
|
|
extern VOID
|
|
SmbCeDiscardExchange(PVOID pExchange);
|
|
|
|
// In addition to providing a flexible mechanism for exchanging packets with
|
|
// the server the exchange engine also provides a mechanism for building and
|
|
// parsing SMB_HEADER's. This functionality is built into the connection
|
|
// engine because the meta data in the headers is used to update the connection
|
|
// engine database.
|
|
|
|
// building SMB headers
|
|
|
|
extern NTSTATUS
|
|
SmbCeBuildSmbHeader(
|
|
IN OUT PSMB_EXCHANGE pExchange,
|
|
IN OUT PVOID pBuffer,
|
|
IN ULONG BufferLength,
|
|
OUT PULONG pRemainingBuffer,
|
|
OUT PUCHAR pLastCommandInHeader,
|
|
OUT PUCHAR *pNextCommand);
|
|
|
|
// parsing SMB headers.
|
|
|
|
extern NTSTATUS
|
|
SmbCeParseSmbHeader(
|
|
PSMB_EXCHANGE pExchange,
|
|
PSMB_HEADER pSmbHeader,
|
|
PGENERIC_ANDX pCommandToProcess,
|
|
NTSTATUS *pSmbResponseStatus,
|
|
ULONG BytesAvailable,
|
|
ULONG BytesIndicated,
|
|
PULONG pBytesConsumed);
|
|
|
|
|
|
// The following routines are intended for use in the connection engine only.
|
|
|
|
extern NTSTATUS
|
|
MRxSmbInitializeSmbCe();
|
|
|
|
extern NTSTATUS
|
|
MRxSmbTearDownSmbCe();
|
|
|
|
extern NTSTATUS
|
|
SmbCePrepareExchangeForReuse(PSMB_EXCHANGE pExchange);
|
|
|
|
extern PVOID
|
|
SmbCeMapSendBufferToCompletionContext(
|
|
PSMB_EXCHANGE pExchange,
|
|
PVOID pBuffer);
|
|
|
|
extern PVOID
|
|
SmbCeMapSendCompletionContextToBuffer(
|
|
PSMB_EXCHANGE pExchange,
|
|
PVOID pContext);
|
|
|
|
|
|
extern SMBCE_EXCHANGE_STATUS
|
|
SmbCeFinalizeExchange(PSMB_EXCHANGE pExchange);
|
|
|
|
extern VOID
|
|
SmbCeFinalizeExchangeOnDisconnect(
|
|
PSMB_EXCHANGE pExchange);
|
|
|
|
extern NTSTATUS
|
|
SmbCeReferenceServer(
|
|
PSMB_EXCHANGE pExchange);
|
|
|
|
|
|
extern NTSTATUS
|
|
SmbCeIncrementActiveExchangeCount();
|
|
|
|
extern VOID
|
|
SmbCeDecrementActiveExchangeCount();
|
|
|
|
extern VOID
|
|
SmbCeSetExpiryTime(
|
|
PSMB_EXCHANGE pExchange);
|
|
|
|
extern BOOLEAN
|
|
SmbCeDetectExpiredExchanges(
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry);
|
|
|
|
extern VOID
|
|
SmbCepFinalizeAssociatedExchange(
|
|
PSMB_EXCHANGE pExchange);
|
|
|
|
extern NTSTATUS
|
|
SmbCeCancelExchange(
|
|
PRX_CONTEXT pRxContext);
|
|
|
|
typedef struct _SMB_CONSTRUCT_NETROOT_EXCHANGE_ {
|
|
union {
|
|
SMB_EXCHANGE;
|
|
SMB_EXCHANGE Exchange;
|
|
};
|
|
SMB_TREE_ID TreeId;
|
|
SMB_USER_ID UserId;
|
|
BOOLEAN fUpdateDefaultSessionEntry;
|
|
BOOLEAN fInitializeNetRoot;
|
|
PMRX_NETROOT_CALLBACK NetRootCallback;
|
|
PMDL pSmbRequestMdl;
|
|
PMDL pSmbResponseMdl;
|
|
PVOID pSmbActualBuffer; // Originally allocated buffer
|
|
PVOID pSmbBuffer; // Start of header
|
|
PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext;
|
|
CSC_SHARE_HANDLE hShare;
|
|
} SMB_CONSTRUCT_NETROOT_EXCHANGE, *PSMB_CONSTRUCT_NETROOT_EXCHANGE;
|
|
|
|
extern
|
|
NTSTATUS
|
|
GetSmbResponseNtStatus(
|
|
IN PSMB_HEADER pSmbHeader,
|
|
IN PSMB_EXCHANGE pExchange
|
|
);
|
|
|
|
extern CHAR InitialSecuritySignature[];
|
|
|
|
#endif // _SMBXCHNG_H_
|
|
|
|
|