📄 transact.c
字号:
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.
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 == STATUS_SUCCESS) {
if (TRUE) { //maybe sometimes we wont copy!
if (CommandToProcess.WordCount > 0) {
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.
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 = 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 ((pSmbHeader->Command == pTransactExchange->SmbCommand) &&
(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);
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 != STATUS_SUCCESS) {
pExchange->Status = Status;
} else {
Status = STATUS_SUCCESS;
SmbCeIncrementPendingLocalOperations(pExchange);
RxPostToWorkerThread(
MRxSmbDeviceObject,
CriticalWorkQueue,
&pExchange->WorkQueueItem,
SendSecondaryRequests,
pExchange);
}
} else {
RxDbgTrace(0,Dbg,("SmbCeTransactExchangeReceive: Invalid interim response\n"));
Status = STATUS_INVALID_NETWORK_RESPONSE;
}
} else {
fIndicationNotSufficient = TRUE;
Status = 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->SmbCommand) {
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 == 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 {
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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -