Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3444 lines
138 KiB

  1. /*++
  2. Copyright (c) 1987 - 1999 Microsoft Corporation
  3. Module Name:
  4. transact.c
  5. Abstract:
  6. This file conatins the implementation of the transact exchange.
  7. --*/
  8. #include "precomp.h"
  9. #pragma hdrstop
  10. #pragma warning(error:4100) // Unreferenced formal parameter
  11. #ifdef ALLOC_PRAGMA
  12. #pragma alloc_text(PAGE, SmbCeInitializeTransactionParameters)
  13. #pragma alloc_text(PAGE, SmbCeUninitializeTransactionParameters)
  14. #pragma alloc_text(PAGE, SmbCeDiscardTransactExchange)
  15. #pragma alloc_text(PAGE, SmbCeSubmitTransactionRequest)
  16. #pragma alloc_text(PAGE, _SmbCeTransact)
  17. #pragma alloc_text(PAGE, SmbTransactBuildHeader)
  18. #pragma alloc_text(PAGE, SmbTransactExchangeStart)
  19. #pragma alloc_text(PAGE, SmbTransactExchangeAbort)
  20. #pragma alloc_text(PAGE, SmbTransactExchangeErrorHandler)
  21. #pragma alloc_text(PAGE, SmbTransactExchangeSendCallbackHandler)
  22. #pragma alloc_text(PAGE, SmbCeInitializeTransactExchange)
  23. #pragma alloc_text(PAGE, SendSecondaryRequests)
  24. #endif
  25. //#define SET_DONTSUBSUME_PARAMS
  26. #ifdef SET_DONTSUBSUME_PARAMS
  27. ULONG MRxSmbDontSubsumeParams = 1;
  28. #else
  29. ULONG MRxSmbDontSubsumeParams = 0;
  30. #endif
  31. #if DBG
  32. #define DONTSUBSUME_PARAMS MRxSmbDontSubsumeParams
  33. #else
  34. #define DONTSUBSUME_PARAMS FALSE
  35. #endif
  36. SMB_TRANSACTION_OPTIONS RxDefaultTransactionOptions = DEFAULT_TRANSACTION_OPTIONS;
  37. RXDT_DefineCategory(TRANSACT);
  38. #define Dbg (DEBUG_TRACE_TRANSACT)
  39. #define MIN(x,y) ((x) < (y) ? (x) : (y))
  40. #define SMB_TRANSACT_MAXIMUM_PARAMETER_SIZE (0xffff)
  41. #define SMB_TRANSACT_MAXIMUM_DATA_SIZE (0xffff)
  42. typedef struct _SMB_TRANSACT_RESP_FORMAT_DESCRIPTION {
  43. ULONG WordCount;
  44. ULONG TotalParameterCount;
  45. ULONG TotalDataCount;
  46. ULONG ParameterCount;
  47. ULONG ParameterOffset;
  48. ULONG ParameterDisplacement;
  49. ULONG DataCount;
  50. ULONG DataOffset;
  51. ULONG DataDisplacement;
  52. ULONG ByteCount;
  53. ULONG ApparentMsgLength;
  54. } SMB_TRANSACT_RESP_FORMAT_DESCRIPTION, *PSMB_TRANSACT_RESP_FORMAT_DESCRIPTION;
  55. NTSTATUS
  56. SmbTransactAccrueAndValidateFormatData(
  57. IN struct _SMB_TRANSACT_EXCHANGE *pTransactExchange, // The exchange instance
  58. IN PSMB_HEADER pSmbHeader,
  59. IN ULONG BytesIndicated,
  60. OUT PSMB_TRANSACT_RESP_FORMAT_DESCRIPTION Format
  61. );
  62. extern NTSTATUS
  63. SmbTransactExchangeFinalize(
  64. PSMB_EXCHANGE pExchange,
  65. BOOLEAN *pPostFinalize);
  66. extern NTSTATUS
  67. ParseTransactResponse(
  68. IN struct _SMB_TRANSACT_EXCHANGE *pTransactExchange, // The exchange instance
  69. IN PSMB_TRANSACT_RESP_FORMAT_DESCRIPTION Format,
  70. IN ULONG BytesIndicated,
  71. IN ULONG BytesAvailable,
  72. OUT ULONG *pBytesTaken,
  73. IN PSMB_HEADER pSmbHeader,
  74. OUT PMDL *pCopyRequestMdlPointer,
  75. OUT PULONG pCopyRequestSize);
  76. extern NTSTATUS
  77. SendSecondaryRequests(PVOID pContext);
  78. extern NTSTATUS
  79. SmbCeInitializeTransactExchange(
  80. PSMB_TRANSACT_EXCHANGE pTransactExchange,
  81. PRX_CONTEXT RxContext,
  82. PSMB_TRANSACTION_OPTIONS pOptions,
  83. PSMB_TRANSACTION_SEND_PARAMETERS pSendParameters,
  84. PSMB_TRANSACTION_RECEIVE_PARAMETERS pReceiveParameters,
  85. PSMB_TRANSACTION_RESUMPTION_CONTEXT pResumptionContext);
  86. NTSTATUS
  87. SmbCeInitializeTransactionParameters(
  88. PVOID pSetup,
  89. USHORT SetupLength,
  90. PVOID pParam,
  91. ULONG ParamLength,
  92. PVOID pData,
  93. ULONG DataLength,
  94. PSMB_TRANSACTION_PARAMETERS pTransactionParameters
  95. )
  96. /*++
  97. Routine Description:
  98. This routine initializes the transaction parameters
  99. Arguments:
  100. pSetup - the setup buffer
  101. SetupLength - the setup buffer length
  102. pParam - the param buffer
  103. ParamLength - the param buffer length
  104. pData - the data buffer
  105. DataLength - the data buffer length
  106. pTransactionParameters - the transaction parameters instance
  107. Return Value:
  108. RXSTATUS - The return status for the operation
  109. Notes:
  110. The TRANSACTION parameters come in two flavours -- the send parameters for the data
  111. that is to be sent to the server and the receive parameters for receiving the data
  112. from the server. There is one subtle difference in the way in which the parameters are
  113. stored and referenced in these two cases. In the send case the Setup buffer is stored
  114. as a pointer itself while in the receive case it is stored in the form of a MDL.
  115. This is because the SMB protocol requires that the Header + setup information for a
  116. transaction request cannot be greated then the maximum SMB buffer size, i.e., setup
  117. information cannot spill to a secondary request. The buffer that is allocated for the
  118. header is made sufficiently large enough to hold the setup data as well. On the other
  119. hand the receives are handled in a two phase manner, -- the indication at the DPC
  120. level followed by a copy data request if required. In order to avoid having to transition
  121. between DPC level and a worker thread the MDL's for the buffers are eagerly evaluated.
  122. --*/
  123. {
  124. NTSTATUS Status = STATUS_SUCCESS;
  125. PMDL pSetupMdl = NULL;
  126. PMDL pParamMdl = NULL;
  127. PMDL pDataMdl = NULL;
  128. PAGED_CODE();
  129. if (pTransactionParameters->Flags & TRANSACTION_RECEIVE_PARAMETERS_FLAG) {
  130. if (pSetup != NULL) {
  131. pSetupMdl = RxAllocateMdl(pSetup,SetupLength);
  132. if (pSetupMdl == NULL) {
  133. Status = STATUS_INSUFFICIENT_RESOURCES;
  134. } else {
  135. RxProbeAndLockPages(pSetupMdl,KernelMode,IoModifyAccess,Status);
  136. if (Status != STATUS_SUCCESS) {
  137. IoFreeMdl(pSetupMdl);
  138. pSetupMdl = NULL;
  139. } else {
  140. if (MmGetSystemAddressForMdlSafe(pSetupMdl,LowPagePriority) == NULL) { //this maps the Mdl
  141. Status = STATUS_INSUFFICIENT_RESOURCES;
  142. }
  143. }
  144. }
  145. }
  146. if ((Status == STATUS_SUCCESS) && (pParam != NULL)) {
  147. pParamMdl = RxAllocateMdl(pParam,ParamLength);
  148. if (pParamMdl == NULL) {
  149. Status = STATUS_INSUFFICIENT_RESOURCES;
  150. } else {
  151. RxProbeAndLockPages(pParamMdl,KernelMode,IoModifyAccess,Status);
  152. if ((Status != STATUS_SUCCESS)) {
  153. IoFreeMdl(pParamMdl);
  154. pParamMdl = NULL;
  155. } else {
  156. if (MmGetSystemAddressForMdlSafe(pParamMdl,LowPagePriority) == NULL) { //this maps the Mdl
  157. Status = STATUS_INSUFFICIENT_RESOURCES;
  158. }
  159. }
  160. }
  161. }
  162. pTransactionParameters->SetupLength = SetupLength;
  163. pTransactionParameters->ParamLength = ParamLength;
  164. pTransactionParameters->pParamMdl = pParamMdl;
  165. pTransactionParameters->pSetupMdl = pSetupMdl;
  166. } else {
  167. pTransactionParameters->SetupLength = SetupLength;
  168. pTransactionParameters->pSetup = pSetup;
  169. pTransactionParameters->ParamLength = ParamLength;
  170. pTransactionParameters->pParam = pParam;
  171. pTransactionParameters->pParamMdl = NULL;
  172. }
  173. ASSERT( !((pData == NULL)&&(DataLength!=0)) );
  174. if ((Status == STATUS_SUCCESS) && (pData != NULL) && (DataLength > 0)) {
  175. pDataMdl = RxAllocateMdl(pData,DataLength);
  176. if (pDataMdl == NULL) {
  177. Status = STATUS_INSUFFICIENT_RESOURCES;
  178. } else {
  179. RxProbeAndLockPages(pDataMdl,KernelMode,IoModifyAccess,Status);
  180. if ((Status != STATUS_SUCCESS)) {
  181. IoFreeMdl(pDataMdl);
  182. pDataMdl = NULL;
  183. } else {
  184. if (MmGetSystemAddressForMdlSafe(pDataMdl,LowPagePriority) == NULL) { //this maps the Mdl
  185. Status = STATUS_INSUFFICIENT_RESOURCES;
  186. }
  187. }
  188. }
  189. }
  190. pTransactionParameters->pDataMdl = pDataMdl;
  191. pTransactionParameters->DataLength = DataLength;
  192. ASSERT((Status != STATUS_SUCCESS) || (DataLength == 0) || (pDataMdl != NULL));
  193. if ((Status != STATUS_SUCCESS)) {
  194. if (pTransactionParameters->Flags & TRANSACTION_RECEIVE_PARAMETERS_FLAG) {
  195. if (pSetupMdl != NULL) {
  196. MmUnlockPages(pSetupMdl); //this unmaps as well
  197. IoFreeMdl(pSetupMdl);
  198. }
  199. if (pParamMdl != NULL) {
  200. MmUnlockPages(pParamMdl);
  201. IoFreeMdl(pParamMdl);
  202. }
  203. }
  204. if (pDataMdl != NULL) {
  205. MmUnlockPages(pDataMdl);
  206. IoFreeMdl(pDataMdl);
  207. }
  208. }
  209. return Status;
  210. }
  211. VOID
  212. SmbCeUninitializeTransactionParameters(
  213. PSMB_TRANSACTION_PARAMETERS pTransactionParameters
  214. )
  215. /*++
  216. Routine Description:
  217. This routine uninitializes the transaction parameters, i.e., free the associated MDL's
  218. Arguments:
  219. pTransactionParameters - the parameter instance for uninitialization
  220. --*/
  221. {
  222. PAGED_CODE();
  223. if (pTransactionParameters->Flags & TRANSACTION_RECEIVE_PARAMETERS_FLAG) {
  224. if (pTransactionParameters->pSetupMdl != NULL) {
  225. MmUnlockPages(pTransactionParameters->pSetupMdl);
  226. IoFreeMdl(pTransactionParameters->pSetupMdl);
  227. }
  228. }
  229. if (pTransactionParameters->pParamMdl != NULL) {
  230. MmUnlockPages(pTransactionParameters->pParamMdl);
  231. IoFreeMdl(pTransactionParameters->pParamMdl);
  232. }
  233. if (pTransactionParameters->pDataMdl != NULL
  234. && !BooleanFlagOn(pTransactionParameters->Flags,SMB_XACT_FLAGS_CALLERS_SENDDATAMDL)) {
  235. MmUnlockPages(pTransactionParameters->pDataMdl);
  236. IoFreeMdl(pTransactionParameters->pDataMdl);
  237. }
  238. }
  239. VOID
  240. SmbCeDiscardTransactExchange(PSMB_TRANSACT_EXCHANGE pTransactExchange)
  241. /*++
  242. Routine Description:
  243. This routine discards a transact exchange
  244. Arguments:
  245. pExchange - the exchange instance
  246. --*/
  247. {
  248. PSMB_TRANSACTION_RESUMPTION_CONTEXT pResumptionContext;
  249. PAGED_CODE();
  250. // Deallocate any transact exchange specfic allocations ...
  251. if (pTransactExchange->pActualPrimaryRequestSmbHeader != NULL) {
  252. RxFreePool(pTransactExchange->pActualPrimaryRequestSmbHeader);
  253. }
  254. if (pTransactExchange->pReceiveSetupMdl != NULL) {
  255. MmUnlockPages(pTransactExchange->pReceiveSetupMdl);
  256. IoFreeMdl(pTransactExchange->pReceiveSetupMdl);
  257. }
  258. if (pTransactExchange->pReceiveParamMdl != NULL) {
  259. MmUnlockPages(pTransactExchange->pReceiveParamMdl);
  260. IoFreeMdl(pTransactExchange->pReceiveParamMdl);
  261. }
  262. if (pTransactExchange->pReceiveDataMdl != NULL) {
  263. MmUnlockPages(pTransactExchange->pReceiveDataMdl);
  264. IoFreeMdl(pTransactExchange->pReceiveDataMdl);
  265. }
  266. if (pTransactExchange->pSendSetupMdl != NULL) {
  267. MmUnlockPages(pTransactExchange->pSendSetupMdl);
  268. IoFreeMdl(pTransactExchange->pSendSetupMdl);
  269. }
  270. if ((pTransactExchange->pSendDataMdl != NULL) &&
  271. !BooleanFlagOn(pTransactExchange->Flags,SMB_XACT_FLAGS_CALLERS_SENDDATAMDL)) {
  272. MmUnlockPages(pTransactExchange->pSendDataMdl);
  273. IoFreeMdl(pTransactExchange->pSendDataMdl);
  274. }
  275. if (pTransactExchange->pSendParamMdl != NULL) {
  276. MmUnlockPages(pTransactExchange->pSendParamMdl);
  277. IoFreeMdl(pTransactExchange->pSendParamMdl);
  278. }
  279. if ((pResumptionContext = pTransactExchange->pResumptionContext) != NULL) {
  280. NTSTATUS FinalStatus;
  281. PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry((PSMB_EXCHANGE)pTransactExchange);
  282. RxDbgTrace(0, Dbg,
  283. ("SmbCeTransactExchangeFinalize: everythings is good! parambytes (%ld) databytes (%ld)\n",
  284. pTransactExchange->ParamBytesReceived, pTransactExchange->DataBytesReceived
  285. ));
  286. FinalStatus = pTransactExchange->Status;
  287. if (pServerEntry->ServerStatus != STATUS_SUCCESS) {
  288. // If the server entry is in error state, the transact cannot receive a response from server.
  289. // In this case, we return the server status.
  290. pResumptionContext->FinalStatusFromServer = pServerEntry->ServerStatus;
  291. } else {
  292. // If the server entry is in good or disconnected state, we return the smb status.
  293. pResumptionContext->FinalStatusFromServer = pTransactExchange->SmbStatus;
  294. }
  295. if ((FinalStatus == STATUS_SUCCESS)||
  296. (FinalStatus == STATUS_MORE_PROCESSING_REQUIRED)) {
  297. FinalStatus = pResumptionContext->FinalStatusFromServer;
  298. }
  299. pResumptionContext->SmbCeResumptionContext.Status = FinalStatus;
  300. pResumptionContext->SetupBytesReceived = pTransactExchange->SetupBytesReceived;
  301. pResumptionContext->DataBytesReceived = pTransactExchange->DataBytesReceived;
  302. pResumptionContext->ParameterBytesReceived = pTransactExchange->ParamBytesReceived;
  303. pResumptionContext->ServerVersion = pTransactExchange->ServerVersion;
  304. SmbCeResume(&pResumptionContext->SmbCeResumptionContext);
  305. }
  306. SmbCeDereferenceAndDiscardExchange((PSMB_EXCHANGE)pTransactExchange);
  307. }
  308. NTSTATUS
  309. SmbCeSubmitTransactionRequest(
  310. PRX_CONTEXT RxContext,
  311. PSMB_TRANSACTION_OPTIONS pOptions,
  312. PSMB_TRANSACTION_PARAMETERS pSendParameters,
  313. PSMB_TRANSACTION_PARAMETERS pReceiveParameters,
  314. PSMB_TRANSACTION_RESUMPTION_CONTEXT pResumptionContext )
  315. /*++
  316. Routine Description:
  317. This routine submits a transaction request, i.e., allocates/initializes a transaction
  318. exchange, sets up the completion information and initiates it
  319. Arguments:
  320. pNetRoot - the netroot for which the transaction request is intended
  321. pOptions - the transaction options
  322. pSendParameters - the transaction parameters to be sent to the server
  323. pReceiveParameters - the transaction results from the server
  324. pResumptionContext - the context for resuming the local activity on completion of the
  325. transaction
  326. Return Value:
  327. RXSTATUS - The return status for the operation
  328. STATUS_PENDING -- if the transcation was initiated successfully
  329. Other error codes if the request could not be submitted successfully
  330. Notes:
  331. Whenever a status of STATUS_PENDING is returned it implies that the transact
  332. exchange has assumed ownership of the MDLs passed in as receive and send
  333. parameters. They will be released on completion of the exchange.
  334. --*/
  335. {
  336. NTSTATUS Status = STATUS_SUCCESS;
  337. RxCaptureFcb;
  338. RxCaptureFobx;
  339. PMRX_V_NET_ROOT pVNetRoot = NULL;
  340. PSMB_TRANSACT_EXCHANGE pTransactExchange;
  341. PSMB_EXCHANGE pExchange = NULL;
  342. PAGED_CODE();
  343. if (capFobx == NULL) {
  344. if (RxContext->MajorFunction == IRP_MJ_CREATE) {
  345. pVNetRoot = RxContext->Create.pVNetRoot;
  346. }
  347. } else {
  348. // These are the root objects which are associated with the device FCB. In
  349. // such cases
  350. pVNetRoot = (PMRX_V_NET_ROOT)capFobx;
  351. if (NodeType(pVNetRoot) != RDBSS_NTC_V_NETROOT) {
  352. pVNetRoot = capFobx->pSrvOpen->pVNetRoot;
  353. }
  354. }
  355. if (pVNetRoot == NULL) {
  356. PSMBCEDB_SERVER_ENTRY pServerEntry;
  357. pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
  358. // Allocate and initialize an exchange for the given net root.
  359. Status = SmbCeInitializeExchange2(
  360. &pExchange,
  361. RxContext,
  362. pServerEntry,
  363. TRANSACT_EXCHANGE,
  364. &TransactExchangeDispatch);
  365. } else {
  366. // Allocate and initialize an exchange for the given net root.
  367. Status = SmbCeInitializeExchange(
  368. &pExchange,
  369. RxContext,
  370. pVNetRoot,
  371. TRANSACT_EXCHANGE,
  372. &TransactExchangeDispatch);
  373. }
  374. if (Status == STATUS_SUCCESS) {
  375. // Initialize the transact exchange
  376. pTransactExchange = (PSMB_TRANSACT_EXCHANGE)pExchange;
  377. Status = SmbCeInitializeTransactExchange(
  378. pTransactExchange,
  379. RxContext,
  380. pOptions,
  381. pSendParameters,
  382. pReceiveParameters,
  383. pResumptionContext);
  384. if (Status == STATUS_SUCCESS) {
  385. // The transact exchange can be either asynchronous or synchronous. In
  386. // the asynchronous case an additional reference is taken which is
  387. // passed onto the caller alongwith the exchange squirelled away in the
  388. // RX_CONTEXT if STATUS_PENDING is being returned. This enables the
  389. // caller to control when the exchange is discarded. This works
  390. // especially well in dealing with cancellation of asynchronous
  391. // exchanges.
  392. // This reference will be accounted for by the finalization routine
  393. // of the transact exchange.
  394. SmbCeReferenceExchange((PSMB_EXCHANGE)pTransactExchange);
  395. if (BooleanFlagOn(pOptions->Flags,SMB_XACT_FLAGS_ASYNCHRONOUS)) {
  396. // The corresponding dereference is the callers responsibility
  397. SmbCeReferenceExchange((PSMB_EXCHANGE)pTransactExchange);
  398. }
  399. pResumptionContext->pTransactExchange = pTransactExchange;
  400. pResumptionContext->SmbCeResumptionContext.Status = STATUS_SUCCESS;
  401. SmbCeIncrementPendingLocalOperations(pExchange);
  402. // Initiate the exchange
  403. Status = SmbCeInitiateExchange(pExchange);
  404. if (Status != STATUS_PENDING) {
  405. pExchange->Status = Status;
  406. if (pExchange->SmbStatus == STATUS_SUCCESS) {
  407. pExchange->SmbStatus = Status;
  408. }
  409. if (BooleanFlagOn(pOptions->Flags,SMB_XACT_FLAGS_ASYNCHRONOUS)) {
  410. PMRXSMB_RX_CONTEXT pMRxSmbContext = MRxSmbGetMinirdrContext(RxContext);
  411. pMRxSmbContext->pExchange = NULL;
  412. // Since the exchange has already been completed there is no
  413. // point in returning the additional reference to the caller
  414. SmbCeDereferenceExchange((PSMB_EXCHANGE)pTransactExchange);
  415. }
  416. }
  417. SmbCeDecrementPendingLocalOperationsAndFinalize(pExchange);
  418. // Map the status to STATUS_PENDING so that continuation routines
  419. // do not attempt to finalize.
  420. Status = STATUS_PENDING;
  421. } else {
  422. PMRXSMB_RX_CONTEXT MRxSmbContext = MRxSmbGetMinirdrContext(RxContext);
  423. ASSERT(MRxSmbContext->pExchange == pExchange);
  424. MRxSmbContext->pExchange = NULL;
  425. SmbCeDiscardExchange(pExchange);
  426. }
  427. }
  428. return Status;
  429. }
  430. NTSTATUS
  431. _SmbCeTransact(
  432. PRX_CONTEXT RxContext,
  433. PSMB_TRANSACTION_OPTIONS pOptions,
  434. PVOID pInputSetupBuffer,
  435. ULONG InputSetupBufferLength,
  436. PVOID pOutputSetupBuffer,
  437. ULONG OutputSetupBufferLength,
  438. PVOID pInputParamBuffer,
  439. ULONG InputParamBufferLength,
  440. PVOID pOutputParamBuffer,
  441. ULONG OutputParamBufferLength,
  442. PVOID pInputDataBuffer,
  443. ULONG InputDataBufferLength,
  444. PVOID pOutputDataBuffer,
  445. ULONG OutputDataBufferLength,
  446. PSMB_TRANSACTION_RESUMPTION_CONTEXT pResumptionContext)
  447. /*++
  448. Routine Description:
  449. This routine implements a standardized mechanism of submitting transaction requests,
  450. and synchronizing with their completion. This does not provide the smae amount of control
  451. that SmbCeSubmitTransactRequest provides. Nevertheless, this implements a common mechanism
  452. that should satisfy most needs
  453. Arguments:
  454. RxContext - the context for the transaction
  455. pOptions - the transaction options
  456. pSetupBuffer - the transaction setup buffer
  457. SetupBufferlength - the setup buffer length
  458. pInputParamBuffer - the Input param buffer
  459. InputParamBufferLength - the input param buffer length
  460. pOutputParamBuffer - the output param buffer
  461. OutputParamBufferlength - the output param buffer length
  462. pInputDataBuffer - the Input data buffer
  463. InputDataBufferLength - the input data buffer length
  464. pOutputDataBuffer - the output data buffer
  465. OutputDataBufferlength - the output data buffer length
  466. pResumptionContext - the transaction resumption context
  467. Return Value:
  468. RXSTATUS - The return status for the operation
  469. STATUS_SUCCESS if successfull.
  470. Other error codes if the request could not be submitted successfully
  471. Notes:
  472. In the case of asynchronous exchanges if STATUS_PENDING is returned the
  473. Exchange instance is squirelled away in the minirdr context associated with
  474. the given RX_CONTEXT instance. This exchange will not be discarded without
  475. the callers intervention. It is the callers responsibility to invoke
  476. SmbCeDereferenceAndDiscardExchange to discard the exchange
  477. --*/
  478. {
  479. NTSTATUS Status;
  480. SMB_TRANSACTION_SEND_PARAMETERS SendParameters;
  481. SMB_TRANSACTION_RECEIVE_PARAMETERS ReceiveParameters;
  482. BOOLEAN fAsynchronous;
  483. PAGED_CODE();
  484. fAsynchronous = BooleanFlagOn(pOptions->Flags,SMB_XACT_FLAGS_ASYNCHRONOUS);
  485. Status = SmbCeInitializeTransactionSendParameters(
  486. pInputSetupBuffer,
  487. (USHORT)InputSetupBufferLength,
  488. pInputParamBuffer,
  489. InputParamBufferLength,
  490. pInputDataBuffer,
  491. InputDataBufferLength,
  492. &SendParameters);
  493. if (Status == STATUS_SUCCESS) {
  494. Status = SmbCeInitializeTransactionReceiveParameters(
  495. pOutputSetupBuffer, // the setup information expected in return
  496. (USHORT)OutputSetupBufferLength, // the length of the setup information
  497. pOutputParamBuffer, // the buffer for the param information
  498. OutputParamBufferLength, // the length of the param buffer
  499. pOutputDataBuffer, // the buffer for data
  500. OutputDataBufferLength, // the length of the buffer
  501. &ReceiveParameters);
  502. if (Status != STATUS_SUCCESS) {
  503. SmbCeUninitializeTransactionSendParameters(&SendParameters);
  504. }
  505. }
  506. if (Status == STATUS_SUCCESS) {
  507. Status = SmbCeSubmitTransactionRequest(
  508. RxContext, // the RXContext for the transaction
  509. pOptions, // transaction options
  510. &SendParameters, // input parameters
  511. &ReceiveParameters, // expected results
  512. pResumptionContext // the context for resumption.
  513. );
  514. if ((Status != STATUS_SUCCESS) &&
  515. (Status != STATUS_PENDING)) {
  516. SmbCeUninitializeTransactionReceiveParameters(&ReceiveParameters);
  517. SmbCeUninitializeTransactionSendParameters(&SendParameters);
  518. } else {
  519. if (!fAsynchronous) {
  520. if (Status == STATUS_PENDING) {
  521. SmbCeWaitOnTransactionResumptionContext(pResumptionContext);
  522. Status = pResumptionContext->SmbCeResumptionContext.Status;
  523. if (Status != STATUS_SUCCESS) {
  524. RxDbgTrace(0,Dbg,("SmbCeTransact: Transaction Request Completion Status %lx\n",Status));
  525. }
  526. } else if (Status != STATUS_SUCCESS) {
  527. RxDbgTrace(0,Dbg,("SmbCeTransact: SmbCeSubmitTransactRequest returned %lx\n",Status));
  528. } else {
  529. Status = pResumptionContext->SmbCeResumptionContext.Status;
  530. }
  531. }
  532. }
  533. }
  534. ASSERT(fAsynchronous || (Status != STATUS_PENDING));
  535. if (fAsynchronous && (Status != STATUS_PENDING)) {
  536. pResumptionContext->SmbCeResumptionContext.Status = Status;
  537. SmbCeResume(&pResumptionContext->SmbCeResumptionContext);
  538. Status = STATUS_PENDING;
  539. }
  540. return Status;
  541. }
  542. NTSTATUS
  543. SmbTransactBuildHeader(
  544. PSMB_TRANSACT_EXCHANGE pTransactExchange,
  545. UCHAR SmbCommand,
  546. PSMB_HEADER pHeader)
  547. /*++
  548. Routine Description:
  549. This routine builds the SMB header for transact exchanges
  550. Arguments:
  551. pTransactExchange - the exchange instance
  552. SmbCommand - the SMB command
  553. pHeader - the SMB buffer header
  554. Return Value:
  555. RXSTATUS - The return status for the operation
  556. Notes:
  557. --*/
  558. {
  559. NTSTATUS Status;
  560. ULONG BufferConsumed;
  561. UCHAR LastCommandInHeader;
  562. PUCHAR pCommand;
  563. PAGED_CODE();
  564. // Initialize the SMB header ...
  565. Status = SmbCeBuildSmbHeader(
  566. (PSMB_EXCHANGE)pTransactExchange,
  567. pHeader,
  568. sizeof(SMB_HEADER),
  569. &BufferConsumed,
  570. &LastCommandInHeader,
  571. &pCommand);
  572. if (Status == STATUS_SUCCESS) {
  573. PSMBCEDB_SERVER_ENTRY pServerEntry;
  574. ASSERT(LastCommandInHeader == SMB_COM_NO_ANDX_COMMAND);
  575. *pCommand = SmbCommand;
  576. pServerEntry = SmbCeGetExchangeServerEntry(pTransactExchange);
  577. if (FlagOn(pServerEntry->Server.DialectFlags,DF_NT_SMBS)) {
  578. // for NT servers, we have to set the pid/pidhigh fields so that RPC will work.
  579. SmbCeSetFullProcessIdInHeader(
  580. (PSMB_EXCHANGE)pTransactExchange,
  581. RxGetRequestorProcessId(pTransactExchange->RxContext),
  582. ((PNT_SMB_HEADER)pHeader));
  583. }
  584. if (pTransactExchange->Flags & SMB_XACT_FLAGS_DFS_AWARE) {
  585. pHeader->Flags2 |= SMB_FLAGS2_DFS;
  586. }
  587. }
  588. return Status;
  589. }
  590. NTSTATUS
  591. SmbTransactExchangeStart(
  592. PSMB_EXCHANGE pExchange)
  593. /*++
  594. Routine Description:
  595. This is the start routine for transact exchanges. This initiates the construction of the
  596. appropriate SMB's if required.
  597. Arguments:
  598. pExchange - the exchange instance
  599. Return Value:
  600. RXSTATUS - The return status for the operation
  601. Notes:
  602. --*/
  603. {
  604. NTSTATUS Status;
  605. PSMB_TRANSACT_EXCHANGE pTransactExchange;
  606. PVOID pActualPrimaryRequestSmbHeader;
  607. PSMB_HEADER pPrimaryRequestSmbHeader;
  608. // The MDL's used in sending the primary request associated with the TRANSACT SMB
  609. PMDL pPartialDataMdl = NULL;
  610. PMDL pPartialParamMdl = NULL;
  611. PMDL pPaddingMdl = NULL;
  612. PMDL pPrimaryRequestSmbMdl = NULL;
  613. PMDL pLastMdlInChain = NULL;
  614. ULONG MaximumSmbBufferSize;
  615. ULONG PrimaryRequestSmbSize = 0;
  616. ULONG PaddingLength = 0;
  617. BOOLEAN QuadwordAlignmentRequired = FALSE;
  618. ULONG ParamBytesToBeSent = 0;
  619. ULONG DataBytesToBeSent = 0;
  620. ULONG ParamOffset,DataOffset;
  621. ULONG SmbLength;
  622. ULONG BccOffset;
  623. ULONG MdlLength;
  624. USHORT *pBcc;
  625. PAGED_CODE();
  626. pTransactExchange = (PSMB_TRANSACT_EXCHANGE)pExchange;
  627. pActualPrimaryRequestSmbHeader = pTransactExchange->pActualPrimaryRequestSmbHeader;
  628. pPrimaryRequestSmbHeader = pTransactExchange->pPrimaryRequestSmbHeader;
  629. ASSERT(pActualPrimaryRequestSmbHeader != NULL);
  630. ASSERT(pPrimaryRequestSmbHeader != NULL);
  631. ASSERT(!(pExchange->SmbCeFlags & SMBCE_EXCHANGE_SESSION_CONSTRUCTOR) &&
  632. !(pExchange->SmbCeFlags & SMBCE_EXCHANGE_NETROOT_CONSTRUCTOR));
  633. // Initialize the SMB header ...
  634. Status = SmbTransactBuildHeader(
  635. pTransactExchange,
  636. pTransactExchange->SmbCommand,
  637. pPrimaryRequestSmbHeader);
  638. if ((Status != STATUS_SUCCESS)) {
  639. // Finalize the exchange.
  640. pExchange->Status = Status;
  641. return Status;
  642. }
  643. PrimaryRequestSmbSize = sizeof(SMB_HEADER);
  644. // Compute the BccOffset and the ParamOffset which is in turn used in computing the
  645. // param and data bytes to be sent as part of the primary request.
  646. switch (pTransactExchange->SmbCommand) {
  647. case SMB_COM_TRANSACTION:
  648. case SMB_COM_TRANSACTION2:
  649. {
  650. PREQ_TRANSACTION pTransactRequest = (PREQ_TRANSACTION)
  651. (pPrimaryRequestSmbHeader + 1);
  652. USHORT SetupLength = pTransactRequest->SetupCount * sizeof(WORD);
  653. BccOffset = sizeof(SMB_HEADER) +
  654. FIELD_OFFSET(REQ_TRANSACTION,Buffer) +
  655. SetupLength;
  656. ParamOffset = ROUND_UP_COUNT(
  657. (BccOffset +
  658. pTransactExchange->TransactionNameLength +
  659. sizeof(USHORT)),
  660. sizeof(DWORD));
  661. pBcc = (PUSHORT)((PBYTE)pPrimaryRequestSmbHeader + BccOffset);
  662. }
  663. break;
  664. case SMB_COM_NT_TRANSACT:
  665. {
  666. PREQ_NT_TRANSACTION pNtTransactRequest = (PREQ_NT_TRANSACTION)
  667. (pPrimaryRequestSmbHeader + 1);
  668. USHORT SetupLength = pNtTransactRequest->SetupCount * sizeof(WORD);
  669. RxDbgTrace( 0, Dbg, ("SmbTransactExchangeSTAAT1: init for NT_T (p,d,mp,md) %d %d %d %d\n",
  670. pNtTransactRequest->TotalParameterCount, pNtTransactRequest->TotalDataCount,
  671. pNtTransactRequest->MaxParameterCount, pNtTransactRequest->MaxDataCount));
  672. RxDbgTrace( 0, Dbg, ("SmbTransactExchangeSTAyuk: init for NT_T (s,ms) %d %d \n",
  673. pNtTransactRequest->SetupCount, pNtTransactRequest->MaxSetupCount));
  674. BccOffset = sizeof(SMB_HEADER) +
  675. FIELD_OFFSET(REQ_NT_TRANSACTION,Buffer[0]) +
  676. SetupLength;
  677. ParamOffset = ROUND_UP_COUNT(
  678. (BccOffset + sizeof(USHORT)),
  679. sizeof(DWORD));
  680. pBcc = (PUSHORT)((PBYTE)pPrimaryRequestSmbHeader + BccOffset);
  681. if (pTransactExchange->NtTransactFunction == NT_TRANSACT_SET_QUOTA) {
  682. QuadwordAlignmentRequired = TRUE;
  683. }
  684. }
  685. break;
  686. default:
  687. ASSERT(!"Valid Smb Command for initiating Transaction");
  688. return STATUS_INVALID_PARAMETER;
  689. }
  690. // Compute the data/param bytes that can be sent as part of the primary request
  691. MaximumSmbBufferSize = pTransactExchange->MaximumTransmitSmbBufferSize;
  692. ParamBytesToBeSent = MIN(
  693. (MaximumSmbBufferSize - ParamOffset),
  694. pTransactExchange->SendParamBufferSize);
  695. if (!QuadwordAlignmentRequired) {
  696. DataOffset = ROUND_UP_COUNT(ParamOffset + ParamBytesToBeSent, sizeof(DWORD));
  697. } else {
  698. DataOffset = ROUND_UP_COUNT(ParamOffset + ParamBytesToBeSent, 2*sizeof(DWORD));
  699. }
  700. if (DataOffset < MaximumSmbBufferSize) {
  701. DataBytesToBeSent = MIN((MaximumSmbBufferSize - DataOffset),
  702. pTransactExchange->SendDataBufferSize);
  703. PaddingLength = DataOffset - (ParamOffset + ParamBytesToBeSent);
  704. } else {
  705. DataBytesToBeSent = 0;
  706. }
  707. if ( DataBytesToBeSent == 0) {
  708. DataOffset = PaddingLength = 0;
  709. }
  710. RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: params,padding,data=%d,%d,%d\n",
  711. ParamBytesToBeSent,PaddingLength,DataBytesToBeSent ));
  712. RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: paramsoffset,dataoffset=%d,%d\n",
  713. ParamOffset,DataOffset ));
  714. RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: phdr,pbcc=%08lx,%08lx\n",
  715. pPrimaryRequestSmbHeader,pBcc ));
  716. // Update the primary request buffer with the final sizes of the data/parameter etc.
  717. switch (pTransactExchange->SmbCommand) {
  718. case SMB_COM_TRANSACTION:
  719. case SMB_COM_TRANSACTION2:
  720. {
  721. PREQ_TRANSACTION pTransactRequest = (PREQ_TRANSACTION)
  722. (pPrimaryRequestSmbHeader + 1);
  723. RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: TRANSACTION/TRANSACTION2\n"));
  724. SmbPutUshort( &pTransactRequest->ParameterCount, (USHORT)ParamBytesToBeSent );
  725. SmbPutUshort( &pTransactRequest->ParameterOffset, (USHORT)ParamOffset);
  726. SmbPutUshort( &pTransactRequest->DataCount, (USHORT)DataBytesToBeSent);
  727. SmbPutUshort( &pTransactRequest->DataOffset, (USHORT)DataOffset);
  728. }
  729. break;
  730. case SMB_COM_NT_TRANSACT:
  731. {
  732. PREQ_NT_TRANSACTION pNtTransactRequest = (PREQ_NT_TRANSACTION)
  733. (pPrimaryRequestSmbHeader + 1);
  734. RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: NT transacton\n"));
  735. RxDbgTrace( 0, Dbg, ("SmbTransactExchangeSTAAT2: init for NT_T (p,d,mp,md) %d %d %d %d\n",
  736. pNtTransactRequest->TotalParameterCount, pNtTransactRequest->TotalDataCount,
  737. pNtTransactRequest->MaxParameterCount, pNtTransactRequest->MaxDataCount));
  738. SmbPutUlong( &pNtTransactRequest->ParameterCount, ParamBytesToBeSent);
  739. SmbPutUlong( &pNtTransactRequest->ParameterOffset, ParamOffset);
  740. SmbPutUlong( &pNtTransactRequest->DataCount, DataBytesToBeSent);
  741. SmbPutUlong( &pNtTransactRequest->DataOffset, DataOffset);
  742. }
  743. break;
  744. default:
  745. ASSERT(!"Valid Smb Command for initiating Transaction");
  746. return STATUS_INVALID_PARAMETER;
  747. }
  748. // Update the Bcc field in the SMB and compute the SMB length
  749. SmbPutUshort(
  750. pBcc,
  751. (USHORT)((ParamOffset - BccOffset - sizeof(USHORT)) +
  752. ParamBytesToBeSent +
  753. PaddingLength +
  754. DataBytesToBeSent)
  755. );
  756. SmbLength = ParamOffset +
  757. ParamBytesToBeSent +
  758. PaddingLength +
  759. DataBytesToBeSent;
  760. // The primary request buffer should be locked down for transmission. In order to
  761. // preclude race conditions while freeing this routine assumes ownership of the buffer.
  762. // There are two reasons why this model has to be adopted ...
  763. // 1) Inititaiting a transaction request can possibly involve a reconnection attempt
  764. // which will involve network traffic. Consequently the transmission of the primary
  765. // request can potentially occur in a worker thread which is different from the one
  766. // initializing the exchange. This problem can be worked around by carrying all the
  767. // possible context around and actually constructing the header as part of this routine.
  768. // But this would imply that those requests which could have been filtered out easily
  769. // because of error conditions etc. will be handled very late.
  770. pTransactExchange->pActualPrimaryRequestSmbHeader = NULL;
  771. pTransactExchange->pPrimaryRequestSmbHeader = NULL;
  772. // Ensure that the MDL's have been probed & locked. The new MDL's have been allocated.
  773. // The partial MDL's are allocated to be large enough to span the maximum buffer
  774. // length possible.
  775. MdlLength = ParamOffset;
  776. if (pTransactExchange->fParamsSubsumedInPrimaryRequest) {
  777. MdlLength += ParamBytesToBeSent + PaddingLength;
  778. }
  779. RxAllocateHeaderMdl(
  780. pPrimaryRequestSmbHeader,
  781. MdlLength,
  782. pPrimaryRequestSmbMdl
  783. );
  784. if (pPrimaryRequestSmbMdl != NULL) {
  785. Status = STATUS_SUCCESS;
  786. } else {
  787. RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: Insuffcient resources for MDL's\n"));
  788. Status = STATUS_INSUFFICIENT_RESOURCES;
  789. }
  790. if ((DataBytesToBeSent > 0) &&
  791. (Status == STATUS_SUCCESS)) {
  792. pPartialDataMdl = RxAllocateMdl(
  793. 0,
  794. (MIN(pTransactExchange->SendDataBufferSize,MaximumSmbBufferSize) +
  795. PAGE_SIZE - 1)
  796. );
  797. if (pPartialDataMdl != NULL) {
  798. Status = STATUS_SUCCESS;
  799. } else {
  800. RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: Insuffcient resources for MDL's\n"));
  801. Status = STATUS_INSUFFICIENT_RESOURCES;
  802. }
  803. }
  804. if ((ParamBytesToBeSent > 0) &&
  805. !pTransactExchange->fParamsSubsumedInPrimaryRequest &&
  806. (Status == STATUS_SUCCESS)) {
  807. pPartialParamMdl = RxAllocateMdl(
  808. pTransactExchange->pSendParamBuffer,
  809. ParamBytesToBeSent);
  810. if (PaddingLength!= 0) {
  811. pPaddingMdl = RxAllocateMdl(0,(sizeof(DWORD) + PAGE_SIZE - 1));
  812. } else {
  813. pPaddingMdl = NULL;
  814. }
  815. if ((pPartialParamMdl != NULL) &&
  816. ((pPaddingMdl != NULL)||(PaddingLength==0))) {
  817. Status = STATUS_SUCCESS;
  818. } else {
  819. RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: no param/pad MDLs %08lx %08lx\n",
  820. pPartialParamMdl,pPaddingMdl));
  821. Status = STATUS_INSUFFICIENT_RESOURCES;
  822. }
  823. }
  824. // At this point the validity of all the parameters will have been ascertained. The trivial
  825. // cases have been filtered out. Start the transact exchange.
  826. // Implementation Note: The Transact exchange implementation relies upon chaining the
  827. // MDL's together to build the relevant request buffers that need be sent. This ensures
  828. // that redundant copying of data is avoided altogether. Depending upon the parameters
  829. // specified the composite MDL that is sent is composed of the following MDL's.
  830. // TRANSACT2 and NT TRANSACT exchanges ...
  831. // The composite buffer is made up off atmost four MDL's that are chained together. These
  832. // are the header buffer, the setup buffer, parameter buffer and the data buffer.
  833. // All the secondary requests are made up off atmost three MDL's that are chained together.
  834. // These are the header buffer, the parameter buffer and the data buffer.
  835. // TRANSACT exchanges ....
  836. // The composite buffer is made up off atmost three MDL's that are chained together. These are
  837. // the header buffer ( includes the name and the setup information) , the parameter buffer
  838. // and the data buffer.
  839. // All the secondary requests are made up off atmost three MDL's that are chained together.
  840. // These are the header buffer, the parameter buffer and the data buffer.
  841. // In all of these cases the number of MDL's can go up by 1 if a padding MDL is required
  842. // between the parameter buffer and the data buffer to ensure that all alignment requirements
  843. // are satisfied.
  844. if ((Status == STATUS_SUCCESS)) {
  845. RxProbeAndLockHeaderPages(pPrimaryRequestSmbMdl,KernelMode,IoModifyAccess,Status);
  846. if (Status != STATUS_SUCCESS) { //do this now. the code below will try to unlock
  847. IoFreeMdl(pPrimaryRequestSmbMdl);
  848. pPrimaryRequestSmbMdl = NULL;
  849. } else {
  850. if (MmGetSystemAddressForMdlSafe(pPrimaryRequestSmbMdl,LowPagePriority) == NULL) { //map it
  851. Status = STATUS_INSUFFICIENT_RESOURCES;
  852. }
  853. }
  854. }
  855. if ((Status == STATUS_SUCCESS)) {
  856. pLastMdlInChain = pPrimaryRequestSmbMdl;
  857. if (ParamBytesToBeSent > 0) {
  858. RxDbgTrace(
  859. 0,
  860. Dbg,
  861. ("SmbCeTransactExchangeStart: Sending Param bytes %ld at offset %ld\n",
  862. ParamBytesToBeSent,
  863. ParamOffset)
  864. );
  865. pTransactExchange->ParamBytesSent = ParamBytesToBeSent;
  866. if (!pTransactExchange->fParamsSubsumedInPrimaryRequest) {
  867. IoBuildPartialMdl(
  868. pTransactExchange->pSendParamMdl,
  869. pPartialParamMdl,
  870. (PBYTE)MmGetMdlVirtualAddress(pTransactExchange->pSendParamMdl),
  871. ParamBytesToBeSent);
  872. // Chain the MDL's together
  873. pLastMdlInChain->Next = pPartialParamMdl;
  874. pLastMdlInChain = pPartialParamMdl;
  875. }
  876. }
  877. // Link the data buffer or portions of it if the size constraints are satisfied
  878. // If padding is required between the parameter and data portions in the
  879. // primary request include the padding MDL, otherwise chain the data MDL
  880. // directly.
  881. if (DataBytesToBeSent > 0) {
  882. if (!pTransactExchange->fParamsSubsumedInPrimaryRequest &&
  883. (PaddingLength > 0)) {
  884. RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: Padding Length %ld\n",PaddingLength));
  885. RxBuildPaddingPartialMdl(pPaddingMdl,PaddingLength);
  886. pLastMdlInChain->Next = pPaddingMdl;
  887. pLastMdlInChain = pPaddingMdl;
  888. }
  889. RxDbgTrace( 0, Dbg,("SmbCeTransactExchangeStart: Sending Data bytes %ld at offset %ld\n",
  890. DataBytesToBeSent, DataOffset) );
  891. pTransactExchange->DataBytesSent = DataBytesToBeSent;
  892. IoBuildPartialMdl(
  893. pTransactExchange->pSendDataMdl,
  894. pPartialDataMdl,
  895. (PBYTE)MmGetMdlVirtualAddress(pTransactExchange->pSendDataMdl),
  896. DataBytesToBeSent);
  897. pLastMdlInChain->Next = pPartialDataMdl;
  898. pLastMdlInChain = pPartialDataMdl;
  899. }
  900. if ((Status == STATUS_SUCCESS)) {
  901. // There are cases in which the transaction exchange can be completed by merely sending
  902. // the primary request SMB. This should be distinguished from those cases in which either
  903. // a response is expected or a number of secondary requests need to be issued based upon
  904. // the parameter buffer length, data buffer length and the flags specified.
  905. if ((pTransactExchange->Flags & SMB_TRANSACTION_NO_RESPONSE ) &&
  906. (pTransactExchange->SendDataBufferSize == DataBytesToBeSent) &&
  907. (pTransactExchange->SendParamBufferSize == ParamBytesToBeSent)) {
  908. // No response is expected in this case. Therefore Send should suffice instead of
  909. // Tranceive
  910. // since we don't expect to do any more here, set the exchange status to success
  911. pExchange->Status = STATUS_SUCCESS;
  912. pTransactExchange->pResumptionContext->FinalStatusFromServer = STATUS_SUCCESS;
  913. RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: SmbCeSend(No Response expected)\n"));
  914. Status = SmbCeSend(
  915. pExchange,
  916. RXCE_SEND_SYNCHRONOUS,
  917. pPrimaryRequestSmbMdl,
  918. SmbLength);
  919. if ((Status != STATUS_SUCCESS)) {
  920. RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: SmbCeSend returned %lx\n",Status));
  921. }
  922. } else {
  923. // This transaction involves ttansmit/receive of multiple SMB's. A tranceive is in
  924. // order.
  925. if ((pTransactExchange->SendDataBufferSize == DataBytesToBeSent) &&
  926. (pTransactExchange->SendParamBufferSize == ParamBytesToBeSent)) {
  927. RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: No Secondary Requests\n"));
  928. pTransactExchange->State = TRANSACT_EXCHANGE_TRANSMITTED_SECONDARY_REQUESTS;
  929. } else {
  930. pTransactExchange->State = TRANSACT_EXCHANGE_TRANSMITTED_PRIMARY_REQUEST;
  931. }
  932. RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: SmbCeTranceive(Response expected)\n"));
  933. Status = SmbCeTranceive(
  934. pExchange,
  935. RXCE_SEND_SYNCHRONOUS,
  936. pPrimaryRequestSmbMdl,
  937. SmbLength);
  938. if ((Status != STATUS_SUCCESS)) {
  939. RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: SmbCeTranceive returned %lx\n",Status));
  940. }
  941. }
  942. }
  943. }
  944. if (pPartialParamMdl != NULL) {
  945. IoFreeMdl(pPartialParamMdl);
  946. }
  947. if (pPartialDataMdl != NULL) {
  948. IoFreeMdl(pPartialDataMdl);
  949. }
  950. if (pPaddingMdl != NULL) {
  951. IoFreeMdl(pPaddingMdl);
  952. }
  953. if (pPrimaryRequestSmbMdl != NULL) {
  954. RxUnlockHeaderPages(pPrimaryRequestSmbMdl);
  955. IoFreeMdl(pPrimaryRequestSmbMdl);
  956. }
  957. RxFreePool(pActualPrimaryRequestSmbHeader);
  958. if (Status != STATUS_PENDING) {
  959. pExchange->Status = Status;
  960. }
  961. return Status;
  962. }
  963. NTSTATUS
  964. SmbTransactExchangeReceive(
  965. IN struct _SMB_EXCHANGE *pExchange, // The exchange instance
  966. IN ULONG BytesIndicated,
  967. IN ULONG BytesAvailable,
  968. OUT ULONG *pBytesTaken,
  969. IN PSMB_HEADER pSmbHeader,
  970. OUT PMDL *pDataBufferPointer,
  971. OUT PULONG pDataSize,
  972. IN ULONG ReceiveFlags)
  973. /*++
  974. Routine Description:
  975. This is the recieve indication handling routine for transact exchanges
  976. Arguments:
  977. pExchange - the exchange instance
  978. BytesIndicated - the number of bytes indicated
  979. Bytes Available - the number of bytes available
  980. pBytesTaken - the number of bytes consumed
  981. pSmbHeader - the byte buffer
  982. pDataBufferPointer - the buffer into which the remaining data is to be copied.
  983. pDataSize - the buffer size.
  984. Return Value:
  985. RXSTATUS - The return status for the operation
  986. Notes:
  987. This routine is called at DPC level.
  988. --*/
  989. {
  990. NTSTATUS Status;
  991. PNTSTATUS pFinalSmbStatus;
  992. BOOLEAN fError = FALSE;
  993. BOOLEAN fIndicationNotSufficient = FALSE;
  994. BOOLEAN fMoreParsingRequired = FALSE;
  995. BOOLEAN fDoErrorProcessing = FALSE;
  996. SMB_TRANSACT_RESP_FORMAT_DESCRIPTION Format;
  997. GENERIC_ANDX CommandToProcess;
  998. ULONG TransactResponseSize = 0;
  999. ULONG SetupBytesOffsetInResponse = 0;
  1000. ULONG SetupBytesInResponse = 0;
  1001. ULONG CopyDataSize = 0;
  1002. PMDL pSetupMdl = NULL;
  1003. PMDL pCopyRequestMdl = NULL;
  1004. PSMB_TRANSACT_EXCHANGE pTransactExchange = (PSMB_TRANSACT_EXCHANGE)pExchange;
  1005. RxDbgTrace( 0, Dbg,
  1006. ("SmbTransactExchangeReceive: Entering w/ Bytes Available (%ld) Bytes Indicated (%ld) State (%ld)\n",
  1007. BytesAvailable,
  1008. BytesIndicated,
  1009. pTransactExchange->State
  1010. ));
  1011. RxDbgTrace( 0, Dbg,
  1012. ("SmbTransactExchangeReceive: Buffer %08lx Consumed (%ld) MDL (%08lx)\n",
  1013. pSmbHeader,
  1014. *pBytesTaken,
  1015. *pDataBufferPointer
  1016. ));
  1017. pFinalSmbStatus = &pTransactExchange->SmbStatus;
  1018. Status = SmbCeParseSmbHeader(
  1019. pExchange,
  1020. pSmbHeader,
  1021. &CommandToProcess,
  1022. pFinalSmbStatus,
  1023. BytesAvailable,
  1024. BytesIndicated,
  1025. pBytesTaken);
  1026. if (Status != STATUS_SUCCESS) {
  1027. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1028. goto FINALLY;
  1029. }
  1030. //this need some explanation. parseheader is written so as to take some extra smbs off the from
  1031. //of the packet...specifically, stuff like sessionsetup&X and TC&X. since no transact is a valid followon
  1032. //it would not make since if (a) not enough were indicated or (b) an early command had an error. so
  1033. //we must have success.
  1034. if (*((PBYTE)(pSmbHeader+1)) == 0 && (pTransactExchange->State!=TRANSACT_EXCHANGE_TRANSMITTED_PRIMARY_REQUEST)) {
  1035. RxDbgTrace(0,Dbg,("SmbTransactExchangeReceive: FinalSmbStatus = %lx\n", *pFinalSmbStatus));
  1036. if (NT_SUCCESS(*pFinalSmbStatus)) {
  1037. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1038. goto FINALLY;
  1039. }
  1040. }
  1041. //we know that status is SUCCESS from the assert above. but we will still continue to check so as
  1042. //to be more resilient when we don't have msg boundaries. we have the following cases depending on the
  1043. //characteristics of the smbresponse
  1044. //
  1045. // non-error: get the data and then return the stored responsestatus. the process of getting the data
  1046. // causes us to update the param and data counts so that we know when we have reached the
  1047. // end of the data. the parse routine re-ups the receive if needed.
  1048. // error: there are main cases:
  1049. // a) the server has sent no data. here we discard the packet and we can just get out. the
  1050. // finalize routine will pickup the status correctly.
  1051. // b) here, we have to discard the packet AND update the byte counts AND re-up the receive
  1052. // if necessary. to discard the packet, we must either compute the apparent msg length from
  1053. // the WC and BC parameters (best) OR use our maximum buffer size
  1054. fMoreParsingRequired = FALSE;
  1055. if (Status == STATUS_SUCCESS) {
  1056. if (TRUE) { //maybe sometimes we wont copy!
  1057. if (CommandToProcess.WordCount > 0) {
  1058. TransactResponseSize = 0;
  1059. // Ensure that at the very least enough bytes have been indicated to determine
  1060. // the length of the setup, parameters and data for the transaction.
  1061. switch (CommandToProcess.AndXCommand) {
  1062. case SMB_COM_NT_TRANSACT:
  1063. case SMB_COM_NT_TRANSACT_SECONDARY:
  1064. TransactResponseSize = FIELD_OFFSET(RESP_NT_TRANSACTION,Buffer);
  1065. break;
  1066. case SMB_COM_TRANSACTION:
  1067. case SMB_COM_TRANSACTION2:
  1068. case SMB_COM_TRANSACTION_SECONDARY:
  1069. case SMB_COM_TRANSACTION2_SECONDARY:
  1070. TransactResponseSize = FIELD_OFFSET(RESP_TRANSACTION,Buffer);
  1071. break;
  1072. default:
  1073. TransactResponseSize = 0xffffffff;
  1074. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1075. break;
  1076. }
  1077. if (BytesIndicated >= (sizeof(SMB_HEADER) + TransactResponseSize)) {
  1078. fMoreParsingRequired = TRUE;
  1079. } else {
  1080. fIndicationNotSufficient = TRUE;
  1081. *pFinalSmbStatus = STATUS_INVALID_NETWORK_RESPONSE;
  1082. }
  1083. } else {
  1084. // allow a response with wordcount==0 to go thru if we're the right state
  1085. fMoreParsingRequired = (pTransactExchange->State==TRANSACT_EXCHANGE_TRANSMITTED_PRIMARY_REQUEST);
  1086. }
  1087. }
  1088. }
  1089. if (fMoreParsingRequired) {
  1090. // The header was successfully parsed and the SMB response did not contain any errors
  1091. // The stage is set for processing the transaction response.
  1092. switch (pTransactExchange->State) {
  1093. case TRANSACT_EXCHANGE_TRANSMITTED_PRIMARY_REQUEST:
  1094. {
  1095. // The primary request for the transaction has been sent and there are
  1096. // secondary requests to be sent.
  1097. // The only response expected at this time is an interim response. Any
  1098. // other response will be treated as an error.
  1099. PRESP_TRANSACTION_INTERIM pInterimResponse;
  1100. RxDbgTrace(0,Dbg,("SmbCeTransactExchangeReceive: Processing interim response\n"));
  1101. if ((*pBytesTaken + FIELD_OFFSET(RESP_TRANSACTION_INTERIM,Buffer)) <= BytesIndicated) {
  1102. pInterimResponse = (PRESP_TRANSACTION_INTERIM)((PBYTE)pSmbHeader + *pBytesTaken);
  1103. if ((pSmbHeader->Command == pTransactExchange->SmbCommand) &&
  1104. (SmbGetUshort(&pInterimResponse->WordCount) == 0) &&
  1105. (SmbGetUshort(&pInterimResponse->ByteCount) == 0)) {
  1106. // The interim response was valid. Transition the state of the exchange
  1107. // and transmit the secondary requests.
  1108. *pBytesTaken += FIELD_OFFSET(RESP_TRANSACTION_INTERIM,Buffer);
  1109. pTransactExchange->State = TRANSACT_EXCHANGE_RECEIVED_INTERIM_RESPONSE;
  1110. // Determine if any secondary transaction requests need to be sent. if none are
  1111. // required then modify the state
  1112. ASSERT((pTransactExchange->ParamBytesSent < pTransactExchange->SendParamBufferSize) ||
  1113. (pTransactExchange->DataBytesSent < pTransactExchange->SendDataBufferSize));
  1114. ASSERT((pTransactExchange->ParamBytesSent <= pTransactExchange->SendParamBufferSize) &&
  1115. (pTransactExchange->DataBytesSent <= pTransactExchange->SendDataBufferSize));
  1116. if (!(pTransactExchange->Flags & SMB_TRANSACTION_NO_RESPONSE )) {
  1117. Status = SmbCeReceive(pExchange);
  1118. }
  1119. if (Status != STATUS_SUCCESS) {
  1120. pExchange->Status = Status;
  1121. } else {
  1122. Status = STATUS_SUCCESS;
  1123. SmbCeIncrementPendingLocalOperations(pExchange);
  1124. RxPostToWorkerThread(
  1125. MRxSmbDeviceObject,
  1126. CriticalWorkQueue,
  1127. &pExchange->WorkQueueItem,
  1128. SendSecondaryRequests,
  1129. pExchange);
  1130. }
  1131. } else {
  1132. RxDbgTrace(0,Dbg,("SmbCeTransactExchangeReceive: Invalid interim response\n"));
  1133. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1134. }
  1135. } else {
  1136. fIndicationNotSufficient = TRUE;
  1137. Status = STATUS_MORE_PROCESSING_REQUIRED;
  1138. }
  1139. }
  1140. break;
  1141. case TRANSACT_EXCHANGE_RECEIVED_INTERIM_RESPONSE:
  1142. RxDbgTrace(0,Dbg,("SmbCeTransactExchangeReceive: received again while in interim response\n"));
  1143. //no break: this is okay
  1144. case TRANSACT_EXCHANGE_TRANSMITTED_SECONDARY_REQUESTS:
  1145. case TRANSACT_EXCHANGE_RECEIVED_PRIMARY_RESPONSE:
  1146. {
  1147. BOOLEAN fPrimaryResponse = FALSE;
  1148. PRESP_TRANSACTION pTransactResponse;
  1149. PRESP_NT_TRANSACTION pNtTransactResponse;
  1150. ULONG TotalParamBytesInResponse;
  1151. ULONG TotalDataBytesInResponse;
  1152. RxDbgTrace(0,Dbg,("SmbCeTransactExchangeReceive: Processing Primary/Secondary response\n"));
  1153. //do this here so there's only one copy if the code
  1154. pTransactResponse = (PRESP_TRANSACTION)((PBYTE)pSmbHeader +
  1155. SmbGetUshort(&CommandToProcess.AndXOffset));
  1156. // All the requests ( both primary and secondary have been sent ). The
  1157. // only responses expected in this state are (1) a primary response and (2) a
  1158. // secondary response. Any other response is an error.
  1159. if (pSmbHeader->Command == pTransactExchange->SmbCommand) {
  1160. switch (pSmbHeader->Command) {
  1161. case SMB_COM_TRANSACTION:
  1162. case SMB_COM_TRANSACTION2:
  1163. //pTransactResponse = (PRESP_TRANSACTION)((PBYTE)pSmbHeader +
  1164. // SmbGetUshort(&CommandToProcess.AndXOffset));
  1165. fPrimaryResponse = TRUE;
  1166. SetupBytesOffsetInResponse = FIELD_OFFSET(RESP_TRANSACTION,Buffer);
  1167. SetupBytesInResponse = sizeof(USHORT) * pTransactResponse->SetupCount;
  1168. // Initialize the total count of data and param bytes that will be received from
  1169. // the server during the course ofthe transaction response.
  1170. TotalParamBytesInResponse = SmbGetUshort(&pTransactResponse->TotalParameterCount);
  1171. TotalDataBytesInResponse = SmbGetUshort(&pTransactResponse->TotalDataCount);
  1172. // fall through
  1173. case SMB_COM_TRANSACTION_SECONDARY:
  1174. case SMB_COM_TRANSACTION2_SECONDARY:
  1175. TransactResponseSize = FIELD_OFFSET(RESP_TRANSACTION,Buffer);
  1176. break;
  1177. case SMB_COM_NT_TRANSACT:
  1178. //pNtTransactResponse = (PRESP_NT_TRANSACTION)((PBYTE)pSmbHeader +
  1179. // SmbGetUshort(&CommandToProcess.AndXOffset));
  1180. pNtTransactResponse = (PRESP_NT_TRANSACTION)pTransactResponse;
  1181. fPrimaryResponse = TRUE;
  1182. SetupBytesOffsetInResponse = FIELD_OFFSET(RESP_NT_TRANSACTION,Buffer);
  1183. SetupBytesInResponse = sizeof(USHORT) * pNtTransactResponse->SetupCount;
  1184. // Initialize the total count of data and param bytes that will be received from
  1185. // the server during the course ofthe transaction response.
  1186. TotalParamBytesInResponse = SmbGetUshort(&pNtTransactResponse->TotalParameterCount);
  1187. TotalDataBytesInResponse = SmbGetUshort(&pNtTransactResponse->TotalDataCount);
  1188. // fall through ..
  1189. case SMB_COM_NT_TRANSACT_SECONDARY:
  1190. TransactResponseSize = FIELD_OFFSET(RESP_NT_TRANSACTION,Buffer);
  1191. break;
  1192. default:
  1193. // Abort the exchange. An unexpected response was received during the
  1194. // course of the transaction.
  1195. ASSERT(!"Valid network response");
  1196. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1197. }
  1198. if (Status == STATUS_SUCCESS) {
  1199. if (fPrimaryResponse) {
  1200. RxDbgTrace( 0,
  1201. Dbg,
  1202. ("SmbTransactExchangeReceive: Primary Response Setup Bytes(%ld) Param Bytes (%ld) Data Bytes (%ld)\n",
  1203. SetupBytesInResponse,
  1204. TotalParamBytesInResponse,
  1205. TotalDataBytesInResponse
  1206. )
  1207. );
  1208. if ((TotalParamBytesInResponse > pTransactExchange->ReceiveParamBufferSize) ||
  1209. (TotalDataBytesInResponse > pTransactExchange->ReceiveDataBufferSize)) {
  1210. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1211. goto FINALLY;
  1212. } else {
  1213. pTransactExchange->ReceiveParamBufferSize = TotalParamBytesInResponse;
  1214. pTransactExchange->ReceiveDataBufferSize = TotalDataBytesInResponse;
  1215. }
  1216. }
  1217. if (Status == STATUS_SUCCESS &&
  1218. TransactResponseSize + *pBytesTaken <= BytesIndicated) {
  1219. if (fPrimaryResponse &&
  1220. (SetupBytesInResponse > 0)) {
  1221. PBYTE pSetupStartAddress;
  1222. ULONG SetupBytesIndicated = MIN(SetupBytesInResponse,
  1223. BytesIndicated - SetupBytesOffsetInResponse);
  1224. if( pTransactExchange->pReceiveSetupMdl ) {
  1225. pSetupStartAddress = (PBYTE)MmGetSystemAddressForMdlSafe(
  1226. pTransactExchange->pReceiveSetupMdl,
  1227. LowPagePriority
  1228. );
  1229. if( pSetupStartAddress == NULL ) {
  1230. Status = STATUS_INSUFFICIENT_RESOURCES;
  1231. } else {
  1232. if (SetupBytesInResponse == SetupBytesIndicated) {
  1233. RtlCopyMemory(
  1234. pSetupStartAddress,
  1235. ((PBYTE)pSmbHeader + SetupBytesOffsetInResponse),
  1236. SetupBytesIndicated);
  1237. pSetupStartAddress += SetupBytesIndicated;
  1238. SetupBytesInResponse -= SetupBytesIndicated;
  1239. SetupBytesOffsetInResponse += SetupBytesIndicated;
  1240. pTransactExchange->SetupBytesReceived = SetupBytesInResponse;
  1241. } else {
  1242. ASSERT(!"this code doesn't work");
  1243. RxDbgTrace(0,Dbg,("SmbTransactExchangeReceive: Setup Bytes Partially Indicated\n"));
  1244. // Some setup bytes have not been indicated. An MDL needs to be
  1245. // created for copying the data. This MDL should also include the padding
  1246. // MDL for copying the padding bytes ...
  1247. pSetupMdl = RxAllocateMdl(pSetupStartAddress,SetupBytesInResponse);
  1248. if ( pSetupMdl != NULL ) {
  1249. IoBuildPartialMdl(
  1250. pTransactExchange->pReceiveSetupMdl,
  1251. pSetupMdl,
  1252. pSetupStartAddress,
  1253. SetupBytesInResponse);
  1254. } else {
  1255. Status = STATUS_INSUFFICIENT_RESOURCES;
  1256. }
  1257. }
  1258. }
  1259. }
  1260. RxDbgTrace(0,Dbg,("SmbTransactExchangeReceive: Setup Bytes Indicated (%ld)\n",SetupBytesIndicated));
  1261. }
  1262. if (Status == STATUS_SUCCESS) {
  1263. // from here, we cannot go back and redo the header....so we have to change state so
  1264. //that the copy routine doesn't try to reparse
  1265. pTransactExchange->State = TRANSACT_EXCHANGE_RECEIVED_PRIMARY_RESPONSE;
  1266. Status = SmbTransactAccrueAndValidateFormatData(
  1267. pTransactExchange,
  1268. pSmbHeader,
  1269. BytesIndicated,
  1270. &Format);
  1271. if (Status != STATUS_SUCCESS) {
  1272. goto FINALLY;
  1273. }
  1274. Status = ParseTransactResponse(
  1275. pTransactExchange,&Format,
  1276. BytesIndicated,
  1277. BytesAvailable,
  1278. pBytesTaken,
  1279. pSmbHeader,
  1280. &pCopyRequestMdl,
  1281. &CopyDataSize);
  1282. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  1283. // Link the setup MDL with the MDL returned
  1284. if (pSetupMdl != NULL) {
  1285. if (pCopyRequestMdl != NULL) {
  1286. pSetupMdl->Next = pCopyRequestMdl;
  1287. }
  1288. pCopyRequestMdl = pSetupMdl;
  1289. CopyDataSize += SetupBytesInResponse;
  1290. }
  1291. }
  1292. //check if the server has sent extra bytes.....
  1293. // ---------------------------------------------------------------------------------------------
  1294. {
  1295. ULONG ApparentMsgLength = max(BytesAvailable,Format.ApparentMsgLength);
  1296. ULONG DeficitBytes = ApparentMsgLength - (*pBytesTaken+CopyDataSize);
  1297. if (ApparentMsgLength < *pBytesTaken+CopyDataSize) {
  1298. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1299. goto FINALLY;
  1300. }
  1301. if (DeficitBytes > 0) {
  1302. RxLog(("XtraBytes %lx %lx",pTransactExchange,DeficitBytes));
  1303. if (CopyDataSize==0) {
  1304. if (*pBytesTaken > BytesAvailable) {
  1305. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1306. goto FINALLY;
  1307. }
  1308. RxLog(("Extra Bytes were sent and copydatasize==0........\n"));
  1309. *pBytesTaken = BytesAvailable; //cant take more than this
  1310. } else {
  1311. PMDL LastMdl,TrailingBytesMdl;
  1312. if ( DeficitBytes > TRAILING_BYTES_BUFFERSIZE) {
  1313. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1314. goto FINALLY;
  1315. }
  1316. TrailingBytesMdl = &pTransactExchange->TrailingBytesMdl;
  1317. MmInitializeMdl(
  1318. TrailingBytesMdl,
  1319. &pTransactExchange->TrailingBytesBuffer.Bytes[0],
  1320. DeficitBytes
  1321. );
  1322. MmBuildMdlForNonPagedPool(TrailingBytesMdl);
  1323. LastMdl = pCopyRequestMdl;
  1324. ASSERT(LastMdl != NULL);
  1325. for (;LastMdl->Next!=NULL;LastMdl=LastMdl->Next) ;
  1326. ASSERT(LastMdl != NULL);
  1327. ASSERT(LastMdl->Next == NULL);
  1328. LastMdl->Next = TrailingBytesMdl;
  1329. CopyDataSize += DeficitBytes;
  1330. }
  1331. }
  1332. }
  1333. // ---------------------------------------------------------------------------------------------
  1334. RxDbgTrace(0,Dbg,("SmbTransactExchangeReceive: ParseTransactResponse returned %lx\n",Status));
  1335. }
  1336. *pDataBufferPointer = pCopyRequestMdl;
  1337. *pDataSize = CopyDataSize;
  1338. } else {
  1339. RxDbgTrace(0,Dbg,("SmbTransactExchangeReceive: Indication not sufficient: trsz %08lx bytestakn %08lx \n",
  1340. TransactResponseSize, *pBytesTaken));
  1341. fIndicationNotSufficient = TRUE;
  1342. if (Status == STATUS_SUCCESS) {
  1343. Status = STATUS_MORE_PROCESSING_REQUIRED;
  1344. }
  1345. }
  1346. }
  1347. } else {
  1348. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1349. }
  1350. }
  1351. break;
  1352. default:
  1353. {
  1354. ASSERT(!"Valid Transact Exchange State for receiving responses");
  1355. RxDbgTrace( 0, Dbg, ("SmbTransactExchangeReceive: Aborting Exchange -- invalid state\n"));
  1356. }
  1357. break;
  1358. }
  1359. } else {
  1360. // We get here if either the status or the smbstatus is not success.
  1361. // If sufficient bytes were not indicated for processing the header a copy data request
  1362. // needs to be posted. this occurs if status is status_more_processing_required
  1363. RxDbgTrace( 0, Dbg, ("SmbTransactExchangeReceive: bad status(es) from parseheadr %08lx %08lx\n",
  1364. Status,*pFinalSmbStatus));
  1365. fDoErrorProcessing = TRUE;
  1366. }
  1367. if ((Status == STATUS_SUCCESS) &&
  1368. (pTransactExchange->ParamBytesReceived == pTransactExchange->ReceiveParamBufferSize) &&
  1369. (pTransactExchange->DataBytesReceived == pTransactExchange->ReceiveDataBufferSize) &&
  1370. (pTransactExchange->PendingCopyRequests == 0)) {
  1371. NOTHING;
  1372. } else if (fDoErrorProcessing) {
  1373. BOOLEAN DoItTheShortWay = TRUE;
  1374. ULONG ApparentMsgLength;
  1375. RxDbgTrace(0,Dbg,("SmbTransactExchangeReceive: Error processing response %lx .. Exchange aborted\n",Status));
  1376. if (BytesAvailable > BytesIndicated ||
  1377. !FlagOn(ReceiveFlags,TDI_RECEIVE_ENTIRE_MESSAGE)) {
  1378. Status = SmbTransactAccrueAndValidateFormatData(
  1379. pTransactExchange,
  1380. pSmbHeader,
  1381. BytesIndicated,
  1382. &Format);
  1383. if (Status != STATUS_SUCCESS) {
  1384. goto FINALLY;
  1385. }
  1386. ApparentMsgLength = max(BytesAvailable,Format.ApparentMsgLength);
  1387. //if wordcount!=0 then the server is sending us bytes.....we have to continue doing
  1388. //receives until we have seen all the bytes
  1389. if ((pTransactExchange->ParameterBytesSeen<Format.ParameterCount) ||
  1390. (pTransactExchange->DataBytesSeen<Format.DataCount)) {
  1391. NTSTATUS ReceiveStatus;
  1392. // The exchange has been successfully completed. Finalize it.
  1393. RxDbgTrace(0,Dbg,("ParseTransactResponse: Register for more error responses\n"));
  1394. RxLog(("TxErr: %lx %lx %lx",pTransactExchange,
  1395. pTransactExchange->ParameterBytesSeen,pTransactExchange->DataBytesSeen));
  1396. ReceiveStatus = SmbCeReceive((PSMB_EXCHANGE)pTransactExchange);
  1397. if (ReceiveStatus != STATUS_SUCCESS) {
  1398. // There was an error in registering the receive. Abandon the transaction.
  1399. Status = ReceiveStatus;
  1400. RxLog(("TxErrAbandon %lx",pTransactExchange));
  1401. //Make it fail the next two tests.....
  1402. ApparentMsgLength = 0; DoItTheShortWay = FALSE;
  1403. }
  1404. }
  1405. //netbt will not allow us to discard the packet by setting taken=available. so, check for
  1406. //available>indicated. if true, take the bytes by conjuring up a buffer
  1407. if (ApparentMsgLength>BytesIndicated) {
  1408. //we'll have to lay down a buffer for this so that NetBT won't blow the session away
  1409. ASSERT(pTransactExchange->Status == STATUS_MORE_PROCESSING_REQUIRED);
  1410. pTransactExchange->DiscardBuffer = RxAllocatePoolWithTag(
  1411. NonPagedPool,
  1412. ApparentMsgLength,
  1413. MRXSMB_XACT_POOLTAG);
  1414. if (pTransactExchange->DiscardBuffer!=NULL) {
  1415. *pBytesTaken = 0;
  1416. *pDataSize = ApparentMsgLength;
  1417. *pDataBufferPointer = &pTransactExchange->TrailingBytesMdl;
  1418. MmInitializeMdl(*pDataBufferPointer,
  1419. pTransactExchange->DiscardBuffer,
  1420. ApparentMsgLength
  1421. );
  1422. MmBuildMdlForNonPagedPool(*pDataBufferPointer);
  1423. pTransactExchange->SaveTheRealStatus = Status;
  1424. RxLog(("XRtakebytes %lx %lx\n",pTransactExchange,Status));
  1425. Status = STATUS_MORE_PROCESSING_REQUIRED;
  1426. DoItTheShortWay = FALSE;
  1427. }
  1428. }
  1429. }
  1430. if (DoItTheShortWay) {
  1431. goto FINALLY;
  1432. }
  1433. }
  1434. RxDbgTrace( 0, Dbg,
  1435. ("SmbTransactExchangeReceiveExit: Bytes Consumed (%ld) Status (%08lx) MDL (%08lx) size(%08lx)\n",
  1436. *pBytesTaken, Status, *pDataBufferPointer, *pDataSize
  1437. ));
  1438. return Status;
  1439. FINALLY:
  1440. *pBytesTaken = BytesAvailable;
  1441. *pDataBufferPointer = NULL;
  1442. // Abort the exchange
  1443. pTransactExchange->Status = Status;
  1444. Status = STATUS_SUCCESS;
  1445. RxDbgTrace(0,Dbg,("SmbTransactExchangeReceive: Exchange aborted.\n",Status));
  1446. return Status;
  1447. UNREFERENCED_PARAMETER(ReceiveFlags);
  1448. }
  1449. NTSTATUS
  1450. SmbTransactExchangeAbort(
  1451. PSMB_EXCHANGE pExchange)
  1452. /*++
  1453. Routine Description:
  1454. This is the abort routine for transact exchanges
  1455. Arguments:
  1456. pExchange - the exchange instance
  1457. Return Value:
  1458. RXSTATUS - The return status for the operation
  1459. --*/
  1460. {
  1461. PAGED_CODE();
  1462. // The SMB exchange completed with an error. Invoke the RDBSS callback routine
  1463. // and scavenge the exchange instance.
  1464. pExchange->Status = STATUS_REQUEST_ABORTED;
  1465. return STATUS_SUCCESS;
  1466. }
  1467. NTSTATUS
  1468. SmbTransactExchangeErrorHandler(
  1469. IN PSMB_EXCHANGE pExchange) // the SMB exchange instance
  1470. /*++
  1471. Routine Description:
  1472. This is the error indication handling routine for transact exchanges
  1473. Arguments:
  1474. pExchange - the exchange instance
  1475. Return Value:
  1476. RXSTATUS - The return status for the operation
  1477. --*/
  1478. {
  1479. PAGED_CODE();
  1480. // The SMB exchange completed with an error. Invoke the RDBSS callback routine
  1481. // and scavenge the exchange instance.
  1482. return STATUS_SUCCESS;
  1483. UNREFERENCED_PARAMETER(pExchange);
  1484. }
  1485. NTSTATUS
  1486. SmbTransactExchangeSendCallbackHandler(
  1487. IN PSMB_EXCHANGE pExchange, // The exchange instance
  1488. IN PMDL pXmitBuffer,
  1489. IN NTSTATUS SendCompletionStatus)
  1490. /*++
  1491. Routine Description:
  1492. This is the send call back indication handling routine for transact exchanges
  1493. Arguments:
  1494. pExchange - the exchange instance
  1495. Return Value:
  1496. RXSTATUS - The return status for the operation
  1497. --*/
  1498. {
  1499. PAGED_CODE();
  1500. return STATUS_SUCCESS;
  1501. UNREFERENCED_PARAMETER(pExchange);
  1502. UNREFERENCED_PARAMETER(pXmitBuffer);
  1503. UNREFERENCED_PARAMETER(SendCompletionStatus);
  1504. }
  1505. NTSTATUS
  1506. SmbTransactExchangeCopyDataHandler(
  1507. IN PSMB_EXCHANGE pExchange, // The exchange instance
  1508. IN PMDL pDataBuffer, // the buffer
  1509. IN ULONG DataSize)
  1510. /*++
  1511. Routine Description:
  1512. This is the copy data handling routine for transact exchanges
  1513. Arguments:
  1514. pExchange - the exchange instance
  1515. pDataBuffer - the buffer
  1516. DataSize - the amount of data returned
  1517. Return Value:
  1518. RXSTATUS - The return status for the operation
  1519. --*/
  1520. {
  1521. NTSTATUS Status = STATUS_SUCCESS;
  1522. PSMB_TRANSACT_EXCHANGE pTransactExchange = (PSMB_TRANSACT_EXCHANGE)pExchange;
  1523. PMDL pCopyRequestMdl = NULL;
  1524. PMDL pCurMdl = NULL;
  1525. ULONG CopyRequestSize = 0;
  1526. PMDL TrailingBytesMdl = &pTransactExchange->TrailingBytesMdl;
  1527. ULONG BytesConsumed;
  1528. RxDbgTrace(+1,Dbg,("SmbTransactExchangeCopyDataHandler: Entered\n"));
  1529. if (pTransactExchange->DiscardBuffer!=NULL) {
  1530. //we just copied to get rid of the buffer....
  1531. //free the buffer, set the status and get out
  1532. RxFreePool(pTransactExchange->DiscardBuffer);
  1533. Status = pTransactExchange->SaveTheRealStatus;
  1534. RxDbgTrace(-1,Dbg,("SmbTransactExchangeCopyDataHandler: Discard Exit, status =%08lx\n"));
  1535. DbgPrint("copyHandlerDiscard, st=%08lx\n",Status);
  1536. return Status;
  1537. }
  1538. switch (pTransactExchange->State) {
  1539. case TRANSACT_EXCHANGE_TRANSMITTED_PRIMARY_REQUEST :
  1540. case TRANSACT_EXCHANGE_TRANSMITTED_SECONDARY_REQUESTS :
  1541. {
  1542. PSMB_HEADER pSmbHeader = (PSMB_HEADER)MmGetSystemAddressForMdlSafe(pDataBuffer,LowPagePriority);
  1543. RxDbgTrace(0,Dbg,("SmbTransactExchangeCopyDataHandler: Reparsing response\n"));
  1544. if (pSmbHeader == NULL) {
  1545. Status = STATUS_INSUFFICIENT_RESOURCES;
  1546. } else {
  1547. // The response could not be parsed with the indicated bytes. Invoke
  1548. // the receive method to resume parsing of the complete SMB
  1549. Status = SmbTransactExchangeReceive(
  1550. pExchange,
  1551. DataSize,
  1552. DataSize,
  1553. &BytesConsumed,
  1554. pSmbHeader,
  1555. &pCopyRequestMdl,
  1556. &CopyRequestSize,
  1557. TDI_RECEIVE_ENTIRE_MESSAGE);
  1558. }
  1559. if (Status == STATUS_SUCCESS) {
  1560. ASSERT(BytesConsumed == DataSize);
  1561. ASSERT(pCopyRequestMdl == NULL);
  1562. ASSERT(CopyRequestSize == 0);
  1563. }
  1564. }
  1565. break;
  1566. case TRANSACT_EXCHANGE_RECEIVED_PRIMARY_RESPONSE :
  1567. {
  1568. RxDbgTrace(0,Dbg,("SmbTransactExchangeCopyDataHandler: Completing secondary response processing\n"));
  1569. // In this state only secondary responses will be received. All the secondary
  1570. // responses can be parsed from the indication. Therefore it is sufficient to
  1571. // merely free the MDL's and re-register with the connection engine for
  1572. // receiving subsequent requests.
  1573. InterlockedDecrement(&pTransactExchange->PendingCopyRequests);
  1574. if ((pTransactExchange->ParamBytesReceived == pTransactExchange->ReceiveParamBufferSize) &&
  1575. (pTransactExchange->DataBytesReceived == pTransactExchange->ReceiveDataBufferSize) &&
  1576. (pTransactExchange->PendingCopyRequests == 0)) {
  1577. // The exchange has been successfully completed. Finalize it.
  1578. RxDbgTrace(0,Dbg,("SmbTransactExchangeCopyDataHandler: Processed last secondary response successfully\n"));
  1579. pExchange->Status = STATUS_SUCCESS;
  1580. }
  1581. }
  1582. break;
  1583. default:
  1584. {
  1585. ASSERT(!"Valid State fore receiving copy data completion indication");
  1586. pExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
  1587. }
  1588. break;
  1589. }
  1590. // Free up the data buffers.
  1591. pCurMdl = pDataBuffer;
  1592. while (pCurMdl != NULL) {
  1593. PMDL pPrevMdl = pCurMdl;
  1594. pCurMdl = pCurMdl->Next;
  1595. if (pPrevMdl!=TrailingBytesMdl) {
  1596. IoFreeMdl(pPrevMdl);
  1597. }
  1598. }
  1599. RxDbgTrace(-1,Dbg,("SmbTransactExchangeCopyDataHandler: Exit\n"));
  1600. return Status;
  1601. }
  1602. NTSTATUS
  1603. SmbCeInitializeTransactExchange(
  1604. PSMB_TRANSACT_EXCHANGE pTransactExchange,
  1605. PRX_CONTEXT RxContext,
  1606. PSMB_TRANSACTION_OPTIONS pOptions,
  1607. PSMB_TRANSACTION_SEND_PARAMETERS pSendParameters,
  1608. PSMB_TRANSACTION_RECEIVE_PARAMETERS pReceiveParameters,
  1609. PSMB_TRANSACTION_RESUMPTION_CONTEXT pResumptionContext)
  1610. /*++
  1611. Routine Description:
  1612. This routine initializes a transact exchange instance
  1613. Arguments:
  1614. pTransactExchange - the exchange instance
  1615. RxContext - RDBSS context for the file involved in the transaction.
  1616. pOptions - the transaction options
  1617. pSendParameters - the parameters to be sent to the server
  1618. pReceiveParameters - the results from the server
  1619. pResumptionContext - the resumption context
  1620. Return Value:
  1621. RXSTATUS - The return status for the operation
  1622. --*/
  1623. {
  1624. NTSTATUS Status = STATUS_SUCCESS;
  1625. RxCaptureFobx;
  1626. UCHAR SmbCommand;
  1627. PMDL pSendDataMdl;
  1628. PMDL pSendParamMdl; //used if we can't subsume
  1629. PMDL pReceiveDataMdl;
  1630. PMDL pReceiveParamMdl;
  1631. PVOID pSendSetupBuffer;
  1632. ULONG SendSetupBufferSize;
  1633. PMDL pReceiveSetupMdl;
  1634. ULONG ReceiveSetupBufferSize;
  1635. ULONG SendDataBufferSize;
  1636. ULONG ReceiveDataBufferSize;
  1637. PVOID pSendParamBuffer;
  1638. ULONG SendParamBufferSize;
  1639. ULONG ReceiveParamBufferSize;
  1640. ULONG MaxSmbBufferSize = 0;
  1641. ULONG PrimaryRequestSmbSize = 0;
  1642. // The fields in theSMB request that are dialect independent and need to be filled in
  1643. PUSHORT pBcc; // the byte count field
  1644. PUSHORT pSetup; // the setup data
  1645. PBYTE pParam; // the param data
  1646. BOOLEAN fTransactionNameInUnicode = FALSE;
  1647. PSMB_EXCHANGE pExchange = (PSMB_EXCHANGE)pTransactExchange;
  1648. PVOID pActualPrimaryRequestSmbHeader;
  1649. PSMB_HEADER pPrimaryRequestSmbHeader;
  1650. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1651. PAGED_CODE();
  1652. ASSERT(pTransactExchange->Type == TRANSACT_EXCHANGE);
  1653. pTransactExchange->RxContext = RxContext;
  1654. pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  1655. {
  1656. PMRXSMB_RX_CONTEXT pMRxSmbContext = MRxSmbGetMinirdrContext(RxContext);
  1657. pMRxSmbContext->pExchange = (PSMB_EXCHANGE)pTransactExchange;
  1658. }
  1659. ASSERT(pSendParameters != NULL);
  1660. if (pSendParameters != NULL) {
  1661. pSendDataMdl = pSendParameters->pDataMdl;
  1662. pSendParamBuffer = pSendParameters->pParam;
  1663. SendParamBufferSize = pSendParameters->ParamLength;
  1664. pSendParamMdl = pSendParameters->pParamMdl;
  1665. pSendSetupBuffer = pSendParameters->pSetup;
  1666. SendSetupBufferSize = pSendParameters->SetupLength;
  1667. SendDataBufferSize = pSendParameters->DataLength;
  1668. ASSERT( !((pSendDataMdl == NULL)&&(SendDataBufferSize!=0)) );
  1669. RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: at the top pbuf/psize/dsize=%08lx/%08lx\n"
  1670. ,pSendParamBuffer,SendParamBufferSize,SendDataBufferSize));
  1671. } else {
  1672. Status = STATUS_INVALID_PARAMETER;
  1673. RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: Invalid Parameters\n",Status));
  1674. return Status;
  1675. }
  1676. if (pReceiveParameters != NULL) {
  1677. pReceiveDataMdl = pReceiveParameters->pDataMdl;
  1678. pReceiveParamMdl = pReceiveParameters->pParamMdl;
  1679. pReceiveSetupMdl = pReceiveParameters->pSetupMdl;
  1680. ReceiveDataBufferSize = ((pReceiveDataMdl != NULL) ? MmGetMdlByteCount(pReceiveDataMdl) : 0);
  1681. ASSERT (ReceiveDataBufferSize==pReceiveParameters->DataLength);
  1682. ReceiveParamBufferSize = ((pReceiveParamMdl != NULL) ? MmGetMdlByteCount(pReceiveParamMdl) : 0);
  1683. ReceiveSetupBufferSize = ((pReceiveSetupMdl != NULL) ? MmGetMdlByteCount(pReceiveSetupMdl) : 0);
  1684. } else {
  1685. pReceiveDataMdl = pReceiveParamMdl = pReceiveSetupMdl = NULL;
  1686. ReceiveDataBufferSize = ReceiveParamBufferSize = ReceiveDataBufferSize = 0;
  1687. }
  1688. MaxSmbBufferSize = MIN (pServerEntry->Server.MaximumBufferSize,
  1689. pOptions->MaximumTransmitSmbBufferSize);
  1690. pTransactExchange->MaximumTransmitSmbBufferSize = MaxSmbBufferSize;
  1691. // Ensure that the SMB dialect supports the exchange capability.
  1692. switch (pServerEntry->Server.Dialect) {
  1693. case NTLANMAN_DIALECT:
  1694. {
  1695. if (FlagOn(pServerEntry->Server.DialectFlags,DF_UNICODE)) {
  1696. fTransactionNameInUnicode = TRUE;
  1697. }
  1698. }
  1699. break;
  1700. case LANMAN10_DIALECT:
  1701. case WFW10_DIALECT:
  1702. {
  1703. // these guys only support transact...not T2 or NT. look for the name.....
  1704. if (pOptions->pTransactionName == NULL) {
  1705. RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: Server Dialect does not support nameless transactions\n"));
  1706. return STATUS_NOT_SUPPORTED;
  1707. }
  1708. }
  1709. //no break intentional........
  1710. case LANMAN12_DIALECT:
  1711. case LANMAN21_DIALECT:
  1712. {
  1713. // The NT_TRANSACT SMB is supported by NT servers only. Ensure that no attempt is being made
  1714. // to send an NT_TRANSACT SMB to a non NT server aka downlevel
  1715. if (pOptions->NtTransactFunction != 0) {
  1716. RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: Server Dialect does not support transactions\n"));
  1717. return STATUS_NOT_SUPPORTED;
  1718. }
  1719. fTransactionNameInUnicode = FALSE;
  1720. }
  1721. break;
  1722. default:
  1723. RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: Server Dialect does not support transactions\n"));
  1724. return STATUS_NOT_SUPPORTED;
  1725. }
  1726. PrimaryRequestSmbSize = sizeof(SMB_HEADER) + SendSetupBufferSize;
  1727. // Ensure that the parameter sizes are all valid. The parameter and the data buffer
  1728. // must be less than the maximum size to begin with.
  1729. if ( pOptions->NtTransactFunction == 0) {
  1730. if ((SendParamBufferSize > SMB_TRANSACT_MAXIMUM_PARAMETER_SIZE) ||
  1731. (ReceiveParamBufferSize > SMB_TRANSACT_MAXIMUM_PARAMETER_SIZE) ||
  1732. (SendDataBufferSize > SMB_TRANSACT_MAXIMUM_DATA_SIZE) ||
  1733. (ReceiveDataBufferSize > SMB_TRANSACT_MAXIMUM_DATA_SIZE)) {
  1734. RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: Parameters exceed maximum value\n"));
  1735. return STATUS_INVALID_PARAMETER;
  1736. }
  1737. PrimaryRequestSmbSize += sizeof(REQ_TRANSACTION);
  1738. // In all cases the name is sent as a UNICODE string if the appropriate capability is
  1739. // supported. The only exception to this rule is for mail slots for which the name is
  1740. // always transmitted as an ANSI string. Account for the null character as well in the
  1741. // transaction name length.
  1742. if (pOptions->pTransactionName != NULL) {
  1743. if (!fTransactionNameInUnicode) {
  1744. pTransactExchange->TransactionNameLength = RtlUnicodeStringToAnsiSize(pOptions->pTransactionName);
  1745. } else {
  1746. pTransactExchange->TransactionNameLength = pOptions->pTransactionName->Length + sizeof(WCHAR);
  1747. PrimaryRequestSmbSize += (ULONG)((PBYTE)ALIGN_SMB_WSTR(PrimaryRequestSmbSize)
  1748. - (PBYTE)(ULONG_PTR)PrimaryRequestSmbSize);
  1749. }
  1750. SmbCommand = SMB_COM_TRANSACTION;
  1751. } else {
  1752. // SMB protocol requires that a single NULL byte be sent as part of all
  1753. // TRANSACT2 transactions.
  1754. pTransactExchange->TransactionNameLength = 1;
  1755. SmbCommand = SMB_COM_TRANSACTION2;
  1756. }
  1757. PrimaryRequestSmbSize += pTransactExchange->TransactionNameLength;
  1758. } else {
  1759. PrimaryRequestSmbSize += sizeof(REQ_NT_TRANSACTION);
  1760. SmbCommand = SMB_COM_NT_TRANSACT;
  1761. pTransactExchange->TransactionNameLength = 0;
  1762. }
  1763. // The header, setup bytes and the name if specified must be part of the primary
  1764. // request SMB for a transaction to be successful. The secondary requests have no
  1765. // provision for sending setup/name.
  1766. if (PrimaryRequestSmbSize > MaxSmbBufferSize) {
  1767. RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: Primary request + setup exceeds maximum buffer size\n"));
  1768. return STATUS_INVALID_PARAMETER;
  1769. }
  1770. // Include the byte count size and then align the size to a DWORD boundary.
  1771. PrimaryRequestSmbSize = ROUND_UP_COUNT(PrimaryRequestSmbSize+sizeof(USHORT),sizeof(DWORD));
  1772. // Try to allocate for the param buffer as well if possible. The additional DWORD
  1773. // takes into account the worst case of alignment padding required.
  1774. //if ( (PrimaryRequestSmbSize + SendParamBufferSize + sizeof(DWORD)) > MaxSmbBufferSize)
  1775. if ((SendParamBufferSize!=0)
  1776. && (((PrimaryRequestSmbSize + SendParamBufferSize) > MaxSmbBufferSize)
  1777. || (DONTSUBSUME_PARAMS)) ){
  1778. // The param will spill over to a secondary request. Do not attempt to over
  1779. // allocate the primary request. if we can't subsume the params, then we'll need an MDL
  1780. // to partial from.
  1781. RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: cannot subsume params\n"));
  1782. pTransactExchange->fParamsSubsumedInPrimaryRequest = FALSE;
  1783. pSendParamMdl = RxAllocateMdl(pSendParamBuffer,SendParamBufferSize);
  1784. if (pSendParamMdl == NULL) {
  1785. Status = STATUS_INSUFFICIENT_RESOURCES;
  1786. } else {
  1787. RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: BIGPARAMMDL %08lx\n",pSendParamMdl));
  1788. RxProbeAndLockPages(pSendParamMdl,KernelMode,IoModifyAccess,Status);
  1789. if (Status != STATUS_SUCCESS) {
  1790. IoFreeMdl(pSendParamMdl);
  1791. } else {
  1792. if (MmGetSystemAddressForMdlSafe(pSendParamMdl,LowPagePriority) == NULL) { //map it
  1793. Status = STATUS_INSUFFICIENT_RESOURCES;
  1794. }
  1795. pSendParameters->pParamMdl = pSendParamMdl; // save it away
  1796. }
  1797. }
  1798. } else {
  1799. PrimaryRequestSmbSize = ROUND_UP_COUNT(PrimaryRequestSmbSize+SendParamBufferSize,sizeof(DWORD));
  1800. // Update the transact exchange to reflect the fact that no separate param MDL is
  1801. // required.
  1802. pTransactExchange->fParamsSubsumedInPrimaryRequest = TRUE;
  1803. }
  1804. pActualPrimaryRequestSmbHeader = (PSMB_HEADER)RxAllocatePoolWithTag(
  1805. PagedPool,
  1806. (PrimaryRequestSmbSize + 4 + TRANSPORT_HEADER_SIZE),
  1807. MRXSMB_XACT_POOLTAG); //up to 4 pad bytes
  1808. if (pActualPrimaryRequestSmbHeader == NULL) {
  1809. RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: Cannot allocate primary request SMB\n"));
  1810. Status = STATUS_INSUFFICIENT_RESOURCES;
  1811. }
  1812. else {
  1813. (PCHAR) pPrimaryRequestSmbHeader =
  1814. (PCHAR) pActualPrimaryRequestSmbHeader + TRANSPORT_HEADER_SIZE;
  1815. }
  1816. if (Status == STATUS_SUCCESS) {
  1817. switch (SmbCommand) {
  1818. case SMB_COM_TRANSACTION :
  1819. case SMB_COM_TRANSACTION2:
  1820. {
  1821. PREQ_TRANSACTION pTransactRequest;
  1822. pTransactRequest = (PREQ_TRANSACTION)(pPrimaryRequestSmbHeader + 1);
  1823. pTransactRequest->WordCount = (UCHAR)(14 + (SendSetupBufferSize/sizeof(USHORT)));
  1824. SmbPutUshort(
  1825. &pTransactRequest->TotalParameterCount,
  1826. (USHORT)SendParamBufferSize);
  1827. SmbPutUshort(
  1828. &pTransactRequest->TotalDataCount,
  1829. (USHORT)SendDataBufferSize);
  1830. SmbPutUshort(
  1831. &pTransactRequest->MaxParameterCount,
  1832. (USHORT)ReceiveParamBufferSize);
  1833. SmbPutUshort(
  1834. &pTransactRequest->MaxDataCount,
  1835. (USHORT)ReceiveDataBufferSize);
  1836. pTransactRequest->MaxSetupCount = (UCHAR)(ReceiveSetupBufferSize/sizeof(USHORT));
  1837. pTransactRequest->Reserved = 0;
  1838. pTransactRequest->Reserved3 = 0;
  1839. SmbPutUshort(&pTransactRequest->Reserved2, 0);
  1840. SmbPutUshort( &pTransactRequest->Flags, pOptions->Flags&~SMB_XACT_INTERNAL_FLAGS_MASK );
  1841. pTransactRequest->SetupCount = (UCHAR)(SendSetupBufferSize/sizeof(USHORT));
  1842. SmbPutUlong(&pTransactRequest->Timeout, pOptions->TimeoutIntervalInMilliSeconds);
  1843. pSetup = (PUSHORT)pTransactRequest->Buffer;
  1844. // Copy the transact name and align the buffer if required.
  1845. if (pOptions->pTransactionName != NULL) {
  1846. PBYTE pName;
  1847. ULONG TransactionNameLength = pTransactExchange->TransactionNameLength;
  1848. // Set the name field in the SMB.
  1849. pName = (PBYTE)pSetup +
  1850. SendSetupBufferSize +
  1851. sizeof(USHORT); // account for the bcc field
  1852. ASSERT(SmbCommand == SMB_COM_TRANSACTION);
  1853. RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: TransactionName(Length %ld) %ws\n",
  1854. TransactionNameLength,
  1855. pOptions->pTransactionName->Buffer));
  1856. if (fTransactionNameInUnicode) {
  1857. pName = ALIGN_SMB_WSTR(pName);
  1858. Status = SmbPutUnicodeString(&pName,
  1859. pOptions->pTransactionName,
  1860. &TransactionNameLength);
  1861. } else {
  1862. Status = SmbPutUnicodeStringAsOemString(&pName,
  1863. pOptions->pTransactionName,
  1864. &TransactionNameLength);
  1865. }
  1866. }
  1867. pParam = (PBYTE)pSetup +
  1868. SendSetupBufferSize +
  1869. sizeof(USHORT) + // the bcc field
  1870. pTransactExchange->TransactionNameLength;
  1871. pParam = ROUND_UP_POINTER(pParam, sizeof(DWORD));
  1872. }
  1873. break;
  1874. case SMB_COM_NT_TRANSACT:
  1875. {
  1876. PREQ_NT_TRANSACTION pNtTransactRequest;
  1877. pNtTransactRequest = (PREQ_NT_TRANSACTION)(pPrimaryRequestSmbHeader + 1);
  1878. pNtTransactRequest->WordCount = (UCHAR)(19 + (SendSetupBufferSize/sizeof(USHORT)));
  1879. SmbPutUlong( &pNtTransactRequest->TotalParameterCount, SendParamBufferSize);
  1880. SmbPutUlong( &pNtTransactRequest->TotalDataCount, SendDataBufferSize);
  1881. SmbPutUlong( &pNtTransactRequest->MaxParameterCount, ReceiveParamBufferSize);
  1882. SmbPutUlong( &pNtTransactRequest->MaxDataCount, ReceiveDataBufferSize);
  1883. RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: init for NT_T (p,d,mp,md) %d %d %d %d\n",
  1884. pNtTransactRequest->TotalParameterCount, pNtTransactRequest->TotalDataCount,
  1885. pNtTransactRequest->MaxParameterCount, pNtTransactRequest->MaxDataCount));
  1886. pNtTransactRequest->MaxSetupCount = (UCHAR)(ReceiveSetupBufferSize / sizeof(USHORT));
  1887. SmbPutUshort( &pNtTransactRequest->Flags, pOptions->Flags&~SMB_XACT_INTERNAL_FLAGS_MASK );
  1888. SmbPutUshort( &pNtTransactRequest->Function, pOptions->NtTransactFunction );
  1889. pNtTransactRequest->SetupCount = (UCHAR)(SendSetupBufferSize/sizeof(USHORT));
  1890. pSetup = (PUSHORT)pNtTransactRequest->Buffer;
  1891. pParam = (PBYTE)pSetup +
  1892. SendSetupBufferSize +
  1893. sizeof(USHORT); // the bcc field
  1894. pParam = ROUND_UP_POINTER(pParam, sizeof(DWORD));
  1895. }
  1896. break;
  1897. default:
  1898. ASSERT(!"Valid Smb Command Type for Transact exchange");
  1899. Status = STATUS_INVALID_PARAMETER;
  1900. }
  1901. }
  1902. if (Status == STATUS_SUCCESS) {
  1903. // All related initialization of a transaction exchange has been
  1904. // completed. At this point the transact exchange assumes ownership
  1905. // of the various buffers ( specified as MDLs ) in the receive and
  1906. // send parameters. It will get rid of them during finalization
  1907. // of the exchange. In order to ensure that the caller does not
  1908. // attempt to free any of these buffers they are reset in the
  1909. // receive/send parameters.
  1910. // Copy the setup data
  1911. RtlCopyMemory(pSetup,pSendSetupBuffer,SendSetupBufferSize);
  1912. if (pTransactExchange->fParamsSubsumedInPrimaryRequest) {
  1913. RxDbgTrace( 0, Dbg, ("SmbTransactExchangeInitialize: subsuming where/size=%08lx/%08lx\n"
  1914. ,pSendParamBuffer,SendParamBufferSize));
  1915. RtlCopyMemory(pParam,pSendParamBuffer,SendParamBufferSize);
  1916. }
  1917. // Initialize the transact exchange.
  1918. pTransactExchange->Status = STATUS_MORE_PROCESSING_REQUIRED;
  1919. pTransactExchange->Mid = 0;
  1920. pTransactExchange->SmbCommand = SmbCommand;
  1921. pTransactExchange->pActualPrimaryRequestSmbHeader = pActualPrimaryRequestSmbHeader;
  1922. pTransactExchange->pPrimaryRequestSmbHeader = pPrimaryRequestSmbHeader;
  1923. pTransactExchange->PrimaryRequestSmbSize = PrimaryRequestSmbSize;
  1924. pTransactExchange->pSendDataMdl = pSendDataMdl;
  1925. pTransactExchange->SendDataBufferSize = SendDataBufferSize;
  1926. pTransactExchange->pReceiveDataMdl = pReceiveDataMdl;
  1927. pTransactExchange->ReceiveDataBufferSize = ReceiveDataBufferSize;
  1928. pTransactExchange->DataBytesSent = 0;
  1929. pTransactExchange->DataBytesReceived = 0;
  1930. pTransactExchange->pSendParamBuffer = pSendParamBuffer;
  1931. pTransactExchange->SendParamBufferSize = SendParamBufferSize;
  1932. pTransactExchange->pSendParamMdl = pSendParamMdl;
  1933. pTransactExchange->pReceiveParamMdl = pReceiveParamMdl;
  1934. pTransactExchange->ReceiveParamBufferSize = ReceiveParamBufferSize;
  1935. pTransactExchange->ParamBytesSent = 0;
  1936. pTransactExchange->ParamBytesReceived = 0;
  1937. pTransactExchange->pReceiveSetupMdl = pReceiveSetupMdl;
  1938. pTransactExchange->ReceiveSetupBufferSize = ReceiveSetupBufferSize;
  1939. pTransactExchange->SetupBytesReceived = 0;
  1940. pTransactExchange->NtTransactFunction = pOptions->NtTransactFunction;
  1941. pTransactExchange->Flags = pOptions->Flags;
  1942. if ((capFobx != NULL) &&
  1943. BooleanFlagOn(capFobx->Flags,FOBX_FLAG_DFS_OPEN)) {
  1944. pTransactExchange->Flags |= SMB_XACT_FLAGS_DFS_AWARE;
  1945. } else if (RxContext->MajorFunction == IRP_MJ_CREATE) {
  1946. PMRX_NET_ROOT pNetRoot = RxContext->pFcb->pNetRoot;
  1947. if (FlagOn(pNetRoot->Flags,NETROOT_FLAG_DFS_AWARE_NETROOT) &&
  1948. RxContext->Create.NtCreateParameters.DfsContext == UIntToPtr(DFS_OPEN_CONTEXT)) {
  1949. pTransactExchange->Flags |= SMB_XACT_FLAGS_DFS_AWARE;
  1950. }
  1951. }
  1952. pTransactExchange->pResumptionContext = pResumptionContext;
  1953. // Reset the Send and Receive parameter data structures to transfer
  1954. // the ownership of the MDLs to the exchange.
  1955. if (pSendParameters->Flags & SMB_XACT_FLAGS_CALLERS_SENDDATAMDL) {
  1956. pTransactExchange->Flags |= SMB_XACT_FLAGS_CALLERS_SENDDATAMDL;
  1957. }
  1958. RtlZeroMemory(
  1959. pSendParameters,
  1960. sizeof(SMB_TRANSACTION_SEND_PARAMETERS));
  1961. RtlZeroMemory(
  1962. pReceiveParameters,
  1963. sizeof(SMB_TRANSACTION_RECEIVE_PARAMETERS));
  1964. }
  1965. if (Status != STATUS_SUCCESS) {
  1966. // Clean up the memory allocated in an effort to initialize the transact exchange
  1967. if (pActualPrimaryRequestSmbHeader) {
  1968. RxFreePool(pActualPrimaryRequestSmbHeader);
  1969. }
  1970. } else {
  1971. PMRXSMB_RX_CONTEXT pMRxSmbContext = MRxSmbGetMinirdrContext(RxContext);
  1972. pMRxSmbContext->pExchange = (PSMB_EXCHANGE)pTransactExchange;
  1973. pTransactExchange->SmbCeFlags &= ~SMBCE_EXCHANGE_ATTEMPT_RECONNECTS;
  1974. if (pOptions->Flags & SMB_XACT_FLAGS_INDEFINITE_DELAY_IN_RESPONSE ) {
  1975. pTransactExchange->SmbCeFlags |= SMBCE_EXCHANGE_INDEFINITE_DELAY_IN_RESPONSE;
  1976. }
  1977. }
  1978. return Status;
  1979. }
  1980. NTSTATUS
  1981. SmbTransactExchangeFinalize(
  1982. PSMB_EXCHANGE pExchange,
  1983. BOOLEAN *pPostFinalize)
  1984. /*++
  1985. Routine Description:
  1986. This routine finalizes the transact exchange. It resumes the RDBSS by invoking
  1987. the call back and discards the exchange
  1988. Arguments:
  1989. pExchange - the exchange instance
  1990. CurrentIrql - the interrupt request level
  1991. pPostFinalize - set to TRUE if the request is to be posted
  1992. Return Value:
  1993. RXSTATUS - The return status for the operation
  1994. --*/
  1995. {
  1996. PSMB_TRANSACT_EXCHANGE pTransactExchange;
  1997. PSMB_TRANSACTION_RESUMPTION_CONTEXT pResumptionContext;
  1998. LONG References;
  1999. ASSERT(pExchange->Type == TRANSACT_EXCHANGE);
  2000. pTransactExchange = (PSMB_TRANSACT_EXCHANGE)pExchange;
  2001. RxLog((">>>XE %lx",pTransactExchange));
  2002. if ((pTransactExchange->ReceiveParamBufferSize > 0) &&
  2003. (pTransactExchange->ReceiveParamBufferSize !=
  2004. pTransactExchange->ParamBytesReceived)) {
  2005. RxDbgTrace(0, Dbg,
  2006. ("SmbCeTransactExchangeFinalize: Param Bytes Receive error ... expected(%ld) received(%ld)\n",
  2007. pTransactExchange->ReceiveParamBufferSize, pTransactExchange->ParamBytesReceived
  2008. ));
  2009. }
  2010. if ((pTransactExchange->ReceiveDataBufferSize > 0) &&
  2011. (pTransactExchange->ReceiveDataBufferSize !=
  2012. pTransactExchange->DataBytesReceived)) {
  2013. RxDbgTrace(0, Dbg,
  2014. ("SmbCeTransactExchangeFinalize: Data Bytes Receive error ... expected(%ld) received(%ld)\n",
  2015. pTransactExchange->ReceiveDataBufferSize, pTransactExchange->DataBytesReceived
  2016. ));
  2017. }
  2018. if (RxShouldPostCompletion()) {
  2019. RxPostToWorkerThread(
  2020. MRxSmbDeviceObject,
  2021. CriticalWorkQueue,
  2022. &pExchange->WorkQueueItem,
  2023. SmbCeDiscardTransactExchange,
  2024. pTransactExchange);
  2025. } else {
  2026. SmbCeDiscardTransactExchange(pTransactExchange);
  2027. }
  2028. return STATUS_SUCCESS;
  2029. UNREFERENCED_PARAMETER(pPostFinalize);
  2030. }
  2031. NTSTATUS
  2032. SmbTransactAccrueAndValidateFormatData(
  2033. IN struct _SMB_TRANSACT_EXCHANGE *pTransactExchange, // The exchange instance
  2034. IN PSMB_HEADER pSmbHeader,
  2035. IN ULONG BytesIndicated,
  2036. OUT PSMB_TRANSACT_RESP_FORMAT_DESCRIPTION Format
  2037. )
  2038. /*++
  2039. Routine Description:
  2040. This is the recieve indication handling routine for net root construction exchanges
  2041. Arguments:
  2042. Return Value:
  2043. RXSTATUS - The return status for the operation
  2044. STATUS_SUCCESS -- all the data was indicated and it was valid
  2045. STATUS_INVALID_NETWORK_RESPONSE -- something about the format parameters is untoward.
  2046. Notes:
  2047. This routine is called at DPC level.
  2048. --*/
  2049. {
  2050. NTSTATUS Status = STATUS_SUCCESS;
  2051. PRESP_TRANSACTION pTransactResponse = (PRESP_TRANSACTION)(pSmbHeader+1);
  2052. PBYTE WordCountPtr;
  2053. UCHAR WordCount;
  2054. PBYTE ByteCountPtr;
  2055. USHORT ByteCount;
  2056. RtlZeroMemory(Format,sizeof(*Format));
  2057. Format->WordCount = WordCount = pTransactResponse->WordCount;
  2058. ByteCountPtr = (&pTransactResponse->WordCount)+1+(sizeof(USHORT)*WordCount);
  2059. if (((ULONG)(ByteCountPtr+sizeof(USHORT)-((PBYTE)pSmbHeader)))>BytesIndicated) {
  2060. ByteCount = SmbGetUshort(ByteCountPtr);
  2061. DbgPrint("ExtraTransactBytes wc,bcp,bc,smbh %lx,%lx,%lx,%lx\n",
  2062. WordCount,ByteCountPtr,ByteCount,pSmbHeader);
  2063. return STATUS_INVALID_NETWORK_RESPONSE;
  2064. }
  2065. Format->ByteCount = ByteCount = SmbGetUshort(ByteCountPtr);
  2066. Format->ApparentMsgLength = (ULONG)((ByteCountPtr+sizeof(USHORT)-((PBYTE)pSmbHeader))+ByteCount);
  2067. if (WordCount==0) {
  2068. return(STATUS_SUCCESS);
  2069. }
  2070. switch (pSmbHeader->Command) {
  2071. case SMB_COM_TRANSACTION2:
  2072. case SMB_COM_TRANSACTION:
  2073. case SMB_COM_TRANSACTION_SECONDARY:
  2074. case SMB_COM_TRANSACTION2_SECONDARY:
  2075. {
  2076. Format->TotalParameterCount = SmbGetUshort(&pTransactResponse->TotalParameterCount);
  2077. Format->TotalDataCount = SmbGetUshort(&pTransactResponse->TotalDataCount);
  2078. Format->ParameterCount = SmbGetUshort(&pTransactResponse->ParameterCount);
  2079. Format->ParameterOffset = SmbGetUshort(&pTransactResponse->ParameterOffset);
  2080. Format->ParameterDisplacement = SmbGetUshort(&pTransactResponse->ParameterDisplacement);
  2081. Format->DataCount = SmbGetUshort(&pTransactResponse->DataCount);
  2082. Format->DataOffset = SmbGetUshort(&pTransactResponse->DataOffset);
  2083. Format->DataDisplacement = SmbGetUshort(&pTransactResponse->DataDisplacement);
  2084. }
  2085. break;
  2086. case SMB_COM_NT_TRANSACT:
  2087. case SMB_COM_NT_TRANSACT_SECONDARY:
  2088. {
  2089. PRESP_NT_TRANSACTION pNtTransactResponse;
  2090. pNtTransactResponse = (PRESP_NT_TRANSACTION)(pTransactResponse);
  2091. Format->TotalParameterCount = SmbGetUlong(&pNtTransactResponse->TotalParameterCount);
  2092. Format->TotalDataCount = SmbGetUlong(&pNtTransactResponse->TotalDataCount);
  2093. Format->ParameterCount = SmbGetUlong(&pNtTransactResponse->ParameterCount);
  2094. Format->ParameterOffset = SmbGetUlong(&pNtTransactResponse->ParameterOffset);
  2095. Format->ParameterDisplacement = SmbGetUlong(&pNtTransactResponse->ParameterDisplacement);
  2096. Format->DataCount = SmbGetUlong(&pNtTransactResponse->DataCount);
  2097. Format->DataOffset = SmbGetUlong(&pNtTransactResponse->DataOffset);
  2098. Format->DataDisplacement = SmbGetUlong(&pNtTransactResponse->DataDisplacement);
  2099. }
  2100. break;
  2101. default:
  2102. // Bug Check
  2103. return STATUS_INVALID_NETWORK_RESPONSE;
  2104. }
  2105. //do this here so we can use it as validation criterion
  2106. pTransactExchange->ParameterBytesSeen += Format->ParameterCount;
  2107. pTransactExchange->DataBytesSeen += Format->DataCount;
  2108. return Status;
  2109. }
  2110. NTSTATUS
  2111. ParseTransactResponse(
  2112. IN struct _SMB_TRANSACT_EXCHANGE *pTransactExchange, // The exchange instance
  2113. IN PSMB_TRANSACT_RESP_FORMAT_DESCRIPTION Format,
  2114. IN ULONG BytesIndicated,
  2115. IN ULONG BytesAvailable,
  2116. OUT ULONG *pBytesTaken,
  2117. IN PSMB_HEADER pSmbHeader,
  2118. OUT PMDL *pCopyRequestMdlPointer,
  2119. OUT PULONG pCopyRequestSize)
  2120. /*++
  2121. Routine Description:
  2122. This is the recieve indication handling routine for net root construction exchanges
  2123. Arguments:
  2124. pTransactExchange - the exchange instance
  2125. BytesIndicated - the number of bytes indicated
  2126. Bytes Available - the number of bytes available
  2127. pBytesTaken - the number of bytes consumed
  2128. pSmbHeader - the byte buffer
  2129. pCopyRequestMdlPointer - the buffer into which the remaining data is to be copied.
  2130. pCopyRequestSize - the buffer size.
  2131. Return Value:
  2132. RXSTATUS - The return status for the operation
  2133. STATUS_MORE_PROCESSING_REQUIRED -- if a copy of the data needs to be done before
  2134. processing can be completed. This occurs because all the data was not indicated
  2135. STATUS_SUCCESS -- all the data was indicated and it was valid
  2136. STATUS_* -- They indicate an error which would normally leads to the abortion of the
  2137. exchange.
  2138. Notes:
  2139. This routine is called at DPC level.
  2140. --*/
  2141. {
  2142. NTSTATUS Status = STATUS_SUCCESS;
  2143. ULONG ParamBytesInResponse = 0;
  2144. ULONG ParamOffsetInResponse = 0;
  2145. ULONG DataBytesInResponse = 0;
  2146. ULONG DataOffsetInResponse = 0;
  2147. ULONG PaddingLength = 0;
  2148. PMDL pFirstMdlInCopyDataRequestChain = NULL;
  2149. PMDL pLastMdlInCopyDataRequestChain = NULL;
  2150. PMDL pParamMdl = NULL;
  2151. PMDL pPaddingMdl = NULL;
  2152. PMDL pDataMdl = NULL;
  2153. PBYTE pParamStartAddress;
  2154. PBYTE pDataStartAddress;
  2155. PBYTE pSmbBuffer = (PBYTE)pSmbHeader;
  2156. switch (pSmbHeader->Command) {
  2157. case SMB_COM_TRANSACTION2:
  2158. case SMB_COM_TRANSACTION:
  2159. case SMB_COM_TRANSACTION_SECONDARY:
  2160. case SMB_COM_TRANSACTION2_SECONDARY:
  2161. {
  2162. PRESP_TRANSACTION pTransactResponse;
  2163. pTransactResponse = (PRESP_TRANSACTION)(pSmbBuffer + *pBytesTaken);
  2164. *pBytesTaken = *pBytesTaken + sizeof(RESP_TRANSACTION);
  2165. }
  2166. break;
  2167. case SMB_COM_NT_TRANSACT:
  2168. case SMB_COM_NT_TRANSACT_SECONDARY:
  2169. {
  2170. PRESP_NT_TRANSACTION pNtTransactResponse;
  2171. pNtTransactResponse = (PRESP_NT_TRANSACTION)(pSmbBuffer + *pBytesTaken);
  2172. *pBytesTaken = *pBytesTaken + sizeof(RESP_NT_TRANSACTION);
  2173. }
  2174. break;
  2175. default:
  2176. // Bug Check
  2177. ASSERT(!"Valid SMB command in Transaction response");
  2178. return STATUS_INVALID_NETWORK_RESPONSE;
  2179. }
  2180. ParamBytesInResponse = Format->ParameterCount;
  2181. ParamOffsetInResponse = Format->ParameterOffset;
  2182. DataBytesInResponse = Format->DataCount;
  2183. DataOffsetInResponse = Format->DataOffset;
  2184. if (ParamBytesInResponse > 0) {
  2185. ASSERT(pTransactExchange->pReceiveParamMdl != NULL);
  2186. pParamStartAddress = (PBYTE)MmGetSystemAddressForMdlSafe(pTransactExchange->pReceiveParamMdl,LowPagePriority);
  2187. if (pParamStartAddress == NULL) {
  2188. Status = STATUS_INSUFFICIENT_RESOURCES;
  2189. } else {
  2190. pParamStartAddress += Format->ParameterDisplacement;
  2191. }
  2192. } else {
  2193. pParamStartAddress = NULL;
  2194. }
  2195. if (DataBytesInResponse > 0) {
  2196. ASSERT(pTransactExchange->pReceiveDataMdl != NULL);
  2197. pDataStartAddress = (PBYTE)MmGetSystemAddressForMdlSafe(pTransactExchange->pReceiveDataMdl,LowPagePriority);
  2198. if (pDataStartAddress == NULL) {
  2199. Status = STATUS_INSUFFICIENT_RESOURCES;
  2200. } else {
  2201. pDataStartAddress += Format->DataDisplacement;
  2202. }
  2203. } else {
  2204. pDataStartAddress = NULL;
  2205. }
  2206. RxDbgTrace( 0, Dbg, ("ParseTransactResponse: Param Bytes(%ld) Param Offset (%ld) Data Bytes (%ld) Data Offset(%ld)\n",
  2207. ParamBytesInResponse,
  2208. ParamOffsetInResponse,
  2209. DataBytesInResponse,
  2210. DataOffsetInResponse));
  2211. // If either the param bytes or the data bytes have already been indicated, copy
  2212. // them into the respective buffers and trim the size of the MDL for the copy
  2213. // data request.
  2214. if (ParamOffsetInResponse <= BytesIndicated && Status == STATUS_SUCCESS) {
  2215. *pBytesTaken = ParamOffsetInResponse;
  2216. if (ParamBytesInResponse > 0) {
  2217. ULONG ParamBytesIndicated = MIN(
  2218. ParamBytesInResponse,
  2219. BytesIndicated - ParamOffsetInResponse);
  2220. RxDbgTrace( 0, Dbg, ("ParseTransactResponse: Param Bytes indicated %ld\n",ParamBytesIndicated));
  2221. RtlCopyMemory(
  2222. pParamStartAddress,
  2223. (pSmbBuffer + ParamOffsetInResponse),
  2224. ParamBytesIndicated);
  2225. *pBytesTaken = *pBytesTaken + ParamBytesIndicated;
  2226. pParamStartAddress += ParamBytesIndicated;
  2227. ParamBytesInResponse -= ParamBytesIndicated;
  2228. ParamOffsetInResponse += ParamBytesIndicated;
  2229. pTransactExchange->ParamBytesReceived += ParamBytesIndicated;
  2230. }
  2231. }
  2232. if (DataOffsetInResponse <= BytesIndicated && Status == STATUS_SUCCESS) {
  2233. *pBytesTaken = DataOffsetInResponse; //you have to move up EVEN IF NO BYTES!!!!!
  2234. if (DataBytesInResponse > 0) {
  2235. ULONG DataBytesIndicated = MIN(
  2236. DataBytesInResponse,
  2237. BytesIndicated - DataOffsetInResponse);
  2238. RxDbgTrace( 0, Dbg, ("ParseTransactResponse: Data Bytes indicated %ld\n",DataBytesIndicated));
  2239. RtlCopyMemory(
  2240. pDataStartAddress,
  2241. (pSmbBuffer + DataOffsetInResponse),
  2242. DataBytesIndicated);
  2243. *pBytesTaken = *pBytesTaken + DataBytesIndicated;
  2244. pDataStartAddress += DataBytesIndicated;
  2245. DataBytesInResponse -= DataBytesIndicated;
  2246. DataOffsetInResponse += DataBytesIndicated;
  2247. pTransactExchange->DataBytesReceived += DataBytesIndicated;
  2248. }
  2249. }
  2250. RxDbgTrace( 0, Dbg, ("ParseTransactResponse: Made it past the copies......... \n"));
  2251. if (ParamBytesInResponse > 0 && Status == STATUS_SUCCESS) {
  2252. // There are more param bytes that have not been indicated. Set up an MDL
  2253. // to copy them over.
  2254. RxDbgTrace( 0, Dbg, ("ParseTransactResponse: Posting Copy request for Param Bytes %ld\n",ParamBytesInResponse));
  2255. pParamMdl = RxAllocateMdl(
  2256. ((PBYTE)MmGetMdlVirtualAddress(pTransactExchange->pReceiveParamMdl)
  2257. + pTransactExchange->ParamBytesReceived),
  2258. ParamBytesInResponse);
  2259. if (pParamMdl != NULL) {
  2260. IoBuildPartialMdl(
  2261. pTransactExchange->pReceiveParamMdl,
  2262. pParamMdl,
  2263. ((PBYTE)MmGetMdlVirtualAddress(pTransactExchange->pReceiveParamMdl)
  2264. + pTransactExchange->ParamBytesReceived),
  2265. ParamBytesInResponse);
  2266. pFirstMdlInCopyDataRequestChain = pParamMdl;
  2267. pLastMdlInCopyDataRequestChain = pParamMdl;
  2268. } else {
  2269. Status = STATUS_INSUFFICIENT_RESOURCES;
  2270. }
  2271. pTransactExchange->ParamBytesReceived += ParamBytesInResponse;
  2272. }
  2273. if ((Status == STATUS_SUCCESS) &&
  2274. (DataBytesInResponse > 0)) {
  2275. RxDbgTrace( 0, Dbg, ("ParseTransactResponse: Posting Copy request for Data Bytes %ld\n",DataBytesInResponse));
  2276. // In certain cases a padding MDL needs to be inserted between the param and data portions
  2277. // of the response to consume the padding bytes sent by the server.
  2278. if ((ParamBytesInResponse > 0) &&
  2279. ((PaddingLength = DataOffsetInResponse -
  2280. (ParamBytesInResponse + ParamOffsetInResponse)) > 0)) {
  2281. RxDbgTrace( 0, Dbg, ("ParseTransactResponse: Posting Copy request for padding bytes %ld\n",PaddingLength));
  2282. // There are some padding bytes present. Construct an MDL to consume them
  2283. //pPaddingMdl = RxAllocateMdl(&MRxSmb_pPaddingData,PaddingLength);
  2284. ASSERT(!"this doesn't work");
  2285. if (pPaddingMdl != NULL) {
  2286. if (pLastMdlInCopyDataRequestChain != NULL) {
  2287. pLastMdlInCopyDataRequestChain->Next = pPaddingMdl;
  2288. } else {
  2289. pFirstMdlInCopyDataRequestChain = pPaddingMdl;
  2290. }
  2291. pLastMdlInCopyDataRequestChain = pPaddingMdl;
  2292. } else {
  2293. Status = STATUS_INSUFFICIENT_RESOURCES;
  2294. }
  2295. }
  2296. // There are more data bytes which have not been indicated. Set up an MDL
  2297. // to copy them over.
  2298. if (Status == STATUS_SUCCESS) {
  2299. if (pTransactExchange->pReceiveDataMdl->ByteCount >= DataBytesInResponse) {
  2300. pDataMdl = RxAllocateMdl(
  2301. ((PBYTE)MmGetMdlVirtualAddress(pTransactExchange->pReceiveDataMdl)
  2302. + pTransactExchange->DataBytesReceived),
  2303. DataBytesInResponse);
  2304. if (pDataMdl != NULL) {
  2305. IoBuildPartialMdl(
  2306. pTransactExchange->pReceiveDataMdl,
  2307. pDataMdl,
  2308. ((PBYTE)MmGetMdlVirtualAddress(pTransactExchange->pReceiveDataMdl)
  2309. + pTransactExchange->DataBytesReceived),
  2310. DataBytesInResponse);
  2311. if (pLastMdlInCopyDataRequestChain != NULL) {
  2312. pLastMdlInCopyDataRequestChain->Next = pDataMdl;
  2313. } else {
  2314. pFirstMdlInCopyDataRequestChain = pDataMdl;
  2315. }
  2316. pLastMdlInCopyDataRequestChain = pDataMdl;
  2317. pTransactExchange->DataBytesReceived += DataBytesInResponse;
  2318. } else {
  2319. Status = STATUS_INSUFFICIENT_RESOURCES;
  2320. }
  2321. } else {
  2322. Status = STATUS_INVALID_NETWORK_RESPONSE;
  2323. }
  2324. }
  2325. }
  2326. if (Status != STATUS_SUCCESS) {
  2327. if (pDataMdl != NULL) {
  2328. IoFreeMdl(pDataMdl);
  2329. }
  2330. if (pPaddingMdl != NULL) {
  2331. IoFreeMdl(pPaddingMdl);
  2332. }
  2333. if (pParamMdl != NULL) {
  2334. IoFreeMdl(pParamMdl);
  2335. }
  2336. } else {
  2337. if (pFirstMdlInCopyDataRequestChain != NULL) {
  2338. ULONG MdlLength = ParamBytesInResponse+PaddingLength+DataBytesInResponse;
  2339. *pCopyRequestMdlPointer = pFirstMdlInCopyDataRequestChain;
  2340. *pCopyRequestSize = MdlLength;
  2341. RxDbgTrace( 0, Dbg, ("ParseTransactResponse: final mdl and copy size %08lx %08lx(%ld)\n",
  2342. pFirstMdlInCopyDataRequestChain,MdlLength,MdlLength));
  2343. IF_DEBUG {
  2344. PMDL imdl = pFirstMdlInCopyDataRequestChain;
  2345. ULONG mdllength = MdlLength;
  2346. mdllength -= MmGetMdlByteCount(imdl);
  2347. for (;;) {
  2348. if (!(imdl=imdl->Next)) break;
  2349. mdllength -= MmGetMdlByteCount(imdl);
  2350. }
  2351. ASSERT(mdllength==0);
  2352. }
  2353. InterlockedIncrement(&pTransactExchange->PendingCopyRequests);
  2354. Status = STATUS_MORE_PROCESSING_REQUIRED;
  2355. }
  2356. if ((pTransactExchange->ParamBytesReceived < pTransactExchange->ReceiveParamBufferSize) ||
  2357. (pTransactExchange->DataBytesReceived < pTransactExchange->ReceiveDataBufferSize)) {
  2358. NTSTATUS ReceiveStatus;
  2359. // The exchange has been successfully completed. Finalize it.
  2360. RxDbgTrace(0,Dbg,("ParseTransactResponse: Register for more responses\n"));
  2361. ReceiveStatus = SmbCeReceive((PSMB_EXCHANGE)pTransactExchange);
  2362. if (ReceiveStatus != STATUS_SUCCESS) {
  2363. // There was an error in registering the receive. Abandon the
  2364. // transaction.
  2365. Status = ReceiveStatus;
  2366. }
  2367. }
  2368. }
  2369. return Status;
  2370. UNREFERENCED_PARAMETER(BytesAvailable);
  2371. }
  2372. #if DBG
  2373. ULONG SmbSendBadSecondary = 0;
  2374. #endif
  2375. NTSTATUS
  2376. SendSecondaryRequests(PVOID pContext)
  2377. /*++
  2378. Routine Description:
  2379. This routine sends all the secondary requests associated with the transaction
  2380. Arguments:
  2381. pTransactExchange - the exchange instance
  2382. Return Value:
  2383. RXSTATUS - The return status for the operation
  2384. Notes:
  2385. --*/
  2386. {
  2387. PSMB_EXCHANGE pExchange = (PSMB_EXCHANGE)pContext;
  2388. PSMB_TRANSACT_EXCHANGE pTransactExchange = (PSMB_TRANSACT_EXCHANGE)pExchange;
  2389. NTSTATUS Status = STATUS_SUCCESS;
  2390. ULONG MaximumSmbBufferSize;
  2391. // The MDL's used in sending the primary request associated with the TRANSACT SMB
  2392. PMDL pPartialDataMdl = NULL;
  2393. PMDL pPartialParamMdl = NULL;
  2394. PMDL pPaddingMdl = NULL;
  2395. PMDL pSecondaryRequestSmbMdl = NULL;
  2396. PMDL pLastMdlInChain = NULL;
  2397. ULONG SecondaryRequestSmbSize = 0;
  2398. ULONG SmbLength;
  2399. ULONG PaddingLength;
  2400. ULONG ParamOffset,ParamDisplacement;
  2401. ULONG DataOffset,DataDisplacement;
  2402. ULONG ByteCountOffset;
  2403. USHORT ByteCount;
  2404. PUSHORT pByteCount;
  2405. ULONG ParamBytesToBeSent; // Param bytes to be sent per request
  2406. ULONG DataBytesToBeSent; // data bytes to be sent per request
  2407. ULONG SendParamBufferSize; // Total param bytes to be sent in secondary requests
  2408. ULONG SendDataBufferSize; // Total data bytes to be sent in secondary requests
  2409. PBYTE pSendParamStartAddress = NULL;
  2410. PBYTE pSendDataStartAddress = NULL;
  2411. PBYTE pOriginalParamBuffer = NULL;
  2412. PBYTE pOriginalDataBuffer = NULL;
  2413. ULONG TotalParamBytes,TotalDataBytes;
  2414. BOOLEAN ParamPartialMdlAlreadyUsed = FALSE;
  2415. BOOLEAN DataPartialMdlAlreadyUsed = FALSE;
  2416. PVOID pActualSecondaryRequestSmbHeader = NULL;
  2417. PSMB_HEADER pSecondaryRequestSmbHeader = NULL;
  2418. PAGED_CODE();
  2419. ASSERT(pTransactExchange->State == TRANSACT_EXCHANGE_RECEIVED_INTERIM_RESPONSE);
  2420. TotalParamBytes = pTransactExchange->SendParamBufferSize;
  2421. SendParamBufferSize = TotalParamBytes - pTransactExchange->ParamBytesSent;
  2422. TotalDataBytes = pTransactExchange->SendDataBufferSize;
  2423. SendDataBufferSize = TotalDataBytes - pTransactExchange->DataBytesSent;
  2424. ASSERT((SendParamBufferSize > 0) || (SendDataBufferSize > 0));
  2425. switch (pTransactExchange->SmbCommand) {
  2426. case SMB_COM_TRANSACTION:
  2427. SecondaryRequestSmbSize = sizeof(SMB_HEADER) +
  2428. FIELD_OFFSET(REQ_TRANSACTION_SECONDARY,Buffer);
  2429. break;
  2430. case SMB_COM_TRANSACTION2:
  2431. SecondaryRequestSmbSize = sizeof(SMB_HEADER) +
  2432. FIELD_OFFSET(REQ_TRANSACTION_SECONDARY,Buffer)
  2433. + sizeof(USHORT); //add in the extra word
  2434. break;
  2435. case SMB_COM_NT_TRANSACT:
  2436. SecondaryRequestSmbSize = sizeof(SMB_HEADER) +
  2437. FIELD_OFFSET(REQ_NT_TRANSACTION_SECONDARY,Buffer);
  2438. break;
  2439. default:
  2440. ASSERT(!"Valid Smb Command in transaction exchange");
  2441. Status = STATUS_TRANSACTION_ABORTED;
  2442. }
  2443. SecondaryRequestSmbSize = QuadAlign(SecondaryRequestSmbSize); //pad to quadword boundary
  2444. pActualSecondaryRequestSmbHeader = (PSMB_HEADER)
  2445. RxAllocatePoolWithTag(
  2446. NonPagedPool,
  2447. SecondaryRequestSmbSize + TRANSPORT_HEADER_SIZE,
  2448. MRXSMB_XACT_POOLTAG);
  2449. if ((Status == STATUS_SUCCESS) && pActualSecondaryRequestSmbHeader != NULL) {
  2450. (PCHAR) pSecondaryRequestSmbHeader =
  2451. (PCHAR) pActualSecondaryRequestSmbHeader + TRANSPORT_HEADER_SIZE;
  2452. // Initialize the SMB header ...
  2453. ASSERT(
  2454. ((SMB_COM_TRANSACTION+1) == SMB_COM_TRANSACTION_SECONDARY)
  2455. &&((SMB_COM_TRANSACTION2+1)== SMB_COM_TRANSACTION2_SECONDARY)
  2456. &&((SMB_COM_NT_TRANSACT+1) == SMB_COM_NT_TRANSACT_SECONDARY)
  2457. );
  2458. Status = SmbTransactBuildHeader(
  2459. pTransactExchange, // the exchange instance
  2460. (UCHAR)(pTransactExchange->SmbCommand+1), // the SMB command ..see the asserts above
  2461. pSecondaryRequestSmbHeader); // the SMB buffer
  2462. RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: SmbCeBuildSmbHeader returned %lx\n",Status));
  2463. } else {
  2464. Status = STATUS_INSUFFICIENT_RESOURCES;
  2465. }
  2466. if (Status == STATUS_SUCCESS) {
  2467. MaximumSmbBufferSize = pTransactExchange->MaximumTransmitSmbBufferSize;
  2468. // Ensure that the MDL's have been probed & locked. The new MDL's have been allocated.
  2469. // The partial MDL's are allocated to be large enough to span the maximum buffer
  2470. // length possible.
  2471. // Initialize the data related MDL's for the secondary request
  2472. if (SendDataBufferSize > 0) {
  2473. RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: Data Bytes remaining %ld\n",SendDataBufferSize));
  2474. pOriginalDataBuffer = (PBYTE)MmGetMdlVirtualAddress(pTransactExchange->pSendDataMdl);
  2475. pSendDataStartAddress = pOriginalDataBuffer + pTransactExchange->DataBytesSent;
  2476. pPartialDataMdl = RxAllocateMdl(
  2477. 0,
  2478. (MIN(pTransactExchange->SendDataBufferSize,
  2479. MaximumSmbBufferSize) +
  2480. PAGE_SIZE - 1));
  2481. if (pPartialDataMdl == NULL) {
  2482. Status = STATUS_INSUFFICIENT_RESOURCES;
  2483. }
  2484. }
  2485. // Initialize the parameter related MDL's for the secondary request
  2486. if ((SendParamBufferSize > 0) && (Status == STATUS_SUCCESS)) {
  2487. RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: Param Bytes remaining %ld\n",SendParamBufferSize));
  2488. pOriginalParamBuffer = (PBYTE)MmGetMdlVirtualAddress(pTransactExchange->pSendParamMdl);
  2489. pSendParamStartAddress = pOriginalParamBuffer + pTransactExchange->ParamBytesSent;
  2490. pPartialParamMdl = RxAllocateMdl(
  2491. 0,
  2492. (MIN(pTransactExchange->SendParamBufferSize,
  2493. MaximumSmbBufferSize) +
  2494. PAGE_SIZE - 1));
  2495. pPaddingMdl = RxAllocateMdl(0,(sizeof(DWORD) + PAGE_SIZE - 1));
  2496. if ((pPartialParamMdl == NULL) ||
  2497. (pPaddingMdl == NULL)) {
  2498. RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: Error allocating param MDLS\n"));
  2499. Status = STATUS_INSUFFICIENT_RESOURCES;
  2500. }
  2501. }
  2502. // Initialize the secondary request SMB MDL
  2503. if (Status == STATUS_SUCCESS) {
  2504. RxAllocateHeaderMdl(
  2505. pSecondaryRequestSmbHeader,
  2506. SecondaryRequestSmbSize,
  2507. pSecondaryRequestSmbMdl
  2508. );
  2509. if (pSecondaryRequestSmbMdl != NULL) {
  2510. RxProbeAndLockHeaderPages(
  2511. pSecondaryRequestSmbMdl,
  2512. KernelMode,
  2513. IoModifyAccess,
  2514. Status);
  2515. if (Status != STATUS_SUCCESS) {
  2516. IoFreeMdl(pSecondaryRequestSmbMdl);
  2517. pSecondaryRequestSmbMdl = NULL;
  2518. } else {
  2519. if (MmGetSystemAddressForMdlSafe(pSecondaryRequestSmbMdl,LowPagePriority) == NULL) { //map it
  2520. Status = STATUS_INSUFFICIENT_RESOURCES;
  2521. }
  2522. }
  2523. } else {
  2524. RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: Error allocating 2ndsmb MDL\n"));
  2525. Status = STATUS_INSUFFICIENT_RESOURCES;
  2526. }
  2527. }
  2528. }
  2529. while ((Status == STATUS_SUCCESS) &&
  2530. ((SendParamBufferSize > 0) || (SendDataBufferSize > 0))) {
  2531. PaddingLength = 0;
  2532. DataBytesToBeSent = 0;
  2533. ParamBytesToBeSent = 0;
  2534. ParamDisplacement = 0;
  2535. pLastMdlInChain = pSecondaryRequestSmbMdl;
  2536. ParamOffset = DataOffset = SecondaryRequestSmbSize;
  2537. ParamBytesToBeSent = MIN((MaximumSmbBufferSize - ParamOffset),
  2538. SendParamBufferSize);
  2539. if (ParamBytesToBeSent > 0) {
  2540. // Form a MDL for the portion of the parameter buffer being transmitted
  2541. if (ParamPartialMdlAlreadyUsed) {
  2542. MmPrepareMdlForReuse(pPartialParamMdl);
  2543. }
  2544. ParamPartialMdlAlreadyUsed = TRUE;
  2545. IoBuildPartialMdl(
  2546. pTransactExchange->pSendParamMdl,
  2547. pPartialParamMdl,
  2548. pSendParamStartAddress,
  2549. ParamBytesToBeSent);
  2550. ParamDisplacement = (ULONG)(pSendParamStartAddress - pOriginalParamBuffer);
  2551. pSendParamStartAddress += ParamBytesToBeSent;
  2552. SendParamBufferSize -= ParamBytesToBeSent;
  2553. DataOffset += QuadAlign(ParamBytesToBeSent);
  2554. pLastMdlInChain->Next = pPartialParamMdl;
  2555. pLastMdlInChain = pPartialParamMdl;
  2556. } else {
  2557. // don't do this! the padding stuff uses it. you can set it later
  2558. // ParamOffset = 0;
  2559. }
  2560. if ((DataOffset < MaximumSmbBufferSize) && (SendDataBufferSize > 0) ) {
  2561. // There is room for data bytes to be sent
  2562. // Check if we need a padding MDL ....
  2563. PaddingLength = DataOffset - (ParamOffset + ParamBytesToBeSent);
  2564. if (PaddingLength > 0) {
  2565. RxDbgTrace( 0, Dbg, ("SmbCeTransactExchangeStart: Padding Length %ld\n",PaddingLength));
  2566. RxBuildPaddingPartialMdl(pPaddingMdl,PaddingLength);
  2567. pLastMdlInChain->Next = pPaddingMdl;
  2568. pLastMdlInChain = pPaddingMdl;
  2569. }
  2570. // Link the data buffer or portions of it if the size constraints are satisfied
  2571. DataBytesToBeSent = MIN((MaximumSmbBufferSize - DataOffset),
  2572. SendDataBufferSize);
  2573. ASSERT (DataBytesToBeSent > 0);
  2574. // Form a MDL for the portions of the data buffer being sent
  2575. if (DataPartialMdlAlreadyUsed) {
  2576. MmPrepareMdlForReuse(pPartialDataMdl);
  2577. }
  2578. DataPartialMdlAlreadyUsed = TRUE;
  2579. IoBuildPartialMdl(
  2580. pTransactExchange->pSendDataMdl,
  2581. pPartialDataMdl,
  2582. pSendDataStartAddress,
  2583. DataBytesToBeSent);
  2584. // chain the data MDL
  2585. pLastMdlInChain->Next = pPartialDataMdl;
  2586. pLastMdlInChain = pPartialDataMdl;
  2587. DataDisplacement = (ULONG)(pSendDataStartAddress - pOriginalDataBuffer);
  2588. pSendDataStartAddress += DataBytesToBeSent;
  2589. SendDataBufferSize -= DataBytesToBeSent;
  2590. } else {
  2591. DataOffset = DataDisplacement = 0;
  2592. DbgDoit(if (SmbSendBadSecondary){DataOffset = QuadAlign(ParamOffset + ParamBytesToBeSent);});
  2593. }
  2594. if (ParamBytesToBeSent == 0) {
  2595. ParamOffset = 0;
  2596. }
  2597. RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: Secondary Request Param(%ld) padding(%ld) Data(%ld)\n",
  2598. ParamBytesToBeSent,
  2599. PaddingLength,
  2600. DataBytesToBeSent));
  2601. RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: ParamO(%ld) DataO(%ld)\n",ParamOffset,DataOffset));
  2602. RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: ParamD(%ld) DataD(%ld)\n",ParamDisplacement,DataDisplacement));
  2603. RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: TotParam(%ld) TotData(%ld)\n",TotalParamBytes,TotalDataBytes));
  2604. // Update the secondary request buffer with the final sizes of the data/parameter etc.
  2605. switch (pTransactExchange->SmbCommand) {
  2606. case SMB_COM_TRANSACTION:
  2607. case SMB_COM_TRANSACTION2:
  2608. {
  2609. PREQ_TRANSACTION_SECONDARY pTransactRequest;
  2610. //ASSERT(!"this has not been tested");
  2611. pTransactRequest = (PREQ_TRANSACTION_SECONDARY)(pSecondaryRequestSmbHeader + 1);
  2612. pTransactRequest->WordCount = 8; // Count of parameter words = 8
  2613. SmbPutUshort(&pTransactRequest->TotalParameterCount, (USHORT)TotalParamBytes); // Total parameter bytes being sent
  2614. SmbPutUshort(&pTransactRequest->TotalDataCount, (USHORT)TotalDataBytes); // Total data bytes being sent
  2615. SmbPutUshort(&pTransactRequest->ParameterCount, (USHORT)ParamBytesToBeSent); // Parameter bytes sent this buffer
  2616. SmbPutUshort(&pTransactRequest->ParameterOffset, (USHORT)ParamOffset); // Offset (from header start) to params
  2617. SmbPutUshort(&pTransactRequest->ParameterDisplacement, (USHORT)ParamDisplacement); // Displacement of these param bytes
  2618. SmbPutUshort(&pTransactRequest->DataCount, (USHORT)DataBytesToBeSent); // Parameter bytes sent this buffer
  2619. SmbPutUshort(&pTransactRequest->DataOffset, (USHORT)DataOffset); // Offset (from header start) to Datas
  2620. SmbPutUshort(&pTransactRequest->DataDisplacement, (USHORT)DataDisplacement); // Displacement of these Data bytes
  2621. ByteCountOffset = FIELD_OFFSET(REQ_TRANSACTION_SECONDARY,ByteCount);
  2622. if (pTransactExchange->SmbCommand == SMB_COM_TRANSACTION2 ) {
  2623. ByteCountOffset += sizeof(USHORT);
  2624. pTransactRequest->WordCount++; //one extra word
  2625. SmbPutUshort((&pTransactRequest->DataDisplacement)+1, 0); //the +1 is to move up 1 USHORT
  2626. }
  2627. }
  2628. break;
  2629. case SMB_COM_NT_TRANSACT:
  2630. {
  2631. PREQ_NT_TRANSACTION_SECONDARY pNtTransactRequest;
  2632. pNtTransactRequest= (PREQ_NT_TRANSACTION_SECONDARY)(pSecondaryRequestSmbHeader + 1);
  2633. pNtTransactRequest->WordCount = 18; // Count of parameter words = 18
  2634. pNtTransactRequest->Reserved1 = 0; // MBZ
  2635. SmbPutUshort(&pNtTransactRequest->Reserved2, 0); // MBZ
  2636. SmbPutUlong(&pNtTransactRequest->TotalParameterCount, TotalParamBytes); // Total parameter bytes being sent
  2637. SmbPutUlong(&pNtTransactRequest->TotalDataCount, TotalDataBytes); // Total data bytes being sent
  2638. SmbPutUlong(&pNtTransactRequest->ParameterCount, ParamBytesToBeSent); // Parameter bytes sent this buffer
  2639. SmbPutUlong(&pNtTransactRequest->ParameterOffset, ParamOffset); // Offset (from header start) to params
  2640. SmbPutUlong(&pNtTransactRequest->ParameterDisplacement, ParamDisplacement); // Displacement of these param bytes
  2641. SmbPutUlong(&pNtTransactRequest->DataCount, DataBytesToBeSent); // Parameter bytes sent this buffer
  2642. SmbPutUlong(&pNtTransactRequest->DataOffset, DataOffset); // Offset (from header start) to Datas
  2643. SmbPutUlong(&pNtTransactRequest->DataDisplacement, DataDisplacement); // Displacement of these Data bytes
  2644. pNtTransactRequest->Reserved3 = 0; // MBZ
  2645. ByteCountOffset = FIELD_OFFSET(REQ_NT_TRANSACTION_SECONDARY,ByteCount);
  2646. }
  2647. break;
  2648. default:
  2649. ASSERT(!"Valid Smb Command for initiating Transaction");
  2650. Status = STATUS_INVALID_PARAMETER;
  2651. break;
  2652. }
  2653. // Send the secondary SMB
  2654. SmbLength = SecondaryRequestSmbSize +
  2655. ParamBytesToBeSent +
  2656. PaddingLength +
  2657. DataBytesToBeSent;
  2658. ByteCount = (USHORT)(SmbLength-(sizeof(SMB_HEADER)+ByteCountOffset+sizeof(USHORT)));
  2659. pByteCount = (PUSHORT)((PBYTE)pSecondaryRequestSmbHeader+sizeof(SMB_HEADER)+ByteCountOffset);
  2660. SmbPutUshort(pByteCount,ByteCount);
  2661. RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: len %d bytecount %d(%x)\n", SmbLength, ByteCount, ByteCount));
  2662. RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: msgmdl=%08lx\n", pSecondaryRequestSmbHeader));
  2663. RxLog(("2nd: %lx %lx %lx %lx %lx %lx",ParamOffset,ParamDisplacement,TotalParamBytes,DataOffset,DataDisplacement,TotalDataBytes));
  2664. RxLog(("2nd:: %lx %lx",ByteCount,SmbLength));
  2665. Status = SmbCeSend(
  2666. pExchange,
  2667. RXCE_SEND_SYNCHRONOUS,
  2668. pSecondaryRequestSmbMdl,
  2669. SmbLength);
  2670. RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: SmbCeSend returned %lx\n",Status));
  2671. if ((Status != STATUS_PENDING) && (Status != STATUS_SUCCESS)) {
  2672. RxDbgTrace( 0, Dbg, ("SendSecondaryRequests: SmbCeSend returned bad status %lx\n",Status));
  2673. //here we should just get out
  2674. goto FINALLY; //yes we cold have said break....but that's not what we're doing
  2675. } else {
  2676. Status = STATUS_SUCCESS;
  2677. }
  2678. }
  2679. FINALLY:
  2680. if (pPartialDataMdl != NULL) {
  2681. IoFreeMdl(pPartialDataMdl);
  2682. }
  2683. if (pActualSecondaryRequestSmbHeader != NULL) {
  2684. RxFreePool(pActualSecondaryRequestSmbHeader);
  2685. }
  2686. if (pPartialParamMdl != NULL) {
  2687. IoFreeMdl(pPartialParamMdl);
  2688. }
  2689. if (pPaddingMdl != NULL) {
  2690. IoFreeMdl(pPaddingMdl);
  2691. }
  2692. if (pSecondaryRequestSmbMdl != NULL) {
  2693. RxUnlockHeaderPages(pSecondaryRequestSmbMdl);
  2694. IoFreeMdl(pSecondaryRequestSmbMdl);
  2695. }
  2696. //we always finalize......but we only set the status if there's an error or
  2697. // we expect no response
  2698. if ((Status != STATUS_SUCCESS) || (pTransactExchange->Flags & SMB_TRANSACTION_NO_RESPONSE )) {
  2699. pExchange->Status = Status;
  2700. }
  2701. SmbCeDecrementPendingLocalOperationsAndFinalize(pExchange);
  2702. return Status;
  2703. }
  2704. SMB_EXCHANGE_DISPATCH_VECTOR
  2705. TransactExchangeDispatch = {
  2706. SmbTransactExchangeStart,
  2707. SmbTransactExchangeReceive,
  2708. SmbTransactExchangeCopyDataHandler,
  2709. NULL, // SmbTransactExchangeSendCallbackHandler
  2710. SmbTransactExchangeFinalize,
  2711. NULL
  2712. };
  2713. #ifndef RX_NO_DBGFIELD_HLPRS
  2714. #define DECLARE_FIELD_HLPR(x) ULONG SmbPseTxeField_##x = FIELD_OFFSET(SMB_TRANSACT_EXCHANGE,x);
  2715. #define DECLARE_FIELD_HLPR2(x,y) ULONG SmbPseTxeField_##x##y = FIELD_OFFSET(SMB_TRANSACT_EXCHANGE,x.y);
  2716. DECLARE_FIELD_HLPR(RxContext);
  2717. DECLARE_FIELD_HLPR(ReferenceCount);
  2718. DECLARE_FIELD_HLPR(State);
  2719. DECLARE_FIELD_HLPR(pSendDataMdl);
  2720. DECLARE_FIELD_HLPR(pReceiveDataMdl);
  2721. DECLARE_FIELD_HLPR(pSendParamMdl);
  2722. DECLARE_FIELD_HLPR(pReceiveParamMdl);
  2723. DECLARE_FIELD_HLPR(pSendSetupMdl);
  2724. DECLARE_FIELD_HLPR(pReceiveSetupMdl);
  2725. DECLARE_FIELD_HLPR(PrimaryRequestSmbSize);
  2726. DECLARE_FIELD_HLPR(SmbCommand);
  2727. DECLARE_FIELD_HLPR(NtTransactFunction);
  2728. DECLARE_FIELD_HLPR(Flags);
  2729. DECLARE_FIELD_HLPR(Fid);
  2730. #endif