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.

3633 lines
148 KiB

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