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.

867 lines
29 KiB

  1. /*++
  2. Copyright (c) 1989 - 1999 Microsoft Corporation
  3. Module Name:
  4. sndrcv.c
  5. Abstract:
  6. This module implements all functions related to transmitting and recieving SMB's on
  7. all transports. The functionality common to all transports are handled in this
  8. module while transport specific functionality are handled in the appropriate
  9. ??sndrcv.c modules.
  10. vcsndrcv.c -- virtual circuit(connection) related send/receive functionality
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text(PAGE, SmbCeSend)
  16. #pragma alloc_text(PAGE, SmbCeSendToServer)
  17. #endif
  18. RXDT_DefineCategory(SMBSNDRCV);
  19. #define Dbg (DEBUG_TRACE_SMBSNDRCV)
  20. #ifdef RDBSSLOG
  21. //this stuff must be in nonpaged memory
  22. //// 1 2 3 4 5 6 7 8 9
  23. char MRxSmbMiniSniff_SurrogateFormat[] = "%S%S%N%N%N%N%N%N%N";
  24. //// 2 3 4 5 6 7 8 9
  25. char MRxSmbMiniSniff_ActualFormat[] = "Minisniff (%s) srv %lx cmd/mid %lx status %lx len %04lx flg %06lx xc %08lx rx %08lx";
  26. char MRxSmbMiniSniffTranceive[] = "Tranceive";
  27. char MRxSmbMiniSniffReceive[] = "Receive";
  28. char MRxSmbMiniSniffReceiveEcho[] = "RcvEcho";
  29. char MRxSmbMiniSniffReceiveDiscard[] = "RcvDiscard";
  30. char MRxSmbMiniSniffReceiveDiscardOplock[] = "RcvDiscardOplock";
  31. char MRxSmbMiniSniffReceiveIndicateOplock[] = "RcvIndicateOplock";
  32. char MRxSmbMiniSniffSend[] = "Send";
  33. char MRxSmbMiniSniffSendSrv[] = "SendToServer";
  34. VOID
  35. RxMiniSniffer(
  36. IN PSZ TagString,
  37. IN PSMBCEDB_SERVER_ENTRY pServerEntry,
  38. IN ULONG Length,
  39. IN PSMB_EXCHANGE pExchange,
  40. IN PSMB_HEADER pSmbHeader
  41. )
  42. {
  43. PRX_CONTEXT RxContext = NULL;
  44. //return;
  45. if (pExchange!=NULL) {
  46. RxContext = pExchange->RxContext;
  47. }
  48. RxLog((MRxSmbMiniSniff_SurrogateFormat, MRxSmbMiniSniff_ActualFormat,
  49. TagString,
  50. pServerEntry,
  51. (ULONG)(pSmbHeader->Command<<24) | SmbGetUshort(&pSmbHeader->Mid),
  52. SmbGetUlong( & ((PNT_SMB_HEADER)pSmbHeader)->Status.NtStatus ),
  53. Length,
  54. (pSmbHeader->Flags<<16)|SmbGetUshort(&pSmbHeader->Flags2),
  55. pExchange,RxContext));
  56. }
  57. #else
  58. #define RxMiniSniffer(a,b,c,d,e) {NOTHING;}
  59. #endif //ifdef RDBSSLOG
  60. NTSTATUS
  61. SmbCeTranceive(
  62. PSMB_EXCHANGE pExchange,
  63. ULONG SendOptions,
  64. PMDL pSmbMdl,
  65. ULONG SendLength)
  66. /*++
  67. Routine Description:
  68. This routine transmits/receives a SMB for a give exchange
  69. Arguments:
  70. pServerEntry - the server entry
  71. pExchange - the exchange instance issuing this SMB.
  72. SendOptions - options for send
  73. pSmbMdl - the SMB that needs to be sent.
  74. SendLength - length of data to be transmitted
  75. Return Value:
  76. STATUS_PENDING - the transmit/receive request has been passed on successfully to the underlying
  77. connection engine.
  78. Other Status codes correspond to error situations.
  79. --*/
  80. {
  81. NTSTATUS Status = STATUS_SUCCESS;
  82. PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  83. PSMB_HEADER pSmbHeader = MmGetSystemAddressForMdlSafe(pSmbMdl,LowPagePriority);
  84. USHORT Mid;
  85. PVOID pSendCompletionContext = NULL;
  86. if (pSmbHeader == NULL) {
  87. Status = STATUS_INSUFFICIENT_RESOURCES;
  88. } else {
  89. Status = SmbCeIncrementPendingOperations(
  90. pExchange,
  91. (SMBCE_LOCAL_OPERATION | SMBCE_SEND_COMPLETE_OPERATION | SMBCE_RECEIVE_OPERATION),
  92. __FILE__,
  93. __LINE__);
  94. }
  95. if (Status == STATUS_SUCCESS) {
  96. PSMBCE_SERVER_TRANSPORT pTransport;
  97. // Ensure that the transport associated with the exchange is valid.
  98. // It is not always possible to make decisions w.r.t changing
  99. // transports since it is a function of the protocol choosen at the
  100. // higher level. Therefore no attempts to reconnect are made at this
  101. // level.
  102. pTransport = pServerEntry->pTransport;
  103. if (pTransport == NULL) {
  104. Status = STATUS_CONNECTION_DISCONNECTED;
  105. }
  106. if (Status == STATUS_SUCCESS &&
  107. !(pExchange->SmbCeFlags & SMBCE_EXCHANGE_MID_VALID)) {
  108. // Associate the exchange with a mid
  109. Status = SmbCeAssociateExchangeWithMid(pServerEntry,pExchange);
  110. }
  111. if (Status == STATUS_SUCCESS) {
  112. if (pExchange->pDispatchVector->SendCompletionHandler != NULL) {
  113. Status = SmbCeAssociateBufferWithExchange(pServerEntry,pExchange,pSmbMdl);
  114. if (Status == STATUS_SUCCESS) {
  115. pSendCompletionContext = pSmbMdl;
  116. }
  117. }
  118. // If there is no send completion handling associated with this tranceive
  119. // decrement the count.
  120. if (pSendCompletionContext == NULL) {
  121. SmbCeDecrementPendingSendCompleteOperations(pExchange);
  122. }
  123. if (Status == STATUS_SUCCESS) {
  124. // Stamp the MID allocated for the request and send the SMB.
  125. pSmbHeader->Mid = pExchange->Mid;
  126. //RxLog(("Smb (TR) %lx %lx %lx\n",pServerEntry,pSmbHeader->Command,pSmbHeader->Mid));
  127. RxMiniSniffer(MRxSmbMiniSniffTranceive,pServerEntry,SendLength,pExchange,pSmbHeader);
  128. // Update the expiry time on the exchange if required.
  129. SmbCeSetExpiryTime(pExchange);
  130. if (InterlockedCompareExchange(
  131. &pExchange->CancellationStatus,
  132. SMBCE_EXCHANGE_NOT_CANCELLED,
  133. SMBCE_EXCHANGE_NOT_CANCELLED) == SMBCE_EXCHANGE_NOT_CANCELLED) {
  134. if (Status == STATUS_SUCCESS) {
  135. // Update the operation counts for the exchange instance.
  136. // Refer to Header for detailed explanation
  137. Status = (pTransport->pDispatchVector->Tranceive)(
  138. pTransport,
  139. pServerEntry,
  140. pExchange,
  141. SendOptions,
  142. pSmbMdl,
  143. SendLength,
  144. pSendCompletionContext);
  145. }
  146. } else {
  147. if (pSendCompletionContext != NULL) {
  148. SmbCeDecrementPendingSendCompleteOperations(pExchange);
  149. }
  150. Status = STATUS_CANCELLED;
  151. }
  152. if ((Status != STATUS_PENDING) &&
  153. (Status != STATUS_SUCCESS)) {
  154. pExchange->Status = Status;
  155. SmbCeDecrementPendingReceiveOperations(pExchange);
  156. InterlockedIncrement(&MRxSmbStatistics.InitiallyFailedOperations);
  157. } else {
  158. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.SmbsTransmitted,1);
  159. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.BytesTransmitted,SendLength);
  160. }
  161. }
  162. } else {
  163. SmbCeDecrementPendingReceiveOperations(pExchange);
  164. SmbCeDecrementPendingSendCompleteOperations(pExchange);
  165. }
  166. if ((Status != STATUS_SUCCESS) && (Status != STATUS_PENDING)) {
  167. pExchange->SmbStatus = Status;
  168. }
  169. SmbCeDecrementPendingLocalOperationsAndFinalize(pExchange);
  170. Status = STATUS_PENDING;
  171. }
  172. return Status;
  173. }
  174. NTSTATUS
  175. SmbCeReceive(
  176. PSMB_EXCHANGE pExchange)
  177. /*++
  178. Routine Description:
  179. This routine receives a SMB for a give exchange
  180. Arguments:
  181. pExchange - the exchange instance issuing this SMB.
  182. Return Value:
  183. STATUS_SUCCESS - the exchange has been setup for receiving an SMB
  184. Other Status codes correspond to error situations.
  185. --*/
  186. {
  187. NTSTATUS Status = STATUS_SUCCESS;
  188. ASSERT(pExchange->SmbCeFlags & SMBCE_EXCHANGE_MID_VALID);
  189. Status = SmbCeIncrementPendingOperations(pExchange, (SMBCE_RECEIVE_OPERATION),__FILE__,__LINE__);
  190. if (Status == STATUS_SUCCESS) {
  191. // Update the expiry time on the exchange if required.
  192. SmbCeSetExpiryTime(pExchange);
  193. }
  194. return Status;
  195. }
  196. NTSTATUS
  197. SmbCeSend(
  198. PSMB_EXCHANGE pExchange,
  199. ULONG SendOptions,
  200. PMDL pSmbMdl,
  201. ULONG SendLength)
  202. /*++
  203. Routine Description:
  204. This routine transmits a SMB for a give exchange
  205. Arguments:
  206. pServerEntry - the server entry
  207. pExchange - the exchange instance issuing this SMB.
  208. SendOptions - options for send
  209. pSmbMdl - the SMB that needs to be sent.
  210. SendLength - length of data to be transmitted
  211. Return Value:
  212. For asynchronous sends ....
  213. STATUS_PENDING - the request was passed onto the underlying transport and
  214. the quiescent state routine will be called in the future.
  215. any other status code -- indicates an error in passing the request and the
  216. quiescent state routine will never be called in the future.
  217. For synchronous sends
  218. the appropriate status but will never return STATUS_PENDING.
  219. Notes:
  220. This routine always expects an exchange with the appropriate SendCompletionHandler.
  221. --*/
  222. {
  223. NTSTATUS Status = STATUS_SUCCESS;
  224. PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  225. PSMB_HEADER pSmbHeader = (PSMB_HEADER)MmGetSystemAddressForMdlSafe(pSmbMdl,LowPagePriority);
  226. PVOID pSendCompletionContext = NULL;
  227. PAGED_CODE();
  228. ASSERT(pExchange != NULL);
  229. if (pSmbHeader == NULL) {
  230. Status = STATUS_INSUFFICIENT_RESOURCES;
  231. } else {
  232. Status = SmbCeIncrementPendingOperations(
  233. pExchange,
  234. (SMBCE_LOCAL_OPERATION | SMBCE_SEND_COMPLETE_OPERATION),
  235. __FILE__,
  236. __LINE__);
  237. }
  238. if (Status == STATUS_SUCCESS) {
  239. PSMBCE_SERVER_TRANSPORT pTransport;
  240. // Ensure that the transport associated with the exchange is valid.
  241. // It is not always possible to make decisions w.r.t changing
  242. // transports since it is a function of the protocol choosen at the
  243. // higher level. Therefore no attempts to reconnect are made at this
  244. // level.
  245. pTransport = pServerEntry->pTransport;
  246. ASSERT(pTransport != NULL);
  247. if (SmbCeGetServerType(pServerEntry) == SMBCEDB_FILE_SERVER) {
  248. if (!(pExchange->SmbCeFlags & SMBCE_EXCHANGE_MID_VALID)) {
  249. // Associate the exchange with a mid if it does not already have a valid mid.
  250. Status = SmbCeAssociateExchangeWithMid(pServerEntry,pExchange);
  251. }
  252. if (Status == STATUS_SUCCESS) {
  253. // if the MID association was successful copy the MID onto the SMB and setup
  254. // a send completion context if required
  255. pSmbHeader->Mid = pExchange->Mid;
  256. if (!(SendOptions & RXCE_SEND_SYNCHRONOUS)) {
  257. ASSERT(pExchange->pDispatchVector->SendCompletionHandler != NULL);
  258. Status = SmbCeAssociateBufferWithExchange(pServerEntry,pExchange,pSmbMdl);
  259. if (Status == STATUS_SUCCESS) {
  260. pSendCompletionContext = pSmbMdl;
  261. }
  262. }
  263. }
  264. }
  265. if ((pSendCompletionContext == NULL) ||
  266. (Status != STATUS_SUCCESS)) {
  267. SmbCeDecrementPendingSendCompleteOperations(pExchange);
  268. }
  269. if (Status == STATUS_SUCCESS) {
  270. // Update the expiry time on the exchange if required.
  271. SmbCeSetExpiryTime(pExchange);
  272. if (InterlockedCompareExchange(
  273. &pExchange->CancellationStatus,
  274. SMBCE_EXCHANGE_NOT_CANCELLED,
  275. SMBCE_EXCHANGE_NOT_CANCELLED) == SMBCE_EXCHANGE_NOT_CANCELLED) {
  276. if (Status == STATUS_SUCCESS) {
  277. Status = (pTransport->pDispatchVector->Send)(
  278. pTransport,
  279. pServerEntry,
  280. SendOptions,
  281. pSmbMdl,
  282. SendLength,
  283. pSendCompletionContext);
  284. }
  285. } else {
  286. if (pSendCompletionContext != NULL) {
  287. SmbCeDecrementPendingSendCompleteOperations(pExchange);
  288. }
  289. Status = STATUS_CANCELLED;
  290. }
  291. }
  292. RxMiniSniffer(MRxSmbMiniSniffSend,pServerEntry,SendLength,pExchange,pSmbHeader);
  293. if ((Status != STATUS_SUCCESS) && (Status != STATUS_PENDING)) {
  294. pExchange->SmbStatus = Status;
  295. InterlockedIncrement(&MRxSmbStatistics.InitiallyFailedOperations);
  296. } else {
  297. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.SmbsTransmitted,1);
  298. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.BytesTransmitted,SendLength);
  299. }
  300. SmbCeDecrementPendingLocalOperationsAndFinalize(pExchange);
  301. if (!(SendOptions & RXCE_SEND_SYNCHRONOUS)) {
  302. Status = STATUS_PENDING;
  303. } else {
  304. ASSERT(Status != STATUS_PENDING);
  305. }
  306. }
  307. return Status;
  308. }
  309. NTSTATUS
  310. SmbCeSendToServer(
  311. PSMBCEDB_SERVER_ENTRY pServerEntry,
  312. ULONG SendOptions,
  313. PMDL pSmbMdl,
  314. ULONG SendLength)
  315. /*++
  316. Routine Description:
  317. This routine transmits a SMB to a given server synchronously.
  318. Arguments:
  319. pServerEntry - the server entry
  320. SendOptions - options for send
  321. pSmbMdl - the SMB that needs to be sent.
  322. SendLength - length of data to be transmitted
  323. Return Value:
  324. STATUS_SUCCESS if successful
  325. otherwise appropriate error code
  326. --*/
  327. {
  328. NTSTATUS Status = STATUS_SUCCESS;
  329. PSMB_HEADER pSmbHeader = (PSMB_HEADER)MmGetSystemAddressForMdlSafe(pSmbMdl,LowPagePriority);
  330. PVOID pSendCompletionContext = NULL;
  331. PAGED_CODE();
  332. if (pSmbHeader == NULL) {
  333. Status = STATUS_INSUFFICIENT_RESOURCES;
  334. } else {
  335. if (pServerEntry->pTransport != NULL) {
  336. Status = (pServerEntry->pTransport->pDispatchVector->Send)(
  337. pServerEntry->pTransport,
  338. pServerEntry,
  339. (SendOptions | RXCE_SEND_SYNCHRONOUS),
  340. pSmbMdl,
  341. SendLength,
  342. pSendCompletionContext);
  343. if (!NT_SUCCESS(Status)) {
  344. InterlockedIncrement(&MRxSmbStatistics.InitiallyFailedOperations);
  345. } else {
  346. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.SmbsTransmitted,1);
  347. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.BytesTransmitted,SendLength);
  348. RxMiniSniffer(MRxSmbMiniSniffSendSrv,pServerEntry,SendLength,NULL,pSmbHeader);
  349. }
  350. } else {
  351. Status = STATUS_CONNECTION_DISCONNECTED;
  352. }
  353. }
  354. ASSERT(Status != STATUS_PENDING);
  355. return Status;
  356. }
  357. NTSTATUS
  358. SmbCeReceiveInd(
  359. IN PSMBCEDB_SERVER_ENTRY pServerEntry,
  360. IN ULONG BytesIndicated,
  361. IN ULONG BytesAvailable,
  362. OUT ULONG *pBytesTaken,
  363. IN PVOID pTsdu, // pointer describing this TSDU, typically a lump of bytes
  364. OUT PMDL *pDataBufferPointer, // the buffer in which data is to be copied.
  365. OUT PULONG pDataBufferSize, // amount of data to copy
  366. IN ULONG ReceiveFlags
  367. )
  368. /*++
  369. Routine Description:
  370. This routine handles the receive indication for SMB's along all vcs in a connection to a
  371. server.
  372. Arguments:
  373. pServerEntry - the server entry
  374. BytesIndicated - the bytes that are present in the indication.
  375. BytesAvailable - the total data available
  376. pTsdu - the data
  377. pDataBufferPointer - the buffer for copying the data not indicated.
  378. pDataBufferSize - the length of the buffer
  379. Return Value:
  380. STATUS_SUCCESS -
  381. Other Status codes correspond to error situations.
  382. --*/
  383. {
  384. NTSTATUS Status;
  385. BYTE *pSmbCommand;
  386. PSMB_EXCHANGE pExchange;
  387. PSMB_HEADER pSmbHeader = (PSMB_HEADER)pTsdu;
  388. // Perform the quick tests by which ill formed SMB's, mangled SMB's can be rejected.
  389. // e.g., any indication which is of non zero length which is less then the length of
  390. // a SMB_HEADER plus the minimum SMB message body length of 3 bytes cannot be a valid
  391. // SMB.
  392. if ((BytesAvailable < sizeof(SMB_HEADER) + 2) ||
  393. (SmbGetUlong(((PULONG )pSmbHeader->Protocol)) != (ULONG)SMB_HEADER_PROTOCOL) ||
  394. (pSmbHeader->Command == SMB_COM_NO_ANDX_COMMAND) ) {
  395. RxLog(("SmbCeReceiveInd: Invalid Response for %lx\n",pServerEntry));
  396. *pBytesTaken = BytesIndicated;
  397. return STATUS_SUCCESS;
  398. }
  399. ASSERT(pServerEntry->Header.ObjectType == SMBCEDB_OT_SERVER);
  400. if (pSmbHeader->Command == SMB_COM_ECHO) {
  401. PSMBCE_RESUMPTION_CONTEXT pResumptionContext = NULL;
  402. InterlockedExchange(
  403. &pServerEntry->Server.EchoProbeState,
  404. ECHO_PROBE_IDLE);
  405. pServerEntry->Server.EchoExpiryTime.QuadPart = 0;
  406. *pBytesTaken = BytesIndicated;
  407. RxMiniSniffer(MRxSmbMiniSniffReceiveEcho,pServerEntry,BytesIndicated,NULL,pSmbHeader);
  408. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.SmbsReceived,1);
  409. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.BytesReceived,BytesIndicated);
  410. return STATUS_SUCCESS;
  411. }
  412. //RxLog(("Smb (Rece) %lx %lx %lx\n",pServerEntry,pSmbHeader->Command,pSmbHeader->Mid));
  413. // Perform the tests for detecting oplock break SMB's. These are SMB's with the
  414. // command SMB_COM_LOCKING_ANDX with the LOCKING_ANDX_OPLOCK_RELEASE bit set.
  415. // These SMB's are transformed into buffering state change requests which are
  416. // processed by the RDBSS.
  417. //
  418. if (pSmbHeader->Command == SMB_COM_LOCKING_ANDX) {
  419. if (BytesIndicated == LOCK_BROKEN_SIZE) {
  420. PREQ_LOCKING_ANDX pOplockBreakRequest = (PREQ_LOCKING_ANDX)(pSmbHeader + 1);
  421. if (SmbGetUshort(&pOplockBreakRequest->LockType) & LOCKING_ANDX_OPLOCK_RELEASE) {
  422. ULONG NewOplockLevel;
  423. switch (pOplockBreakRequest->OplockLevel) {
  424. case OPLOCK_BROKEN_TO_II:
  425. NewOplockLevel = SMB_OPLOCK_LEVEL_II;
  426. break;
  427. case OPLOCK_BROKEN_TO_NONE:
  428. default:
  429. NewOplockLevel = SMB_OPLOCK_LEVEL_NONE;
  430. }
  431. RxMiniSniffer(MRxSmbMiniSniffReceiveIndicateOplock,pServerEntry,BytesIndicated,NULL,pSmbHeader);
  432. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.SmbsReceived,1);
  433. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.BytesReceived,BytesIndicated);
  434. if (pServerEntry->pRdbssSrvCall != NULL) {
  435. RxIndicateChangeOfBufferingState(
  436. pServerEntry->pRdbssSrvCall,
  437. MRxSmbMakeSrvOpenKey(pSmbHeader->Tid,pOplockBreakRequest->Fid),
  438. ULongToPtr(NewOplockLevel));
  439. }
  440. RxDbgTrace(0,Dbg,("SmbCeReceiveInd: OPLOCK Break Request TID(%lx) FID(%lx)\n",
  441. pSmbHeader->Tid,pOplockBreakRequest->Fid));
  442. RxLog(("OPLOCK Break: FID %lx Level %x\n",pOplockBreakRequest->Fid,pOplockBreakRequest->OplockLevel));
  443. //DbgPrint("OPLOCK Break: FID %lx Level %x\n",pOplockBreakRequest->Fid,pOplockBreakRequest->OplockLevel);
  444. *pBytesTaken = BytesIndicated;
  445. return STATUS_SUCCESS;
  446. }
  447. }
  448. }
  449. // Handle the cases when the server responds to the oplock break response.
  450. if (pSmbHeader->Mid == SMBCE_OPLOCK_RESPONSE_MID) {
  451. *pBytesTaken = BytesIndicated;
  452. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.SmbsReceived,1);
  453. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.BytesReceived,BytesIndicated);
  454. RxMiniSniffer(MRxSmbMiniSniffReceiveDiscardOplock,pServerEntry,BytesIndicated,NULL,pSmbHeader);
  455. return STATUS_SUCCESS;
  456. }
  457. InterlockedIncrement(&pServerEntry->Server.SmbsReceivedSinceLastStrobe);
  458. // Initialize the copy data buffer and size to begin with.
  459. *pDataBufferPointer = NULL;
  460. *pDataBufferSize = 0;
  461. // Map the MID to the associated exchange.
  462. if (pSmbHeader->Command == SMB_COM_NEGOTIATE) {
  463. pExchange = SmbResetServerEntryNegotiateExchange(pServerEntry);
  464. if (pExchange != NULL) {
  465. SmbCeDecrementPendingLocalOperations(pExchange);
  466. }
  467. } else {
  468. pExchange = SmbCeMapMidToExchange(pServerEntry,pSmbHeader->Mid);
  469. }
  470. RxMiniSniffer(MRxSmbMiniSniffReceive,pServerEntry,BytesIndicated,pExchange,pSmbHeader);
  471. // Note that the absence of a request entry cannot be asserted. It is conceivable that
  472. // requests could have been cancelled.
  473. if ((pExchange != NULL) &&
  474. (SmbCeIncrementPendingOperations(
  475. pExchange,
  476. (SMBCE_LOCAL_OPERATION | SMBCE_COPY_DATA_OPERATION),
  477. __FILE__,
  478. __LINE__) == STATUS_SUCCESS)) {
  479. // Invoke the receive indication handler
  480. Status = SMB_EXCHANGE_DISPATCH(pExchange,
  481. Receive,
  482. (pExchange,
  483. BytesIndicated,
  484. BytesAvailable,
  485. pBytesTaken,
  486. pTsdu,
  487. pDataBufferPointer,
  488. pDataBufferSize,
  489. ReceiveFlags));
  490. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.SmbsReceived,1);
  491. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.BytesReceived,*pBytesTaken);
  492. RxDbgTrace(0, Dbg, ("SmbCeReceiveInd: SMB_EXCHANGE_DISPATCH returned %lx,taken/mdl=%08lx/%08lx\n",
  493. Status,*pBytesTaken,*pDataBufferPointer));
  494. ASSERT ( (Status==STATUS_MORE_PROCESSING_REQUIRED)==((*pDataBufferPointer)!=NULL));
  495. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  496. Status = SmbCeAssociateBufferWithExchange(pServerEntry,pExchange,*pDataBufferPointer);
  497. if (Status != STATUS_SUCCESS) {
  498. DbgPrint("VctIndReceive:Error handling copy data request %lx\n",Status);
  499. pExchange->Status = Status;
  500. *pBytesTaken = BytesAvailable;
  501. Status = STATUS_SUCCESS;
  502. } else {
  503. Status = STATUS_MORE_PROCESSING_REQUIRED;
  504. }
  505. }
  506. if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
  507. SmbCeDecrementPendingCopyDataOperations(pExchange);
  508. } else {
  509. // Update the expiry time on the exchange if required.
  510. SmbCeSetExpiryTime(pExchange);
  511. }
  512. SmbCeDecrementPendingReceiveOperations(pExchange);
  513. SmbCeDecrementPendingLocalOperationsAndFinalize(pExchange);
  514. if (((*pBytesTaken + *pDataBufferSize) < BytesAvailable) &&
  515. (Status != STATUS_MORE_PROCESSING_REQUIRED)) {
  516. RxDbgTrace(0,Dbg,("SmbCeReceiveInd:Not consuming all indicated data\n"));
  517. *pBytesTaken = BytesAvailable;
  518. }
  519. } else {
  520. // Should we change over to a strategy in which the transport pipeline is kept
  521. // open by consuming all indicated data
  522. // DbgBreakPoint();
  523. RxLog(("SmbCeReceiveInd:No resumption context %lx\n",pServerEntry));
  524. Status = STATUS_SUCCESS;
  525. *pBytesTaken = BytesAvailable;
  526. }
  527. ASSERT((*pBytesTaken + *pDataBufferSize) >= BytesAvailable);
  528. ASSERT(Status == STATUS_SUCCESS ||
  529. Status == STATUS_DATA_NOT_ACCEPTED ||
  530. Status == STATUS_MORE_PROCESSING_REQUIRED);
  531. return Status;
  532. }
  533. NTSTATUS
  534. SmbCeDataReadyInd(
  535. IN PSMBCEDB_SERVER_ENTRY pServerEntry,
  536. IN PMDL pBuffer,
  537. IN ULONG DataSize,
  538. IN NTSTATUS CopyDataStatus
  539. )
  540. /*++
  541. Routine Description:
  542. This routine handles the indication when the requested data has been copied
  543. Arguments:
  544. pServerEntry - the server instance
  545. pBuffer - the buffer being returned
  546. DataSize - the amount of data copied in bytes
  547. Return Value:
  548. STATUS_SUCCESS - the server call construction has been finalized.
  549. Other Status codes correspond to error situations.
  550. --*/
  551. {
  552. NTSTATUS Status;
  553. PSMB_EXCHANGE pExchange;
  554. // Map the buffer to the exchange
  555. pExchange = SmbCeGetExchangeAssociatedWithBuffer(pServerEntry,pBuffer);
  556. RxDbgTrace(0, Dbg, ("VctIndDataReady: Processing Exchange %lx\n",pExchange));
  557. if (pExchange != NULL) {
  558. if (CopyDataStatus == STATUS_SUCCESS) {
  559. // Notify the exchange of the completion
  560. //ExInterlockedAddLargeStatistic(&MRxSmbStatistics.SmbsReceived,1);
  561. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.BytesReceived,DataSize);
  562. SMB_EXCHANGE_DISPATCH(
  563. pExchange,
  564. CopyDataHandler,
  565. (pExchange,pBuffer,DataSize));
  566. } else {
  567. pExchange->Status = STATUS_CONNECTION_DISCONNECTED;
  568. pExchange->SmbStatus = STATUS_CONNECTION_DISCONNECTED;
  569. }
  570. // Resume the exchange that was waiting for the data.
  571. SmbCeDecrementPendingCopyDataOperationsAndFinalize(pExchange);
  572. } else {
  573. // the exchange was cancelled while the copy was in progress. Free up the buffer
  574. if (pBuffer != NULL) {
  575. IoFreeMdl(pBuffer);
  576. }
  577. }
  578. return STATUS_SUCCESS;
  579. }
  580. NTSTATUS
  581. SmbCeErrorInd(
  582. IN PSMBCEDB_SERVER_ENTRY pServerEntry,
  583. IN NTSTATUS IndicatedStatus
  584. )
  585. /*++
  586. Routine Description:
  587. This routine handles the error indication
  588. Arguments:
  589. pEventContext - the server instance
  590. Status - the error
  591. Return Value:
  592. STATUS_SUCCESS
  593. --*/
  594. {
  595. NTSTATUS Status;
  596. PSMB_EXCHANGE pExchange;
  597. DbgPrint("@@@@@@ Error Indication for %lx @@@@@\n",pServerEntry);
  598. InterlockedIncrement(&MRxSmbStatistics.NetworkErrors);
  599. // Post to the worker queue to resume all the outstanding requests
  600. pServerEntry->ServerStatus = IndicatedStatus;
  601. SmbCeReferenceServerEntry(pServerEntry);
  602. Status = RxDispatchToWorkerThread(
  603. MRxSmbDeviceObject,
  604. CriticalWorkQueue,
  605. SmbCeResumeAllOutstandingRequestsOnError,
  606. pServerEntry);
  607. if (Status != STATUS_SUCCESS) {
  608. DbgPrint("Error Indication not dispatched\n");
  609. RxLog(("SmbCeErrorInd(SE) %lx\n", pServerEntry));
  610. }
  611. return STATUS_SUCCESS;
  612. }
  613. NTSTATUS
  614. SmbCeSendCompleteInd(
  615. IN PSMBCEDB_SERVER_ENTRY pServerEntry,
  616. IN PVOID pCompletionContext,
  617. IN NTSTATUS SendCompletionStatus
  618. )
  619. /*++
  620. Routine Description:
  621. This routine handles the send complete indication for asynchronous sends
  622. Arguments:
  623. pServerEntry - the server instance
  624. pCompletionContext - the context for identifying the send request
  625. SendCompletionStatus - the send completion status
  626. Return Value:
  627. STATUS_SUCCESS always ..
  628. --*/
  629. {
  630. NTSTATUS Status;
  631. PSMB_EXCHANGE pExchange;
  632. PVOID pSendBuffer = pCompletionContext;
  633. if (pCompletionContext != NULL) {
  634. // Map the MID to the associated exchange
  635. pExchange = SmbCeGetExchangeAssociatedWithBuffer(
  636. pServerEntry,
  637. pSendBuffer);
  638. if (pExchange != NULL) {
  639. // Resume the exchange which was waiting for this response
  640. RxDbgTrace(0, Dbg, ("SmbCeSendCompleteInd: Send Completion Status %lx\n",SendCompletionStatus));
  641. if (pExchange->pDispatchVector->SendCompletionHandler != NULL) {
  642. Status = SMB_EXCHANGE_DISPATCH(pExchange,
  643. SendCompletionHandler,
  644. (pExchange,
  645. pSendBuffer,
  646. SendCompletionStatus));
  647. }
  648. RxDbgTrace(0, Dbg, ("SmbCeSendCompleteInd: SMB_EXCHANGE_DISPATCH returned %lx\n",Status));
  649. SmbCeDecrementPendingSendCompleteOperationsAndFinalize(pExchange);
  650. }
  651. }
  652. return STATUS_SUCCESS;
  653. }
  654.