📄 transact.c
字号:
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 == 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 == 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 == STATUS_SUCCESS)) {
RxProbeAndLockHeaderPages(pPrimaryRequestSmbMdl,KernelMode,IoModifyAccess,Status);
if (Status != 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 == 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 == STATUS_SUCCESS)) {
// 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 != 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"));
Status = SmbCeTranceive(
pExchange,
RXCE_SEND_SYNCHRONOUS,
pPrimaryRequestSmbMdl,
SmbLength);
if ((Status != 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) {
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;
SMB_TRANSACT_RESP_FORMAT_DESCRIPTION Format;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -