3607 lines
143 KiB
C
3607 lines
143 KiB
C
/*++ BUILD Version: 0009 // Increment this if a change has global effects
|
|
Copyright (c) 1987-1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
transact.c
|
|
|
|
Abstract:
|
|
|
|
This file conatins the implementation of the transact exchange.
|
|
|
|
Author:
|
|
|
|
Balan Sethu Raman (SethuR) 06-Feb-95 Created
|
|
|
|
Revision:
|
|
|
|
Joe Linn (JoeLi) -- Revise multiple packet implementation
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#include "align.h"
|
|
#pragma warning(error:4100) // Unreferenced formal parameter
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, SmbCeInitializeTransactionParameters)
|
|
#pragma alloc_text(PAGE, SmbCeUninitializeTransactionParameters)
|
|
#pragma alloc_text(PAGE, SmbCeDiscardTransactExchange)
|
|
#pragma alloc_text(PAGE, SmbCeSubmitTransactionRequest)
|
|
#pragma alloc_text(PAGE, _SmbCeTransact)
|
|
#pragma alloc_text(PAGE, SmbTransactBuildHeader)
|
|
#pragma alloc_text(PAGE, SmbTransactExchangeStart)
|
|
#pragma alloc_text(PAGE, SmbTransactExchangeAbort)
|
|
#pragma alloc_text(PAGE, SmbTransactExchangeErrorHandler)
|
|
#pragma alloc_text(PAGE, SmbTransactExchangeSendCallbackHandler)
|
|
#pragma alloc_text(PAGE, SmbCeInitializeTransactExchange)
|
|
#pragma alloc_text(PAGE, SendSecondaryRequests)
|
|
#endif
|
|
|
|
//#define SET_DONTSUBSUME_PARAMS
|
|
#ifdef SET_DONTSUBSUME_PARAMS
|
|
ULONG MRxSmbDontSubsumeParams = 1;
|
|
#else
|
|
ULONG MRxSmbDontSubsumeParams = 0;
|
|
#endif
|
|
#if DBG
|
|
#define DONTSUBSUME_PARAMS MRxSmbDontSubsumeParams
|
|
#else
|
|
#define DONTSUBSUME_PARAMS FALSE
|
|
#endif
|
|
|
|
SMB_TRANSACTION_OPTIONS RxDefaultTransactionOptions = DEFAULT_TRANSACTION_OPTIONS;
|
|
|
|
RXDT_DefineCategory(TRANSACT);
|
|
#define Dbg (DEBUG_TRACE_TRANSACT)
|
|
|
|
#define MIN(x,y) ((x) < (y) ? (x) : (y))
|
|
|
|
#define SMB_TRANSACT_MAXIMUM_PARAMETER_SIZE (0xffff)
|
|
#define SMB_TRANSACT_MAXIMUM_DATA_SIZE (0xffff)
|
|
|
|
typedef struct _SMB_TRANSACT_RESP_FORMAT_DESCRIPTION {
|
|
ULONG WordCount;
|
|
ULONG TotalParameterCount;
|
|
ULONG TotalDataCount;
|
|
ULONG ParameterCount;
|
|
ULONG ParameterOffset;
|
|
ULONG ParameterDisplacement;
|
|
ULONG DataCount;
|
|
ULONG DataOffset;
|
|
ULONG DataDisplacement;
|
|
ULONG ByteCount;
|
|
ULONG ApparentMsgLength;
|
|
} SMB_TRANSACT_RESP_FORMAT_DESCRIPTION, *PSMB_TRANSACT_RESP_FORMAT_DESCRIPTION;
|
|
|
|
NTSTATUS
|
|
SmbTransactAccrueAndValidateFormatData(
|
|
IN struct _SMB_TRANSACT_EXCHANGE *pTransactExchange, // The exchange instance
|
|
IN PSMB_HEADER pSmbHeader,
|
|
IN ULONG BytesIndicated,
|
|
OUT PSMB_TRANSACT_RESP_FORMAT_DESCRIPTION Format
|
|
);
|
|
|
|
extern NTSTATUS
|
|
SmbTransactExchangeFinalize(
|
|
PSMB_EXCHANGE pExchange,
|
|
BOOLEAN *pPostFinalize);
|
|
|
|
extern NTSTATUS
|
|
ParseTransactResponse(
|
|
IN struct _SMB_TRANSACT_EXCHANGE *pTransactExchange, // The exchange instance
|
|
IN PSMB_TRANSACT_RESP_FORMAT_DESCRIPTION Format,
|
|
IN ULONG BytesIndicated,
|
|
IN ULONG BytesAvailable,
|
|
OUT ULONG *pBytesTaken,
|
|
IN PSMB_HEADER pSmbHeader,
|
|
OUT PMDL *pCopyRequestMdlPointer,
|
|
OUT PULONG pCopyRequestSize);
|
|
|
|
|
|
extern NTSTATUS
|
|
SendSecondaryRequests(PVOID pContext);
|
|
|
|
extern NTSTATUS
|
|
SmbCeInitializeTransactExchange(
|
|
PSMB_TRANSACT_EXCHANGE pTransactExchange,
|
|
PRX_CONTEXT RxContext,
|
|
PSMB_TRANSACTION_OPTIONS pOptions,
|
|
PSMB_TRANSACTION_SEND_PARAMETERS pSendParameters,
|
|
PSMB_TRANSACTION_RECEIVE_PARAMETERS pReceiveParameters,
|
|
PSMB_TRANSACTION_RESUMPTION_CONTEXT pResumptionContext);
|
|
|
|
NTSTATUS
|
|
SmbCeInitializeTransactionParameters(
|
|
PVOID pSetup,
|
|
USHORT SetupLength,
|
|
PVOID pParam,
|
|
ULONG ParamLength,
|
|
PVOID pData,
|
|
ULONG DataLength,
|
|
PSMB_TRANSACTION_PARAMETERS pTransactionParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the transaction parameters
|
|
|
|
Arguments:
|
|
|
|
pSetup - the setup buffer
|
|
|
|
SetupLength - the setup buffer length
|
|
|
|
pParam - the param buffer
|
|
|
|
ParamLength - the param buffer length
|
|
|
|
pData - the data buffer
|
|
|
|
DataLength - the data buffer length
|
|
|
|
pTransactionParameters - the transaction parameters instance
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
|
|
The TRANSACTION parameters come in two flavours -- the send parameters for the data
|
|
that is to be sent to the server and the receive parameters for receiving the data
|
|
from the server. There is one subtle difference in the way in which the parameters are
|
|
stored and referenced in these two cases. In the send case the Setup buffer is stored
|
|
as a pointer itself while in the receive case it is stored in the form of a MDL.
|
|
|
|
This is because the SMB protocol requires that the Header + setup information for a
|
|
transaction request cannot be greated then the maximum SMB buffer size, i.e., setup
|
|
information cannot spill to a secondary request. The buffer that is allocated for the
|
|
header is made sufficiently large enough to hold the setup data as well. On the other
|
|
hand the receives are handled in a two phase manner, -- the indication at the DPC
|
|
level followed by a copy data request if required. In order to avoid having to transition
|
|
between DPC level and a worker thread the MDL's for the buffers are eagerly evaluated.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PMDL pSetupMdl = NULL;
|
|
PMDL pParamMdl = NULL;
|
|
PMDL pDataMdl = NULL;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (pTransactionParameters->Flags & TRANSACTION_RECEIVE_PARAMETERS_FLAG) {
|
|
if ((pSetup != NULL) && (SetupLength > 0)) {
|
|
pSetupMdl = RxAllocateMdl(pSetup,SetupLength);
|
|
if (pSetupMdl == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else {
|
|
RxProbeAndLockPages(pSetupMdl,KernelMode,IoModifyAccess,Status);
|
|
if ((Status != RX_MAP_STATUS(SUCCESS))) {
|
|
IoFreeMdl(pSetupMdl);
|
|
pSetupMdl = NULL;
|
|
} else {
|
|
if (MmGetSystemAddressForMdlSafe(pSetupMdl,LowPagePriority) == NULL) { //this maps the Mdl
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((Status == RX_MAP_STATUS(SUCCESS)) && (pParam != NULL) && (ParamLength > 0)) {
|
|
pParamMdl = RxAllocateMdl(pParam,ParamLength);
|
|
if (pParamMdl == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else {
|
|
RxProbeAndLockPages(pParamMdl,KernelMode,IoModifyAccess,Status);
|
|
if ((Status != RX_MAP_STATUS(SUCCESS))) {
|
|
IoFreeMdl(pParamMdl);
|
|
pParamMdl = NULL;
|
|
} else {
|
|
if (MmGetSystemAddressForMdlSafe(pParamMdl,LowPagePriority) == NULL) { //this maps the Mdl
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pTransactionParameters->SetupLength = SetupLength;
|
|
pTransactionParameters->ParamLength = ParamLength;
|
|
pTransactionParameters->pParamMdl = pParamMdl;
|
|
pTransactionParameters->pSetupMdl = pSetupMdl;
|
|
} else {
|
|
pTransactionParameters->SetupLength = SetupLength;
|
|
pTransactionParameters->pSetup = pSetup;
|
|
pTransactionParameters->ParamLength = ParamLength;
|
|
pTransactionParameters->pParam = pParam;
|
|
pTransactionParameters->pParamMdl = NULL;
|
|
}
|
|
|
|
ASSERT( !((pData == NULL)&&(DataLength!=0)) );
|
|
if ((Status == RX_MAP_STATUS(SUCCESS)) && (pData != NULL) && (DataLength > 0)) {
|
|
pDataMdl = RxAllocateMdl(pData,DataLength);
|
|
if (pDataMdl == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else {
|
|
RxProbeAndLockPages(pDataMdl,KernelMode,IoModifyAccess,Status);
|
|
if ((Status != RX_MAP_STATUS(SUCCESS))) {
|
|
IoFreeMdl(pDataMdl);
|
|
pDataMdl = NULL;
|
|
} else {
|
|
if (MmGetSystemAddressForMdlSafe(pDataMdl,LowPagePriority) == NULL) { //this maps the Mdl
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pTransactionParameters->pDataMdl = pDataMdl;
|
|
pTransactionParameters->DataLength = DataLength;
|
|
ASSERT((Status != RX_MAP_STATUS(SUCCESS)) || (DataLength == 0) || (pDataMdl != NULL));
|
|
|
|
if ((Status != RX_MAP_STATUS(SUCCESS))) {
|
|
if (pTransactionParameters->Flags & TRANSACTION_RECEIVE_PARAMETERS_FLAG) {
|
|
if (pSetupMdl != NULL) {
|
|
MmUnlockPages(pSetupMdl); //this unmaps as well
|
|
IoFreeMdl(pSetupMdl);
|
|
}
|
|
|
|
if (pParamMdl != NULL) {
|
|
MmUnlockPages(pParamMdl);
|
|
IoFreeMdl(pParamMdl);
|
|
}
|
|
}
|
|
|
|
if (pDataMdl != NULL) {
|
|
MmUnlockPages(pDataMdl);
|
|
IoFreeMdl(pDataMdl);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
SmbCeUninitializeTransactionParameters(
|
|
PSMB_TRANSACTION_PARAMETERS pTransactionParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine uninitializes the transaction parameters, i.e., free the associated MDL's
|
|
|
|
Arguments:
|
|
|
|
pTransactionParameters - the parameter instance for uninitialization
|
|
|
|
--*/
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (pTransactionParameters->Flags & TRANSACTION_RECEIVE_PARAMETERS_FLAG) {
|
|
if (pTransactionParameters->pSetupMdl != NULL) {
|
|
MmUnlockPages(pTransactionParameters->pSetupMdl);
|
|
IoFreeMdl(pTransactionParameters->pSetupMdl);
|
|
}
|
|
}
|
|
|
|
if (pTransactionParameters->pParamMdl != NULL) {
|
|
MmUnlockPages(pTransactionParameters->pParamMdl);
|
|
IoFreeMdl(pTransactionParameters->pParamMdl);
|
|
}
|
|
|
|
if (pTransactionParameters->pDataMdl != NULL
|
|
&& !BooleanFlagOn(pTransactionParameters->Flags,SMB_XACT_FLAGS_CALLERS_SENDDATAMDL)) {
|
|
MmUnlockPages(pTransactionParameters->pDataMdl);
|
|
IoFreeMdl(pTransactionParameters->pDataMdl);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
SmbCeDiscardTransactExchange(PSMB_TRANSACT_EXCHANGE pTransactExchange)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine discards a transact exchange
|
|
|
|
Arguments:
|
|
|
|
pExchange - the exchange instance
|
|
|
|
--*/
|
|
{
|
|
PSMB_TRANSACTION_RESUMPTION_CONTEXT pResumptionContext;
|
|
|
|
PAGED_CODE();
|
|
|
|
// Deallocate any transact exchange specfic allocations ...
|
|
if (pTransactExchange->pActualPrimaryRequestSmbHeader != NULL) {
|
|
RxFreePool(pTransactExchange->pActualPrimaryRequestSmbHeader);
|
|
}
|
|
|
|
if (pTransactExchange->pReceiveSetupMdl != NULL) {
|
|
MmUnlockPages(pTransactExchange->pReceiveSetupMdl);
|
|
IoFreeMdl(pTransactExchange->pReceiveSetupMdl);
|
|
}
|
|
|
|
if (pTransactExchange->pReceiveParamMdl != NULL) {
|
|
MmUnlockPages(pTransactExchange->pReceiveParamMdl);
|
|
IoFreeMdl(pTransactExchange->pReceiveParamMdl);
|
|
}
|
|
|
|
if (pTransactExchange->pReceiveDataMdl != NULL) {
|
|
MmUnlockPages(pTransactExchange->pReceiveDataMdl);
|
|
IoFreeMdl(pTransactExchange->pReceiveDataMdl);
|
|
}
|
|
|
|
if (pTransactExchange->pSendSetupMdl != NULL) {
|
|
MmUnlockPages(pTransactExchange->pSendSetupMdl);
|
|
IoFreeMdl(pTransactExchange->pSendSetupMdl);
|
|
}
|
|
|
|
if ((pTransactExchange->pSendDataMdl != NULL) &&
|
|
!BooleanFlagOn(pTransactExchange->Flags,SMB_XACT_FLAGS_CALLERS_SENDDATAMDL)) {
|
|
MmUnlockPages(pTransactExchange->pSendDataMdl);
|
|
IoFreeMdl(pTransactExchange->pSendDataMdl);
|
|
}
|
|
|
|
if (pTransactExchange->pSendParamMdl != NULL) {
|
|
MmUnlockPages(pTransactExchange->pSendParamMdl);
|
|
IoFreeMdl(pTransactExchange->pSendParamMdl);
|
|
}
|
|
|
|
if ((pResumptionContext = pTransactExchange->pResumptionContext) != NULL) {
|
|
NTSTATUS FinalStatus;
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry((PSMB_EXCHANGE)pTransactExchange);
|
|
|
|
RxDbgTrace(0, Dbg,
|
|
("SmbCeTransactExchangeFinalize: everythings is good! parambytes (%ld) databytes (%ld)\n",
|
|
pTransactExchange->ParamBytesReceived, pTransactExchange->DataBytesReceived
|
|
));
|
|
|
|
FinalStatus = pTransactExchange->Status;
|
|
|
|
if (pTransactExchange->Status != STATUS_SUCCESS) {
|
|
FinalStatus = CscTransitionVNetRootForDisconnectedOperation(
|
|
pTransactExchange->RxContext,
|
|
SmbCeGetExchangeVNetRoot(pTransactExchange),
|
|
pTransactExchange->Status);
|
|
}
|
|
else if (pTransactExchange->SmbStatus != STATUS_SUCCESS)
|
|
{
|
|
FinalStatus = CscTransitionVNetRootForDisconnectedOperation(
|
|
pTransactExchange->RxContext,
|
|
SmbCeGetExchangeVNetRoot(pTransactExchange),
|
|
pTransactExchange->SmbStatus);
|
|
|
|
}
|
|
|
|
if (pServerEntry->ServerStatus != STATUS_SUCCESS &&
|
|
!SmbCeIsServerInDisconnectedMode(pServerEntry) &&
|
|
!FlagOn(pTransactExchange->SmbCeFlags,SMBCE_EXCHANGE_MAILSLOT_OPERATION)) {
|
|
// If the server entry is in error state, the transact cannot receive a response from server.
|
|
// In this case, we return the server status.
|
|
pResumptionContext->FinalStatusFromServer = pServerEntry->ServerStatus;
|
|
} else {
|
|
// If the server entry is in good or disconnected state, we return the smb status.
|
|
pResumptionContext->FinalStatusFromServer = pTransactExchange->SmbStatus;
|
|
}
|
|
|
|
if ((FinalStatus == STATUS_SUCCESS)||
|
|
(FinalStatus == STATUS_MORE_PROCESSING_REQUIRED)) {
|
|
|
|
FinalStatus = pResumptionContext->FinalStatusFromServer;
|
|
}
|
|
|
|
pResumptionContext->SmbCeResumptionContext.Status = FinalStatus;
|
|
pResumptionContext->SetupBytesReceived = pTransactExchange->SetupBytesReceived;
|
|
pResumptionContext->DataBytesReceived = pTransactExchange->DataBytesReceived;
|
|
pResumptionContext->ParameterBytesReceived = pTransactExchange->ParamBytesReceived;
|
|
pResumptionContext->ServerVersion = pTransactExchange->ServerVersion;
|
|
|
|
SmbCeResume(&pResumptionContext->SmbCeResumptionContext);
|
|
}
|
|
|
|
SmbCeDereferenceAndDiscardExchange((PSMB_EXCHANGE)pTransactExchange);
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbCeSubmitTransactionRequest(
|
|
PRX_CONTEXT RxContext,
|
|
PSMB_TRANSACTION_OPTIONS pOptions,
|
|
PSMB_TRANSACTION_PARAMETERS pSendParameters,
|
|
PSMB_TRANSACTION_PARAMETERS pReceiveParameters,
|
|
PSMB_TRANSACTION_RESUMPTION_CONTEXT pResumptionContext )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine submits a transaction request, i.e., allocates/initializes a transaction
|
|
exchange, sets up the completion information and initiates it
|
|
|
|
Arguments:
|
|
|
|
pNetRoot - the netroot for which the transaction request is intended
|
|
|
|
pOptions - the transaction options
|
|
|
|
pSendParameters - the transaction parameters to be sent to the server
|
|
|
|
pReceiveParameters - the transaction results from the server
|
|
|
|
pResumptionContext - the context for resuming the local activity on completion of the
|
|
transaction
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
STATUS_PENDING -- if the transcation was initiated successfully
|
|
Other error codes if the request could not be submitted successfully
|
|
|
|
Notes:
|
|
|
|
Whenever a status of STATUS_PENDING is returned it implies that the transact
|
|
exchange has assumed ownership of the MDLs passed in as receive and send
|
|
parameters. They will be released on completion of the exchange.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
RxCaptureFcb;
|
|
RxCaptureFobx;
|
|
|
|
PMRX_V_NET_ROOT pVNetRoot = NULL;
|
|
|
|
PSMB_TRANSACT_EXCHANGE pTransactExchange;
|
|
PSMB_EXCHANGE pExchange = NULL;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (capFobx == NULL) {
|
|
if (RxContext->MajorFunction == IRP_MJ_CREATE) {
|
|
pVNetRoot = RxContext->Create.pVNetRoot;
|
|
}
|
|
} else {
|
|
// These are the root objects which are associated with the device FCB. In
|
|
// such cases
|
|
|
|
pVNetRoot = (PMRX_V_NET_ROOT)capFobx;
|
|
|
|
if (NodeType(pVNetRoot) != RDBSS_NTC_V_NETROOT) {
|
|
pVNetRoot = capFobx->pSrvOpen->pVNetRoot;
|
|
}
|
|
}
|
|
|
|
if (pVNetRoot == NULL) {
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
|
|
|
pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
|
|
|
|
// Allocate and initialize an exchange for the given net root.
|
|
Status = SmbCeInitializeExchange2(
|
|
&pExchange,
|
|
RxContext,
|
|
pServerEntry,
|
|
TRANSACT_EXCHANGE,
|
|
&TransactExchangeDispatch);
|
|
} else {
|
|
// Allocate and initialize an exchange for the given net root.
|
|
Status = SmbCeInitializeExchange(
|
|
&pExchange,
|
|
RxContext,
|
|
pVNetRoot,
|
|
TRANSACT_EXCHANGE,
|
|
&TransactExchangeDispatch);
|
|
}
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
// Initialize the transact exchange
|
|
pTransactExchange = (PSMB_TRANSACT_EXCHANGE)pExchange;
|
|
|
|
Status = SmbCeInitializeTransactExchange(
|
|
pTransactExchange,
|
|
RxContext,
|
|
pOptions,
|
|
pSendParameters,
|
|
pReceiveParameters,
|
|
pResumptionContext);
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
// The transact exchange can be either asynchronous or synchronous. In
|
|
// the asynchronous case an additional reference is taken which is
|
|
// passed onto the caller alongwith the exchange squirelled away in the
|
|
// RX_CONTEXT if STATUS_PENDING is being returned. This enables the
|
|
// caller to control when the exchange is discarded. This works
|
|
// especially well in dealing with cancellation of asynchronous
|
|
// exchanges.
|
|
|
|
// This reference will be accounted for by the finalization routine
|
|
// of the transact exchange.
|
|
SmbCeReferenceExchange((PSMB_EXCHANGE)pTransactExchange);
|
|
|
|
if (BooleanFlagOn(pOptions->Flags,SMB_XACT_FLAGS_ASYNCHRONOUS)) {
|
|
// The corresponding dereference is the callers responsibility
|
|
SmbCeReferenceExchange((PSMB_EXCHANGE)pTransactExchange);
|
|
}
|
|
|
|
if (pTransactExchange->Flags & SMB_XACT_FLAGS_MAILSLOT_OPERATION) {
|
|
pTransactExchange->SmbCeFlags |= SMBCE_EXCHANGE_MAILSLOT_OPERATION;
|
|
}
|
|
|
|
pResumptionContext->pTransactExchange = pTransactExchange;
|
|
pResumptionContext->SmbCeResumptionContext.Status = STATUS_SUCCESS;
|
|
|
|
SmbCeIncrementPendingLocalOperations(pExchange);
|
|
|
|
// Initiate the exchange
|
|
Status = SmbCeInitiateExchange(pExchange);
|
|
|
|
if (Status != STATUS_PENDING) {
|
|
pExchange->Status = Status;
|
|
|
|
if (pExchange->SmbStatus == STATUS_SUCCESS) {
|
|
pExchange->SmbStatus = Status;
|
|
}
|
|
|
|
if (BooleanFlagOn(pOptions->Flags,SMB_XACT_FLAGS_ASYNCHRONOUS)) {
|
|
PMRXSMB_RX_CONTEXT pMRxSmbContext = MRxSmbGetMinirdrContext(RxContext);
|
|
|
|
pMRxSmbContext->pExchange = NULL;
|
|
|
|
// Since the exchange has already been completed there is no
|
|
// point in returning the additional reference to the caller
|
|
SmbCeDereferenceExchange((PSMB_EXCHANGE)pTransactExchange);
|
|
}
|
|
}
|
|
|
|
SmbCeDecrementPendingLocalOperationsAndFinalize(pExchange);
|
|
|
|
// Map the status to STATUS_PENDING so that continuation routines
|
|
// do not attempt to finalize.
|
|
Status = STATUS_PENDING;
|
|
} else {
|
|
PMRXSMB_RX_CONTEXT MRxSmbContext = MRxSmbGetMinirdrContext(RxContext);
|
|
|
|
ASSERT(MRxSmbContext->pExchange == pExchange);
|
|
MRxSmbContext->pExchange = NULL;
|
|
|
|
SmbCeDiscardExchange(pExchange);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
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)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine implements a standardized mechanism of submitting transaction requests,
|
|
and synchronizing with their completion. This does not provide the smae amount of control
|
|
that SmbCeSubmitTransactRequest provides. Nevertheless, this implements a common mechanism
|
|
that should satisfy most needs
|
|
|
|
Arguments:
|
|
|
|
RxContext - the context for the transaction
|
|
|
|
pOptions - the transaction options
|
|
|
|
pSetupBuffer - the transaction setup buffer
|
|
|
|
SetupBufferlength - the setup buffer length
|
|
|
|
pInputParamBuffer - the Input param buffer
|
|
|
|
InputParamBufferLength - the input param buffer length
|
|
|
|
pOutputParamBuffer - the output param buffer
|
|
|
|
OutputParamBufferlength - the output param buffer length
|
|
|
|
pInputDataBuffer - the Input data buffer
|
|
|
|
InputDataBufferLength - the input data buffer length
|
|
|
|
pOutputDataBuffer - the output data buffer
|
|
|
|
OutputDataBufferlength - the output data buffer length
|
|
|
|
pResumptionContext - the transaction resumption context
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
STATUS_SUCCESS if successfull.
|
|
Other error codes if the request could not be submitted successfully
|
|
|
|
Notes:
|
|
|
|
In the case of asynchronous exchanges if STATUS_PENDING is returned the
|
|
Exchange instance is squirelled away in the minirdr context associated with
|
|
the given RX_CONTEXT instance. This exchange will not be discarded without
|
|
the callers intervention. It is the callers responsibility to invoke
|
|
SmbCeDereferenceAndDiscardExchange to discard the exchange
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
SMB_TRANSACTION_SEND_PARAMETERS SendParameters;
|
|
SMB_TRANSACTION_RECEIVE_PARAMETERS ReceiveParameters;
|
|
BOOLEAN fAsynchronous;
|
|
|
|
PAGED_CODE();
|
|
|
|
fAsynchronous = BooleanFlagOn(pOptions->Flags,SMB_XACT_FLAGS_ASYNCHRONOUS);
|
|
|
|
Status = SmbCeInitializeTransactionSendParameters(
|
|
pInputSetupBuffer,
|
|
(USHORT)InputSetupBufferLength,
|
|
pInputParamBuffer,
|
|
InputParamBufferLength,
|
|
pInputDataBuffer,
|
|
InputDataBufferLength,
|
|
&SendParameters);
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
Status = SmbCeInitializeTransactionReceiveParameters(
|
|
pOutputSetupBuffer, // the setup information expected in return
|
|
(USHORT)OutputSetupBufferLength, // the length of the setup information
|
|
pOutputParamBuffer, // the buffer for the param information
|
|
OutputParamBufferLength, // the length of the param buffer
|
|
pOutputDataBuffer, // the buffer for data
|
|
OutputDataBufferLength, // the length of the buffer
|
|
&ReceiveParameters);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
SmbCeUninitializeTransactionSendParameters(&SendParameters);
|
|
}
|
|
}
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
Status = SmbCeSubmitTransactionRequest(
|
|
RxContext, // the RXContext for the transaction
|
|
pOptions, // transaction options
|
|
&SendParameters, // input parameters
|
|
&ReceiveParameters, // expected results
|
|
pResumptionContext // the context for resumption.
|
|
);
|
|
|
|
if ((Status != STATUS_SUCCESS) &&
|
|
(Status != STATUS_PENDING)) {
|
|
SmbCeUninitializeTransactionReceiveParameters(&ReceiveParameters);
|
|
SmbCeUninitializeTransactionSendParameters(&SendParameters);
|
|
} else {
|
|
if (!fAsynchronous) {
|
|
if (Status == STATUS_PENDING) {
|
|
SmbCeWaitOnTransactionResumptionContext(pResumptionContext);
|
|
Status = pResumptionContext->SmbCeResumptionContext.Status;
|
|
if (Status != STATUS_SUCCESS) {
|
|
RxDbgTrace(0,Dbg,("SmbCeTransact: Transaction Request Completion Status %lx\n",Status));
|
|
}
|
|
} else if (Status != STATUS_SUCCESS) {
|
|
RxDbgTrace(0,Dbg,("SmbCeTransact: SmbCeSubmitTransactRequest returned %lx\n",Status));
|
|
} else {
|
|
Status = pResumptionContext->SmbCeResumptionContext.Status;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ASSERT(fAsynchronous || (Status != STATUS_PENDING));
|
|
|
|
if (fAsynchronous && (Status != STATUS_PENDING)) {
|
|
pResumptionContext->SmbCeResumptionContext.Status = Status;
|
|
pResumptionContext->FinalStatusFromServer = Status;
|
|
SmbCeResume(&pResumptionContext->SmbCeResumptionContext);
|
|
Status = STATUS_PENDING;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbTransactBuildHeader(
|
|
PSMB_TRANSACT_EXCHANGE pTransactExchange,
|
|
UCHAR SmbCommand,
|
|
PSMB_HEADER pHeader)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine builds the SMB header for transact exchanges
|
|
|
|
Arguments:
|
|
|
|
pTransactExchange - the exchange instance
|
|
|
|
SmbCommand - the SMB command
|
|
|
|
pHeader - the SMB buffer header
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG BufferConsumed;
|
|
|
|
UCHAR LastCommandInHeader;
|
|
PUCHAR pCommand;
|
|
|
|
PAGED_CODE();
|
|
|
|
// Initialize the SMB header ...
|
|
Status = SmbCeBuildSmbHeader(
|
|
(PSMB_EXCHANGE)pTransactExchange,
|
|
pHeader,
|
|
sizeof(SMB_HEADER),
|
|
&BufferConsumed,
|
|
&LastCommandInHeader,
|
|
&pCommand);
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
|
|
|
ASSERT(LastCommandInHeader == SMB_COM_NO_ANDX_COMMAND);
|
|
*pCommand = SmbCommand;
|
|
|
|
pServerEntry = SmbCeGetExchangeServerEntry(pTransactExchange);
|
|
|
|
if (FlagOn(pServerEntry->Server.DialectFlags,DF_NT_SMBS)) {
|
|
// for NT servers, we have to set the pid/pidhigh fields so that RPC will work. unless this is a
|
|
// mailslot write.
|
|
if (!(pTransactExchange->Flags & SMB_XACT_FLAGS_MAILSLOT_OPERATION)) {
|
|
SmbCeSetFullProcessIdInHeader(
|
|
(PSMB_EXCHANGE)pTransactExchange,
|
|
RxGetRequestorProcessId(pTransactExchange->RxContext),
|
|
((PNT_SMB_HEADER)pHeader));
|
|
}
|
|
}
|
|
|
|
if (pTransactExchange->Flags & SMB_XACT_FLAGS_MAILSLOT_OPERATION) {
|
|
pHeader->Flags2 &= ~(SMB_FLAGS2_NT_STATUS);
|
|
}
|
|
|
|
if (pTransactExchange->Flags & SMB_XACT_FLAGS_DFS_AWARE) {
|
|
pHeader->Flags2 |= SMB_FLAGS2_DFS;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmbTransactExchangeStart(
|
|
PSMB_EXCHANGE pExchange)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the start routine for transact exchanges. This initiates the construction of the
|
|
appropriate SMB's if required.
|
|
|
|
Arguments:
|
|
|
|
pExchange - the exchange instance
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PSMB_TRANSACT_EXCHANGE pTransactExchange;
|
|
PVOID pActualPrimaryRequestSmbHeader;
|
|
PSMB_HEADER pPrimaryRequestSmbHeader;
|
|
|
|
// The MDL's used in sending the primary request associated with the TRANSACT SMB
|
|
PMDL pPartialDataMdl = NULL;
|
|
PMDL pPartialParamMdl = NULL;
|
|
PMDL pPaddingMdl = NULL;
|
|
PMDL pPrimaryRequestSmbMdl = NULL;
|
|
PMDL pLastMdlInChain = NULL;
|
|
|
|
ULONG MaximumSmbBufferSize;
|
|
ULONG PrimaryRequestSmbSize = 0;
|
|
ULONG PaddingLength = 0;
|
|
BOOLEAN QuadwordAlignmentRequired = FALSE;
|
|
|
|
ULONG ParamBytesToBeSent = 0;
|
|
ULONG DataBytesToBeSent = 0;
|
|
|
|
ULONG ParamOffset,DataOffset;
|
|
ULONG SmbLength;
|
|
ULONG BccOffset;
|
|
ULONG MdlLength;
|
|
|
|
USHORT *pBcc;
|
|
|
|
PAGED_CODE();
|
|
|
|
pTransactExchange = (PSMB_TRANSACT_EXCHANGE)pExchange;
|
|
|
|
pActualPrimaryRequestSmbHeader = pTransactExchange->pActualPrimaryRequestSmbHeader;
|
|
pPrimaryRequestSmbHeader = pTransactExchange->pPrimaryRequestSmbHeader;
|
|
|
|
ASSERT(pActualPrimaryRequestSmbHeader != NULL);
|
|
ASSERT(pPrimaryRequestSmbHeader != NULL);
|
|
|
|
ASSERT(!(pExchange->SmbCeFlags & SMBCE_EXCHANGE_SESSION_CONSTRUCTOR) &&
|
|
!(pExchange->SmbCeFlags & SMBCE_EXCHANGE_NETROOT_CONSTRUCTOR));
|
|
|
|
// Initialize the SMB header ...
|
|
Status = SmbTransactBuildHeader(
|
|
pTransactExchange,
|
|
pTransactExchange->TransactSmbCommand,
|
|
pPrimaryRequestSmbHeader);
|
|
|
|
if ((Status != RX_MAP_STATUS(SUCCESS))) {
|
|
// Finalize the exchange.
|
|
pExchange->Status = Status;
|
|
return Status;
|
|
}
|
|
|
|
PrimaryRequestSmbSize = sizeof(SMB_HEADER);
|
|
|
|
// Compute the BccOffset and the ParamOffset which is in turn used in computing the
|
|
// param and data bytes to be sent as part of the primary request.
|
|
switch (pTransactExchange->TransactSmbCommand) {
|
|
case SMB_COM_TRANSACTION:
|
|
case SMB_COM_TRANSACTION2:
|
|
{
|
|
PREQ_TRANSACTION pTransactRequest = (PREQ_TRANSACTION)
|
|
(pPrimaryRequestSmbHeader + 1);
|
|
USHORT SetupLength = pTransactRequest->SetupCount * sizeof(WORD);
|
|
|
|
BccOffset = sizeof(SMB_HEADER) +
|
|
FIELD_OFFSET(REQ_TRANSACTION,Buffer) +
|
|
SetupLength;
|
|
|
|
ParamOffset = ROUND_UP_COUNT(
|
|
(BccOffset +
|
|
pTransactExchange->TransactionNameLength +
|
|
sizeof(USHORT)),
|
|
ALIGN_DWORD);
|
|
|
|
pBcc = (PUSHORT)((PBYTE)pPrimaryRequestSmbHeader + BccOffset);
|
|
}
|
|
break;
|
|
|
|
case SMB_COM_NT_TRANSACT:
|
|
{
|
|
PREQ_NT_TRANSACTION pNtTransactRequest = (PREQ_NT_TRANSACTION)
|
|
(pPrimaryRequestSmbHeader + 1);
|
|
USHORT SetupLength = pNtTransactRequest->SetupCount * sizeof(WORD);
|
|
|
|
RxDbgTrace( 0, Dbg, ("SmbTransactExchangeSTAAT1: init for NT_T (p,d,mp,md) %d %d %d %d\n",
|
|
pNtTransactRequest->TotalParameterCount, pNtTransactRequest->TotalDataCount,
|
|
pNtTransactRequest->MaxParameterCount, pNtTransactRequest->MaxDataCount));
|
|
RxDbgTrace( 0, Dbg, ("SmbTransactExchangeSTAyuk: init for NT_T (s,ms) %d %d \n",
|
|
pNtTransactRequest->SetupCount, pNtTransactRequest->MaxSetupCount));
|
|
|
|
|
|
BccOffset = sizeof(SMB_HEADER) +
|
|
FIELD_OFFSET(REQ_NT_TRANSACTION,Buffer[0]) +
|
|
SetupLength;
|
|
|
|
ParamOffset = ROUND_UP_COUNT(
|
|
(BccOffset + sizeof(USHORT)),
|
|
ALIGN_DWORD);
|
|
|
|
pBcc = (PUSHORT)((PBYTE)pPrimaryRequestSmbHeader + BccOffset);
|
|
|
|
if (pTransactExchange->NtTransactFunction == NT_TRANSACT_SET_QUOTA) {
|
|
QuadwordAlignmentRequired = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT(!"Valid Smb Command for initiating Transaction");
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Compute the data/param bytes that can be sent as part of the primary request
|
|
MaximumSmbBufferSize = pTransactExchange->MaximumTransmitSmbBufferSize;
|
|
|
|
ParamBytesToBeSent = MIN(
|
|
(MaximumSmbBufferSize - ParamOffset),
|
|
pTransactExchange->SendParamBufferSize);
|
|
if (!QuadwordAlignmentRequired) {
|
|
DataOffset = ROUND_UP_COUNT(ParamOffset + ParamBytesToBeSent, ALIGN_DWORD);
|
|
} else {
|
|
DataOffset = ROUND_UP_COUNT(ParamOffset + ParamBytesToBeSent, ALIGN_QUAD);
|
|
}
|
|
|
|
if (DataOffset < MaximumSmbBufferSize) {
|
|
DataBytesToBeSent = MIN((MaximumSmbBufferSize - DataOffset),
|
|
pTransactExchange->SendDataBufferSize);
|
|
PaddingLength = DataOffset - (ParamOffset + ParamBytesToBeSent);
|
|
} else {
|
|
DataBytesToBeSent = 0;
|
|
}
|
|
|
|
if ( DataBytesToBeSent == 0) {
|
|
DataOffset = PaddingLength = 0;
|
|
}
|
|
|
|
RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: params,padding,data=%d,%d,%d\n",
|
|
ParamBytesToBeSent,PaddingLength,DataBytesToBeSent ));
|
|
RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: paramsoffset,dataoffset=%d,%d\n",
|
|
ParamOffset,DataOffset ));
|
|
RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: phdr,pbcc=%08lx,%08lx\n",
|
|
pPrimaryRequestSmbHeader,pBcc ));
|
|
|
|
// Update the primary request buffer with the final sizes of the data/parameter etc.
|
|
switch (pTransactExchange->TransactSmbCommand) {
|
|
case SMB_COM_TRANSACTION:
|
|
case SMB_COM_TRANSACTION2:
|
|
{
|
|
PREQ_TRANSACTION pTransactRequest = (PREQ_TRANSACTION)
|
|
(pPrimaryRequestSmbHeader + 1);
|
|
|
|
RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: TRANSACTION/TRANSACTION2\n"));
|
|
|
|
SmbPutUshort( &pTransactRequest->ParameterCount, (USHORT)ParamBytesToBeSent );
|
|
SmbPutUshort( &pTransactRequest->ParameterOffset, (USHORT)ParamOffset);
|
|
SmbPutUshort( &pTransactRequest->DataCount, (USHORT)DataBytesToBeSent);
|
|
SmbPutUshort( &pTransactRequest->DataOffset, (USHORT)DataOffset);
|
|
}
|
|
break;
|
|
|
|
case SMB_COM_NT_TRANSACT:
|
|
{
|
|
PREQ_NT_TRANSACTION pNtTransactRequest = (PREQ_NT_TRANSACTION)
|
|
(pPrimaryRequestSmbHeader + 1);
|
|
|
|
RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: NT transacton\n"));
|
|
RxDbgTrace( 0, Dbg, ("SmbTransactExchangeSTAAT2: init for NT_T (p,d,mp,md) %d %d %d %d\n",
|
|
pNtTransactRequest->TotalParameterCount, pNtTransactRequest->TotalDataCount,
|
|
pNtTransactRequest->MaxParameterCount, pNtTransactRequest->MaxDataCount));
|
|
|
|
|
|
SmbPutUlong( &pNtTransactRequest->ParameterCount, ParamBytesToBeSent);
|
|
SmbPutUlong( &pNtTransactRequest->ParameterOffset, ParamOffset);
|
|
SmbPutUlong( &pNtTransactRequest->DataCount, DataBytesToBeSent);
|
|
SmbPutUlong( &pNtTransactRequest->DataOffset, DataOffset);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT(!"Valid Smb Command for initiating Transaction");
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Update the Bcc field in the SMB and compute the SMB length
|
|
SmbPutUshort(
|
|
pBcc,
|
|
(USHORT)((ParamOffset - BccOffset - sizeof(USHORT)) +
|
|
ParamBytesToBeSent +
|
|
PaddingLength +
|
|
DataBytesToBeSent)
|
|
);
|
|
|
|
SmbLength = ParamOffset +
|
|
ParamBytesToBeSent +
|
|
PaddingLength +
|
|
DataBytesToBeSent;
|
|
|
|
// The primary request buffer should be locked down for transmission. In order to
|
|
// preclude race conditions while freeing this routine assumes ownership of the buffer.
|
|
// There are two reasons why this model has to be adopted ...
|
|
// 1) Inititaiting a transaction request can possibly involve a reconnection attempt
|
|
// which will involve network traffic. Consequently the transmission of the primary
|
|
// request can potentially occur in a worker thread which is different from the one
|
|
// initializing the exchange. This problem can be worked around by carrying all the
|
|
// possible context around and actually constructing the header as part of this routine.
|
|
// But this would imply that those requests which could have been filtered out easily
|
|
// because of error conditions etc. will be handled very late.
|
|
|
|
pTransactExchange->pActualPrimaryRequestSmbHeader = NULL;
|
|
pTransactExchange->pPrimaryRequestSmbHeader = NULL;
|
|
|
|
// Ensure that the MDL's have been probed & locked. The new MDL's have been allocated.
|
|
// The partial MDL's are allocated to be large enough to span the maximum buffer
|
|
// length possible.
|
|
|
|
MdlLength = ParamOffset;
|
|
if (pTransactExchange->fParamsSubsumedInPrimaryRequest) {
|
|
MdlLength += ParamBytesToBeSent + PaddingLength;
|
|
}
|
|
|
|
RxAllocateHeaderMdl(
|
|
pPrimaryRequestSmbHeader,
|
|
MdlLength,
|
|
pPrimaryRequestSmbMdl
|
|
);
|
|
|
|
if (pPrimaryRequestSmbMdl != NULL) {
|
|
Status = STATUS_SUCCESS;
|
|
} else {
|
|
RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: Insuffcient resources for MDL's\n"));
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
if ((DataBytesToBeSent > 0) &&
|
|
(Status == RX_MAP_STATUS(SUCCESS))) {
|
|
pPartialDataMdl = RxAllocateMdl(
|
|
0,
|
|
(MIN(pTransactExchange->SendDataBufferSize,MaximumSmbBufferSize) +
|
|
PAGE_SIZE - 1)
|
|
);
|
|
|
|
if (pPartialDataMdl != NULL) {
|
|
Status = STATUS_SUCCESS;
|
|
} else {
|
|
RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: Insuffcient resources for MDL's\n"));
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
|
|
if ((ParamBytesToBeSent > 0) &&
|
|
!pTransactExchange->fParamsSubsumedInPrimaryRequest &&
|
|
(Status == RX_MAP_STATUS(SUCCESS))) {
|
|
|
|
pPartialParamMdl = RxAllocateMdl(
|
|
pTransactExchange->pSendParamBuffer,
|
|
ParamBytesToBeSent);
|
|
|
|
if (PaddingLength!= 0) {
|
|
pPaddingMdl = RxAllocateMdl(0,(sizeof(DWORD) + PAGE_SIZE - 1));
|
|
} else {
|
|
pPaddingMdl = NULL;
|
|
}
|
|
|
|
if ((pPartialParamMdl != NULL) &&
|
|
((pPaddingMdl != NULL)||(PaddingLength==0))) {
|
|
Status = STATUS_SUCCESS;
|
|
} else {
|
|
RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: no param/pad MDLs %08lx %08lx\n",
|
|
pPartialParamMdl,pPaddingMdl));
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
|
|
// At this point the validity of all the parameters will have been ascertained. The trivial
|
|
// cases have been filtered out. Start the transact exchange.
|
|
|
|
// Implementation Note: The Transact exchange implementation relies upon chaining the
|
|
// MDL's together to build the relevant request buffers that need be sent. This ensures
|
|
// that redundant copying of data is avoided altogether. Depending upon the parameters
|
|
// specified the composite MDL that is sent is composed of the following MDL's.
|
|
// TRANSACT2 and NT TRANSACT exchanges ...
|
|
// The composite buffer is made up off atmost four MDL's that are chained together. These
|
|
// are the header buffer, the setup buffer, parameter buffer and the data buffer.
|
|
// All the secondary requests are made up off atmost three MDL's that are chained together.
|
|
// These are the header buffer, the parameter buffer and the data buffer.
|
|
// TRANSACT exchanges ....
|
|
// The composite buffer is made up off atmost three MDL's that are chained together. These are
|
|
// the header buffer ( includes the name and the setup information) , the parameter buffer
|
|
// and the data buffer.
|
|
// All the secondary requests are made up off atmost three MDL's that are chained together.
|
|
// These are the header buffer, the parameter buffer and the data buffer.
|
|
// In all of these cases the number of MDL's can go up by 1 if a padding MDL is required
|
|
// between the parameter buffer and the data buffer to ensure that all alignment requirements
|
|
// are satisfied.
|
|
|
|
if ((Status == RX_MAP_STATUS(SUCCESS))) {
|
|
|
|
RxProbeAndLockHeaderPages(pPrimaryRequestSmbMdl,KernelMode,IoModifyAccess,Status);
|
|
if ((Status != RX_MAP_STATUS(SUCCESS))) { //do this now. the code below will try to unlock
|
|
IoFreeMdl(pPrimaryRequestSmbMdl);
|
|
pPrimaryRequestSmbMdl = NULL;
|
|
} else {
|
|
if (MmGetSystemAddressForMdlSafe(pPrimaryRequestSmbMdl,LowPagePriority) == NULL) { //map it
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((Status == RX_MAP_STATUS(SUCCESS))) {
|
|
pLastMdlInChain = pPrimaryRequestSmbMdl;
|
|
|
|
if (ParamBytesToBeSent > 0) {
|
|
RxDbgTrace(
|
|
0,
|
|
Dbg,
|
|
("SmbCeTransactExchangeStart: Sending Param bytes %ld at offset %ld\n",
|
|
ParamBytesToBeSent,
|
|
ParamOffset)
|
|
);
|
|
pTransactExchange->ParamBytesSent = ParamBytesToBeSent;
|
|
|
|
if (!pTransactExchange->fParamsSubsumedInPrimaryRequest) {
|
|
IoBuildPartialMdl(
|
|
pTransactExchange->pSendParamMdl,
|
|
pPartialParamMdl,
|
|
(PBYTE)MmGetMdlVirtualAddress(pTransactExchange->pSendParamMdl),
|
|
ParamBytesToBeSent);
|
|
|
|
// Chain the MDL's together
|
|
pLastMdlInChain->Next = pPartialParamMdl;
|
|
pLastMdlInChain = pPartialParamMdl;
|
|
}
|
|
}
|
|
|
|
// Link the data buffer or portions of it if the size constraints are satisfied
|
|
// If padding is required between the parameter and data portions in the
|
|
// primary request include the padding MDL, otherwise chain the data MDL
|
|
// directly.
|
|
if (DataBytesToBeSent > 0) {
|
|
if (!pTransactExchange->fParamsSubsumedInPrimaryRequest &&
|
|
(PaddingLength > 0)) {
|
|
RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: Padding Length %ld\n",PaddingLength));
|
|
|
|
RxBuildPaddingPartialMdl(pPaddingMdl,PaddingLength);
|
|
pLastMdlInChain->Next = pPaddingMdl;
|
|
pLastMdlInChain = pPaddingMdl;
|
|
}
|
|
|
|
RxDbgTrace( 0, Dbg,("SmbCeTransactExchangeStart: Sending Data bytes %ld at offset %ld\n",
|
|
DataBytesToBeSent, DataOffset) );
|
|
|
|
pTransactExchange->DataBytesSent = DataBytesToBeSent;
|
|
|
|
IoBuildPartialMdl(
|
|
pTransactExchange->pSendDataMdl,
|
|
pPartialDataMdl,
|
|
(PBYTE)MmGetMdlVirtualAddress(pTransactExchange->pSendDataMdl),
|
|
DataBytesToBeSent);
|
|
|
|
pLastMdlInChain->Next = pPartialDataMdl;
|
|
pLastMdlInChain = pPartialDataMdl;
|
|
}
|
|
|
|
if ((Status == RX_MAP_STATUS(SUCCESS))) {
|
|
|
|
if (FlagOn(pTransactExchange->SmbCeFlags,SMBCE_EXCHANGE_MAILSLOT_OPERATION)) {
|
|
pTransactExchange->SmbCeFlags |= SMBCE_EXCHANGE_MID_VALID;
|
|
pTransactExchange->Mid = SMBCE_MAILSLOT_OPERATION_MID;
|
|
}
|
|
|
|
// There are cases in which the transaction exchange can be completed by merely sending
|
|
// the primary request SMB. This should be distinguished from those cases in which either
|
|
// a response is expected or a number of secondary requests need to be issued based upon
|
|
// the parameter buffer length, data buffer length and the flags specified.
|
|
if ((pTransactExchange->Flags & SMB_TRANSACTION_NO_RESPONSE ) &&
|
|
(pTransactExchange->SendDataBufferSize == DataBytesToBeSent) &&
|
|
(pTransactExchange->SendParamBufferSize == ParamBytesToBeSent)) {
|
|
// No response is expected in this case. Therefore Send should suffice instead of
|
|
// Tranceive
|
|
|
|
// since we don't expect to do any more here, set the exchange status to success
|
|
pExchange->Status = STATUS_SUCCESS;
|
|
pTransactExchange->pResumptionContext->FinalStatusFromServer = STATUS_SUCCESS;
|
|
|
|
RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: SmbCeSend(No Response expected)\n"));
|
|
Status = SmbCeSend(
|
|
pExchange,
|
|
RXCE_SEND_SYNCHRONOUS,
|
|
pPrimaryRequestSmbMdl,
|
|
SmbLength);
|
|
|
|
if ((Status != RX_MAP_STATUS(SUCCESS))) {
|
|
RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: SmbCeSend returned %lx\n",Status));
|
|
}
|
|
} else {
|
|
// This transaction involves ttansmit/receive of multiple SMB's. A tranceive is in
|
|
// order.
|
|
|
|
if ((pTransactExchange->SendDataBufferSize == DataBytesToBeSent) &&
|
|
(pTransactExchange->SendParamBufferSize == ParamBytesToBeSent)) {
|
|
RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: No Secondary Requests\n"));
|
|
pTransactExchange->State = TRANSACT_EXCHANGE_TRANSMITTED_SECONDARY_REQUESTS;
|
|
} else {
|
|
pTransactExchange->State = TRANSACT_EXCHANGE_TRANSMITTED_PRIMARY_REQUEST;
|
|
}
|
|
|
|
RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: SmbCeTranceive(Response expected)\n"));
|
|
//CODE.IMPROVEMENT send.sync????.........yeeeeech.
|
|
Status = SmbCeTranceive(
|
|
pExchange,
|
|
RXCE_SEND_SYNCHRONOUS,
|
|
pPrimaryRequestSmbMdl,
|
|
SmbLength);
|
|
|
|
if ((Status != RX_MAP_STATUS(SUCCESS))) {
|
|
RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: SmbCeTranceive returned %lx\n",Status));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pPartialParamMdl != NULL) {
|
|
IoFreeMdl(pPartialParamMdl);
|
|
}
|
|
|
|
if (pPartialDataMdl != NULL) {
|
|
IoFreeMdl(pPartialDataMdl);
|
|
}
|
|
|
|
if (pPaddingMdl != NULL) {
|
|
IoFreeMdl(pPaddingMdl);
|
|
}
|
|
|
|
if (pPrimaryRequestSmbMdl != NULL) {
|
|
if (RxMdlIsLocked(pPrimaryRequestSmbMdl))
|
|
{
|
|
RxUnlockHeaderPages(pPrimaryRequestSmbMdl);
|
|
}
|
|
IoFreeMdl(pPrimaryRequestSmbMdl);
|
|
}
|
|
|
|
RxFreePool(pActualPrimaryRequestSmbHeader);
|
|
|
|
if (Status != STATUS_PENDING) {
|
|
pExchange->Status = Status;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbTransactExchangeReceive(
|
|
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,
|
|
IN ULONG ReceiveFlags)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the recieve indication handling routine for transact 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 - the byte buffer
|
|
|
|
pDataBufferPointer - the buffer 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.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PNTSTATUS pFinalSmbStatus;
|
|
|
|
BOOLEAN fError = FALSE;
|
|
BOOLEAN fIndicationNotSufficient = FALSE;
|
|
BOOLEAN fMoreParsingRequired = FALSE;
|
|
BOOLEAN fDoErrorProcessing = FALSE; //this is a hack CODE.IMPROVEMENT
|
|
|
|
SMB_TRANSACT_RESP_FORMAT_DESCRIPTION Format;
|
|
|
|
GENERIC_ANDX CommandToProcess;
|
|
|
|
ULONG TransactResponseSize = 0;
|
|
ULONG SetupBytesOffsetInResponse = 0;
|
|
ULONG SetupBytesInResponse = 0;
|
|
ULONG CopyDataSize = 0;
|
|
|
|
PMDL pSetupMdl = NULL;
|
|
PMDL pCopyRequestMdl = NULL;
|
|
|
|
PSMB_TRANSACT_EXCHANGE pTransactExchange = (PSMB_TRANSACT_EXCHANGE)pExchange;
|
|
|
|
RxDbgTrace( 0, Dbg,
|
|
("SmbTransactExchangeReceive: Entering w/ Bytes Available (%ld) Bytes Indicated (%ld) State (%ld)\n",
|
|
BytesAvailable,
|
|
BytesIndicated,
|
|
pTransactExchange->State
|
|
));
|
|
RxDbgTrace( 0, Dbg,
|
|
("SmbTransactExchangeReceive: Buffer %08lx Consumed (%ld) MDL (%08lx)\n",
|
|
pSmbHeader,
|
|
*pBytesTaken,
|
|
*pDataBufferPointer
|
|
));
|
|
|
|
pFinalSmbStatus = &pTransactExchange->SmbStatus;
|
|
Status = SmbCeParseSmbHeader(
|
|
pExchange,
|
|
pSmbHeader,
|
|
&CommandToProcess,
|
|
pFinalSmbStatus,
|
|
BytesAvailable,
|
|
BytesIndicated,
|
|
pBytesTaken);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
|
goto FINALLY;
|
|
}
|
|
|
|
//this need some explanation. parseheader is written so as to take some extra smbs off the from
|
|
//of the packet...specifically, stuff like sessionsetup&X and TC&X. since no transact is a valid followon
|
|
//it would not make since if (a) not enough were indicated or (b) an early command had an error. so
|
|
//we must have success. CODE.REVIEW.JOELINN you should look in parseheader and (1) remove the *taken=avail and
|
|
//(b) look for asserts that the server sends stuff back correctly. these must be changed into BAD_RESPONSE_AND_DISCARDs
|
|
//the "Status = STATUS_SUCCESS" is to try to get the compiler to optimize.
|
|
|
|
if (*((PBYTE)(pSmbHeader+1)) == 0 && (pTransactExchange->State!=TRANSACT_EXCHANGE_TRANSMITTED_PRIMARY_REQUEST)) {
|
|
RxDbgTrace(0,Dbg,("SmbTransactExchangeReceive: FinalSmbStatus = %lx\n", *pFinalSmbStatus));
|
|
|
|
if (NT_SUCCESS(*pFinalSmbStatus)) {
|
|
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
|
goto FINALLY;
|
|
}
|
|
}
|
|
|
|
//we know that status is SUCCESS from the assert above. but we will still continue to check so as
|
|
//to be more resilient when we don't have msg boundaries. we have the following cases depending on the
|
|
//characteristics of the smbresponse
|
|
//
|
|
// non-error: get the data and then return the stored responsestatus. the process of getting the data
|
|
// causes us to update the param and data counts so that we know when we have reached the
|
|
// end of the data. the parse routine re-ups the receive if needed.
|
|
// error: there are main cases:
|
|
// a) the server has sent no data. here we discard the packet and we can just get out. the
|
|
// finalize routine will pickup the status correctly.
|
|
// b) here, we have to discard the packet AND update the byte counts AND re-up the receive
|
|
// if necessary. to discard the packet, we must either compute the apparent msg length from
|
|
// the WC and BC parameters (best) OR use our maximum buffer size
|
|
|
|
fMoreParsingRequired = FALSE;
|
|
|
|
if ((Status == RX_MAP_STATUS(SUCCESS))) {
|
|
if (TRUE) { //maybe sometimes we wont copy!
|
|
if (CommandToProcess.WordCount > 0) {
|
|
ULONG TransactResponseSize = 0;
|
|
|
|
// Ensure that at the very least enough bytes have been indicated to determine
|
|
// the length of the setup, parameters and data for the transaction.
|
|
|
|
//CODE.IMPROVEMENT.ASHAMED this is very clumsy....we should have computed this earlier.
|
|
// and saved it in the exchange. at a minimum move it to the validateformat routine
|
|
switch (CommandToProcess.AndXCommand) {
|
|
case SMB_COM_NT_TRANSACT:
|
|
case SMB_COM_NT_TRANSACT_SECONDARY:
|
|
TransactResponseSize = FIELD_OFFSET(RESP_NT_TRANSACTION,Buffer);
|
|
break;
|
|
|
|
case SMB_COM_TRANSACTION:
|
|
case SMB_COM_TRANSACTION2:
|
|
case SMB_COM_TRANSACTION_SECONDARY:
|
|
case SMB_COM_TRANSACTION2_SECONDARY:
|
|
TransactResponseSize = FIELD_OFFSET(RESP_TRANSACTION,Buffer);
|
|
break;
|
|
|
|
default:
|
|
TransactResponseSize = 0xffffffff;
|
|
Status = RX_MAP_STATUS(INVALID_NETWORK_RESPONSE);
|
|
break;
|
|
}
|
|
|
|
if (BytesIndicated >= (sizeof(SMB_HEADER) + TransactResponseSize)) {
|
|
fMoreParsingRequired = TRUE;
|
|
} else {
|
|
fIndicationNotSufficient = TRUE;
|
|
*pFinalSmbStatus = STATUS_INVALID_NETWORK_RESPONSE;
|
|
}
|
|
} else {
|
|
// allow a response with wordcount==0 to go thru if we're the right state
|
|
fMoreParsingRequired = (pTransactExchange->State==TRANSACT_EXCHANGE_TRANSMITTED_PRIMARY_REQUEST);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fMoreParsingRequired) {
|
|
// The header was successfully parsed and the SMB response did not contain any errors
|
|
// The stage is set for processing the transaction response.
|
|
|
|
switch (pTransactExchange->State) {
|
|
case TRANSACT_EXCHANGE_TRANSMITTED_PRIMARY_REQUEST:
|
|
{
|
|
// The primary request for the transaction has been sent and there are
|
|
// secondary requests to be sent.
|
|
// The only response expected at this time is an interim response. Any
|
|
// other response will be treated as an error.
|
|
PRESP_TRANSACTION_INTERIM pInterimResponse;
|
|
|
|
RxDbgTrace(0,Dbg,("SmbCeTransactExchangeReceive: Processing interim response\n"));
|
|
|
|
if ((*pBytesTaken + FIELD_OFFSET(RESP_TRANSACTION_INTERIM,Buffer)) <= BytesIndicated) {
|
|
pInterimResponse = (PRESP_TRANSACTION_INTERIM)((PBYTE)pSmbHeader + *pBytesTaken);
|
|
if ((NT_SUCCESS(pExchange->SmbStatus)) &&
|
|
(pSmbHeader->Command == pTransactExchange->TransactSmbCommand) &&
|
|
(SmbGetUshort(&pInterimResponse->WordCount) == 0) &&
|
|
(SmbGetUshort(&pInterimResponse->ByteCount) == 0)) {
|
|
|
|
// The interim response was valid. Transition the state of the exchange
|
|
// and transmit the secondary requests.
|
|
*pBytesTaken += FIELD_OFFSET(RESP_TRANSACTION_INTERIM,Buffer);
|
|
//CODE.IMPROVEMENT that only works if the server doesn't send extra crap
|
|
pTransactExchange->State = TRANSACT_EXCHANGE_RECEIVED_INTERIM_RESPONSE;
|
|
|
|
// Determine if any secondary transaction requests need to be sent. if none are
|
|
// required then modify the state
|
|
ASSERT((pTransactExchange->ParamBytesSent < pTransactExchange->SendParamBufferSize) ||
|
|
(pTransactExchange->DataBytesSent < pTransactExchange->SendDataBufferSize));
|
|
ASSERT((pTransactExchange->ParamBytesSent <= pTransactExchange->SendParamBufferSize) &&
|
|
(pTransactExchange->DataBytesSent <= pTransactExchange->SendDataBufferSize));
|
|
|
|
if (!(pTransactExchange->Flags & SMB_TRANSACTION_NO_RESPONSE )) {
|
|
Status = SmbCeReceive(pExchange);
|
|
}
|
|
|
|
if ((Status != RX_MAP_STATUS(SUCCESS))) {
|
|
pExchange->Status = Status;
|
|
} else {
|
|
Status = STATUS_SUCCESS;
|
|
SmbCeIncrementPendingLocalOperations(pExchange);
|
|
RxPostToWorkerThread(
|
|
MRxSmbDeviceObject,
|
|
CriticalWorkQueue,
|
|
&pExchange->WorkQueueItem,
|
|
SendSecondaryRequests,
|
|
pExchange);
|
|
}
|
|
} else if( !NT_SUCCESS(pExchange->SmbStatus) ) {
|
|
RxDbgTrace(0,Dbg,("SmbCeTransactExchangeReceive: Error on Response\n"));
|
|
Status = pExchange->SmbStatus;
|
|
} else {
|
|
RxDbgTrace(0,Dbg,("SmbCeTransactExchangeReceive: Invalid interim response\n"));
|
|
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
|
}
|
|
} else {
|
|
fIndicationNotSufficient = TRUE;
|
|
Status = RX_MAP_STATUS(MORE_PROCESSING_REQUIRED);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TRANSACT_EXCHANGE_RECEIVED_INTERIM_RESPONSE:
|
|
RxDbgTrace(0,Dbg,("SmbCeTransactExchangeReceive: received again while in interim response\n"));
|
|
//no break: this is okay
|
|
case TRANSACT_EXCHANGE_TRANSMITTED_SECONDARY_REQUESTS:
|
|
case TRANSACT_EXCHANGE_RECEIVED_PRIMARY_RESPONSE:
|
|
{
|
|
BOOLEAN fPrimaryResponse = FALSE;
|
|
PRESP_TRANSACTION pTransactResponse;
|
|
PRESP_NT_TRANSACTION pNtTransactResponse;
|
|
ULONG TotalParamBytesInResponse;
|
|
ULONG TotalDataBytesInResponse;
|
|
|
|
RxDbgTrace(0,Dbg,("SmbCeTransactExchangeReceive: Processing Primary/Secondary response\n"));
|
|
|
|
//do this here so there's only one copy if the code
|
|
pTransactResponse = (PRESP_TRANSACTION)((PBYTE)pSmbHeader +
|
|
SmbGetUshort(&CommandToProcess.AndXOffset));
|
|
|
|
// All the requests ( both primary and secondary have been sent ). The
|
|
// only responses expected in this state are (1) a primary response and (2) a
|
|
// secondary response. Any other response is an error.
|
|
if (pSmbHeader->Command == pTransactExchange->TransactSmbCommand) {
|
|
switch (pSmbHeader->Command) {
|
|
case SMB_COM_TRANSACTION:
|
|
case SMB_COM_TRANSACTION2:
|
|
//pTransactResponse = (PRESP_TRANSACTION)((PBYTE)pSmbHeader +
|
|
// SmbGetUshort(&CommandToProcess.AndXOffset));
|
|
fPrimaryResponse = TRUE;
|
|
SetupBytesOffsetInResponse = FIELD_OFFSET(RESP_TRANSACTION,Buffer);
|
|
SetupBytesInResponse = sizeof(USHORT) * pTransactResponse->SetupCount;
|
|
|
|
// Initialize the total count of data and param bytes that will be received from
|
|
// the server during the course ofthe transaction response.
|
|
TotalParamBytesInResponse = SmbGetUshort(&pTransactResponse->TotalParameterCount);
|
|
TotalDataBytesInResponse = SmbGetUshort(&pTransactResponse->TotalDataCount);
|
|
|
|
// fall through
|
|
case SMB_COM_TRANSACTION_SECONDARY:
|
|
case SMB_COM_TRANSACTION2_SECONDARY:
|
|
TransactResponseSize = FIELD_OFFSET(RESP_TRANSACTION,Buffer);
|
|
break;
|
|
case SMB_COM_NT_TRANSACT:
|
|
//pNtTransactResponse = (PRESP_NT_TRANSACTION)((PBYTE)pSmbHeader +
|
|
// SmbGetUshort(&CommandToProcess.AndXOffset));
|
|
pNtTransactResponse = (PRESP_NT_TRANSACTION)pTransactResponse;
|
|
fPrimaryResponse = TRUE;
|
|
SetupBytesOffsetInResponse = FIELD_OFFSET(RESP_NT_TRANSACTION,Buffer);
|
|
SetupBytesInResponse = sizeof(USHORT) * pNtTransactResponse->SetupCount;
|
|
|
|
// Initialize the total count of data and param bytes that will be received from
|
|
// the server during the course ofthe transaction response.
|
|
TotalParamBytesInResponse = SmbGetUshort(&pNtTransactResponse->TotalParameterCount);
|
|
TotalDataBytesInResponse = SmbGetUshort(&pNtTransactResponse->TotalDataCount);
|
|
|
|
// fall through ..
|
|
case SMB_COM_NT_TRANSACT_SECONDARY:
|
|
TransactResponseSize = FIELD_OFFSET(RESP_NT_TRANSACTION,Buffer);
|
|
break;
|
|
|
|
default:
|
|
// Abort the exchange. An unexpected response was received during the
|
|
// course of the transaction.
|
|
ASSERT(!"Valid network response");
|
|
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
|
}
|
|
|
|
if ((Status == RX_MAP_STATUS(SUCCESS))) {
|
|
if (fPrimaryResponse) {
|
|
RxDbgTrace( 0,
|
|
Dbg,
|
|
("SmbTransactExchangeReceive: Primary Response Setup Bytes(%ld) Param Bytes (%ld) Data Bytes (%ld)\n",
|
|
SetupBytesInResponse,
|
|
TotalParamBytesInResponse,
|
|
TotalDataBytesInResponse
|
|
)
|
|
);
|
|
|
|
if ((TotalParamBytesInResponse > pTransactExchange->ReceiveParamBufferSize) ||
|
|
(TotalDataBytesInResponse > pTransactExchange->ReceiveDataBufferSize)) {
|
|
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
|
goto FINALLY;
|
|
} else {
|
|
pTransactExchange->ReceiveParamBufferSize = TotalParamBytesInResponse;
|
|
pTransactExchange->ReceiveDataBufferSize = TotalDataBytesInResponse;
|
|
}
|
|
}
|
|
|
|
if (Status == STATUS_SUCCESS &&
|
|
TransactResponseSize + *pBytesTaken <= BytesIndicated) {
|
|
if (fPrimaryResponse &&
|
|
(SetupBytesInResponse > 0)) {
|
|
|
|
PBYTE pSetupStartAddress;
|
|
ULONG SetupBytesIndicated = MIN(SetupBytesInResponse,
|
|
BytesIndicated - SetupBytesOffsetInResponse);
|
|
|
|
if( pTransactExchange->pReceiveSetupMdl ) {
|
|
pSetupStartAddress = (PBYTE)MmGetSystemAddressForMdlSafe(
|
|
pTransactExchange->pReceiveSetupMdl,
|
|
LowPagePriority
|
|
);
|
|
|
|
if( pSetupStartAddress == NULL ) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else {
|
|
if (SetupBytesInResponse == SetupBytesIndicated) {
|
|
RtlCopyMemory(
|
|
pSetupStartAddress,
|
|
((PBYTE)pSmbHeader + SetupBytesOffsetInResponse),
|
|
SetupBytesIndicated);
|
|
|
|
pSetupStartAddress += SetupBytesIndicated;
|
|
SetupBytesInResponse -= SetupBytesIndicated;
|
|
SetupBytesOffsetInResponse += SetupBytesIndicated;
|
|
pTransactExchange->SetupBytesReceived = SetupBytesInResponse;
|
|
} else {
|
|
// NTRAID-87018-2/10/2000 yunlin we do a indication_not_sufficient
|
|
ASSERT(!"this code doesn't work");
|
|
RxDbgTrace(0,Dbg,("SmbTransactExchangeReceive: Setup Bytes Partially Indicated\n"));
|
|
// Some setup bytes have not been indicated. An MDL needs to be
|
|
// created for copying the data. This MDL should also include the padding
|
|
// MDL for copying the padding bytes ...
|
|
pSetupMdl = RxAllocateMdl(pSetupStartAddress,SetupBytesInResponse);
|
|
|
|
if ( pSetupMdl != NULL ) {
|
|
IoBuildPartialMdl(
|
|
pTransactExchange->pReceiveSetupMdl,
|
|
pSetupMdl,
|
|
pSetupStartAddress,
|
|
SetupBytesInResponse);
|
|
} else {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
RxDbgTrace(0,Dbg,("SmbTransactExchangeReceive: Setup Bytes Indicated (%ld)\n",SetupBytesIndicated));
|
|
}
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
// from here, we cannot go back and redo the header....so we have to change state so
|
|
//that the copy routine doesn't try to reparse
|
|
pTransactExchange->State = TRANSACT_EXCHANGE_RECEIVED_PRIMARY_RESPONSE;
|
|
|
|
Status = SmbTransactAccrueAndValidateFormatData(
|
|
pTransactExchange,
|
|
pSmbHeader,
|
|
BytesIndicated,
|
|
&Format);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
goto FINALLY;
|
|
}
|
|
|
|
Status = ParseTransactResponse(
|
|
pTransactExchange,&Format,
|
|
BytesIndicated,
|
|
BytesAvailable,
|
|
pBytesTaken,
|
|
pSmbHeader,
|
|
&pCopyRequestMdl,
|
|
&CopyDataSize);
|
|
|
|
if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
|
|
// Link the setup MDL with the MDL returned
|
|
if (pSetupMdl != NULL) {
|
|
if (pCopyRequestMdl != NULL) {
|
|
pSetupMdl->Next = pCopyRequestMdl;
|
|
}
|
|
|
|
pCopyRequestMdl = pSetupMdl;
|
|
CopyDataSize += SetupBytesInResponse;
|
|
}
|
|
}
|
|
|
|
//check if the server has sent extra bytes.....
|
|
// ---------------------------------------------------------------------------------------------
|
|
{
|
|
ULONG ApparentMsgLength = max(BytesAvailable,Format.ApparentMsgLength);
|
|
ULONG DeficitBytes = ApparentMsgLength - (*pBytesTaken+CopyDataSize);
|
|
|
|
if (ApparentMsgLength < *pBytesTaken+CopyDataSize) {
|
|
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
|
goto FINALLY;
|
|
}
|
|
|
|
if (DeficitBytes > 0) {
|
|
RxLog(("XtraBytes %lx %lx",pTransactExchange,DeficitBytes));
|
|
SmbLog(LOG,
|
|
SmbTransactExchangeReceive_1,
|
|
LOGPTR(pTransactExchange)
|
|
LOGULONG(DeficitBytes));
|
|
|
|
if (CopyDataSize==0) {
|
|
if (*pBytesTaken > BytesAvailable) {
|
|
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
|
goto FINALLY;
|
|
}
|
|
|
|
RxLog(("Extra Bytes were sent and copydatasize==0........\n"));
|
|
SmbLog(LOG,
|
|
SmbTransactExchangeReceive_2,
|
|
LOGULONG(CopyDataSize));
|
|
*pBytesTaken = BytesAvailable; //cant take more than this
|
|
} else {
|
|
PMDL LastMdl,TrailingBytesMdl;
|
|
|
|
if ( DeficitBytes > TRAILING_BYTES_BUFFERSIZE) {
|
|
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
|
goto FINALLY;
|
|
}
|
|
|
|
TrailingBytesMdl = &pTransactExchange->TrailingBytesMdl;
|
|
|
|
MmInitializeMdl(
|
|
TrailingBytesMdl,
|
|
&pTransactExchange->TrailingBytesBuffer.Bytes[0],
|
|
DeficitBytes
|
|
);
|
|
MmBuildMdlForNonPagedPool(TrailingBytesMdl);
|
|
LastMdl = pCopyRequestMdl;
|
|
ASSERT(LastMdl != NULL);
|
|
for (;LastMdl->Next!=NULL;LastMdl=LastMdl->Next) ;
|
|
ASSERT(LastMdl != NULL);
|
|
ASSERT(LastMdl->Next == NULL);
|
|
LastMdl->Next = TrailingBytesMdl;
|
|
CopyDataSize += DeficitBytes;
|
|
}
|
|
}
|
|
}
|
|
// ---------------------------------------------------------------------------------------------
|
|
|
|
|
|
RxDbgTrace(0,Dbg,("SmbTransactExchangeReceive: ParseTransactResponse returned %lx\n",Status));
|
|
}
|
|
|
|
*pDataBufferPointer = pCopyRequestMdl;
|
|
*pDataSize = CopyDataSize;
|
|
} else {
|
|
RxDbgTrace(0,Dbg,("SmbTransactExchangeReceive: Indication not sufficient: trsz %08lx bytestakn %08lx \n",
|
|
TransactResponseSize, *pBytesTaken));
|
|
fIndicationNotSufficient = TRUE;
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
Status = STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
ASSERT(!"Valid Transact Exchange State for receiving responses");
|
|
RxDbgTrace( 0, Dbg, ("SmbTransactExchangeReceive: Aborting Exchange -- invalid state\n"));
|
|
}
|
|
break;
|
|
}
|
|
} else {
|
|
// We get here if either the status or the smbstatus is not success.
|
|
// If sufficient bytes were not indicated for processing the header a copy data request
|
|
// needs to be posted. this occurs if status is status_more_processing_required
|
|
RxDbgTrace( 0, Dbg, ("SmbTransactExchangeReceive: bad status(es) from parseheadr %08lx %08lx\n",
|
|
Status,*pFinalSmbStatus));
|
|
fDoErrorProcessing = TRUE;
|
|
}
|
|
|
|
if ((Status == RX_MAP_STATUS(SUCCESS)) &&
|
|
(pTransactExchange->ParamBytesReceived == pTransactExchange->ReceiveParamBufferSize) &&
|
|
(pTransactExchange->DataBytesReceived == pTransactExchange->ReceiveDataBufferSize) &&
|
|
(pTransactExchange->PendingCopyRequests == 0)) {
|
|
|
|
NOTHING;
|
|
|
|
} else if (fDoErrorProcessing) {
|
|
BOOLEAN DoItTheShortWay = TRUE;
|
|
ULONG ApparentMsgLength;
|
|
RxDbgTrace(0,Dbg,("SmbTransactExchangeReceive: Error processing response %lx .. Exchange aborted\n",Status));
|
|
|
|
if (BytesAvailable > BytesIndicated ||
|
|
!FlagOn(ReceiveFlags,TDI_RECEIVE_ENTIRE_MESSAGE)) {
|
|
|
|
Status = SmbTransactAccrueAndValidateFormatData(
|
|
pTransactExchange,
|
|
pSmbHeader,
|
|
BytesIndicated,
|
|
&Format);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
goto FINALLY;
|
|
}
|
|
|
|
ApparentMsgLength = max(BytesAvailable,Format.ApparentMsgLength);
|
|
|
|
//if wordcount!=0 then the server is sending us bytes.....we have to continue doing
|
|
//receives until we have seen all the bytes
|
|
if ((pTransactExchange->ParameterBytesSeen<Format.ParameterCount) ||
|
|
(pTransactExchange->DataBytesSeen<Format.DataCount)) {
|
|
NTSTATUS ReceiveStatus;
|
|
|
|
// The exchange has been successfully completed. Finalize it.
|
|
RxDbgTrace(0,Dbg,("ParseTransactResponse: Register for more error responses\n"));
|
|
RxLog(("TxErr: %lx %lx %lx",pTransactExchange,
|
|
pTransactExchange->ParameterBytesSeen,pTransactExchange->DataBytesSeen));
|
|
SmbLog(LOG,
|
|
SmbTransactExchangeReceive_3,
|
|
LOGPTR(pTransactExchange)
|
|
LOGULONG(pTransactExchange->ParameterBytesSeen)
|
|
LOGULONG(pTransactExchange->DataBytesSeen));
|
|
ReceiveStatus = SmbCeReceive((PSMB_EXCHANGE)pTransactExchange);
|
|
if (ReceiveStatus != STATUS_SUCCESS) {
|
|
// There was an error in registering the receive. Abandon the transaction.
|
|
Status = ReceiveStatus;
|
|
RxLog(("TxErrAbandon %lx",pTransactExchange));
|
|
SmbLog(LOG,
|
|
SmbTransactExchangeReceive_4,
|
|
LOGPTR(pTransactExchange)
|
|
LOGULONG(Status));
|
|
//Make it fail the next two tests.....
|
|
ApparentMsgLength = 0; DoItTheShortWay = FALSE; //CODE.IMPROVEMENT bad coding...use some escape
|
|
}
|
|
}
|
|
|
|
//netbt will not allow us to discard the packet by setting taken=available. so, check for
|
|
//available>indicated. if true, take the bytes by conjuring up a buffer
|
|
|
|
if (ApparentMsgLength>BytesIndicated) {
|
|
//we'll have to lay down a buffer for this so that NetBT won't blow the session away
|
|
//CODE.IMPROVEMENT we should put this code into OE a well.......
|
|
//CODE.IMPROVEMENT if we had an smbbuf (as suggested above) we could use that
|
|
// to do the copy
|
|
ASSERT(pTransactExchange->Status == STATUS_MORE_PROCESSING_REQUIRED);
|
|
pTransactExchange->DiscardBuffer = RxAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
ApparentMsgLength,
|
|
MRXSMB_XACT_POOLTAG);
|
|
if (pTransactExchange->DiscardBuffer!=NULL) {
|
|
*pBytesTaken = 0;
|
|
*pDataSize = ApparentMsgLength;
|
|
*pDataBufferPointer = &pTransactExchange->TrailingBytesMdl;
|
|
MmInitializeMdl(*pDataBufferPointer,
|
|
pTransactExchange->DiscardBuffer,
|
|
ApparentMsgLength
|
|
);
|
|
|
|
MmBuildMdlForNonPagedPool(*pDataBufferPointer);
|
|
pTransactExchange->SaveTheRealStatus = Status;
|
|
RxLog(("XRtakebytes %lx %lx\n",pTransactExchange,Status));
|
|
SmbLog(LOG,
|
|
SmbTransactExchangeReceive_5,
|
|
LOGPTR(pTransactExchange)
|
|
LOGULONG(Status));
|
|
Status = STATUS_MORE_PROCESSING_REQUIRED;
|
|
DoItTheShortWay = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (DoItTheShortWay) {
|
|
goto FINALLY;
|
|
}
|
|
}
|
|
|
|
RxDbgTrace( 0, Dbg,
|
|
("SmbTransactExchangeReceiveExit: Bytes Consumed (%ld) Status (%08lx) MDL (%08lx) size(%08lx)\n",
|
|
*pBytesTaken, Status, *pDataBufferPointer, *pDataSize
|
|
));
|
|
|
|
if ((Status == STATUS_SUCCESS) ||
|
|
(Status == STATUS_MORE_PROCESSING_REQUIRED)) {
|
|
return Status;
|
|
}
|
|
|
|
FINALLY:
|
|
*pBytesTaken = BytesAvailable;
|
|
*pDataBufferPointer = NULL;
|
|
|
|
// Abort the exchange
|
|
pTransactExchange->Status = Status;
|
|
Status = STATUS_SUCCESS;
|
|
|
|
RxDbgTrace(0,Dbg,("SmbTransactExchangeReceive: Exchange aborted.\n",Status));
|
|
|
|
return Status;
|
|
|
|
UNREFERENCED_PARAMETER(ReceiveFlags);
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbTransactExchangeAbort(
|
|
PSMB_EXCHANGE pExchange)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the abort routine for transact exchanges
|
|
|
|
Arguments:
|
|
|
|
pExchange - the exchange instance
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
PAGED_CODE();
|
|
|
|
// The SMB exchange completed with an error. Invoke the RDBSS callback routine
|
|
// and scavenge the exchange instance.
|
|
|
|
pExchange->Status = STATUS_REQUEST_ABORTED;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbTransactExchangeErrorHandler(
|
|
IN PSMB_EXCHANGE pExchange) // the SMB exchange instance
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the error indication handling routine for transact exchanges
|
|
|
|
Arguments:
|
|
|
|
pExchange - the exchange instance
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
PAGED_CODE();
|
|
|
|
// The SMB exchange completed with an error. Invoke the RDBSS callback routine
|
|
// and scavenge the exchange instance.
|
|
return STATUS_SUCCESS;
|
|
|
|
UNREFERENCED_PARAMETER(pExchange);
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbTransactExchangeSendCallbackHandler(
|
|
IN PSMB_EXCHANGE pExchange, // The exchange instance
|
|
IN PMDL pXmitBuffer,
|
|
IN NTSTATUS SendCompletionStatus)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the send call back indication handling routine for transact exchanges
|
|
|
|
Arguments:
|
|
|
|
pExchange - the exchange instance
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
PAGED_CODE();
|
|
|
|
return STATUS_SUCCESS;
|
|
UNREFERENCED_PARAMETER(pExchange);
|
|
UNREFERENCED_PARAMETER(pXmitBuffer);
|
|
UNREFERENCED_PARAMETER(SendCompletionStatus);
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbTransactExchangeCopyDataHandler(
|
|
IN PSMB_EXCHANGE pExchange, // The exchange instance
|
|
IN PMDL pDataBuffer, // the buffer
|
|
IN ULONG DataSize)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the copy data handling routine for transact exchanges
|
|
|
|
Arguments:
|
|
|
|
pExchange - the exchange instance
|
|
|
|
pDataBuffer - the buffer
|
|
|
|
DataSize - the amount of data returned
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PSMB_TRANSACT_EXCHANGE pTransactExchange = (PSMB_TRANSACT_EXCHANGE)pExchange;
|
|
|
|
PMDL pCopyRequestMdl = NULL;
|
|
PMDL pCurMdl = NULL;
|
|
ULONG CopyRequestSize = 0;
|
|
PMDL TrailingBytesMdl = &pTransactExchange->TrailingBytesMdl;
|
|
|
|
ULONG BytesConsumed;
|
|
|
|
RxDbgTrace(+1,Dbg,("SmbTransactExchangeCopyDataHandler: Entered\n"));
|
|
|
|
if (pTransactExchange->DiscardBuffer!=NULL) {
|
|
//we just copied to get rid of the buffer....
|
|
//free the buffer, set the status and get out
|
|
RxFreePool(pTransactExchange->DiscardBuffer);
|
|
Status = pTransactExchange->SaveTheRealStatus;
|
|
RxDbgTrace(-1,Dbg,("SmbTransactExchangeCopyDataHandler: Discard Exit, status =%08lx\n"));
|
|
DbgPrint("copyHandlerDiscard, st=%08lx\n",Status);
|
|
return Status;
|
|
}
|
|
|
|
switch (pTransactExchange->State) {
|
|
case TRANSACT_EXCHANGE_TRANSMITTED_PRIMARY_REQUEST :
|
|
case TRANSACT_EXCHANGE_TRANSMITTED_SECONDARY_REQUESTS :
|
|
{
|
|
PSMB_HEADER pSmbHeader = (PSMB_HEADER)MmGetSystemAddressForMdlSafe(pDataBuffer,LowPagePriority);
|
|
|
|
RxDbgTrace(0,Dbg,("SmbTransactExchangeCopyDataHandler: Reparsing response\n"));
|
|
|
|
if (pSmbHeader == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else {
|
|
// The response could not be parsed with the indicated bytes. Invoke
|
|
// the receive method to resume parsing of the complete SMB
|
|
Status = SmbTransactExchangeReceive(
|
|
pExchange,
|
|
DataSize,
|
|
DataSize,
|
|
&BytesConsumed,
|
|
pSmbHeader,
|
|
&pCopyRequestMdl,
|
|
&CopyRequestSize,
|
|
TDI_RECEIVE_ENTIRE_MESSAGE);
|
|
}
|
|
|
|
if ((Status == RX_MAP_STATUS(SUCCESS))) {
|
|
ASSERT(BytesConsumed == DataSize);
|
|
ASSERT(pCopyRequestMdl == NULL);
|
|
ASSERT(CopyRequestSize == 0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TRANSACT_EXCHANGE_RECEIVED_PRIMARY_RESPONSE :
|
|
{
|
|
RxDbgTrace(0,Dbg,("SmbTransactExchangeCopyDataHandler: Completing secondary response processing\n"));
|
|
|
|
// In this state only secondary responses will be received. All the secondary
|
|
// responses can be parsed from the indication. Therefore it is sufficient to
|
|
// merely free the MDL's and re-register with the connection engine for
|
|
// receiving subsequent requests.
|
|
InterlockedDecrement(&pTransactExchange->PendingCopyRequests);
|
|
|
|
if ((pTransactExchange->ParamBytesReceived == pTransactExchange->ReceiveParamBufferSize) &&
|
|
(pTransactExchange->DataBytesReceived == pTransactExchange->ReceiveDataBufferSize) &&
|
|
(pTransactExchange->PendingCopyRequests == 0)) {
|
|
// The exchange has been successfully completed. Finalize it.
|
|
RxDbgTrace(0,Dbg,("SmbTransactExchangeCopyDataHandler: Processed last secondary response successfully\n"));
|
|
pExchange->Status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
ASSERT(!"Valid State fore receiving copy data completion indication");
|
|
pExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Free up the data buffers.
|
|
pCurMdl = pDataBuffer;
|
|
|
|
while (pCurMdl != NULL) {
|
|
PMDL pPrevMdl = pCurMdl;
|
|
pCurMdl = pCurMdl->Next;
|
|
if (pPrevMdl!=TrailingBytesMdl) {
|
|
IoFreeMdl(pPrevMdl);
|
|
}
|
|
}
|
|
|
|
RxDbgTrace(-1,Dbg,("SmbTransactExchangeCopyDataHandler: Exit\n"));
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbCeInitializeTransactExchange(
|
|
PSMB_TRANSACT_EXCHANGE pTransactExchange,
|
|
PRX_CONTEXT RxContext,
|
|
PSMB_TRANSACTION_OPTIONS pOptions,
|
|
PSMB_TRANSACTION_SEND_PARAMETERS pSendParameters,
|
|
PSMB_TRANSACTION_RECEIVE_PARAMETERS pReceiveParameters,
|
|
PSMB_TRANSACTION_RESUMPTION_CONTEXT pResumptionContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes a transact exchange instance
|
|
|
|
Arguments:
|
|
|
|
pTransactExchange - the exchange instance
|
|
|
|
RxContext - RDBSS context for the file involved in the transaction.
|
|
|
|
pOptions - the transaction options
|
|
|
|
pSendParameters - the parameters to be sent to the server
|
|
|
|
pReceiveParameters - the results from the server
|
|
|
|
pResumptionContext - the resumption context
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
RxCaptureFobx;
|
|
|
|
UCHAR SmbCommand;
|
|
|
|
PMDL pSendDataMdl;
|
|
PMDL pSendParamMdl; //used if we can't subsume
|
|
PMDL pReceiveDataMdl;
|
|
PMDL pReceiveParamMdl;
|
|
|
|
PVOID pSendSetupBuffer;
|
|
ULONG SendSetupBufferSize;
|
|
|
|
PMDL pReceiveSetupMdl;
|
|
ULONG ReceiveSetupBufferSize;
|
|
|
|
ULONG SendDataBufferSize;
|
|
ULONG ReceiveDataBufferSize;
|
|
|
|
PVOID pSendParamBuffer;
|
|
ULONG SendParamBufferSize;
|
|
ULONG ReceiveParamBufferSize;
|
|
|
|
ULONG MaxSmbBufferSize = 0;
|
|
ULONG PrimaryRequestSmbSize = 0;
|
|
|
|
// The fields in theSMB request that are dialect independent and need to be filled in
|
|
PUSHORT pBcc; // the byte count field
|
|
PUSHORT pSetup; // the setup data
|
|
PBYTE pParam; // the param data
|
|
|
|
BOOLEAN fTransactionNameInUnicode = FALSE;
|
|
|
|
PSMB_EXCHANGE pExchange = (PSMB_EXCHANGE)pTransactExchange;
|
|
|
|
PVOID pActualPrimaryRequestSmbHeader;
|
|
PSMB_HEADER pPrimaryRequestSmbHeader;
|
|
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT(pTransactExchange->Type == TRANSACT_EXCHANGE);
|
|
|
|
pTransactExchange->RxContext = RxContext;
|
|
pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
|
|
|
|
{
|
|
PMRXSMB_RX_CONTEXT pMRxSmbContext = MRxSmbGetMinirdrContext(RxContext);
|
|
pMRxSmbContext->pExchange = (PSMB_EXCHANGE)pTransactExchange;
|
|
}
|
|
|
|
ASSERT(pSendParameters != NULL);
|
|
if (pSendParameters != NULL) {
|
|
pSendDataMdl = pSendParameters->pDataMdl;
|
|
pSendParamBuffer = pSendParameters->pParam;
|
|
SendParamBufferSize = pSendParameters->ParamLength;
|
|
pSendParamMdl = pSendParameters->pParamMdl;
|
|
pSendSetupBuffer = pSendParameters->pSetup;
|
|
SendSetupBufferSize = pSendParameters->SetupLength;
|
|
SendDataBufferSize = pSendParameters->DataLength;
|
|
ASSERT( !((pSendDataMdl == NULL)&&(SendDataBufferSize!=0)) );
|
|
RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: at the top pbuf/psize/dsize=%08lx/%08lx\n"
|
|
,pSendParamBuffer,SendParamBufferSize,SendDataBufferSize));
|
|
} else {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: Invalid Parameters\n",Status));
|
|
return Status;
|
|
}
|
|
|
|
if (pReceiveParameters != NULL) {
|
|
pReceiveDataMdl = pReceiveParameters->pDataMdl;
|
|
pReceiveParamMdl = pReceiveParameters->pParamMdl;
|
|
pReceiveSetupMdl = pReceiveParameters->pSetupMdl;
|
|
|
|
ReceiveDataBufferSize = ((pReceiveDataMdl != NULL) ? MmGetMdlByteCount(pReceiveDataMdl) : 0);
|
|
ASSERT (ReceiveDataBufferSize==pReceiveParameters->DataLength);
|
|
ReceiveParamBufferSize = ((pReceiveParamMdl != NULL) ? MmGetMdlByteCount(pReceiveParamMdl) : 0);
|
|
ReceiveSetupBufferSize = ((pReceiveSetupMdl != NULL) ? MmGetMdlByteCount(pReceiveSetupMdl) : 0);
|
|
} else {
|
|
pReceiveDataMdl = pReceiveParamMdl = pReceiveSetupMdl = NULL;
|
|
ReceiveDataBufferSize = ReceiveParamBufferSize = ReceiveDataBufferSize = 0;
|
|
}
|
|
|
|
MaxSmbBufferSize = MIN (pServerEntry->Server.MaximumBufferSize,
|
|
pOptions->MaximumTransmitSmbBufferSize);
|
|
pTransactExchange->MaximumTransmitSmbBufferSize = MaxSmbBufferSize;
|
|
|
|
//CODE.IMPROVEMENT this switch should be replace by four ifs each testing for the right df-flag....
|
|
|
|
// Ensure that the SMB dialect supports the exchange capability.
|
|
switch (pServerEntry->Server.Dialect) {
|
|
case NTLANMAN_DIALECT:
|
|
{
|
|
if (!FlagOn(pOptions->Flags,SMB_XACT_FLAGS_MAILSLOT_OPERATION) &&
|
|
FlagOn(pServerEntry->Server.DialectFlags,DF_UNICODE)) {
|
|
fTransactionNameInUnicode = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case LANMAN10_DIALECT:
|
|
case WFW10_DIALECT:
|
|
{
|
|
// these guys only support transact...not T2 or NT. look for the name.....
|
|
if (pOptions->pTransactionName == NULL) {
|
|
RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: Server Dialect does not support nameless transactions\n"));
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
}
|
|
//no break intentional........
|
|
case LANMAN12_DIALECT:
|
|
case LANMAN21_DIALECT:
|
|
{
|
|
// The NT_TRANSACT SMB is supported by NT servers only. Ensure that no attempt is being made
|
|
// to send an NT_TRANSACT SMB to a non NT server aka downlevel
|
|
if (pOptions->NtTransactFunction != 0) {
|
|
RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: Server Dialect does not support transactions\n"));
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
fTransactionNameInUnicode = FALSE;
|
|
}
|
|
break;
|
|
default:
|
|
RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: Server Dialect does not support transactions\n"));
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
PrimaryRequestSmbSize = sizeof(SMB_HEADER) + SendSetupBufferSize;
|
|
|
|
// Ensure that the parameter sizes are all valid. The parameter and the data buffer
|
|
// must be less than the maximum size to begin with.
|
|
if ( pOptions->NtTransactFunction == 0) {
|
|
if ((SendParamBufferSize > SMB_TRANSACT_MAXIMUM_PARAMETER_SIZE) ||
|
|
(ReceiveParamBufferSize > SMB_TRANSACT_MAXIMUM_PARAMETER_SIZE) ||
|
|
(SendDataBufferSize > SMB_TRANSACT_MAXIMUM_DATA_SIZE) ||
|
|
(ReceiveDataBufferSize > SMB_TRANSACT_MAXIMUM_DATA_SIZE)) {
|
|
RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: Parameters exceed maximum value\n"));
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
PrimaryRequestSmbSize += sizeof(REQ_TRANSACTION);
|
|
|
|
// In all cases the name is sent as a UNICODE string if the appropriate capability is
|
|
// supported. The only exception to this rule is for mail slots for which the name is
|
|
// always transmitted as an ANSI string. Account for the null character as well in the
|
|
// transaction name length.
|
|
if (pOptions->pTransactionName != NULL) {
|
|
if (!fTransactionNameInUnicode) {
|
|
pTransactExchange->TransactionNameLength = RtlUnicodeStringToAnsiSize(pOptions->pTransactionName);
|
|
} else {
|
|
pTransactExchange->TransactionNameLength = pOptions->pTransactionName->Length + sizeof(WCHAR);
|
|
|
|
PrimaryRequestSmbSize += (ULONG)((PBYTE)ALIGN_SMB_WSTR(PrimaryRequestSmbSize)
|
|
- (PBYTE)(ULONG_PTR)PrimaryRequestSmbSize);
|
|
}
|
|
|
|
SmbCommand = SMB_COM_TRANSACTION;
|
|
} else {
|
|
// SMB protocol requires that a single NULL byte be sent as part of all
|
|
// TRANSACT2 transactions.
|
|
pTransactExchange->TransactionNameLength = 1;
|
|
|
|
SmbCommand = SMB_COM_TRANSACTION2;
|
|
}
|
|
|
|
PrimaryRequestSmbSize += pTransactExchange->TransactionNameLength;
|
|
} else {
|
|
PrimaryRequestSmbSize += sizeof(REQ_NT_TRANSACTION);
|
|
SmbCommand = SMB_COM_NT_TRANSACT;
|
|
pTransactExchange->TransactionNameLength = 0;
|
|
}
|
|
|
|
// The header, setup bytes and the name if specified must be part of the primary
|
|
// request SMB for a transaction to be successful. The secondary requests have no
|
|
// provision for sending setup/name.
|
|
if (PrimaryRequestSmbSize > MaxSmbBufferSize) {
|
|
RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: Primary request + setup exceeds maximum buffer size\n"));
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Include the byte count size and then align the size to a DWORD boundary.
|
|
PrimaryRequestSmbSize = ROUND_UP_COUNT(PrimaryRequestSmbSize+sizeof(USHORT),ALIGN_DWORD);
|
|
|
|
// Try to allocate for the param buffer as well if possible. The additional DWORD
|
|
// takes into account the worst case of alignment padding required.
|
|
//if ( (PrimaryRequestSmbSize + SendParamBufferSize + sizeof(DWORD)) > MaxSmbBufferSize)
|
|
if ((SendParamBufferSize!=0)
|
|
&& (((PrimaryRequestSmbSize + SendParamBufferSize) > MaxSmbBufferSize)
|
|
|| (DONTSUBSUME_PARAMS)) ){
|
|
// The param will spill over to a secondary request. Do not attempt to over
|
|
// allocate the primary request. if we can't subsume the params, then we'll need an MDL
|
|
// to partial from.
|
|
|
|
RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: cannot subsume params\n"));
|
|
pTransactExchange->fParamsSubsumedInPrimaryRequest = FALSE;
|
|
pSendParamMdl = RxAllocateMdl(pSendParamBuffer,SendParamBufferSize);
|
|
if (pSendParamMdl == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else {
|
|
RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: BIGPARAMMDL %08lx\n",pSendParamMdl));
|
|
RxProbeAndLockPages(pSendParamMdl,KernelMode,IoModifyAccess,Status);
|
|
if ((Status != RX_MAP_STATUS(SUCCESS))) {
|
|
IoFreeMdl(pSendParamMdl);
|
|
} else {
|
|
if (MmGetSystemAddressForMdlSafe(pSendParamMdl,LowPagePriority) == NULL) { //map it
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
pSendParameters->pParamMdl = pSendParamMdl; // save it away
|
|
}
|
|
}
|
|
} else {
|
|
PrimaryRequestSmbSize = ROUND_UP_COUNT(PrimaryRequestSmbSize+SendParamBufferSize,ALIGN_DWORD);
|
|
|
|
// Update the transact exchange to reflect the fact that no separate param MDL is
|
|
// required.
|
|
pTransactExchange->fParamsSubsumedInPrimaryRequest = TRUE;
|
|
}
|
|
|
|
//CODE.IMPROVEMENT this should be replaced by a call to get a smbbuf as in OrdExchg
|
|
|
|
pActualPrimaryRequestSmbHeader = (PSMB_HEADER)RxAllocatePoolWithTag(
|
|
PagedPool,
|
|
(PrimaryRequestSmbSize + 4 + TRANSPORT_HEADER_SIZE),
|
|
MRXSMB_XACT_POOLTAG); //up to 4 pad bytes
|
|
|
|
if (pActualPrimaryRequestSmbHeader == NULL) {
|
|
RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: Cannot allocate primary request SMB\n"));
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
else {
|
|
(PCHAR) pPrimaryRequestSmbHeader =
|
|
(PCHAR) pActualPrimaryRequestSmbHeader + TRANSPORT_HEADER_SIZE;
|
|
}
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
switch (SmbCommand) {
|
|
case SMB_COM_TRANSACTION :
|
|
case SMB_COM_TRANSACTION2:
|
|
{
|
|
PREQ_TRANSACTION pTransactRequest;
|
|
|
|
pTransactRequest = (PREQ_TRANSACTION)(pPrimaryRequestSmbHeader + 1);
|
|
pTransactRequest->WordCount = (UCHAR)(14 + (SendSetupBufferSize/sizeof(USHORT)));
|
|
SmbPutUshort(
|
|
&pTransactRequest->TotalParameterCount,
|
|
(USHORT)SendParamBufferSize);
|
|
SmbPutUshort(
|
|
&pTransactRequest->TotalDataCount,
|
|
(USHORT)SendDataBufferSize);
|
|
SmbPutUshort(
|
|
&pTransactRequest->MaxParameterCount,
|
|
(USHORT)ReceiveParamBufferSize);
|
|
SmbPutUshort(
|
|
&pTransactRequest->MaxDataCount,
|
|
(USHORT)ReceiveDataBufferSize);
|
|
|
|
pTransactRequest->MaxSetupCount = (UCHAR)(ReceiveSetupBufferSize/sizeof(USHORT));
|
|
|
|
pTransactRequest->Reserved = 0;
|
|
pTransactRequest->Reserved3 = 0;
|
|
SmbPutUshort(&pTransactRequest->Reserved2, 0);
|
|
|
|
SmbPutUshort( &pTransactRequest->Flags, pOptions->Flags&~SMB_XACT_INTERNAL_FLAGS_MASK );
|
|
pTransactRequest->SetupCount = (UCHAR)(SendSetupBufferSize/sizeof(USHORT));
|
|
SmbPutUlong(&pTransactRequest->Timeout, pOptions->TimeoutIntervalInMilliSeconds);
|
|
pSetup = (PUSHORT)pTransactRequest->Buffer;
|
|
|
|
// Copy the transact name and align the buffer if required.
|
|
if (pOptions->pTransactionName != NULL) {
|
|
PBYTE pName;
|
|
ULONG TransactionNameLength = pTransactExchange->TransactionNameLength;
|
|
|
|
// Set the name field in the SMB.
|
|
pName = (PBYTE)pSetup +
|
|
SendSetupBufferSize +
|
|
sizeof(USHORT); // account for the bcc field
|
|
|
|
ASSERT(SmbCommand == SMB_COM_TRANSACTION);
|
|
RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: TransactionName(Length %ld) %ws\n",
|
|
TransactionNameLength,
|
|
pOptions->pTransactionName->Buffer));
|
|
|
|
if (fTransactionNameInUnicode) {
|
|
pName = ALIGN_SMB_WSTR(pName);
|
|
Status = SmbPutUnicodeString(&pName,
|
|
pOptions->pTransactionName,
|
|
&TransactionNameLength);
|
|
} else {
|
|
Status = SmbPutUnicodeStringAsOemString(&pName,
|
|
pOptions->pTransactionName,
|
|
&TransactionNameLength);
|
|
}
|
|
}
|
|
|
|
pParam = (PBYTE)pSetup +
|
|
SendSetupBufferSize +
|
|
sizeof(USHORT) + // the bcc field
|
|
pTransactExchange->TransactionNameLength;
|
|
pParam = ROUND_UP_POINTER(pParam, ALIGN_DWORD);
|
|
}
|
|
break;
|
|
|
|
case SMB_COM_NT_TRANSACT:
|
|
{
|
|
PREQ_NT_TRANSACTION pNtTransactRequest;
|
|
|
|
pNtTransactRequest = (PREQ_NT_TRANSACTION)(pPrimaryRequestSmbHeader + 1);
|
|
pNtTransactRequest->WordCount = (UCHAR)(19 + (SendSetupBufferSize/sizeof(USHORT)));
|
|
|
|
SmbPutUlong( &pNtTransactRequest->TotalParameterCount, SendParamBufferSize);
|
|
SmbPutUlong( &pNtTransactRequest->TotalDataCount, SendDataBufferSize);
|
|
SmbPutUlong( &pNtTransactRequest->MaxParameterCount, ReceiveParamBufferSize);
|
|
SmbPutUlong( &pNtTransactRequest->MaxDataCount, ReceiveDataBufferSize);
|
|
RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: init for NT_T (p,d,mp,md) %d %d %d %d\n",
|
|
pNtTransactRequest->TotalParameterCount, pNtTransactRequest->TotalDataCount,
|
|
pNtTransactRequest->MaxParameterCount, pNtTransactRequest->MaxDataCount));
|
|
|
|
pNtTransactRequest->MaxSetupCount = (UCHAR)(ReceiveSetupBufferSize / sizeof(USHORT));
|
|
SmbPutUshort( &pNtTransactRequest->Flags, pOptions->Flags&~SMB_XACT_INTERNAL_FLAGS_MASK );
|
|
SmbPutUshort( &pNtTransactRequest->Function, pOptions->NtTransactFunction );
|
|
pNtTransactRequest->SetupCount = (UCHAR)(SendSetupBufferSize/sizeof(USHORT));
|
|
pSetup = (PUSHORT)pNtTransactRequest->Buffer;
|
|
pParam = (PBYTE)pSetup +
|
|
SendSetupBufferSize +
|
|
sizeof(USHORT); // the bcc field
|
|
pParam = ROUND_UP_POINTER(pParam, ALIGN_DWORD);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT(!"Valid Smb Command Type for Transact exchange");
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
// All related initialization of a transaction exchange has been
|
|
// completed. At this point the transact exchange assumes ownership
|
|
// of the various buffers ( specified as MDLs ) in the receive and
|
|
// send parameters. It will get rid of them during finalization
|
|
// of the exchange. In order to ensure that the caller does not
|
|
// attempt to free any of these buffers they are reset in the
|
|
// receive/send parameters.
|
|
|
|
// Copy the setup data
|
|
RtlCopyMemory(pSetup,pSendSetupBuffer,SendSetupBufferSize);
|
|
|
|
if (pTransactExchange->fParamsSubsumedInPrimaryRequest) {
|
|
RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: subsuming where/size=%08lx/%08lx\n"
|
|
,pSendParamBuffer,SendParamBufferSize));
|
|
RtlCopyMemory(pParam,pSendParamBuffer,SendParamBufferSize);
|
|
}
|
|
|
|
// Initialize the transact exchange.
|
|
pTransactExchange->Status = STATUS_MORE_PROCESSING_REQUIRED;
|
|
|
|
pTransactExchange->Mid = 0;
|
|
pTransactExchange->TransactSmbCommand = SmbCommand;
|
|
pTransactExchange->pActualPrimaryRequestSmbHeader = pActualPrimaryRequestSmbHeader;
|
|
pTransactExchange->pPrimaryRequestSmbHeader = pPrimaryRequestSmbHeader;
|
|
pTransactExchange->PrimaryRequestSmbSize = PrimaryRequestSmbSize;
|
|
|
|
pTransactExchange->pSendDataMdl = pSendDataMdl;
|
|
pTransactExchange->SendDataBufferSize = SendDataBufferSize;
|
|
pTransactExchange->pReceiveDataMdl = pReceiveDataMdl;
|
|
pTransactExchange->ReceiveDataBufferSize = ReceiveDataBufferSize;
|
|
pTransactExchange->DataBytesSent = 0;
|
|
pTransactExchange->DataBytesReceived = 0;
|
|
|
|
pTransactExchange->pSendParamBuffer = pSendParamBuffer;
|
|
pTransactExchange->SendParamBufferSize = SendParamBufferSize;
|
|
pTransactExchange->pSendParamMdl = pSendParamMdl;
|
|
pTransactExchange->pReceiveParamMdl = pReceiveParamMdl;
|
|
pTransactExchange->ReceiveParamBufferSize = ReceiveParamBufferSize;
|
|
pTransactExchange->ParamBytesSent = 0;
|
|
pTransactExchange->ParamBytesReceived = 0;
|
|
|
|
pTransactExchange->pReceiveSetupMdl = pReceiveSetupMdl;
|
|
pTransactExchange->ReceiveSetupBufferSize = ReceiveSetupBufferSize;
|
|
pTransactExchange->SetupBytesReceived = 0;
|
|
|
|
pTransactExchange->NtTransactFunction = pOptions->NtTransactFunction;
|
|
pTransactExchange->Flags = pOptions->Flags;
|
|
|
|
if ((capFobx != NULL) &&
|
|
BooleanFlagOn(capFobx->Flags,FOBX_FLAG_DFS_OPEN)) {
|
|
pTransactExchange->Flags |= SMB_XACT_FLAGS_DFS_AWARE;
|
|
} else if (RxContext->MajorFunction == IRP_MJ_CREATE) {
|
|
PMRX_NET_ROOT pNetRoot = RxContext->pFcb->pNetRoot;
|
|
|
|
if (FlagOn(pNetRoot->Flags,NETROOT_FLAG_DFS_AWARE_NETROOT) &&
|
|
RxContext->Create.NtCreateParameters.DfsContext == UIntToPtr(DFS_OPEN_CONTEXT)) {
|
|
pTransactExchange->Flags |= SMB_XACT_FLAGS_DFS_AWARE;
|
|
}
|
|
}
|
|
|
|
pTransactExchange->pResumptionContext = pResumptionContext;
|
|
|
|
// Reset the Send and Receive parameter data structures to transfer
|
|
// the ownership of the MDLs to the exchange.
|
|
|
|
if (pSendParameters->Flags & SMB_XACT_FLAGS_CALLERS_SENDDATAMDL) {
|
|
pTransactExchange->Flags |= SMB_XACT_FLAGS_CALLERS_SENDDATAMDL;
|
|
}
|
|
|
|
RtlZeroMemory(
|
|
pSendParameters,
|
|
sizeof(SMB_TRANSACTION_SEND_PARAMETERS));
|
|
|
|
RtlZeroMemory(
|
|
pReceiveParameters,
|
|
sizeof(SMB_TRANSACTION_RECEIVE_PARAMETERS));
|
|
}
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
// Clean up the memory allocated in an effort to initialize the transact exchange
|
|
if (pActualPrimaryRequestSmbHeader) {
|
|
|
|
RxFreePool(pActualPrimaryRequestSmbHeader);
|
|
}
|
|
} else {
|
|
PMRXSMB_RX_CONTEXT pMRxSmbContext = MRxSmbGetMinirdrContext(RxContext);
|
|
|
|
pMRxSmbContext->pExchange = (PSMB_EXCHANGE)pTransactExchange;
|
|
|
|
if (!FlagOn(pTransactExchange->Flags,SMB_XACT_FLAGS_MAILSLOT_OPERATION)) {
|
|
// No reconnection attempts are allowed in transact exchanges except mailslot
|
|
pTransactExchange->SmbCeFlags &= ~SMBCE_EXCHANGE_ATTEMPT_RECONNECTS;
|
|
}
|
|
|
|
if (pOptions->Flags & SMB_XACT_FLAGS_INDEFINITE_DELAY_IN_RESPONSE ) {
|
|
pTransactExchange->SmbCeFlags |= SMBCE_EXCHANGE_INDEFINITE_DELAY_IN_RESPONSE;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbTransactExchangeFinalize(
|
|
PSMB_EXCHANGE pExchange,
|
|
BOOLEAN *pPostFinalize)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine finalizes the transact exchange. It resumes the RDBSS by invoking
|
|
the call back and discards the exchange
|
|
|
|
Arguments:
|
|
|
|
pExchange - the exchange instance
|
|
|
|
CurrentIrql - the interrupt request level
|
|
|
|
pPostFinalize - set to TRUE if the request is to be posted
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
PSMB_TRANSACT_EXCHANGE pTransactExchange;
|
|
PSMB_TRANSACTION_RESUMPTION_CONTEXT pResumptionContext;
|
|
LONG References;
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
|
|
|
|
ASSERT(pExchange->Type == TRANSACT_EXCHANGE);
|
|
|
|
pTransactExchange = (PSMB_TRANSACT_EXCHANGE)pExchange;
|
|
|
|
RxLog((">>>XE %lx",pTransactExchange));
|
|
SmbLog(LOG,
|
|
SmbTransactExchangeFinalize,
|
|
LOGPTR(pTransactExchange));
|
|
|
|
// Disassociate the MID associated with the exchange
|
|
if (pExchange->SmbCeFlags & SMBCE_EXCHANGE_MID_VALID) {
|
|
SmbCeDissociateMidFromExchange(pExchange->SmbCeContext.pServerEntry,pExchange);
|
|
}
|
|
|
|
if ((pTransactExchange->ReceiveParamBufferSize > 0) &&
|
|
(pTransactExchange->ReceiveParamBufferSize !=
|
|
pTransactExchange->ParamBytesReceived)) {
|
|
RxDbgTrace(0, Dbg,
|
|
("SmbCeTransactExchangeFinalize: Param Bytes Receive error ... expected(%ld) received(%ld)\n",
|
|
pTransactExchange->ReceiveParamBufferSize, pTransactExchange->ParamBytesReceived
|
|
));
|
|
}
|
|
|
|
if ((pTransactExchange->ReceiveDataBufferSize > 0) &&
|
|
(pTransactExchange->ReceiveDataBufferSize !=
|
|
pTransactExchange->DataBytesReceived)) {
|
|
RxDbgTrace(0, Dbg,
|
|
("SmbCeTransactExchangeFinalize: Data Bytes Receive error ... expected(%ld) received(%ld)\n",
|
|
pTransactExchange->ReceiveDataBufferSize, pTransactExchange->DataBytesReceived
|
|
));
|
|
}
|
|
|
|
if (RxShouldPostCompletion()) {
|
|
RxPostToWorkerThread(
|
|
MRxSmbDeviceObject,
|
|
CriticalWorkQueue,
|
|
&pExchange->WorkQueueItem,
|
|
SmbCeDiscardTransactExchange,
|
|
pTransactExchange);
|
|
} else {
|
|
SmbCeDiscardTransactExchange(pTransactExchange);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
UNREFERENCED_PARAMETER(pPostFinalize);
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbTransactAccrueAndValidateFormatData(
|
|
IN struct _SMB_TRANSACT_EXCHANGE *pTransactExchange, // The exchange instance
|
|
IN PSMB_HEADER pSmbHeader,
|
|
IN ULONG BytesIndicated,
|
|
OUT PSMB_TRANSACT_RESP_FORMAT_DESCRIPTION Format
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the recieve indication handling routine for net root construction exchanges
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
STATUS_SUCCESS -- all the data was indicated and it was valid
|
|
STATUS_INVALID_NETWORK_RESPONSE -- something about the format parameters is untoward.
|
|
|
|
Notes:
|
|
|
|
This routine is called at DPC level.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = RX_MAP_STATUS(SUCCESS);
|
|
PRESP_TRANSACTION pTransactResponse = (PRESP_TRANSACTION)(pSmbHeader+1);
|
|
PBYTE WordCountPtr;
|
|
UCHAR WordCount;
|
|
PBYTE ByteCountPtr;
|
|
USHORT ByteCount;
|
|
|
|
RtlZeroMemory(Format,sizeof(*Format));
|
|
|
|
Format->WordCount = WordCount = pTransactResponse->WordCount;
|
|
ByteCountPtr = (&pTransactResponse->WordCount)+1+(sizeof(USHORT)*WordCount);
|
|
|
|
if (((ULONG)(ByteCountPtr+sizeof(USHORT)-((PBYTE)pSmbHeader)))>BytesIndicated) {
|
|
ByteCount = SmbGetUshort(ByteCountPtr);
|
|
DbgPrint("ExtraTransactBytes wc,bcp,bc,smbh %lx,%lx,%lx,%lx\n",
|
|
WordCount,ByteCountPtr,ByteCount,pSmbHeader);
|
|
return STATUS_INVALID_NETWORK_RESPONSE;
|
|
}
|
|
|
|
Format->ByteCount = ByteCount = SmbGetUshort(ByteCountPtr);
|
|
Format->ApparentMsgLength = (ULONG)((ByteCountPtr+sizeof(USHORT)-((PBYTE)pSmbHeader))+ByteCount);
|
|
|
|
if (WordCount==0) {
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
#if 0
|
|
ULONG WordCount;
|
|
ULONG TotalParameterCount;
|
|
ULONG TotalDataCount;
|
|
ULONG ParameterCount;
|
|
ULONG ParameterOffset;
|
|
ULONG ParameterDisplacement;
|
|
ULONG DataCount;
|
|
ULONG DataOffset;
|
|
ULONG DataDisplacement;
|
|
ULONG ByteCount;
|
|
ULONG ApparentMsgLength;
|
|
#endif
|
|
|
|
// where is the validation: stuff that should be checked is
|
|
// a) that the values fit in the params and data spcified
|
|
// b) that we are not over the limit on bytes received
|
|
// c) that the response that we are receiving is valid for the command that we sent
|
|
// we didn't compute ApparentMsgLength.......
|
|
// The validation has not been done here. We rely on Transact Receive routine to detect the invalid response.
|
|
|
|
//CODE.IMPROVEMENT we could save some space with an unstuffer here........... but
|
|
// we'd have to amortize the cost over a lot more places. we should look on RISC machines to see if they turn it
|
|
// into a single copy.
|
|
|
|
switch (pSmbHeader->Command) {
|
|
case SMB_COM_TRANSACTION2:
|
|
case SMB_COM_TRANSACTION:
|
|
case SMB_COM_TRANSACTION_SECONDARY:
|
|
case SMB_COM_TRANSACTION2_SECONDARY:
|
|
{
|
|
Format->TotalParameterCount = SmbGetUshort(&pTransactResponse->TotalParameterCount);
|
|
Format->TotalDataCount = SmbGetUshort(&pTransactResponse->TotalDataCount);
|
|
|
|
Format->ParameterCount = SmbGetUshort(&pTransactResponse->ParameterCount);
|
|
Format->ParameterOffset = SmbGetUshort(&pTransactResponse->ParameterOffset);
|
|
Format->ParameterDisplacement = SmbGetUshort(&pTransactResponse->ParameterDisplacement);
|
|
|
|
Format->DataCount = SmbGetUshort(&pTransactResponse->DataCount);
|
|
Format->DataOffset = SmbGetUshort(&pTransactResponse->DataOffset);
|
|
Format->DataDisplacement = SmbGetUshort(&pTransactResponse->DataDisplacement);
|
|
}
|
|
break;
|
|
|
|
case SMB_COM_NT_TRANSACT:
|
|
case SMB_COM_NT_TRANSACT_SECONDARY:
|
|
{
|
|
PRESP_NT_TRANSACTION pNtTransactResponse;
|
|
|
|
pNtTransactResponse = (PRESP_NT_TRANSACTION)(pTransactResponse);
|
|
|
|
Format->TotalParameterCount = SmbGetUlong(&pNtTransactResponse->TotalParameterCount);
|
|
Format->TotalDataCount = SmbGetUlong(&pNtTransactResponse->TotalDataCount);
|
|
|
|
Format->ParameterCount = SmbGetUlong(&pNtTransactResponse->ParameterCount);
|
|
Format->ParameterOffset = SmbGetUlong(&pNtTransactResponse->ParameterOffset);
|
|
Format->ParameterDisplacement = SmbGetUlong(&pNtTransactResponse->ParameterDisplacement);
|
|
|
|
Format->DataCount = SmbGetUlong(&pNtTransactResponse->DataCount);
|
|
Format->DataOffset = SmbGetUlong(&pNtTransactResponse->DataOffset);
|
|
Format->DataDisplacement = SmbGetUlong(&pNtTransactResponse->DataDisplacement);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
// Bug Check
|
|
return STATUS_INVALID_NETWORK_RESPONSE;
|
|
}
|
|
|
|
//do this here so we can use it as validation criterion
|
|
pTransactExchange->ParameterBytesSeen += Format->ParameterCount;
|
|
pTransactExchange->DataBytesSeen += Format->DataCount;
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ParseTransactResponse(
|
|
IN struct _SMB_TRANSACT_EXCHANGE *pTransactExchange, // The exchange instance
|
|
IN PSMB_TRANSACT_RESP_FORMAT_DESCRIPTION Format,
|
|
IN ULONG BytesIndicated,
|
|
IN ULONG BytesAvailable,
|
|
OUT ULONG *pBytesTaken,
|
|
IN PSMB_HEADER pSmbHeader,
|
|
OUT PMDL *pCopyRequestMdlPointer,
|
|
OUT PULONG pCopyRequestSize)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the recieve indication handling routine for net root construction exchanges
|
|
|
|
Arguments:
|
|
|
|
pTransactExchange - the exchange instance
|
|
|
|
BytesIndicated - the number of bytes indicated
|
|
|
|
Bytes Available - the number of bytes available
|
|
|
|
pBytesTaken - the number of bytes consumed
|
|
|
|
pSmbHeader - the byte buffer
|
|
|
|
pCopyRequestMdlPointer - the buffer into which the remaining data is to be copied.
|
|
|
|
pCopyRequestSize - the buffer size.
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
STATUS_MORE_PROCESSING_REQUIRED -- if a copy of the data needs to be done before
|
|
processing can be completed. This occurs because all the data was not indicated
|
|
STATUS_SUCCESS -- all the data was indicated and it was valid
|
|
STATUS_* -- They indicate an error which would normally leads to the abortion of the
|
|
exchange.
|
|
|
|
Notes:
|
|
|
|
This routine is called at DPC level.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
ULONG ParamBytesInResponse = 0;
|
|
ULONG ParamOffsetInResponse = 0;
|
|
ULONG DataBytesInResponse = 0;
|
|
ULONG DataOffsetInResponse = 0;
|
|
|
|
ULONG PaddingLength = 0;
|
|
|
|
PMDL pFirstMdlInCopyDataRequestChain = NULL;
|
|
PMDL pLastMdlInCopyDataRequestChain = NULL;
|
|
PMDL pParamMdl = NULL;
|
|
PMDL pPaddingMdl = NULL;
|
|
PMDL pDataMdl = NULL;
|
|
|
|
PBYTE pParamStartAddress;
|
|
PBYTE pDataStartAddress;
|
|
PBYTE pSmbBuffer = (PBYTE)pSmbHeader;
|
|
|
|
switch (pSmbHeader->Command) {
|
|
case SMB_COM_TRANSACTION2:
|
|
case SMB_COM_TRANSACTION:
|
|
case SMB_COM_TRANSACTION_SECONDARY:
|
|
case SMB_COM_TRANSACTION2_SECONDARY:
|
|
{
|
|
PRESP_TRANSACTION pTransactResponse;
|
|
|
|
pTransactResponse = (PRESP_TRANSACTION)(pSmbBuffer + *pBytesTaken);
|
|
*pBytesTaken = *pBytesTaken + sizeof(RESP_TRANSACTION);
|
|
}
|
|
break;
|
|
case SMB_COM_NT_TRANSACT:
|
|
case SMB_COM_NT_TRANSACT_SECONDARY:
|
|
{
|
|
PRESP_NT_TRANSACTION pNtTransactResponse;
|
|
|
|
pNtTransactResponse = (PRESP_NT_TRANSACTION)(pSmbBuffer + *pBytesTaken);
|
|
*pBytesTaken = *pBytesTaken + sizeof(RESP_NT_TRANSACTION);
|
|
}
|
|
break;
|
|
default:
|
|
// Bug Check
|
|
ASSERT(!"Valid SMB command in Transaction response");
|
|
return STATUS_INVALID_NETWORK_RESPONSE;
|
|
}
|
|
|
|
#if 0
|
|
ULONG WordCount;
|
|
ULONG TotalParameterCount;
|
|
ULONG TotalDataCount;
|
|
ULONG ParameterCount;
|
|
ULONG ParameterOffset;
|
|
ULONG ParameterDisplacement;
|
|
ULONG DataCount;
|
|
ULONG DataOffset;
|
|
ULONG DataDisplacement;
|
|
ULONG ByteCount;
|
|
ULONG ApparentMsgLength;
|
|
#endif
|
|
ParamBytesInResponse = Format->ParameterCount;
|
|
ParamOffsetInResponse = Format->ParameterOffset;
|
|
DataBytesInResponse = Format->DataCount;
|
|
DataOffsetInResponse = Format->DataOffset;
|
|
|
|
if (ParamBytesInResponse > 0) {
|
|
ASSERT(pTransactExchange->pReceiveParamMdl != NULL);
|
|
pParamStartAddress = (PBYTE)MmGetSystemAddressForMdlSafe(pTransactExchange->pReceiveParamMdl,LowPagePriority);
|
|
|
|
if (pParamStartAddress == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else {
|
|
pParamStartAddress += Format->ParameterDisplacement;
|
|
}
|
|
} else {
|
|
pParamStartAddress = NULL;
|
|
}
|
|
|
|
if (DataBytesInResponse > 0) {
|
|
ASSERT(pTransactExchange->pReceiveDataMdl != NULL);
|
|
pDataStartAddress = (PBYTE)MmGetSystemAddressForMdlSafe(pTransactExchange->pReceiveDataMdl,LowPagePriority);
|
|
|
|
if (pDataStartAddress == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else {
|
|
pDataStartAddress += Format->DataDisplacement;
|
|
}
|
|
} else {
|
|
pDataStartAddress = NULL;
|
|
}
|
|
|
|
RxDbgTrace( 0, Dbg, ("ParseTransactResponse: Param Bytes(%ld) Param Offset (%ld) Data Bytes (%ld) Data Offset(%ld)\n",
|
|
ParamBytesInResponse,
|
|
ParamOffsetInResponse,
|
|
DataBytesInResponse,
|
|
DataOffsetInResponse));
|
|
|
|
// If either the param bytes or the data bytes have already been indicated, copy
|
|
// them into the respective buffers and trim the size of the MDL for the copy
|
|
// data request.
|
|
|
|
if (ParamOffsetInResponse <= BytesIndicated) {
|
|
*pBytesTaken = ParamOffsetInResponse;
|
|
if (ParamBytesInResponse > 0) {
|
|
ULONG ParamBytesIndicated = MIN(
|
|
ParamBytesInResponse,
|
|
BytesIndicated - ParamOffsetInResponse);
|
|
|
|
RxDbgTrace( 0, Dbg, ("ParseTransactResponse: Param Bytes indicated %ld\n",ParamBytesIndicated));
|
|
RtlCopyMemory(
|
|
pParamStartAddress,
|
|
(pSmbBuffer + ParamOffsetInResponse),
|
|
ParamBytesIndicated);
|
|
|
|
*pBytesTaken = *pBytesTaken + ParamBytesIndicated;
|
|
pParamStartAddress += ParamBytesIndicated;
|
|
ParamBytesInResponse -= ParamBytesIndicated;
|
|
ParamOffsetInResponse += ParamBytesIndicated;
|
|
pTransactExchange->ParamBytesReceived += ParamBytesIndicated;
|
|
}
|
|
}
|
|
|
|
if ( (DataOffsetInResponse <= BytesIndicated) &&
|
|
(DataOffsetInResponse > 0) ) {
|
|
*pBytesTaken = DataOffsetInResponse; //you have to move up EVEN IF NO BYTES!!!!!
|
|
if (DataBytesInResponse > 0) {
|
|
ULONG DataBytesIndicated = MIN(
|
|
DataBytesInResponse,
|
|
BytesIndicated - DataOffsetInResponse);
|
|
|
|
RxDbgTrace( 0, Dbg, ("ParseTransactResponse: Data Bytes indicated %ld\n",DataBytesIndicated));
|
|
RtlCopyMemory(
|
|
pDataStartAddress,
|
|
(pSmbBuffer + DataOffsetInResponse),
|
|
DataBytesIndicated);
|
|
|
|
*pBytesTaken = *pBytesTaken + DataBytesIndicated;
|
|
pDataStartAddress += DataBytesIndicated;
|
|
DataBytesInResponse -= DataBytesIndicated;
|
|
DataOffsetInResponse += DataBytesIndicated;
|
|
pTransactExchange->DataBytesReceived += DataBytesIndicated;
|
|
}
|
|
}
|
|
|
|
RxDbgTrace( 0, Dbg, ("ParseTransactResponse: Made it past the copies......... \n"));
|
|
|
|
if (ParamBytesInResponse > 0) {
|
|
// There are more param bytes that have not been indicated. Set up an MDL
|
|
// to copy them over.
|
|
|
|
RxDbgTrace( 0, Dbg, ("ParseTransactResponse: Posting Copy request for Param Bytes %ld\n",ParamBytesInResponse));
|
|
pParamMdl = RxAllocateMdl(
|
|
((PBYTE)MmGetMdlVirtualAddress(pTransactExchange->pReceiveParamMdl)
|
|
+ pTransactExchange->ParamBytesReceived),
|
|
ParamBytesInResponse);
|
|
|
|
if (pParamMdl != NULL) {
|
|
IoBuildPartialMdl(
|
|
pTransactExchange->pReceiveParamMdl,
|
|
pParamMdl,
|
|
((PBYTE)MmGetMdlVirtualAddress(pTransactExchange->pReceiveParamMdl)
|
|
+ pTransactExchange->ParamBytesReceived),
|
|
ParamBytesInResponse);
|
|
pFirstMdlInCopyDataRequestChain = pParamMdl;
|
|
pLastMdlInCopyDataRequestChain = pParamMdl;
|
|
} else {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
pTransactExchange->ParamBytesReceived += ParamBytesInResponse;
|
|
}
|
|
|
|
if ((Status == RX_MAP_STATUS(SUCCESS)) &&
|
|
(DataBytesInResponse > 0)) {
|
|
|
|
RxDbgTrace( 0, Dbg, ("ParseTransactResponse: Posting Copy request for Data Bytes %ld\n",DataBytesInResponse));
|
|
|
|
// In certain cases a padding MDL needs to be inserted between the param and data portions
|
|
// of the response to consume the padding bytes sent by the server.
|
|
if ((ParamBytesInResponse > 0) &&
|
|
((PaddingLength = DataOffsetInResponse -
|
|
(ParamBytesInResponse + ParamOffsetInResponse)) > 0)) {
|
|
RxDbgTrace( 0, Dbg, ("ParseTransactResponse: Posting Copy request for padding bytes %ld\n",PaddingLength));
|
|
// There are some padding bytes present. Construct an MDL to consume them
|
|
//pPaddingMdl = RxAllocateMdl(&MRxSmb_pPaddingData,PaddingLength);
|
|
ASSERT(!"this doesn't work");
|
|
if (pPaddingMdl != NULL) {
|
|
if (pLastMdlInCopyDataRequestChain != NULL) {
|
|
pLastMdlInCopyDataRequestChain->Next = pPaddingMdl;
|
|
} else {
|
|
pFirstMdlInCopyDataRequestChain = pPaddingMdl;
|
|
}
|
|
pLastMdlInCopyDataRequestChain = pPaddingMdl;
|
|
} else {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
|
|
// There are more data bytes which have not been indicated. Set up an MDL
|
|
// to copy them over.
|
|
if ((Status == RX_MAP_STATUS(SUCCESS))) {
|
|
if (pTransactExchange->pReceiveDataMdl->ByteCount >= DataBytesInResponse) {
|
|
pDataMdl = RxAllocateMdl(
|
|
((PBYTE)MmGetMdlVirtualAddress(pTransactExchange->pReceiveDataMdl)
|
|
+ pTransactExchange->DataBytesReceived),
|
|
DataBytesInResponse);
|
|
|
|
if (pDataMdl != NULL) {
|
|
IoBuildPartialMdl(
|
|
pTransactExchange->pReceiveDataMdl,
|
|
pDataMdl,
|
|
((PBYTE)MmGetMdlVirtualAddress(pTransactExchange->pReceiveDataMdl)
|
|
+ pTransactExchange->DataBytesReceived),
|
|
DataBytesInResponse);
|
|
|
|
if (pLastMdlInCopyDataRequestChain != NULL) {
|
|
pLastMdlInCopyDataRequestChain->Next = pDataMdl;
|
|
} else {
|
|
pFirstMdlInCopyDataRequestChain = pDataMdl;
|
|
}
|
|
|
|
pLastMdlInCopyDataRequestChain = pDataMdl;
|
|
pTransactExchange->DataBytesReceived += DataBytesInResponse;
|
|
} else {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
} else {
|
|
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((Status != RX_MAP_STATUS(SUCCESS))) {
|
|
if (pDataMdl != NULL) {
|
|
IoFreeMdl(pDataMdl);
|
|
}
|
|
|
|
if (pPaddingMdl != NULL) {
|
|
IoFreeMdl(pPaddingMdl);
|
|
}
|
|
|
|
if (pParamMdl != NULL) {
|
|
IoFreeMdl(pParamMdl);
|
|
}
|
|
} else {
|
|
if (pFirstMdlInCopyDataRequestChain != NULL) {
|
|
ULONG MdlLength = ParamBytesInResponse+PaddingLength+DataBytesInResponse;
|
|
*pCopyRequestMdlPointer = pFirstMdlInCopyDataRequestChain;
|
|
*pCopyRequestSize = MdlLength;
|
|
RxDbgTrace( 0, Dbg, ("ParseTransactResponse: final mdl and copy size %08lx %08lx(%ld)\n",
|
|
pFirstMdlInCopyDataRequestChain,MdlLength,MdlLength));
|
|
IF_DEBUG {
|
|
PMDL imdl = pFirstMdlInCopyDataRequestChain;
|
|
ULONG mdllength = MdlLength;
|
|
mdllength -= MmGetMdlByteCount(imdl);
|
|
for (;;) {
|
|
if (!(imdl=imdl->Next)) break;
|
|
mdllength -= MmGetMdlByteCount(imdl);
|
|
}
|
|
ASSERT(mdllength==0);
|
|
}
|
|
|
|
InterlockedIncrement(&pTransactExchange->PendingCopyRequests);
|
|
Status = STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
if ((pTransactExchange->ParamBytesReceived < pTransactExchange->ReceiveParamBufferSize) ||
|
|
(pTransactExchange->DataBytesReceived < pTransactExchange->ReceiveDataBufferSize)) {
|
|
NTSTATUS ReceiveStatus;
|
|
|
|
// The exchange has been successfully completed. Finalize it.
|
|
RxDbgTrace(0,Dbg,("ParseTransactResponse: Register for more responses\n"));
|
|
ReceiveStatus = SmbCeReceive((PSMB_EXCHANGE)pTransactExchange);
|
|
if (ReceiveStatus != STATUS_SUCCESS) {
|
|
// There was an error in registering the receive. Abandon the
|
|
// transaction.
|
|
Status = ReceiveStatus;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
|
|
UNREFERENCED_PARAMETER(BytesAvailable);
|
|
|
|
}
|
|
|
|
#if DBG
|
|
ULONG SmbSendBadSecondary = 0;
|
|
#endif
|
|
NTSTATUS
|
|
SendSecondaryRequests(PVOID pContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sends all the secondary requests associated with the transaction
|
|
|
|
Arguments:
|
|
|
|
pTransactExchange - the exchange instance
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
PSMB_EXCHANGE pExchange = (PSMB_EXCHANGE)pContext;
|
|
PSMB_TRANSACT_EXCHANGE pTransactExchange = (PSMB_TRANSACT_EXCHANGE)pExchange;
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
ULONG MaximumSmbBufferSize;
|
|
|
|
// The MDL's used in sending the primary request associated with the TRANSACT SMB
|
|
PMDL pPartialDataMdl = NULL;
|
|
PMDL pPartialParamMdl = NULL;
|
|
PMDL pPaddingMdl = NULL;
|
|
PMDL pSecondaryRequestSmbMdl = NULL;
|
|
PMDL pLastMdlInChain = NULL;
|
|
|
|
ULONG SecondaryRequestSmbSize = 0;
|
|
ULONG SmbLength;
|
|
ULONG PaddingLength;
|
|
|
|
ULONG ParamOffset,ParamDisplacement;
|
|
ULONG DataOffset,DataDisplacement;
|
|
ULONG ByteCountOffset;
|
|
USHORT ByteCount;
|
|
PUSHORT pByteCount;
|
|
|
|
ULONG ParamBytesToBeSent; // Param bytes to be sent per request
|
|
ULONG DataBytesToBeSent; // data bytes to be sent per request
|
|
ULONG SendParamBufferSize; // Total param bytes to be sent in secondary requests
|
|
ULONG SendDataBufferSize; // Total data bytes to be sent in secondary requests
|
|
PBYTE pSendParamStartAddress = NULL;
|
|
PBYTE pSendDataStartAddress = NULL;
|
|
PBYTE pOriginalParamBuffer = NULL;
|
|
PBYTE pOriginalDataBuffer = NULL;
|
|
ULONG TotalParamBytes,TotalDataBytes;
|
|
|
|
BOOLEAN ParamPartialMdlAlreadyUsed = FALSE;
|
|
BOOLEAN DataPartialMdlAlreadyUsed = FALSE;
|
|
|
|
PVOID pActualSecondaryRequestSmbHeader = NULL;
|
|
PSMB_HEADER pSecondaryRequestSmbHeader = NULL;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT(pTransactExchange->State == TRANSACT_EXCHANGE_RECEIVED_INTERIM_RESPONSE);
|
|
|
|
|
|
TotalParamBytes = pTransactExchange->SendParamBufferSize;
|
|
SendParamBufferSize = TotalParamBytes - pTransactExchange->ParamBytesSent;
|
|
|
|
TotalDataBytes = pTransactExchange->SendDataBufferSize;
|
|
SendDataBufferSize = TotalDataBytes - pTransactExchange->DataBytesSent;
|
|
|
|
ASSERT((SendParamBufferSize > 0) || (SendDataBufferSize > 0));
|
|
|
|
switch (pTransactExchange->TransactSmbCommand) {
|
|
case SMB_COM_TRANSACTION:
|
|
SecondaryRequestSmbSize = sizeof(SMB_HEADER) +
|
|
FIELD_OFFSET(REQ_TRANSACTION_SECONDARY,Buffer);
|
|
break;
|
|
|
|
case SMB_COM_TRANSACTION2:
|
|
//CODE.IMPROVEMENT.ASHAMED smb.h should containa REQ_TRANSACTION2_SECONDARY instead
|
|
// of this bogus comment about how the server can ignore it
|
|
SecondaryRequestSmbSize = sizeof(SMB_HEADER) +
|
|
FIELD_OFFSET(REQ_TRANSACTION_SECONDARY,Buffer)
|
|
+ sizeof(USHORT); //add in the extra word
|
|
break;
|
|
|
|
case SMB_COM_NT_TRANSACT:
|
|
SecondaryRequestSmbSize = sizeof(SMB_HEADER) +
|
|
FIELD_OFFSET(REQ_NT_TRANSACTION_SECONDARY,Buffer);
|
|
break;
|
|
|
|
default:
|
|
ASSERT(!"Valid Smb Command in transaction exchange");
|
|
Status = STATUS_TRANSACTION_ABORTED;
|
|
}
|
|
|
|
SecondaryRequestSmbSize = QuadAlign(SecondaryRequestSmbSize); //pad to quadword boundary
|
|
|
|
//CODE.IMPROVEMENT we could overallocate here....sometimes the copy would be faster
|
|
pActualSecondaryRequestSmbHeader = (PSMB_HEADER)
|
|
RxAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
SecondaryRequestSmbSize + TRANSPORT_HEADER_SIZE,
|
|
MRXSMB_XACT_POOLTAG);
|
|
|
|
if ((Status == RX_MAP_STATUS(SUCCESS)) && pActualSecondaryRequestSmbHeader != NULL) {
|
|
|
|
(PCHAR) pSecondaryRequestSmbHeader =
|
|
(PCHAR) pActualSecondaryRequestSmbHeader + TRANSPORT_HEADER_SIZE;
|
|
|
|
// Initialize the SMB header ...
|
|
|
|
ASSERT(
|
|
((SMB_COM_TRANSACTION+1) == SMB_COM_TRANSACTION_SECONDARY)
|
|
&&((SMB_COM_TRANSACTION2+1)== SMB_COM_TRANSACTION2_SECONDARY)
|
|
&&((SMB_COM_NT_TRANSACT+1) == SMB_COM_NT_TRANSACT_SECONDARY)
|
|
);
|
|
|
|
Status = SmbTransactBuildHeader(
|
|
pTransactExchange, // the exchange instance
|
|
(UCHAR)(pTransactExchange->TransactSmbCommand+1), // the SMB command ..see the asserts above
|
|
pSecondaryRequestSmbHeader); // the SMB buffer
|
|
|
|
RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: SmbCeBuildSmbHeader returned %lx\n",Status));
|
|
} else {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
if ((Status == RX_MAP_STATUS(SUCCESS))) {
|
|
MaximumSmbBufferSize = pTransactExchange->MaximumTransmitSmbBufferSize;
|
|
|
|
// Ensure that the MDL's have been probed & locked. The new MDL's have been allocated.
|
|
// The partial MDL's are allocated to be large enough to span the maximum buffer
|
|
// length possible.
|
|
|
|
// Initialize the data related MDL's for the secondary request
|
|
if (SendDataBufferSize > 0) {
|
|
RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: Data Bytes remaining %ld\n",SendDataBufferSize));
|
|
|
|
pOriginalDataBuffer = (PBYTE)MmGetMdlVirtualAddress(pTransactExchange->pSendDataMdl);
|
|
pSendDataStartAddress = pOriginalDataBuffer + pTransactExchange->DataBytesSent;
|
|
|
|
pPartialDataMdl = RxAllocateMdl(
|
|
0,
|
|
(MIN(pTransactExchange->SendDataBufferSize,
|
|
MaximumSmbBufferSize) +
|
|
PAGE_SIZE - 1));
|
|
|
|
if (pPartialDataMdl == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
|
|
// Initialize the parameter related MDL's for the secondary request
|
|
if ((SendParamBufferSize > 0) && (Status == RX_MAP_STATUS(SUCCESS))) {
|
|
RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: Param Bytes remaining %ld\n",SendParamBufferSize));
|
|
pOriginalParamBuffer = (PBYTE)MmGetMdlVirtualAddress(pTransactExchange->pSendParamMdl);
|
|
pSendParamStartAddress = pOriginalParamBuffer + pTransactExchange->ParamBytesSent;
|
|
|
|
pPartialParamMdl = RxAllocateMdl(
|
|
0,
|
|
(MIN(pTransactExchange->SendParamBufferSize,
|
|
MaximumSmbBufferSize) +
|
|
PAGE_SIZE - 1));
|
|
|
|
//CODE.IMPROVEMENT we shouldn't allocate this if datasize==0
|
|
pPaddingMdl = RxAllocateMdl(0,(sizeof(DWORD) + PAGE_SIZE - 1));
|
|
|
|
if ((pPartialParamMdl == NULL) ||
|
|
(pPaddingMdl == NULL)) {
|
|
RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: Error allocating param MDLS\n"));
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
|
|
// Initialize the secondary request SMB MDL
|
|
if ((Status == RX_MAP_STATUS(SUCCESS))) {
|
|
|
|
RxAllocateHeaderMdl(
|
|
pSecondaryRequestSmbHeader,
|
|
SecondaryRequestSmbSize,
|
|
pSecondaryRequestSmbMdl
|
|
);
|
|
|
|
if (pSecondaryRequestSmbMdl != NULL) {
|
|
|
|
RxProbeAndLockHeaderPages(
|
|
pSecondaryRequestSmbMdl,
|
|
KernelMode,
|
|
IoModifyAccess,
|
|
Status);
|
|
|
|
if ((Status != RX_MAP_STATUS(SUCCESS))) {
|
|
IoFreeMdl(pSecondaryRequestSmbMdl);
|
|
pSecondaryRequestSmbMdl = NULL;
|
|
} else {
|
|
if (MmGetSystemAddressForMdlSafe(pSecondaryRequestSmbMdl,LowPagePriority) == NULL) { //map it
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
} else {
|
|
RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: Error allocating 2ndsmb MDL\n"));
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
}
|
|
|
|
while ((Status == RX_MAP_STATUS(SUCCESS)) &&
|
|
((SendParamBufferSize > 0) || (SendDataBufferSize > 0))) {
|
|
PaddingLength = 0;
|
|
DataBytesToBeSent = 0;
|
|
ParamBytesToBeSent = 0;
|
|
ParamDisplacement = 0;
|
|
pLastMdlInChain = pSecondaryRequestSmbMdl;
|
|
|
|
ParamOffset = DataOffset = SecondaryRequestSmbSize;
|
|
|
|
ParamBytesToBeSent = MIN((MaximumSmbBufferSize - ParamOffset),
|
|
SendParamBufferSize);
|
|
|
|
if (ParamBytesToBeSent > 0) {
|
|
// Form a MDL for the portion of the parameter buffer being transmitted
|
|
if (ParamPartialMdlAlreadyUsed) {
|
|
MmPrepareMdlForReuse(pPartialParamMdl);
|
|
}
|
|
|
|
ParamPartialMdlAlreadyUsed = TRUE;
|
|
IoBuildPartialMdl(
|
|
pTransactExchange->pSendParamMdl,
|
|
pPartialParamMdl,
|
|
pSendParamStartAddress,
|
|
ParamBytesToBeSent);
|
|
|
|
ParamDisplacement = (ULONG)(pSendParamStartAddress - pOriginalParamBuffer);
|
|
pSendParamStartAddress += ParamBytesToBeSent;
|
|
SendParamBufferSize -= ParamBytesToBeSent;
|
|
DataOffset += QuadAlign(ParamBytesToBeSent);
|
|
|
|
pLastMdlInChain->Next = pPartialParamMdl;
|
|
pLastMdlInChain = pPartialParamMdl;
|
|
} else {
|
|
// don't do this! the padding stuff uses it. you can set it later
|
|
// ParamOffset = 0;
|
|
}
|
|
|
|
if ((DataOffset < MaximumSmbBufferSize) && (SendDataBufferSize > 0) ) {
|
|
// There is room for data bytes to be sent
|
|
// Check if we need a padding MDL ....
|
|
PaddingLength = DataOffset - (ParamOffset + ParamBytesToBeSent);
|
|
|
|
if (PaddingLength > 0) {
|
|
RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: Padding Length %ld\n",PaddingLength));
|
|
RxBuildPaddingPartialMdl(pPaddingMdl,PaddingLength);
|
|
pLastMdlInChain->Next = pPaddingMdl;
|
|
pLastMdlInChain = pPaddingMdl;
|
|
}
|
|
|
|
// Link the data buffer or portions of it if the size constraints are satisfied
|
|
DataBytesToBeSent = MIN((MaximumSmbBufferSize - DataOffset),
|
|
SendDataBufferSize);
|
|
ASSERT (DataBytesToBeSent > 0);
|
|
|
|
// Form a MDL for the portions of the data buffer being sent
|
|
if (DataPartialMdlAlreadyUsed) {
|
|
MmPrepareMdlForReuse(pPartialDataMdl);
|
|
}
|
|
|
|
DataPartialMdlAlreadyUsed = TRUE;
|
|
IoBuildPartialMdl(
|
|
pTransactExchange->pSendDataMdl,
|
|
pPartialDataMdl,
|
|
pSendDataStartAddress,
|
|
DataBytesToBeSent);
|
|
|
|
// chain the data MDL
|
|
pLastMdlInChain->Next = pPartialDataMdl;
|
|
pLastMdlInChain = pPartialDataMdl;
|
|
|
|
DataDisplacement = (ULONG)(pSendDataStartAddress - pOriginalDataBuffer);
|
|
pSendDataStartAddress += DataBytesToBeSent;
|
|
SendDataBufferSize -= DataBytesToBeSent;
|
|
} else {
|
|
DataOffset = DataDisplacement = 0;
|
|
DbgDoit(if (SmbSendBadSecondary){DataOffset = QuadAlign(ParamOffset + ParamBytesToBeSent);});
|
|
}
|
|
|
|
if (ParamBytesToBeSent == 0) {
|
|
ParamOffset = 0;
|
|
}
|
|
|
|
RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: Secondary Request Param(%ld) padding(%ld) Data(%ld)\n",
|
|
ParamBytesToBeSent,
|
|
PaddingLength,
|
|
DataBytesToBeSent));
|
|
RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: ParamO(%ld) DataO(%ld)\n",ParamOffset,DataOffset));
|
|
RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: ParamD(%ld) DataD(%ld)\n",ParamDisplacement,DataDisplacement));
|
|
RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: TotParam(%ld) TotData(%ld)\n",TotalParamBytes,TotalDataBytes));
|
|
|
|
// Update the secondary request buffer with the final sizes of the data/parameter etc.
|
|
switch (pTransactExchange->TransactSmbCommand) {
|
|
case SMB_COM_TRANSACTION:
|
|
case SMB_COM_TRANSACTION2:
|
|
{
|
|
PREQ_TRANSACTION_SECONDARY pTransactRequest;
|
|
|
|
//ASSERT(!"this has not been tested");
|
|
|
|
pTransactRequest = (PREQ_TRANSACTION_SECONDARY)(pSecondaryRequestSmbHeader + 1);
|
|
|
|
pTransactRequest->WordCount = 8; // Count of parameter words = 8
|
|
SmbPutUshort(&pTransactRequest->TotalParameterCount, (USHORT)TotalParamBytes); // Total parameter bytes being sent
|
|
SmbPutUshort(&pTransactRequest->TotalDataCount, (USHORT)TotalDataBytes); // Total data bytes being sent
|
|
SmbPutUshort(&pTransactRequest->ParameterCount, (USHORT)ParamBytesToBeSent); // Parameter bytes sent this buffer
|
|
SmbPutUshort(&pTransactRequest->ParameterOffset, (USHORT)ParamOffset); // Offset (from header start) to params
|
|
SmbPutUshort(&pTransactRequest->ParameterDisplacement, (USHORT)ParamDisplacement); // Displacement of these param bytes
|
|
SmbPutUshort(&pTransactRequest->DataCount, (USHORT)DataBytesToBeSent); // Parameter bytes sent this buffer
|
|
SmbPutUshort(&pTransactRequest->DataOffset, (USHORT)DataOffset); // Offset (from header start) to Datas
|
|
SmbPutUshort(&pTransactRequest->DataDisplacement, (USHORT)DataDisplacement); // Displacement of these Data bytes
|
|
ByteCountOffset = FIELD_OFFSET(REQ_TRANSACTION_SECONDARY,ByteCount);
|
|
if (pTransactExchange->TransactSmbCommand == SMB_COM_TRANSACTION2 ) {
|
|
//see CODE.IMPROVEMENT.ASHAMED above.......
|
|
ByteCountOffset += sizeof(USHORT);
|
|
pTransactRequest->WordCount++; //one extra word
|
|
SmbPutUshort((&pTransactRequest->DataDisplacement)+1, 0); //the +1 is to move up 1 USHORT
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SMB_COM_NT_TRANSACT:
|
|
{
|
|
PREQ_NT_TRANSACTION_SECONDARY pNtTransactRequest;
|
|
|
|
pNtTransactRequest= (PREQ_NT_TRANSACTION_SECONDARY)(pSecondaryRequestSmbHeader + 1);
|
|
|
|
//CODE.IMPROVEMENT this should be stufferized.....the whole thing should be.
|
|
// (6/15 there are unimplemented things in the stuffer that'd make it hard
|
|
|
|
//CODE.IMPROVEMENT move the constant things to the top
|
|
//CODE.IMPROVEMENT you don't need the macros here because things are alinged.....put in asserts
|
|
// actually, use the aligned stuff
|
|
pNtTransactRequest->WordCount = 18; // Count of parameter words = 18
|
|
pNtTransactRequest->Reserved1 = 0; // MBZ
|
|
SmbPutUshort(&pNtTransactRequest->Reserved2, 0); // MBZ
|
|
SmbPutUlong(&pNtTransactRequest->TotalParameterCount, TotalParamBytes); // Total parameter bytes being sent
|
|
SmbPutUlong(&pNtTransactRequest->TotalDataCount, TotalDataBytes); // Total data bytes being sent
|
|
SmbPutUlong(&pNtTransactRequest->ParameterCount, ParamBytesToBeSent); // Parameter bytes sent this buffer
|
|
SmbPutUlong(&pNtTransactRequest->ParameterOffset, ParamOffset); // Offset (from header start) to params
|
|
SmbPutUlong(&pNtTransactRequest->ParameterDisplacement, ParamDisplacement); // Displacement of these param bytes
|
|
SmbPutUlong(&pNtTransactRequest->DataCount, DataBytesToBeSent); // Parameter bytes sent this buffer
|
|
SmbPutUlong(&pNtTransactRequest->DataOffset, DataOffset); // Offset (from header start) to Datas
|
|
SmbPutUlong(&pNtTransactRequest->DataDisplacement, DataDisplacement); // Displacement of these Data bytes
|
|
pNtTransactRequest->Reserved3 = 0; // MBZ
|
|
|
|
ByteCountOffset = FIELD_OFFSET(REQ_NT_TRANSACTION_SECONDARY,ByteCount);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT(!"Valid Smb Command for initiating Transaction");
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
// Send the secondary SMB
|
|
SmbLength = SecondaryRequestSmbSize +
|
|
ParamBytesToBeSent +
|
|
PaddingLength +
|
|
DataBytesToBeSent;
|
|
|
|
ByteCount = (USHORT)(SmbLength-(sizeof(SMB_HEADER)+ByteCountOffset+sizeof(USHORT)));
|
|
pByteCount = (PUSHORT)((PBYTE)pSecondaryRequestSmbHeader+sizeof(SMB_HEADER)+ByteCountOffset);
|
|
SmbPutUshort(pByteCount,ByteCount);
|
|
|
|
RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: len %d bytecount %d(%x)\n", SmbLength, ByteCount, ByteCount));
|
|
RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: msgmdl=%08lx\n", pSecondaryRequestSmbHeader));
|
|
|
|
RxLog(("2nd: %lx %lx %lx %lx %lx %lx",ParamOffset,ParamDisplacement,TotalParamBytes,DataOffset,DataDisplacement,TotalDataBytes));
|
|
RxLog(("2nd:: %lx %lx",ByteCount,SmbLength));
|
|
SmbLog(LOG,
|
|
SendSecondaryRequests,
|
|
LOGULONG(ParamOffset)
|
|
LOGULONG(ParamDisplacement)
|
|
LOGULONG(TotalParamBytes)
|
|
LOGULONG(DataOffset)
|
|
LOGULONG(DataDisplacement)
|
|
LOGULONG(TotalDataBytes)
|
|
LOGXSHORT(ByteCount)
|
|
LOGULONG(SmbLength));
|
|
|
|
Status = SmbCeSend(
|
|
pExchange,
|
|
RXCE_SEND_SYNCHRONOUS,
|
|
pSecondaryRequestSmbMdl,
|
|
SmbLength);
|
|
|
|
RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: SmbCeSend returned %lx\n",Status));
|
|
if ((Status != RX_MAP_STATUS(PENDING)) && (Status != RX_MAP_STATUS(SUCCESS))) {
|
|
RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: SmbCeSend returned bad status %lx\n",Status));
|
|
//here we should just get out
|
|
goto FINALLY; //yes we cold have said break....but that's not what we're doing
|
|
} else {
|
|
Status = RX_MAP_STATUS(SUCCESS);
|
|
}
|
|
}
|
|
|
|
FINALLY:
|
|
if (pPartialDataMdl != NULL) {
|
|
IoFreeMdl(pPartialDataMdl);
|
|
}
|
|
|
|
if (pActualSecondaryRequestSmbHeader != NULL) {
|
|
RxFreePool(pActualSecondaryRequestSmbHeader);
|
|
}
|
|
|
|
if (pPartialParamMdl != NULL) {
|
|
IoFreeMdl(pPartialParamMdl);
|
|
}
|
|
|
|
if (pPaddingMdl != NULL) {
|
|
IoFreeMdl(pPaddingMdl);
|
|
}
|
|
|
|
if (pSecondaryRequestSmbMdl != NULL) {
|
|
RxUnlockHeaderPages(pSecondaryRequestSmbMdl);
|
|
IoFreeMdl(pSecondaryRequestSmbMdl);
|
|
}
|
|
|
|
//we always finalize......but we only set the status if there's an error or
|
|
// we expect no response
|
|
if ((Status != RX_MAP_STATUS(SUCCESS)) || (pTransactExchange->Flags & SMB_TRANSACTION_NO_RESPONSE )) {
|
|
pExchange->Status = Status;
|
|
|
|
if (!(pTransactExchange->Flags & SMB_TRANSACTION_NO_RESPONSE)) {
|
|
SmbCeDecrementPendingReceiveOperations(pExchange);
|
|
}
|
|
}
|
|
|
|
SmbCeDecrementPendingLocalOperationsAndFinalize(pExchange);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
SMB_EXCHANGE_DISPATCH_VECTOR
|
|
TransactExchangeDispatch = {
|
|
SmbTransactExchangeStart,
|
|
SmbTransactExchangeReceive,
|
|
SmbTransactExchangeCopyDataHandler,
|
|
NULL, // SmbTransactExchangeSendCallbackHandler
|
|
SmbTransactExchangeFinalize,
|
|
NULL
|
|
};
|
|
|
|
|
|
|
|
#ifndef RX_NO_DBGFIELD_HLPRS
|
|
|
|
#define DECLARE_FIELD_HLPR(x) ULONG SmbPseTxeField_##x = FIELD_OFFSET(SMB_TRANSACT_EXCHANGE,x);
|
|
#define DECLARE_FIELD_HLPR2(x,y) ULONG SmbPseTxeField_##x##y = FIELD_OFFSET(SMB_TRANSACT_EXCHANGE,x.y);
|
|
|
|
DECLARE_FIELD_HLPR(RxContext);
|
|
DECLARE_FIELD_HLPR(ReferenceCount);
|
|
DECLARE_FIELD_HLPR(State);
|
|
DECLARE_FIELD_HLPR(pSendDataMdl);
|
|
DECLARE_FIELD_HLPR(pReceiveDataMdl);
|
|
DECLARE_FIELD_HLPR(pSendParamMdl);
|
|
DECLARE_FIELD_HLPR(pReceiveParamMdl);
|
|
DECLARE_FIELD_HLPR(pSendSetupMdl);
|
|
DECLARE_FIELD_HLPR(pReceiveSetupMdl);
|
|
DECLARE_FIELD_HLPR(PrimaryRequestSmbSize);
|
|
DECLARE_FIELD_HLPR(SmbCommand);
|
|
DECLARE_FIELD_HLPR(NtTransactFunction);
|
|
DECLARE_FIELD_HLPR(Flags);
|
|
DECLARE_FIELD_HLPR(Fid);
|
|
#endif
|
|
|
|
|