Source code of Windows XP (NT5)
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.

1025 lines
34 KiB

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