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.

1929 lines
61 KiB

  1. /*++
  2. Copyright (c) 1989-2001 Microsoft Corporation
  3. Module Name:
  4. tdircv.c
  5. Abstract:
  6. TDI receive event handlers
  7. TdiReceiveHandler is the only entry, which is called by TCP.
  8. TdiReceiveHandler acquires the spinlock and increase the refcount
  9. of the ConnectObject. Then it forward the control to the event
  10. handler for current receive state.
  11. The state event handler won't release the spinlock unless it's
  12. going to call functions outside our control, for example,
  13. IoCompleteionRequest and the client event handler.
  14. Author:
  15. Jiandong Ruan
  16. Revision History:
  17. --*/
  18. #include "precomp.h"
  19. #include "tdircv.tmh"
  20. #if DBG
  21. BOOL
  22. IsValidWaitingHeaderState(
  23. IN PSMB_CONNECT ConnectObject
  24. );
  25. BOOL
  26. IsValidIndicateState(
  27. IN PSMB_CONNECT ConnectObject
  28. );
  29. #endif
  30. VOID
  31. KillConnection(
  32. IN PSMB_CONNECT ConnectObject
  33. );
  34. NTSTATUS
  35. IndicateToClient(
  36. IN PSMB_DEVICE DeviceObject,
  37. IN PSMB_CONNECT ConnectObject,
  38. IN ULONG ReceiveFlags,
  39. IN LONG BytesIndicated,
  40. IN LONG BytesAvailable,
  41. OUT LONG *BytesTaken,
  42. IN PVOID Tsdu
  43. );
  44. NTSTATUS
  45. SmbNewMessage(
  46. IN PSMB_CONNECT ConnectObject,
  47. IN LONG BytesIndicated,
  48. OUT LONG *BytesTaken,
  49. IN PVOID Tsdu,
  50. OUT PIRP *Irp
  51. );
  52. NTSTATUS
  53. SmbBuildPartialMdl(
  54. PMDL SourceMdl,
  55. PMDL DestMdl,
  56. LONG Offset
  57. );
  58. NTSTATUS
  59. SmbClientRcvCompletion(
  60. IN PDEVICE_OBJECT DeviceObject,
  61. IN PIRP Irp,
  62. IN PSMB_CONNECT ConnectObject
  63. );
  64. #define TAKE(Bytes) \
  65. ASSERT((Bytes) <= BytesIndicated); \
  66. BytesIndicated -= (Bytes); \
  67. BytesAvailable -= (Bytes); \
  68. (PUCHAR)Tsdu += (Bytes); \
  69. *BytesTaken += (Bytes)
  70. #if DBG
  71. DWORD
  72. SmbGetMdlChainByteCount(
  73. IN PMDL Mdl
  74. )
  75. /*++
  76. Routine Description:
  77. This routine returns the total size of buffers described by the MDL chain.
  78. Arguments:
  79. Return Value:
  80. --*/
  81. {
  82. DWORD Size;
  83. Size = 0;
  84. while(Mdl) {
  85. Size += MmGetMdlByteCount(Mdl);
  86. Mdl = Mdl->Next;
  87. }
  88. return Size;
  89. }
  90. #endif // DBG
  91. PIRP
  92. SmbNextReceiveRequest(
  93. IN PSMB_CONNECT ConnectObject
  94. )
  95. /*++
  96. Routine Description:
  97. Get a client TDI_RECEIVE request queued in the pending list
  98. Arguments:
  99. Return Value:
  100. NULL If there is no pending receive request
  101. PIRP The client IRP pending in the RcvList
  102. --*/
  103. {
  104. PLIST_ENTRY entry;
  105. PIRP PendingIrp;
  106. KIRQL Irql;
  107. if (IsListEmpty(&ConnectObject->RcvList)) {
  108. return NULL;
  109. }
  110. entry = RemoveHeadList(&ConnectObject->RcvList);
  111. PendingIrp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
  112. IoAcquireCancelSpinLock(&Irql);
  113. IoSetCancelRoutine(PendingIrp, NULL);
  114. IoReleaseCancelSpinLock(Irql);
  115. return PendingIrp;
  116. }
  117. VOID
  118. SmbCompleteReceiveRequest(
  119. IN PSMB_CONNECT ConnectObject
  120. )
  121. /*++
  122. Routine Description:
  123. Complete the ConnectObject->ClientIrp
  124. Arguments:
  125. Return Value:
  126. --*/
  127. {
  128. PIRP ClientIrp = NULL;
  129. PIO_STACK_LOCATION IrpSp = NULL;
  130. PTDI_REQUEST_KERNEL_RECEIVE ClientRcvParams = NULL;
  131. LONG BytesReceived = 0;
  132. ASSERT (NULL != ConnectObject->ClientIrp);
  133. ASSERT (NULL != ConnectObject->ClientMdl);
  134. ASSERT (0 == ConnectObject->BytesRemaining || 0 == ConnectObject->FreeBytesInMdl);
  135. ASSERT (ConnectObject->FreeBytesInMdl >= 0);
  136. BytesReceived = ConnectObject->ClientBufferSize - ConnectObject->FreeBytesInMdl;
  137. ASSERT (BytesReceived >= 0);
  138. PUSH_LOCATION(ConnectObject, 0x200000);
  139. ClientIrp = ConnectObject->ClientIrp;
  140. ConnectObject->ClientIrp = NULL;
  141. ConnectObject->ClientMdl = NULL;
  142. IrpSp = IoGetCurrentIrpStackLocation(ClientIrp);
  143. ClientRcvParams = (PTDI_REQUEST_KERNEL_RECEIVE)&IrpSp->Parameters;
  144. if (0 == ConnectObject->BytesRemaining) {
  145. ConnectObject->StateRcvHandler = WaitingHeader;
  146. ConnectObject->HeaderBytesRcved = 0;
  147. ClientRcvParams->ReceiveFlags |= TDI_RECEIVE_ENTIRE_MESSAGE;
  148. ClientIrp->IoStatus.Status = STATUS_SUCCESS;
  149. PUSH_LOCATION(ConnectObject, 0x200010);
  150. } else {
  151. ConnectObject->StateRcvHandler = SmbPartialRcv;
  152. ClientRcvParams->ReceiveFlags &= (~TDI_RECEIVE_ENTIRE_MESSAGE);
  153. ClientIrp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
  154. PUSH_LOCATION(ConnectObject, 0x200020);
  155. }
  156. ClientIrp->IoStatus.Information = BytesReceived;
  157. ConnectObject->BytesReceived += BytesReceived;
  158. SMB_RELEASE_SPINLOCK_DPC(ConnectObject);
  159. IoCompleteRequest(ClientIrp, IO_NETWORK_INCREMENT);
  160. SMB_ACQUIRE_SPINLOCK_DPC(ConnectObject);
  161. SmbDereferenceConnect(ConnectObject, SMB_REF_RECEIVE);
  162. }
  163. NTSTATUS
  164. SmbFillIrp(
  165. IN PSMB_CONNECT ConnectObject,
  166. IN PVOID Tsdu,
  167. IN LONG BytesIndicated,
  168. OUT LONG *BytesTaken
  169. )
  170. /*++
  171. Routine Description:
  172. Arguments:
  173. Return Value:
  174. STATUS_SUCCESS if the IRP has been completed
  175. STATUS_MORE_PROCESSING_REQUIRED if the IRP hasn't been completed. More data
  176. is needed to fill the IRP.
  177. --*/
  178. {
  179. LONG BytesToCopy = 0, BytesCopied = 0;
  180. NTSTATUS status;
  181. ASSERT(BytesIndicated > 0);
  182. ASSERT(BytesIndicated <= ConnectObject->BytesRemaining);
  183. BytesToCopy = SMB_MIN(ConnectObject->FreeBytesInMdl, BytesIndicated);
  184. BytesCopied = 0;
  185. status = TdiCopyBufferToMdl(
  186. Tsdu,
  187. 0,
  188. BytesToCopy,
  189. ConnectObject->ClientMdl,
  190. ConnectObject->ClientBufferSize - ConnectObject->FreeBytesInMdl,
  191. &BytesCopied
  192. );
  193. ASSERT(status == STATUS_SUCCESS);
  194. *BytesTaken = BytesCopied;
  195. ConnectObject->FreeBytesInMdl -= BytesCopied;
  196. ConnectObject->BytesRemaining -= BytesCopied;
  197. if (ConnectObject->FreeBytesInMdl) {
  198. ASSERT (BytesIndicated == BytesCopied);
  199. }
  200. if (0 == ConnectObject->BytesRemaining || 0 == ConnectObject->FreeBytesInMdl) {
  201. ASSERTMSG("Hmm. Never see this", ConnectObject->BytesRemaining == 0);
  202. SmbCompleteReceiveRequest(ConnectObject);
  203. return STATUS_SUCCESS;
  204. }
  205. ASSERT (BytesIndicated == BytesCopied);
  206. ConnectObject->StateRcvHandler = SmbPartialRcv;
  207. ASSERT (ConnectObject->BytesInIndicate || IsValidPartialRcvState(ConnectObject));
  208. return STATUS_MORE_PROCESSING_REQUIRED;
  209. }
  210. VOID
  211. SmbPrepareReceiveIrp(
  212. IN PSMB_CONNECT ConnectObject
  213. )
  214. {
  215. NTSTATUS status;
  216. LONG RcvLength;
  217. PIRP ClientIrp = NULL;
  218. status = SmbBuildPartialMdl(
  219. ConnectObject->ClientMdl,
  220. ConnectObject->PartialMdl,
  221. ConnectObject->ClientBufferSize - ConnectObject->FreeBytesInMdl
  222. );
  223. ASSERT (STATUS_SUCCESS == status);
  224. ClientIrp = ConnectObject->ClientIrp;
  225. RcvLength = SMB_MIN(ConnectObject->BytesRemaining, ConnectObject->FreeBytesInMdl);
  226. ASSERT(RcvLength > 0);
  227. MmGetSystemAddressForMdlSafe(ConnectObject->PartialMdl, HighPagePriority);
  228. // ASSERT(ConnectObject->FreeBytesInMdl >= ConnectObject->BytesRemaining);
  229. TdiBuildReceive(
  230. ClientIrp,
  231. IoGetRelatedDeviceObject(ConnectObject->TcpContext->Connect.ConnectObject),
  232. ConnectObject->TcpContext->Connect.ConnectObject,
  233. (PVOID)SmbClientRcvCompletion,
  234. ConnectObject,
  235. ConnectObject->PartialMdl,
  236. TDI_RECEIVE_NORMAL,
  237. RcvLength
  238. );
  239. ConnectObject->StateRcvHandler = SmbPartialRcv;
  240. ASSERT (ConnectObject->BytesInIndicate || IsValidPartialRcvState(ConnectObject));
  241. }
  242. NTSTATUS
  243. IndicateToClient(
  244. IN PSMB_DEVICE DeviceObject,
  245. IN PSMB_CONNECT ConnectObject,
  246. IN ULONG ReceiveFlags,
  247. IN LONG BytesIndicated,
  248. IN LONG BytesAvailable,
  249. OUT LONG *BytesTaken,
  250. IN PVOID Tsdu
  251. )
  252. /*++
  253. Routine Description:
  254. This level indication handle the cooridination between SmbReceive and Receive
  255. Event Handler.
  256. Arguments:
  257. Return Value:
  258. --*/
  259. {
  260. NTSTATUS status;
  261. PTDI_IND_RECEIVE evReceive = NULL;
  262. PVOID RcvEvContext = NULL;
  263. PIRP ClientIrp = NULL;
  264. LONG BytesToCopy = 0, BytesCopied = 0, ClientBytesTaken = 0;
  265. PIO_STACK_LOCATION IrpSp = NULL;
  266. PTDI_REQUEST_KERNEL_RECEIVE ClientRcvParams = NULL;
  267. *BytesTaken = 0;
  268. ASSERT(ConnectObject->ClientMdl == NULL);
  269. ASSERT(ConnectObject->ClientIrp == NULL);
  270. PUSH_LOCATION(ConnectObject, 0x1000);
  271. ASSERT(BytesIndicated <= ConnectObject->BytesRemaining);
  272. ASSERT(BytesIndicated <= BytesAvailable);
  273. ASSERT(BytesAvailable <= ConnectObject->CurrentPktLength);
  274. ClientBytesTaken = 0;
  275. //
  276. // First fill pending requests if any.
  277. //
  278. while (NULL != (ClientIrp = SmbNextReceiveRequest(ConnectObject))) {
  279. PUSH_LOCATION(ConnectObject, 0x1010);
  280. BREAK_WHEN_TAKE();
  281. ConnectObject->ClientIrp = ClientIrp;
  282. ConnectObject->ClientMdl = ClientIrp->MdlAddress;
  283. IrpSp = IoGetCurrentIrpStackLocation(ClientIrp);
  284. ClientRcvParams = (PTDI_REQUEST_KERNEL_RECEIVE)&IrpSp->Parameters;
  285. ConnectObject->ClientBufferSize = (LONG)ClientRcvParams->ReceiveLength;
  286. ConnectObject->FreeBytesInMdl = ConnectObject->ClientBufferSize;
  287. if (BytesIndicated == 0) {
  288. PUSH_LOCATION(ConnectObject, 0x1020);
  289. SmbPrepareReceiveIrp(ConnectObject);
  290. return STATUS_MORE_PROCESSING_REQUIRED;
  291. }
  292. status = SmbFillIrp(ConnectObject, Tsdu, BytesIndicated, &ClientBytesTaken);
  293. TAKE(ClientBytesTaken);
  294. if (status != STATUS_SUCCESS) {
  295. ASSERT (status == STATUS_MORE_PROCESSING_REQUIRED);
  296. ASSERT (0 != ConnectObject->FreeBytesInMdl);
  297. ASSERT (IsValidPartialRcvState(ConnectObject));
  298. PUSH_LOCATION(ConnectObject, 0x1030);
  299. SmbPrepareReceiveIrp(ConnectObject);
  300. return status;
  301. }
  302. if (0 == ConnectObject->BytesRemaining) {
  303. ASSERT(0 == BytesIndicated);
  304. ASSERT (IsValidWaitingHeaderState(ConnectObject));
  305. PUSH_LOCATION(ConnectObject, 0x1040);
  306. return STATUS_SUCCESS;
  307. }
  308. ASSERT(BytesIndicated > 0);
  309. }
  310. ASSERT(BytesAvailable > 0);
  311. evReceive = ConnectObject->ClientObject->evReceive;
  312. RcvEvContext = ConnectObject->ClientObject->RcvEvContext;
  313. if (evReceive == NULL) {
  314. PUSH_LOCATION(ConnectObject, 0x1050);
  315. return STATUS_SUCCESS;
  316. }
  317. ClientBytesTaken = 0;
  318. SMB_RELEASE_SPINLOCK_DPC(ConnectObject);
  319. SmbPrint(SMB_TRACE_RECEIVE, ("Indication to the client: BytesIndicated=%d BytesAvailable=%d\n",
  320. BytesIndicated, BytesAvailable));
  321. status = (*evReceive) (
  322. RcvEvContext,
  323. ConnectObject->ClientContext,
  324. ReceiveFlags,
  325. (ULONG)BytesIndicated,
  326. (ULONG)BytesAvailable,
  327. (PULONG)&ClientBytesTaken,
  328. Tsdu,
  329. &ClientIrp
  330. );
  331. SMB_ACQUIRE_SPINLOCK_DPC(ConnectObject);
  332. if (status == STATUS_DATA_NOT_ACCEPTED) {
  333. ClientBytesTaken = 0;
  334. PUSH_LOCATION(ConnectObject, 0x1055);
  335. }
  336. //
  337. // The client could disconnect the connection after the spinlock is released
  338. //
  339. if (NULL == ConnectObject->TcpContext) {
  340. // BREAK_WHEN_TAKE();
  341. SMB_RELEASE_SPINLOCK_DPC(ConnectObject);
  342. if (status == STATUS_MORE_PROCESSING_REQUIRED && ClientIrp != NULL) {
  343. ClientIrp->IoStatus.Status = STATUS_CONNECTION_RESET;
  344. ClientIrp->IoStatus.Information = 0;
  345. IoCompleteRequest(ClientIrp, IO_NETWORK_INCREMENT);
  346. }
  347. SMB_ACQUIRE_SPINLOCK_DPC(ConnectObject);
  348. PUSH_LOCATION(ConnectObject, 0x1060);
  349. ConnectObject->ClientIrp = NULL;
  350. ConnectObject->ClientMdl = NULL;
  351. return (*BytesTaken)? STATUS_SUCCESS: STATUS_DATA_NOT_ACCEPTED;
  352. }
  353. if (ClientBytesTaken > BytesIndicated) {
  354. PUSH_LOCATION(ConnectObject, 0x1070);
  355. //
  356. // Client takes too much data, try to recover
  357. //
  358. SmbPrint(SMB_TRACE_RECEIVE, ("IndicateToClient: Client takes too much data "
  359. "Connect %p BytesTaken=%d, BytesIndicated=%d BytesAvailable=%d\n",
  360. ConnectObject, *BytesTaken, BytesIndicated, BytesAvailable));
  361. SmbTrace(SMB_TRACE_RECEIVE, ("Client takes too much data "
  362. "Connect %p BytesTaken=%d, BytesIndicated=%d BytesAvailable=%d",
  363. ConnectObject, *BytesTaken, BytesIndicated, BytesAvailable));
  364. ASSERT (0);
  365. ClientBytesTaken = BytesIndicated;
  366. }
  367. TAKE(ClientBytesTaken);
  368. ConnectObject->BytesRemaining -= ClientBytesTaken;
  369. ConnectObject->BytesReceived += ClientBytesTaken;
  370. //
  371. // Check if a whole message has been taken by the client
  372. //
  373. if (0 == ConnectObject->BytesRemaining) {
  374. ASSERT (status != STATUS_MORE_PROCESSING_REQUIRED);
  375. ASSERT(BytesIndicated == 0 && BytesAvailable == 0);
  376. ConnectObject->StateRcvHandler = WaitingHeader;
  377. ConnectObject->HeaderBytesRcved = 0;
  378. PUSH_LOCATION(ConnectObject, 0x1080);
  379. return status;
  380. }
  381. ConnectObject->StateRcvHandler = SmbPartialRcv;
  382. if (status != STATUS_MORE_PROCESSING_REQUIRED) {
  383. ASSERT (ClientIrp == NULL);
  384. PUSH_LOCATION(ConnectObject, 0x1090);
  385. SmbTrace(SMB_TRACE_RECEIVE, ("Client return %!status! for indication"
  386. "Connect %p BytesTaken=%d, BytesIndicated=%d BytesAvailable=%d",
  387. status, ConnectObject, *BytesTaken, BytesIndicated, BytesAvailable));
  388. // BREAK_WHEN_TAKE();
  389. return status;
  390. }
  391. //
  392. // This partial receive case
  393. //
  394. ASSERT (ClientIrp != NULL);
  395. SmbReferenceConnect(ConnectObject, SMB_REF_RECEIVE);
  396. PUSH_LOCATION(ConnectObject, 0x10a0);
  397. IrpSp = IoGetCurrentIrpStackLocation(ClientIrp);
  398. ClientRcvParams = (PTDI_REQUEST_KERNEL_RECEIVE)&IrpSp->Parameters;
  399. ConnectObject->ClientIrp = ClientIrp;
  400. ConnectObject->ClientMdl = ClientIrp->MdlAddress;
  401. ConnectObject->ClientBufferSize = (LONG)ClientRcvParams->ReceiveLength;
  402. ConnectObject->FreeBytesInMdl = ConnectObject->ClientBufferSize;
  403. // ASSERT(ConnectObject->FreeBytesInMdl >= ConnectObject->BytesRemaining);
  404. if (0 != BytesIndicated) {
  405. PUSH_LOCATION(ConnectObject, 0x10b0);
  406. status = SmbFillIrp(ConnectObject, Tsdu, BytesIndicated, &ClientBytesTaken);
  407. TAKE(ClientBytesTaken);
  408. if (STATUS_SUCCESS == status) {
  409. return STATUS_SUCCESS;
  410. }
  411. ASSERT (status == STATUS_MORE_PROCESSING_REQUIRED);
  412. ASSERT(0 == BytesIndicated);
  413. }
  414. SmbPrepareReceiveIrp(ConnectObject);
  415. return STATUS_MORE_PROCESSING_REQUIRED;
  416. }
  417. NTSTATUS
  418. SmbClientRcvCompletion(
  419. IN PDEVICE_OBJECT DeviceObject,
  420. IN PIRP Irp,
  421. IN PSMB_CONNECT ConnectObject
  422. )
  423. /*++
  424. Routine Description:
  425. This routine handle the completion of a client's TDI_RECEIVE request
  426. Arguments:
  427. Return Value:
  428. --*/
  429. {
  430. KIRQL Irql;
  431. LONG Size;
  432. PUSH_LOCATION(ConnectObject, 0x2000);
  433. SMB_ACQUIRE_SPINLOCK(ConnectObject, Irql);
  434. ASSERT(Irp == ConnectObject->PendingIRPs[SMB_PENDING_RECEIVE]);
  435. ASSERT(Irp == ConnectObject->ClientIrp);
  436. ConnectObject->PendingIRPs[SMB_PENDING_RECEIVE] = NULL;
  437. if (Irp->IoStatus.Status != STATUS_SUCCESS) {
  438. PUSH_LOCATION(ConnectObject, 0x2010);
  439. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p status=%!status!",
  440. ConnectObject, Irp->IoStatus.Status));
  441. ConnectObject->ClientIrp = NULL;
  442. ConnectObject->ClientMdl = NULL;
  443. KillConnection(ConnectObject);
  444. SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
  445. SmbDereferenceConnect(ConnectObject, SMB_REF_RECEIVE);
  446. return STATUS_SUCCESS;
  447. }
  448. Irp->MdlAddress = ConnectObject->ClientMdl;
  449. MmPrepareMdlForReuse(ConnectObject->PartialMdl);
  450. SmbPrint(SMB_TRACE_RECEIVE, ("RcvLength = %d\n", Irp->IoStatus.Information));
  451. Size = (LONG)(Irp->IoStatus.Information);
  452. ConnectObject->FreeBytesInMdl -= Size;
  453. ConnectObject->BytesRemaining -= Size;
  454. ConnectObject->BytesInXport -= Size;
  455. if (ConnectObject->BytesInXport < 0) {
  456. PUSH_LOCATION(ConnectObject, 0x2020);
  457. ConnectObject->BytesInXport = 0;
  458. }
  459. ASSERT (ConnectObject->BytesRemaining >= 0);
  460. ASSERT (ConnectObject->FreeBytesInMdl >= 0);
  461. ASSERT (ConnectObject->BytesInXport >= 0);
  462. ASSERT(Size <= ConnectObject->CurrentPktLength);
  463. if (ConnectObject->FreeBytesInMdl && ConnectObject->BytesRemaining) {
  464. PUSH_LOCATION(ConnectObject, 0x2030);
  465. //
  466. // In most cases, there shouldn't be no more byte in transport
  467. //
  468. ASSERT(ConnectObject->BytesInXport == 0);
  469. SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
  470. //
  471. // We still need to fill the IRP
  472. //
  473. return STATUS_MORE_PROCESSING_REQUIRED;
  474. }
  475. //
  476. // Before complete the client's IRP, bump up the RefCount
  477. //
  478. SmbReferenceConnect(ConnectObject, SMB_REF_RECEIVE);
  479. //
  480. // Complete the client's Irp
  481. //
  482. SmbCompleteReceiveRequest(ConnectObject);
  483. //
  484. // Queue DPC if necessary after complete the client's IRP.
  485. // If we do it before, there could be a race condition
  486. //
  487. // We release the SPINLOCK in SmbCompleteReceiveRequest
  488. // and if the client's completion routine lower the IRQL,
  489. // the client coulde receive out-of-order messages
  490. //
  491. if (ConnectObject->BytesRemaining == 0 && ConnectObject->BytesInXport > 0) {
  492. PUSH_LOCATION(ConnectObject, 0x2060);
  493. //
  494. // Start an DPC to get the session header
  495. //
  496. SmbQueueSessionHeaderDpc(ConnectObject);
  497. }
  498. //
  499. // The ConnectObject should be still valid since we bump up
  500. // the RefCount above
  501. //
  502. SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
  503. SmbDereferenceConnect(ConnectObject, SMB_REF_RECEIVE);
  504. return STATUS_MORE_PROCESSING_REQUIRED;
  505. }
  506. NTSTATUS
  507. SmbHeaderCompletion(
  508. IN PDEVICE_OBJECT DeviceObject,
  509. IN PIRP Irp,
  510. IN PSMB_CONNECT ConnectObject
  511. )
  512. /*++
  513. Routine Description:
  514. Arguments:
  515. Return Value:
  516. --*/
  517. {
  518. KIRQL Irql;
  519. NTSTATUS status;
  520. LONG BytesTaken, BytesRcved;
  521. PIRP NewIrp = NULL;
  522. PDEVICE_OBJECT TcpDeviceObject = NULL;
  523. PFILE_OBJECT TcpFileObject = NULL;
  524. SMB_ACQUIRE_SPINLOCK(ConnectObject, Irql);
  525. PUSH_LOCATION(ConnectObject, 0x3000);
  526. if (NULL == ConnectObject->TcpContext) {
  527. PUSH_LOCATION(ConnectObject, 0x3010);
  528. BREAK_WHEN_TAKE();
  529. goto cleanup;
  530. }
  531. ASSERT(Irp == ConnectObject->PendingIRPs[SMB_PENDING_RECEIVE]);
  532. ConnectObject->PendingIRPs[SMB_PENDING_RECEIVE] = NULL;
  533. BytesRcved = (LONG)Irp->IoStatus.Information;
  534. if ((BytesRcved + ConnectObject->HeaderBytesRcved > SMB_SESSION_HEADER_SIZE) ||
  535. (Irp->IoStatus.Status != STATUS_SUCCESS)) {
  536. PUSH_LOCATION(ConnectObject, 0x3020);
  537. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p status=%!status!",
  538. ConnectObject, Irp->IoStatus.Status));
  539. KillConnection(ConnectObject);
  540. goto cleanup;
  541. }
  542. if (ConnectObject->BytesInXport > BytesRcved) {
  543. PUSH_LOCATION(ConnectObject, 0x3040);
  544. ConnectObject->BytesInXport -= BytesRcved;
  545. } else {
  546. PUSH_LOCATION(ConnectObject, 0x3050);
  547. ConnectObject->BytesInXport = 0;
  548. }
  549. ConnectObject->HeaderBytesRcved += BytesRcved;
  550. if (ConnectObject->HeaderBytesRcved < SMB_SESSION_HEADER_SIZE) {
  551. ASSERT(ConnectObject->BytesInXport == 0);
  552. PUSH_LOCATION(ConnectObject, 0x3060);
  553. //
  554. // Wait for the transport to indicate the remaining bytes
  555. //
  556. goto cleanup;
  557. }
  558. status = SmbNewMessage(
  559. ConnectObject,
  560. 0,
  561. &BytesTaken,
  562. NULL,
  563. &NewIrp
  564. );
  565. ASSERT(BytesTaken == 0);
  566. if (ConnectObject->CurrentPktLength == 0) {
  567. // BREAK_WHEN_TAKE();
  568. PUSH_LOCATION(ConnectObject, 0x3070);
  569. ASSERT(status == STATUS_SUCCESS);
  570. if (ConnectObject->BytesInXport > 0) {
  571. // BREAK_WHEN_TAKE();
  572. PUSH_LOCATION(ConnectObject, 0x3080);
  573. SmbQueueSessionHeaderDpc(ConnectObject);
  574. }
  575. goto cleanup;
  576. }
  577. if (status != STATUS_MORE_PROCESSING_REQUIRED) {
  578. PUSH_LOCATION(ConnectObject, 0x3090);
  579. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p status=%!status!",
  580. ConnectObject, status));
  581. ASSERT(ConnectObject->ClientIrp == NULL);
  582. ASSERT(ConnectObject->ClientMdl == NULL);
  583. // ASSERT(!ConnectObject->Originator);
  584. BREAK_WHEN_TAKE();
  585. //
  586. // Client doesn't give us any IRP, let's waiting
  587. //
  588. goto cleanup;
  589. }
  590. ASSERT(IsValidPartialRcvState(ConnectObject) || IsValidIndicateState(ConnectObject));
  591. ConnectObject->PendingIRPs[SMB_PENDING_RECEIVE] = NewIrp;
  592. //
  593. // Reference the file object while we still holding the spinlock
  594. //
  595. TcpFileObject = ConnectObject->TcpContext->Connect.ConnectObject;
  596. TcpDeviceObject = IoGetRelatedDeviceObject(TcpFileObject);
  597. ObReferenceObject(TcpFileObject);
  598. SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
  599. status = IoCallDriver(TcpDeviceObject, NewIrp);
  600. ObDereferenceObject(TcpFileObject);
  601. SmbDereferenceConnect(ConnectObject, SMB_REF_RECEIVE);
  602. IoFreeMdl(Irp->MdlAddress);
  603. SmbFreeIrp(Irp);
  604. return STATUS_MORE_PROCESSING_REQUIRED;
  605. cleanup:
  606. SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
  607. SmbDereferenceConnect(ConnectObject, SMB_REF_RECEIVE);
  608. IoFreeMdl(Irp->MdlAddress);
  609. SmbFreeIrp(Irp);
  610. return STATUS_MORE_PROCESSING_REQUIRED;
  611. }
  612. NTSTATUS
  613. SmbBuildPartialMdl(
  614. PMDL SourceMdl,
  615. PMDL DestMdl,
  616. LONG Offset
  617. )
  618. {
  619. LONG TotalLength;
  620. PMDL PartialMdl;
  621. PUCHAR NewAddress;
  622. //
  623. // Find the 1st partial filled MDL
  624. //
  625. TotalLength = 0;
  626. PartialMdl = SourceMdl;
  627. do {
  628. if (TotalLength + (LONG)(MmGetMdlByteCount(PartialMdl)) > Offset) {
  629. break;
  630. }
  631. TotalLength += MmGetMdlByteCount(PartialMdl);
  632. PartialMdl = PartialMdl->Next;
  633. } while (PartialMdl);
  634. ASSERT(PartialMdl);
  635. if (PartialMdl == NULL) {
  636. return STATUS_UNSUCCESSFUL;
  637. }
  638. NewAddress = MmGetMdlVirtualAddress(PartialMdl);
  639. NewAddress += (Offset - TotalLength);
  640. IoBuildPartialMdl(PartialMdl, DestMdl, NewAddress, 0);
  641. DestMdl->Next = PartialMdl->Next;
  642. return STATUS_SUCCESS;
  643. }
  644. #ifdef NO_ZERO_BYTE_INDICATE
  645. NTSTATUS
  646. SmbClientRcvCompletionRdr(
  647. IN PDEVICE_OBJECT DeviceObject,
  648. IN PIRP Irp,
  649. IN PSMB_CONNECT ConnectObject
  650. )
  651. {
  652. KIRQL Irql;
  653. NTSTATUS status;
  654. LONG BytesTaken, RcvLength, BytesCopied;
  655. SMB_ACQUIRE_SPINLOCK(ConnectObject, Irql);
  656. ASSERT(Irp == ConnectObject->PendingIRPs[SMB_PENDING_RECEIVE]);
  657. ConnectObject->PendingIRPs[SMB_PENDING_RECEIVE] = NULL;
  658. PUSH_LOCATION(ConnectObject, 0x4000);
  659. if (Irp->IoStatus.Status != STATUS_SUCCESS) {
  660. PUSH_LOCATION(ConnectObject, 0x4010);
  661. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p status=%!status!",
  662. ConnectObject, Irp->IoStatus.Status));
  663. KillConnection(ConnectObject);
  664. goto cleanup;
  665. }
  666. ASSERT(ConnectObject->BytesRemaining == ConnectObject->CurrentPktLength);
  667. if (ConnectObject->BytesInXport > (LONG)Irp->IoStatus.Information) {
  668. ConnectObject->BytesInXport -= (LONG)Irp->IoStatus.Information;
  669. PUSH_LOCATION(ConnectObject, 0x4020);
  670. } else {
  671. ConnectObject->BytesInXport = 0;
  672. PUSH_LOCATION(ConnectObject, 0x4030);
  673. }
  674. ConnectObject->BytesInIndicate += (LONG)(Irp->IoStatus.Information);
  675. //
  676. // If we didn't get enough bytes, bail out
  677. //
  678. if (ConnectObject->BytesInIndicate < MINIMUM_RDR_BUFFER &&
  679. ConnectObject->BytesInIndicate < ConnectObject->CurrentPktLength) {
  680. ASSERT(ConnectObject->BytesInXport == 0);
  681. PUSH_LOCATION(ConnectObject, 0x4040);
  682. goto cleanup;
  683. }
  684. ConnectObject->StateRcvHandler = SmbPartialRcv;
  685. status = IndicateToClient(
  686. ConnectObject->Device,
  687. ConnectObject,
  688. TDI_RECEIVE_NORMAL | TDI_RECEIVE_ENTIRE_MESSAGE,
  689. ConnectObject->BytesInIndicate,
  690. ConnectObject->CurrentPktLength,
  691. &BytesTaken,
  692. ConnectObject->IndicateBuffer
  693. );
  694. ASSERT(BytesTaken <= ConnectObject->BytesInIndicate);
  695. ConnectObject->BytesInIndicate -= BytesTaken;
  696. ASSERT(ConnectObject->BytesInIndicate >= 0);
  697. if (BytesTaken && ConnectObject->BytesInIndicate) {
  698. PUSH_LOCATION(ConnectObject, 0x4050);
  699. RtlMoveMemory(
  700. ConnectObject->IndicateBuffer + BytesTaken,
  701. ConnectObject->IndicateBuffer,
  702. ConnectObject->BytesInIndicate
  703. );
  704. ASSERT(STATUS_SUCCESS == status || STATUS_DATA_NOT_ACCEPTED == status);
  705. }
  706. if (status != STATUS_MORE_PROCESSING_REQUIRED) {
  707. PUSH_LOCATION(ConnectObject, 0x4060);
  708. if (ConnectObject->StateRcvHandler == WaitingHeader && ConnectObject->BytesInXport > 0) {
  709. ASSERT(ConnectObject->BytesRemaining == 0);
  710. SmbQueueSessionHeaderDpc(ConnectObject);
  711. }
  712. goto cleanup;
  713. }
  714. ASSERT(IsValidPartialRcvState(ConnectObject));
  715. ConnectObject->PendingIRPs[SMB_PENDING_RECEIVE] = ConnectObject->ClientIrp;
  716. SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
  717. status = IoCallDriver(
  718. IoGetRelatedDeviceObject(ConnectObject->TcpContext->Connect.ConnectObject),
  719. ConnectObject->ClientIrp
  720. );
  721. SmbPrint(SMB_TRACE_RECEIVE, ("IoCallDriver return 0x%08lx %d of %s\n", status, __LINE__, __FILE__));
  722. SmbDereferenceConnect(ConnectObject, SMB_REF_RECEIVE);
  723. IoFreeMdl(Irp->MdlAddress);
  724. SmbFreeIrp(Irp);
  725. return STATUS_MORE_PROCESSING_REQUIRED;
  726. cleanup:
  727. SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
  728. SmbDereferenceConnect(ConnectObject, SMB_REF_RECEIVE);
  729. IoFreeMdl(Irp->MdlAddress);
  730. SmbFreeIrp(Irp);
  731. return STATUS_MORE_PROCESSING_REQUIRED;
  732. }
  733. PIRP
  734. SmbPrepareIndicateIrp(
  735. IN PSMB_CONNECT ConnectObject
  736. )
  737. {
  738. PIRP Irp = NULL;
  739. PMDL Mdl = NULL;
  740. LONG BytesToRcv = 0;
  741. ASSERT(ConnectObject->CurrentPktLength > 0);
  742. ASSERT(ConnectObject->CurrentPktLength == ConnectObject->BytesRemaining);
  743. ASSERT(ConnectObject->BytesInIndicate >= 0 && ConnectObject->BytesInIndicate < MINIMUM_RDR_BUFFER);
  744. ASSERT(ConnectObject->BytesInIndicate < ConnectObject->CurrentPktLength);
  745. BytesToRcv = SMB_MIN(MINIMUM_RDR_BUFFER - ConnectObject->BytesInIndicate,
  746. ConnectObject->CurrentPktLength - ConnectObject->BytesInIndicate);
  747. PUSH_LOCATION(ConnectObject, 0x6000);
  748. Mdl = IoAllocateMdl(
  749. ConnectObject->IndicateBuffer + ConnectObject->BytesInIndicate,
  750. BytesToRcv,
  751. FALSE,
  752. FALSE,
  753. NULL
  754. );
  755. Irp = SmbAllocIrp(ConnectObject->Device->DeviceObject.StackSize - 1);
  756. if (NULL == Mdl || NULL == Irp) {
  757. goto cleanup;
  758. }
  759. PUSH_LOCATION(ConnectObject, 0x6010);
  760. MmBuildMdlForNonPagedPool(Mdl);
  761. TdiBuildReceive(
  762. Irp,
  763. IoGetRelatedDeviceObject(ConnectObject->TcpContext->Connect.ConnectObject),
  764. ConnectObject->TcpContext->Connect.ConnectObject,
  765. (PVOID)SmbClientRcvCompletionRdr,
  766. ConnectObject,
  767. Mdl,
  768. TDI_RECEIVE_NORMAL,
  769. BytesToRcv
  770. );
  771. return Irp;
  772. cleanup:
  773. PUSH_LOCATION(ConnectObject, 0x6020);
  774. BREAK_WHEN_TAKE();
  775. if (NULL != Irp) {
  776. SmbFreeIrp(Irp);
  777. }
  778. if (NULL != Mdl) {
  779. IoFreeMdl(Mdl);
  780. }
  781. KillConnection(ConnectObject);
  782. return NULL;
  783. }
  784. #endif
  785. NTSTATUS
  786. SmbNewMessage(
  787. IN PSMB_CONNECT ConnectObject,
  788. IN LONG BytesIndicated,
  789. OUT LONG *BytesTaken,
  790. IN PVOID Tsdu,
  791. OUT PIRP *Irp
  792. )
  793. /*++
  794. Routine Description:
  795. This routine is called when we just receive a new message header
  796. Arguments:
  797. Return Value:
  798. --*/
  799. {
  800. LONG BytesToIndicate, BytesCopied, RcvLength;
  801. NTSTATUS status;
  802. *BytesTaken = 0;
  803. *Irp = NULL;
  804. ASSERT(ConnectObject->HeaderBytesRcved == SMB_SESSION_HEADER_SIZE);
  805. ConnectObject->HeaderBytesRcved = 0;
  806. ConnectObject->CurrentPktLength = (LONG)((htonl(ConnectObject->SmbHeader.Length)) & SMB_HEADER_LENGTH_MASK);
  807. ConnectObject->BytesRemaining = ConnectObject->CurrentPktLength;
  808. PUSH_LOCATION(ConnectObject, 0x7000);
  809. if (ConnectObject->CurrentPktLength == 0) {
  810. PUSH_LOCATION(ConnectObject, 0x7010);
  811. return STATUS_SUCCESS;
  812. }
  813. BytesToIndicate = SMB_MIN(BytesIndicated, ConnectObject->CurrentPktLength);
  814. //
  815. // Don't indicate ZERO byte to srv.sys. Like RDR, srv could access beyond
  816. // the indicated area in some corner case!!!
  817. //
  818. #if 0
  819. if (BytesToIndicate < ConnectObject->CurrentPktLength &&
  820. ConnectObject->Originator && BytesToIndicate < MINIMUM_RDR_BUFFER) {
  821. #endif
  822. if (BytesToIndicate < ConnectObject->CurrentPktLength &&
  823. BytesToIndicate < MINIMUM_RDR_BUFFER) {
  824. //
  825. // We need to indicate at least 128 bytes to RDR
  826. //
  827. ConnectObject->BytesInIndicate = 0;
  828. *Irp = SmbPrepareIndicateIrp(ConnectObject);
  829. if (NULL != *Irp) {
  830. ConnectObject->StateRcvHandler = Indicate;
  831. SmbReferenceConnect(ConnectObject, SMB_REF_RECEIVE);
  832. ASSERT(IsValidIndicateState(ConnectObject));
  833. PUSH_LOCATION(ConnectObject, 0x7030);
  834. return STATUS_MORE_PROCESSING_REQUIRED;
  835. } else {
  836. PUSH_LOCATION(ConnectObject, 0x7040);
  837. ASSERT(NULL == ConnectObject->TcpContext);
  838. return STATUS_DATA_NOT_ACCEPTED;
  839. }
  840. }
  841. ConnectObject->StateRcvHandler = SmbPartialRcv;
  842. status = IndicateToClient(
  843. ConnectObject->Device,
  844. ConnectObject,
  845. TDI_RECEIVE_NORMAL | TDI_RECEIVE_ENTIRE_MESSAGE,
  846. BytesToIndicate,
  847. ConnectObject->CurrentPktLength,
  848. BytesTaken,
  849. Tsdu
  850. );
  851. ASSERT(*BytesTaken <= BytesToIndicate);
  852. if (status != STATUS_MORE_PROCESSING_REQUIRED) {
  853. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p status=%!status!",
  854. ConnectObject, status));
  855. ASSERT(ConnectObject->ClientIrp == NULL);
  856. ASSERT(ConnectObject->ClientMdl == NULL);
  857. ASSERTMSG("Client doesn't return an IRP",
  858. status == STATUS_DATA_NOT_ACCEPTED ||
  859. ConnectObject->BytesRemaining == 0 ||
  860. ConnectObject->TcpContext == NULL);
  861. PUSH_LOCATION(ConnectObject, 0x7050);
  862. return status;
  863. }
  864. ASSERT (*BytesTaken == BytesToIndicate);
  865. ASSERT(IsValidPartialRcvState(ConnectObject));
  866. *Irp = ConnectObject->ClientIrp;
  867. PUSH_LOCATION(ConnectObject, 0x7080);
  868. return STATUS_MORE_PROCESSING_REQUIRED;
  869. }
  870. #if DBG
  871. BOOL
  872. IsValidIndicateState(
  873. IN PSMB_CONNECT ConnectObject
  874. )
  875. {
  876. if (ConnectObject->BytesRemaining <= 0 || ConnectObject->BytesRemaining != ConnectObject->CurrentPktLength) {
  877. SmbPrint(SMB_TRACE_RECEIVE, ("IsValidIndicateState: Connect %p BytesRemaining=%d, PktLength=%d\n",
  878. ConnectObject, ConnectObject->BytesRemaining, ConnectObject->CurrentPktLength));
  879. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p BytesRemaining=%d, PktLength=%d",
  880. ConnectObject, ConnectObject->BytesRemaining, ConnectObject->CurrentPktLength));
  881. return FALSE;
  882. }
  883. if (ConnectObject->BytesInIndicate < 0 || ConnectObject->BytesInIndicate >= MINIMUM_RDR_BUFFER) {
  884. SmbPrint(SMB_TRACE_RECEIVE, ("IsValidIndicateState: Connect %p BytesInIndicate=%d\n",
  885. ConnectObject, ConnectObject->BytesInIndicate));
  886. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p BytesInIndicate=%d",
  887. ConnectObject, ConnectObject->BytesInIndicate));
  888. return FALSE;
  889. }
  890. if (NULL != ConnectObject->ClientIrp || NULL != ConnectObject->ClientMdl) {
  891. SmbPrint(SMB_TRACE_RECEIVE, ("IsValidIndicateState: Connect %p ClientIrp=%p, ClientMdl=%p\n",
  892. ConnectObject, ConnectObject->ClientIrp, ConnectObject->ClientMdl));
  893. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p ClientIrp=%p, ClientMdl=%p",
  894. ConnectObject, ConnectObject->ClientIrp, ConnectObject->ClientMdl));
  895. return FALSE;
  896. }
  897. if (ConnectObject->StateRcvHandler != Indicate) {
  898. SmbPrint(SMB_TRACE_RECEIVE, ("IsValidIndicateState: Connect %p Wrong handler\n", ConnectObject));
  899. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p Wrong handler", ConnectObject));
  900. return FALSE;
  901. }
  902. return TRUE;
  903. }
  904. #endif
  905. NTSTATUS
  906. Indicate(
  907. IN PSMB_DEVICE DeviceObject,
  908. IN PSMB_CONNECT ConnectObject,
  909. IN ULONG ReceiveFlags,
  910. IN LONG BytesIndicated,
  911. IN LONG BytesAvailable,
  912. OUT LONG *BytesTaken,
  913. IN PVOID Tsdu,
  914. OUT PIRP *Irp
  915. )
  916. {
  917. PIRP ClientIrp = NULL;
  918. PTDI_REQUEST_KERNEL_RECEIVE ClientRcvParams = NULL;
  919. PIO_STACK_LOCATION IrpSp = NULL;
  920. NTSTATUS status;
  921. LONG BytesToCopy = 0, BytesCopied = 0;
  922. LONG BytesToRcv = 0, RcvLength = 0;
  923. LONG ClientBytesTaken = 0;
  924. PUSH_LOCATION(ConnectObject, 0x8000);
  925. ASSERT(IsValidIndicateState(ConnectObject));
  926. SmbPrint(SMB_TRACE_RECEIVE, ("Indicate: Connect %p Indicate=%d Available=%d\n",
  927. ConnectObject, BytesIndicated, BytesAvailable));
  928. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p Indicate=%d Available=%d",
  929. ConnectObject, BytesIndicated, BytesAvailable));
  930. *BytesTaken = 0;
  931. *Irp = NULL;
  932. ASSERT (ConnectObject->BytesInIndicate <= ConnectObject->CurrentPktLength);
  933. BytesToCopy = SMB_MIN(MINIMUM_RDR_BUFFER - ConnectObject->BytesInIndicate,
  934. ConnectObject->CurrentPktLength - ConnectObject->BytesInIndicate);
  935. BytesToCopy = SMB_MIN(BytesToCopy, BytesIndicated);
  936. RtlCopyMemory(ConnectObject->IndicateBuffer + ConnectObject->BytesInIndicate, Tsdu, BytesToCopy);
  937. TAKE(BytesToCopy);
  938. ConnectObject->BytesInIndicate += BytesToCopy;
  939. if (ConnectObject->BytesInIndicate < MINIMUM_RDR_BUFFER &&
  940. ConnectObject->BytesInIndicate < ConnectObject->CurrentPktLength) {
  941. PUSH_LOCATION(ConnectObject, 0x8010);
  942. //
  943. // After taking all the indicated bytes, the buffer is still not filled
  944. //
  945. ASSERT(BytesIndicated == 0);
  946. ConnectObject->BytesInXport = BytesAvailable;
  947. if (BytesAvailable > 0) {
  948. PUSH_LOCATION(ConnectObject, 0x8020);
  949. *Irp = SmbPrepareIndicateIrp(ConnectObject);
  950. if (NULL != *Irp) {
  951. PUSH_LOCATION(ConnectObject, 0x8030);
  952. SmbReferenceConnect(ConnectObject, SMB_REF_RECEIVE);
  953. return STATUS_MORE_PROCESSING_REQUIRED;
  954. } else {
  955. PUSH_LOCATION(ConnectObject, 0x8040);
  956. SmbReferenceConnect(ConnectObject, SMB_REF_RECEIVE);
  957. ASSERT(NULL == ConnectObject->TcpContext);
  958. return STATUS_DATA_NOT_ACCEPTED;
  959. }
  960. }
  961. return STATUS_SUCCESS;
  962. }
  963. //
  964. // We get a full message or at least 128 bytes
  965. //
  966. ASSERT (ConnectObject->BytesInIndicate == MINIMUM_RDR_BUFFER ||
  967. ConnectObject->BytesInIndicate == ConnectObject->CurrentPktLength);
  968. status = IndicateToClient(
  969. ConnectObject->Device,
  970. ConnectObject,
  971. TDI_RECEIVE_NORMAL | TDI_RECEIVE_ENTIRE_MESSAGE,
  972. ConnectObject->BytesInIndicate,
  973. ConnectObject->CurrentPktLength,
  974. &ClientBytesTaken,
  975. ConnectObject->IndicateBuffer
  976. );
  977. ASSERT(ClientBytesTaken <= ConnectObject->BytesInIndicate);
  978. ConnectObject->BytesInIndicate -= ClientBytesTaken;
  979. if (ConnectObject->BytesInIndicate) {
  980. RtlMoveMemory(
  981. ConnectObject->IndicateBuffer + ClientBytesTaken,
  982. ConnectObject->IndicateBuffer,
  983. ConnectObject->BytesInIndicate
  984. );
  985. PUSH_LOCATION(ConnectObject, 0x8050);
  986. ASSERT(STATUS_DATA_NOT_ACCEPTED == status || STATUS_SUCCESS == status);
  987. }
  988. if (status != STATUS_MORE_PROCESSING_REQUIRED) {
  989. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p status=%!status!",
  990. ConnectObject, status));
  991. PUSH_LOCATION(ConnectObject, 0x8060);
  992. return status;
  993. }
  994. ASSERT(IsValidPartialRcvState(ConnectObject));
  995. PUSH_LOCATION(ConnectObject, 0x8070);
  996. *Irp = ConnectObject->ClientIrp;
  997. return STATUS_MORE_PROCESSING_REQUIRED;
  998. }
  999. #if DBG
  1000. BOOL
  1001. IsValidPartialRcvState(
  1002. IN PSMB_CONNECT ConnectObject
  1003. )
  1004. {
  1005. if (ConnectObject->BytesInIndicate != 0) {
  1006. SmbPrint(SMB_TRACE_RECEIVE, ("IsValidPartialRcvState: Connect %p BytesInIndicate=%d\n",
  1007. ConnectObject, ConnectObject->BytesInIndicate));
  1008. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p BytesInIndicate=%d",
  1009. ConnectObject, ConnectObject->BytesInIndicate));
  1010. return FALSE;
  1011. }
  1012. if (ConnectObject->BytesRemaining <= 0 || ConnectObject->BytesRemaining > ConnectObject->CurrentPktLength) {
  1013. SmbPrint(SMB_TRACE_RECEIVE, ("IsValidPartialRcvState: Connect %p BytesRemaining=%d, PktLength=%d\n",
  1014. ConnectObject, ConnectObject->BytesRemaining, ConnectObject->CurrentPktLength));
  1015. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p BytesRemaining=%d, PktLength=%d",
  1016. ConnectObject, ConnectObject->BytesRemaining, ConnectObject->CurrentPktLength));
  1017. return FALSE;
  1018. }
  1019. if (NULL == ConnectObject->ClientIrp || NULL == ConnectObject->ClientMdl) {
  1020. SmbPrint(SMB_TRACE_RECEIVE, ("IsValidPartialRcvState: Connect %p ClientIrp=%p, ClientMdl=%p\n",
  1021. ConnectObject, ConnectObject->ClientIrp, ConnectObject->ClientMdl));
  1022. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p ClientIrp=%p, ClientMdl=%p",
  1023. ConnectObject, ConnectObject->ClientIrp, ConnectObject->ClientMdl));
  1024. return FALSE;
  1025. }
  1026. /*
  1027. if (ConnectObject->FreeBytesInMdl < ConnectObject->BytesRemaining) {
  1028. SmbPrint(SMB_TRACE_RECEIVE, ("IsValidPartialRcvState: Connect %p BytesRemaining=%d, FreeBytesInMdl=%d\n",
  1029. ConnectObject, ConnectObject->BytesRemaining, ConnectObject->FreeBytesInMdl));
  1030. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p BytesRemaining=%d, FreeBytesInMdl=%d",
  1031. ConnectObject, ConnectObject->BytesRemaining, ConnectObject->FreeBytesInMdl));
  1032. return FALSE;
  1033. }
  1034. */
  1035. if (ConnectObject->StateRcvHandler != SmbPartialRcv) {
  1036. SmbPrint(SMB_TRACE_RECEIVE, ("IsValidPartialRcvState: Connect %p Wrong handler\n", ConnectObject));
  1037. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p Wrong handler", ConnectObject));
  1038. return FALSE;
  1039. }
  1040. if (ConnectObject->CurrentPktLength - ConnectObject->BytesRemaining <
  1041. ConnectObject->ClientBufferSize - ConnectObject->FreeBytesInMdl) {
  1042. SmbPrint(SMB_TRACE_RECEIVE, ("IsValidPartialRcvState: Connect %p BytesRcved=%d BytesCopiedInMdl=%d\n",
  1043. ConnectObject, ConnectObject->CurrentPktLength - ConnectObject->BytesRemaining,
  1044. ConnectObject->ClientBufferSize - ConnectObject->FreeBytesInMdl));
  1045. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p BytesRcved=%d BytesCopiedInMdl=%d",
  1046. ConnectObject, ConnectObject->CurrentPktLength - ConnectObject->BytesRemaining,
  1047. ConnectObject->ClientBufferSize - ConnectObject->FreeBytesInMdl));
  1048. return FALSE;
  1049. }
  1050. return TRUE;
  1051. }
  1052. #endif
  1053. NTSTATUS
  1054. SmbPartialRcv(
  1055. IN PSMB_DEVICE DeviceObject,
  1056. IN PSMB_CONNECT ConnectObject,
  1057. IN ULONG ReceiveFlags,
  1058. IN LONG BytesIndicated,
  1059. IN LONG BytesAvailable,
  1060. OUT LONG *BytesTaken,
  1061. IN PVOID Tsdu,
  1062. OUT PIRP *Irp
  1063. )
  1064. {
  1065. PIRP ClientIrp = NULL;
  1066. PTDI_REQUEST_KERNEL_RECEIVE ClientRcvParams = NULL;
  1067. PIO_STACK_LOCATION IrpSp = NULL;
  1068. LONG BytesToCopy = 0, BytesCopied = 0;
  1069. NTSTATUS status;
  1070. PLIST_ENTRY entry = NULL;
  1071. PUSH_LOCATION(ConnectObject, 0x9000);
  1072. *BytesTaken = 0;
  1073. *Irp = NULL;
  1074. if (ConnectObject->ClientIrp == NULL || ConnectObject->ClientMdl == NULL) {
  1075. PUSH_LOCATION(ConnectObject, 0x9010);
  1076. return STATUS_SUCCESS;
  1077. }
  1078. ASSERT(IsValidPartialRcvState(ConnectObject));
  1079. SmbPrint(SMB_TRACE_RECEIVE, ("PartialRcv: Connect %p Indicate=%d Available=%d\n",
  1080. ConnectObject, BytesIndicated, BytesAvailable));
  1081. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p Indicate=%d Available=%d",
  1082. ConnectObject, BytesIndicated, BytesAvailable));
  1083. while(1) {
  1084. ClientIrp = ConnectObject->ClientIrp;
  1085. BytesToCopy = SMB_MIN(ConnectObject->BytesRemaining, BytesIndicated);
  1086. BytesToCopy = SMB_MIN(BytesToCopy, ConnectObject->FreeBytesInMdl);
  1087. status = TdiCopyBufferToMdl(
  1088. Tsdu,
  1089. 0,
  1090. BytesToCopy,
  1091. ConnectObject->ClientMdl,
  1092. ConnectObject->ClientBufferSize - ConnectObject->FreeBytesInMdl,
  1093. &BytesCopied
  1094. );
  1095. ASSERT(status == STATUS_SUCCESS);
  1096. TAKE(BytesCopied);
  1097. ConnectObject->BytesRemaining -= BytesCopied;
  1098. ConnectObject->FreeBytesInMdl -= BytesCopied;
  1099. if (ConnectObject->BytesRemaining != 0 && ConnectObject->FreeBytesInMdl != 0) {
  1100. PUSH_LOCATION(ConnectObject, 0x9020);
  1101. break;
  1102. }
  1103. ConnectObject->BytesInIndicate = 0;
  1104. SmbCompleteReceiveRequest(ConnectObject);
  1105. if (ConnectObject->BytesRemaining == 0) {
  1106. //
  1107. // Return if a full message
  1108. //
  1109. ASSERT (ConnectObject->StateRcvHandler == WaitingHeader);
  1110. PUSH_LOCATION(ConnectObject, 0x9050);
  1111. return STATUS_SUCCESS;
  1112. }
  1113. ClientIrp = SmbNextReceiveRequest(ConnectObject);
  1114. if (NULL == ClientIrp) {
  1115. PUSH_LOCATION(ConnectObject, 0x9060);
  1116. return STATUS_SUCCESS;
  1117. }
  1118. ConnectObject->ClientIrp = ClientIrp;
  1119. ConnectObject->ClientMdl = ClientIrp->MdlAddress;
  1120. ASSERT(ConnectObject->ClientMdl == NULL);
  1121. IrpSp = IoGetCurrentIrpStackLocation(ClientIrp);
  1122. ClientRcvParams = (PTDI_REQUEST_KERNEL_RECEIVE)&IrpSp->Parameters;
  1123. ConnectObject->ClientBufferSize = (LONG)ClientRcvParams->ReceiveLength;
  1124. ConnectObject->FreeBytesInMdl = ConnectObject->ClientBufferSize;
  1125. PUSH_LOCATION(ConnectObject, 0x9070);
  1126. }
  1127. ASSERT(BytesIndicated == 0);
  1128. ASSERT(BytesAvailable >= 0);
  1129. ConnectObject->BytesInXport = BytesAvailable;
  1130. ASSERT(IsValidPartialRcvState(ConnectObject));
  1131. if (BytesAvailable == 0) {
  1132. PUSH_LOCATION(ConnectObject, 0x9080);
  1133. return STATUS_SUCCESS;
  1134. }
  1135. SmbPrepareReceiveIrp(ConnectObject);
  1136. *Irp = ConnectObject->ClientIrp;
  1137. PUSH_LOCATION(ConnectObject, 0x9090);
  1138. return STATUS_MORE_PROCESSING_REQUIRED;
  1139. }
  1140. #if DBG
  1141. BOOL
  1142. IsValidWaitingHeaderState(
  1143. IN PSMB_CONNECT ConnectObject
  1144. )
  1145. /*++
  1146. Routine Description:
  1147. Teat if the invariant for WaitingHeader state is true or not
  1148. Arguments:
  1149. Return Value:
  1150. --*/
  1151. {
  1152. if (ConnectObject->BytesRemaining != 0) {
  1153. SmbPrint(SMB_TRACE_RECEIVE, ("IsValidWaitingHeaderState: Connect %p BytesRemaining=%d, PktLength=%d\n",
  1154. ConnectObject, ConnectObject->BytesRemaining, ConnectObject->CurrentPktLength));
  1155. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p BytesRemaining=%d, PktLength=%d",
  1156. ConnectObject, ConnectObject->BytesRemaining, ConnectObject->CurrentPktLength));
  1157. return FALSE;
  1158. }
  1159. if (ConnectObject->BytesInIndicate != 0) {
  1160. SmbPrint(SMB_TRACE_RECEIVE, ("IsValidWaitingHeaderState: Connect %p BytesInIndicate=%d\n",
  1161. ConnectObject, ConnectObject->BytesInIndicate));
  1162. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p BytesInIndicate=%d",
  1163. ConnectObject, ConnectObject->BytesInIndicate));
  1164. return FALSE;
  1165. }
  1166. if (NULL != ConnectObject->ClientIrp || NULL != ConnectObject->ClientMdl) {
  1167. SmbPrint(SMB_TRACE_RECEIVE, ("IsValidWaitingHeaderState: Connect %p ClientIrp=%p, ClientMdl=%p\n",
  1168. ConnectObject, ConnectObject->ClientIrp, ConnectObject->ClientMdl));
  1169. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p ClientIrp=%p, ClientMdl=%p",
  1170. ConnectObject, ConnectObject->ClientIrp, ConnectObject->ClientMdl));
  1171. return FALSE;
  1172. }
  1173. if (ConnectObject->StateRcvHandler != WaitingHeader) {
  1174. SmbPrint(SMB_TRACE_RECEIVE, ("IsValidWaitingHeaderState: Connect %p Wrong handler\n",
  1175. ConnectObject));
  1176. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p Wrong handler", ConnectObject));
  1177. return FALSE;
  1178. }
  1179. if (ConnectObject->HeaderBytesRcved >= SMB_SESSION_HEADER_SIZE ||
  1180. ConnectObject->HeaderBytesRcved < 0) {
  1181. SmbPrint(SMB_TRACE_RECEIVE, ("IsValidWaitingHeaderState: Connect %p HeaderBytesRcved=%d\n",
  1182. ConnectObject, ConnectObject->HeaderBytesRcved));
  1183. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p HeaderBytesRcved=%d",
  1184. ConnectObject, ConnectObject->HeaderBytesRcved));
  1185. return FALSE;
  1186. }
  1187. return TRUE;
  1188. }
  1189. #endif
  1190. PIRP __inline
  1191. SmbPrepareSessionHeaderIrp(
  1192. IN PSMB_CONNECT ConnectObject
  1193. )
  1194. {
  1195. PMDL Mdl = NULL;
  1196. PIRP Irp = NULL;
  1197. NTSTATUS status = STATUS_SUCCESS;
  1198. ASSERT (ConnectObject->HeaderBytesRcved >= 0);
  1199. ASSERT (ConnectObject->HeaderBytesRcved < SMB_SESSION_HEADER_SIZE);
  1200. PUSH_LOCATION(ConnectObject, 0xa010);
  1201. Mdl = IoAllocateMdl(
  1202. ((PUCHAR)(&ConnectObject->SmbHeader)) + ConnectObject->HeaderBytesRcved,
  1203. SMB_SESSION_HEADER_SIZE - ConnectObject->HeaderBytesRcved,
  1204. FALSE,
  1205. FALSE,
  1206. NULL
  1207. );
  1208. Irp = SmbAllocIrp(ConnectObject->Device->DeviceObject.StackSize - 1);
  1209. if (NULL == Mdl || NULL == Irp) {
  1210. goto cleanup;
  1211. }
  1212. PUSH_LOCATION(ConnectObject, 0xa020);
  1213. MmBuildMdlForNonPagedPool(Mdl);
  1214. TdiBuildReceive(
  1215. Irp,
  1216. IoGetRelatedDeviceObject(ConnectObject->TcpContext->Connect.ConnectObject),
  1217. ConnectObject->TcpContext->Connect.ConnectObject,
  1218. SmbHeaderCompletion,
  1219. ConnectObject,
  1220. Mdl,
  1221. TDI_RECEIVE_NORMAL,
  1222. SMB_SESSION_HEADER_SIZE - ConnectObject->HeaderBytesRcved
  1223. );
  1224. return Irp;
  1225. cleanup:
  1226. PUSH_LOCATION(ConnectObject, 0xa030);
  1227. BREAK_WHEN_TAKE();
  1228. if (NULL != Irp) {
  1229. SmbFreeIrp(Irp);
  1230. }
  1231. if (NULL != Mdl) {
  1232. IoFreeMdl(Mdl);
  1233. }
  1234. KillConnection(ConnectObject);
  1235. return NULL;
  1236. }
  1237. NTSTATUS
  1238. WaitingHeader(
  1239. IN PSMB_DEVICE DeviceObject,
  1240. IN PSMB_CONNECT ConnectObject,
  1241. IN ULONG ReceiveFlags,
  1242. IN LONG BytesIndicated,
  1243. IN LONG BytesAvailable,
  1244. OUT LONG *BytesTaken,
  1245. IN PVOID Tsdu,
  1246. OUT PIRP *Irp
  1247. )
  1248. {
  1249. LONG ClientBytesTaken = 0;
  1250. PIRP ClientIrp = NULL;
  1251. LONG BytesToCopy;
  1252. NTSTATUS status;
  1253. PUSH_LOCATION(ConnectObject, 0xb000);
  1254. ASSERT(IsValidWaitingHeaderState(ConnectObject));
  1255. SmbPrint(SMB_TRACE_RECEIVE, ("WaitingHeader: Connect %p Indicate=%d Available=%d\n",
  1256. ConnectObject, BytesIndicated, BytesAvailable));
  1257. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p Indicate=%d Available=%d",
  1258. ConnectObject, BytesIndicated, BytesAvailable));
  1259. *BytesTaken = 0;
  1260. *Irp = NULL;
  1261. ASSERT(IsValidWaitingHeaderState(ConnectObject));
  1262. BytesToCopy = SMB_MIN((LONG)SMB_SESSION_HEADER_SIZE-ConnectObject->HeaderBytesRcved,
  1263. BytesIndicated);
  1264. if (BytesToCopy > 0) {
  1265. PUSH_LOCATION(ConnectObject, 0xb020);
  1266. //
  1267. // A new message
  1268. //
  1269. RtlCopyMemory(
  1270. (PUCHAR)(&ConnectObject->SmbHeader) + ConnectObject->HeaderBytesRcved,
  1271. Tsdu,
  1272. BytesToCopy
  1273. );
  1274. TAKE(BytesToCopy);
  1275. ConnectObject->HeaderBytesRcved += BytesToCopy;
  1276. ASSERT(ConnectObject->HeaderBytesRcved <= SMB_SESSION_HEADER_SIZE);
  1277. if (ConnectObject->HeaderBytesRcved == SMB_SESSION_HEADER_SIZE) {
  1278. status = SmbNewMessage(
  1279. ConnectObject,
  1280. BytesIndicated,
  1281. &ClientBytesTaken,
  1282. Tsdu,
  1283. &ClientIrp
  1284. );
  1285. ASSERT(ClientBytesTaken <= BytesIndicated);
  1286. TAKE(ClientBytesTaken);
  1287. ConnectObject->BytesInXport = BytesAvailable;
  1288. if (status == STATUS_MORE_PROCESSING_REQUIRED) {
  1289. PUSH_LOCATION(ConnectObject, 0xb030);
  1290. ASSERT(ClientIrp);
  1291. *Irp = ClientIrp;
  1292. return STATUS_MORE_PROCESSING_REQUIRED;
  1293. }
  1294. if (status != STATUS_SUCCESS) {
  1295. PUSH_LOCATION(ConnectObject, 0xb040);
  1296. // BREAK_WHEN_TAKE();
  1297. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p status=%!status!",
  1298. ConnectObject, status));
  1299. return status;
  1300. }
  1301. ASSERT(ClientBytesTaken == ConnectObject->CurrentPktLength || 0 == BytesIndicated);
  1302. ASSERT(IsValidWaitingHeaderState(ConnectObject) || IsValidIndicateState(ConnectObject));
  1303. return status;
  1304. }
  1305. }
  1306. ASSERT(BytesIndicated == 0);
  1307. ASSERT(ConnectObject->HeaderBytesRcved < SMB_SESSION_HEADER_SIZE);
  1308. if (BytesAvailable > 0) {
  1309. PUSH_LOCATION(ConnectObject, 0xb050);
  1310. ConnectObject->BytesInXport = BytesAvailable;
  1311. *Irp = SmbPrepareSessionHeaderIrp(ConnectObject);
  1312. if (*Irp) {
  1313. PUSH_LOCATION(ConnectObject, 0xb060);
  1314. SmbReferenceConnect(ConnectObject, SMB_REF_RECEIVE);
  1315. return STATUS_MORE_PROCESSING_REQUIRED;
  1316. } else {
  1317. PUSH_LOCATION(ConnectObject, 0xb070);
  1318. return STATUS_DATA_NOT_ACCEPTED;
  1319. }
  1320. }
  1321. ASSERT(BytesAvailable == 0);
  1322. return STATUS_SUCCESS;
  1323. }
  1324. NTSTATUS
  1325. SmbTdiReceiveHandler (
  1326. IN PSMB_DEVICE DeviceObject,
  1327. IN PSMB_TCP_CONNECT TcpConnect,
  1328. IN ULONG ReceiveFlags,
  1329. IN LONG BytesIndicated,
  1330. IN LONG BytesAvailable,
  1331. OUT LONG *BytesTaken,
  1332. IN PVOID Tsdu,
  1333. OUT PIRP *Irp
  1334. )
  1335. /*++
  1336. Routine Description:
  1337. This is the TDI receive event handler we register with TCP.
  1338. Arguments:
  1339. Return Value:
  1340. --*/
  1341. {
  1342. PSMB_CONNECT ConnectObject;
  1343. KIRQL Irql;
  1344. NTSTATUS status = STATUS_SUCCESS;
  1345. *BytesTaken = 0;
  1346. *Irp = NULL;
  1347. if (BytesAvailable == 0) {
  1348. return STATUS_SUCCESS;
  1349. }
  1350. //
  1351. // Reference the ConnectObject
  1352. //
  1353. SMB_ACQUIRE_SPINLOCK(&SmbCfg, Irql);
  1354. ConnectObject = TcpConnect->UpperConnect;
  1355. if (NULL == ConnectObject) {
  1356. SMB_RELEASE_SPINLOCK(&SmbCfg, Irql);
  1357. return STATUS_DATA_NOT_ACCEPTED;
  1358. }
  1359. SmbReferenceConnect(ConnectObject, SMB_REF_RECEIVE);
  1360. SMB_RELEASE_SPINLOCK_DPC(&SmbCfg);
  1361. SmbPrint(SMB_TRACE_RECEIVE, ("TdiReceiveHandler: Connect %p Indicate=%d Available=%d\n",
  1362. ConnectObject, BytesIndicated, BytesAvailable));
  1363. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p Indicate=%d Available=%d",
  1364. ConnectObject, BytesIndicated, BytesAvailable));
  1365. //
  1366. // Access is synchronized through the spinlock. We won't release the
  1367. // spinlock unless we'll call IoCompleteRequest or Client's event
  1368. // handler
  1369. //
  1370. SMB_ACQUIRE_SPINLOCK_DPC(ConnectObject);
  1371. PUSH_LOCATION(ConnectObject, 0xc000);
  1372. if (ConnectObject->State != SMB_CONNECTED) {
  1373. // ASSERT(0);
  1374. PUSH_LOCATION(ConnectObject, 0xc010);
  1375. SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
  1376. SmbDereferenceConnect(ConnectObject, SMB_REF_RECEIVE);
  1377. return STATUS_DATA_NOT_ACCEPTED;
  1378. }
  1379. //
  1380. // An indication comes in while we have an IRP in TCP
  1381. //
  1382. if (ConnectObject->PendingIRPs[SMB_PENDING_RECEIVE]) {
  1383. BREAK_WHEN_TAKE();
  1384. //
  1385. // This might happen if the DPC routine was called
  1386. // The SmbHeaderDpc release the spin lock before calling IoCallDriver.
  1387. // Just in between, we get an indication!!!
  1388. //
  1389. ASSERT(ConnectObject->DpcRequestQueued);
  1390. PUSH_LOCATION(ConnectObject, 0xc020);
  1391. ConnectObject->BytesInXport = BytesAvailable;
  1392. SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
  1393. SmbDereferenceConnect(ConnectObject, SMB_REF_RECEIVE);
  1394. return STATUS_DATA_NOT_ACCEPTED;
  1395. }
  1396. ASSERT(ConnectObject->DpcRequestQueued || ConnectObject->BytesInXport == 0);
  1397. SmbRemoveSessionHeaderDpc(ConnectObject);
  1398. while (BytesAvailable > 0) {
  1399. LONG ClientBytesTaken;
  1400. PIRP ClientIrp;
  1401. ClientIrp = NULL;
  1402. ClientBytesTaken = 0;
  1403. status = (*ConnectObject->StateRcvHandler)(
  1404. DeviceObject,
  1405. ConnectObject,
  1406. ReceiveFlags,
  1407. BytesIndicated,
  1408. BytesAvailable,
  1409. &ClientBytesTaken,
  1410. Tsdu,
  1411. &ClientIrp
  1412. );
  1413. ASSERT(ClientBytesTaken <= BytesIndicated);
  1414. TAKE(ClientBytesTaken);
  1415. SmbPrint(SMB_TRACE_RECEIVE, ("TdiReceiveHandler: Connect %p Indicate=%d Available=%d"
  1416. " Taken=%d ClientTaken=%d status=0x%08lx\n",
  1417. ConnectObject, BytesIndicated, BytesAvailable, *BytesTaken, ClientBytesTaken, status));
  1418. SmbTrace(SMB_TRACE_RECEIVE, ("Connect %p Indicate=%d Available=%d"
  1419. " Taken=%d ClientTaken=%d status=%!status!",
  1420. ConnectObject, BytesIndicated, BytesAvailable, *BytesTaken, ClientBytesTaken, status));
  1421. if (status == STATUS_MORE_PROCESSING_REQUIRED) {
  1422. PUSH_LOCATION(ConnectObject, 0xc030);
  1423. ASSERT(ClientIrp);
  1424. *Irp = ClientIrp;
  1425. goto return_IRP_Exit;
  1426. }
  1427. if (status == STATUS_DATA_NOT_ACCEPTED || (status == STATUS_SUCCESS && ClientBytesTaken == 0)) {
  1428. PUSH_LOCATION(ConnectObject, 0xc040);
  1429. goto take_some_exit;
  1430. }
  1431. ASSERT(status == STATUS_SUCCESS);
  1432. PUSH_LOCATION(ConnectObject, 0xc050);
  1433. }
  1434. take_some_exit:
  1435. PUSH_LOCATION(ConnectObject, 0xc060);
  1436. ConnectObject->BytesInXport = BytesAvailable;
  1437. ConnectObject->PendingIRPs[SMB_PENDING_RECEIVE] = NULL;
  1438. //
  1439. // If any bytes taken, the status should be STATUS_SUCCESS.
  1440. // Although the client doesn't take any bytes, but we could consume the header.
  1441. // Don't return what the client returns.
  1442. //
  1443. if (*BytesTaken) {
  1444. PUSH_LOCATION(ConnectObject, 0xc070);
  1445. status = STATUS_SUCCESS;
  1446. }
  1447. SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
  1448. ASSERT(ConnectObject->RefCount > 1);
  1449. SmbDereferenceConnect(ConnectObject, SMB_REF_RECEIVE);
  1450. return status;
  1451. return_IRP_Exit:
  1452. PUSH_LOCATION(ConnectObject, 0xc080);
  1453. ConnectObject->BytesInXport = BytesAvailable;
  1454. ConnectObject->PendingIRPs[SMB_PENDING_RECEIVE] = *Irp;
  1455. SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
  1456. ASSERT(ConnectObject->RefCount > 1);
  1457. SmbDereferenceConnect(ConnectObject, SMB_REF_RECEIVE);
  1458. IoSetNextIrpStackLocation(*Irp);
  1459. return STATUS_MORE_PROCESSING_REQUIRED;
  1460. }
  1461. VOID
  1462. SmbGetHeaderDpc(
  1463. IN PKDPC Dpc,
  1464. IN PSMB_CONNECT ConnectObject,
  1465. IN PVOID SystemArgument1,
  1466. IN PVOID SystemArgument2
  1467. )
  1468. {
  1469. KIRQL Irql;
  1470. NTSTATUS status;
  1471. PIRP Irp = NULL;
  1472. PDEVICE_OBJECT TcpDeviceObject = NULL;
  1473. PFILE_OBJECT TcpFileObject = NULL;
  1474. PUSH_LOCATION(ConnectObject, 0xd000);
  1475. ASSERT(&ConnectObject->SmbHeaderDpc == Dpc);
  1476. SMB_ACQUIRE_SPINLOCK(ConnectObject, Irql);
  1477. if (ConnectObject->State != SMB_CONNECTED) {
  1478. PUSH_LOCATION(ConnectObject, 0xd010);
  1479. SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
  1480. SmbDereferenceConnect(ConnectObject, SMB_REF_DPC);
  1481. return;
  1482. }
  1483. if (!ConnectObject->DpcRequestQueued) {
  1484. BREAK_WHEN_TAKE();
  1485. PUSH_LOCATION(ConnectObject, 0xd020);
  1486. SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
  1487. //
  1488. // The TdiReceiveHandler has been called. Bail out.
  1489. //
  1490. // Note: TCP could call our receive event handler when new data comes in.
  1491. //
  1492. return;
  1493. }
  1494. ASSERT(NULL == ConnectObject->PendingIRPs[SMB_PENDING_RECEIVE]);
  1495. ASSERT(ConnectObject->BytesInXport > 0);
  1496. ASSERT(ConnectObject->StateRcvHandler == WaitingHeader);
  1497. ASSERT(ConnectObject->BytesRemaining == 0);
  1498. ASSERT(ConnectObject->HeaderBytesRcved == 0);
  1499. Irp = SmbPrepareSessionHeaderIrp(ConnectObject);
  1500. if (NULL != Irp) {
  1501. PUSH_LOCATION(ConnectObject, 0xd030);
  1502. ConnectObject->PendingIRPs[SMB_PENDING_RECEIVE] = Irp;
  1503. ConnectObject->DpcRequestQueued = FALSE;
  1504. TcpFileObject = ConnectObject->TcpContext->Connect.ConnectObject;
  1505. TcpDeviceObject = IoGetRelatedDeviceObject(TcpFileObject);
  1506. //
  1507. // Reference the file object while we still holding the spinlock
  1508. //
  1509. ObReferenceObject(TcpFileObject);
  1510. SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
  1511. //
  1512. // Don't exchange the following 2 statements, we should reference in
  1513. // the context of SMB_REF_RECEIVE and then dereference the DPC context
  1514. //
  1515. SmbReferenceConnect(ConnectObject, SMB_REF_RECEIVE);
  1516. SmbDereferenceConnect(ConnectObject, SMB_REF_DPC);
  1517. status = IoCallDriver(TcpDeviceObject, Irp);
  1518. //
  1519. // Now we can dereference the TcpFileObject. It is the TCP's responsibility to
  1520. // do the synchronization between the deletion of the file object and accessing it
  1521. //
  1522. ObDereferenceObject(TcpFileObject);
  1523. } else {
  1524. PUSH_LOCATION(ConnectObject, 0xd040);
  1525. //
  1526. // The connection should already have been killed
  1527. //
  1528. ASSERT(ConnectObject->TcpContext == NULL);
  1529. SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
  1530. SmbDereferenceConnect(ConnectObject, SMB_REF_DPC);
  1531. }
  1532. }
  1533. VOID
  1534. KillConnection(
  1535. IN PSMB_CONNECT ConnectObject
  1536. )
  1537. /*++
  1538. Routine Description:
  1539. Kill the connection immediately
  1540. Note: the ConnectObject->SpinLock is held when this routine is called
  1541. Arguments:
  1542. Return Value:
  1543. --*/
  1544. {
  1545. // BREAK_WHEN_TAKE();
  1546. PUSH_LOCATION(ConnectObject, 0xe000);
  1547. SaveDisconnectOriginator(ConnectObject, SMB_DISCONNECT_RECEIVE_FAILURE);
  1548. if (ConnectObject->ClientObject == NULL) {
  1549. PUSH_LOCATION(ConnectObject, 0xe010);
  1550. return;
  1551. }
  1552. SmbReferenceConnect(ConnectObject, SMB_REF_DISCONNECT);
  1553. SMB_RELEASE_SPINLOCK_DPC(ConnectObject);
  1554. CommonDisconnectHandler(SmbCfg.SmbDeviceObject, ConnectObject, TDI_DISCONNECT_ABORT);
  1555. SMB_ACQUIRE_SPINLOCK_DPC(ConnectObject);
  1556. SmbDereferenceConnect(ConnectObject, SMB_REF_DISCONNECT);
  1557. }