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.

3628 lines
123 KiB

  1. /*++
  2. Copyright (c) 1993-1999 Microsoft Corporation
  3. Module Name:
  4. recvvc.c
  5. Abstract:
  6. This module contains routines for handling data receive for connection-
  7. oriented endpoints on non-buffering TDI transports.
  8. Author:
  9. David Treadwell (davidtr) 21-Oct-1993
  10. Revision History:
  11. Vadim Eydelman (vadime)
  12. 1998-1999 NT5.0 low-memory tolerance and perf changes
  13. --*/
  14. #include "afdp.h"
  15. VOID
  16. AfdCancelReceive (
  17. IN PDEVICE_OBJECT DeviceObject,
  18. IN PIRP Irp
  19. );
  20. PIRP
  21. AfdGetPendedReceiveIrp (
  22. IN PAFD_CONNECTION Connection,
  23. IN BOOLEAN Expedited
  24. );
  25. NTSTATUS
  26. AfdRestartBufferReceiveWithUserIrp (
  27. IN PDEVICE_OBJECT DeviceObject,
  28. IN PIRP Irp,
  29. IN PVOID Context
  30. );
  31. ULONG
  32. AfdBFillPendingIrps (
  33. PAFD_CONNECTION Connection,
  34. PMDL Mdl,
  35. ULONG DataOffset,
  36. ULONG DataLength,
  37. ULONG Flags,
  38. PLIST_ENTRY CompleteIrpListHead
  39. );
  40. #define AFD_RECEIVE_STREAM 0x80000000
  41. C_ASSERT (AFD_RECEIVE_STREAM!=TDI_RECEIVE_ENTIRE_MESSAGE);
  42. C_ASSERT (AFD_RECEIVE_STREAM!=TDI_RECEIVE_EXPEDITED);
  43. #define AFD_RECEIVE_CHAINED 0x40000000
  44. C_ASSERT (AFD_RECEIVE_CHAINED!=TDI_RECEIVE_ENTIRE_MESSAGE);
  45. C_ASSERT (AFD_RECEIVE_CHAINED!=TDI_RECEIVE_EXPEDITED);
  46. PAFD_BUFFER_HEADER
  47. AfdGetReceiveBuffer (
  48. IN PAFD_CONNECTION Connection,
  49. IN ULONG ReceiveFlags,
  50. IN PAFD_BUFFER_HEADER StartingAfdBuffer OPTIONAL
  51. );
  52. #ifdef ALLOC_PRAGMA
  53. #pragma alloc_text( PAGEAFD, AfdBReceive )
  54. #pragma alloc_text( PAGEAFD, AfdBReceiveEventHandler )
  55. #pragma alloc_text( PAGEAFD, AfdBReceiveExpeditedEventHandler )
  56. #pragma alloc_text( PAGEAFD, AfdCancelReceive )
  57. #pragma alloc_text( PAGEAFD, AfdGetPendedReceiveIrp )
  58. #pragma alloc_text( PAGEAFD, AfdGetReceiveBuffer )
  59. #pragma alloc_text( PAGEAFD, AfdRestartBufferReceive )
  60. #pragma alloc_text( PAGEAFD, AfdRestartBufferReceiveWithUserIrp )
  61. #pragma alloc_text( PAGEAFD, AfdLRRepostReceive)
  62. #pragma alloc_text( PAGEAFD, AfdBChainedReceiveEventHandler )
  63. #pragma alloc_text( PAGEAFD, AfdBFillPendingIrps )
  64. #endif
  65. //
  66. // Macros to make the send restart code more maintainable.
  67. //
  68. #define AfdRestartRecvInfo DeviceIoControl
  69. #define AfdRecvFlags IoControlCode
  70. #define AfdOriginalLength OutputBufferLength
  71. #define AfdCurrentLength InputBufferLength
  72. #define AfdAdjustedLength Type3InputBuffer
  73. NTSTATUS
  74. AfdBReceive (
  75. IN PIRP Irp,
  76. IN PIO_STACK_LOCATION IrpSp,
  77. IN ULONG RecvFlags,
  78. IN ULONG AfdFlags,
  79. IN ULONG RecvLength
  80. )
  81. {
  82. NTSTATUS status;
  83. AFD_LOCK_QUEUE_HANDLE lockHandle;
  84. PAFD_ENDPOINT endpoint;
  85. PAFD_CONNECTION connection;
  86. ULONG bytesReceived;
  87. BOOLEAN peek;
  88. PAFD_BUFFER_HEADER afdBuffer;
  89. BOOLEAN completeMessage;
  90. BOOLEAN partialReceivePossible;
  91. PAFD_BUFFER newAfdBuffer;
  92. //
  93. // Set up some local variables.
  94. //
  95. endpoint = IrpSp->FileObject->FsContext;
  96. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting ||
  97. endpoint->Type == AfdBlockTypeVcBoth );
  98. connection = NULL;
  99. //
  100. // Determine if this is a peek operation.
  101. //
  102. ASSERT( ( RecvFlags & TDI_RECEIVE_EITHER ) != 0 );
  103. ASSERT( ( RecvFlags & TDI_RECEIVE_EITHER ) != TDI_RECEIVE_EITHER );
  104. peek = (BOOLEAN)(( RecvFlags & TDI_RECEIVE_PEEK ) != 0);
  105. //
  106. // Determine whether it is legal to complete this receive with a
  107. // partial message.
  108. //
  109. if ( !IS_MESSAGE_ENDPOINT(endpoint)) {
  110. partialReceivePossible = TRUE;
  111. } else {
  112. if ( (RecvFlags & TDI_RECEIVE_PARTIAL) != 0 ) {
  113. partialReceivePossible = TRUE;
  114. } else {
  115. partialReceivePossible = FALSE;
  116. }
  117. }
  118. //
  119. // Reset the InputBufferLength field of our stack location. We'll
  120. // use this to keep track of how much data we've placed into the IRP
  121. // so far.
  122. //
  123. IrpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength = 0;
  124. Irp->IoStatus.Information = 0;
  125. //
  126. // If this is an inline endpoint, then either type of receive data
  127. // can be used to satisfy this receive.
  128. //
  129. if ( endpoint->InLine ) {
  130. RecvFlags |= TDI_RECEIVE_EITHER;
  131. }
  132. newAfdBuffer = NULL;
  133. //
  134. // Try to get data already bufferred on the connection to satisfy
  135. // this receive.
  136. //
  137. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  138. //
  139. // Check if endpoint was cleaned-up and cancel the request.
  140. //
  141. if (endpoint->EndpointCleanedUp) {
  142. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  143. status = STATUS_CANCELLED;
  144. goto complete;
  145. }
  146. connection = AFD_CONNECTION_FROM_ENDPOINT (endpoint);
  147. if (connection==NULL) {
  148. //
  149. // connection might have been cleaned up by transmit file.
  150. //
  151. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  152. status = STATUS_INVALID_CONNECTION;
  153. goto complete;
  154. }
  155. ASSERT( connection->Type == AfdBlockTypeConnection );
  156. //
  157. // Check whether the remote end has aborted the connection, in which
  158. // case we should complete the receive.
  159. //
  160. if ( connection->Aborted ) {
  161. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  162. status = STATUS_CONNECTION_RESET;
  163. goto complete;
  164. }
  165. if( RecvFlags & TDI_RECEIVE_EXPEDITED ) {
  166. endpoint->EventsActive &= ~AFD_POLL_RECEIVE_EXPEDITED;
  167. }
  168. if( RecvFlags & TDI_RECEIVE_NORMAL ) {
  169. endpoint->EventsActive &= ~AFD_POLL_RECEIVE;
  170. }
  171. IF_DEBUG(EVENT_SELECT) {
  172. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  173. "AfdBReceive: Endp %p, Active %lx\n",
  174. endpoint,
  175. endpoint->EventsActive
  176. ));
  177. }
  178. afdBuffer = AfdGetReceiveBuffer( connection, RecvFlags, NULL);
  179. while ( afdBuffer != NULL ) {
  180. //
  181. // Copy the data to the MDL in the IRP.
  182. //
  183. if ( Irp->MdlAddress != NULL ) {
  184. if (IrpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength==0) {
  185. //
  186. // First time through the loop - make sure we can map the
  187. // entire buffer. We can't afford failing on second entry
  188. // to the loop as we may loose the data we copied on
  189. // the first path.
  190. //
  191. status = AfdMapMdlChain (Irp->MdlAddress);
  192. if (!NT_SUCCESS (status)) {
  193. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  194. goto complete;
  195. }
  196. }
  197. ASSERTMSG (
  198. "NIC Driver freed the packet before it was returned!!!",
  199. !afdBuffer->NdisPacket ||
  200. (MmIsAddressValid (afdBuffer->Context) &&
  201. MmIsAddressValid (MmGetSystemAddressForMdl (afdBuffer->Mdl))) );
  202. status = AfdCopyMdlChainToMdlChain (
  203. Irp->MdlAddress,
  204. IrpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength,
  205. afdBuffer->Mdl,
  206. afdBuffer->DataOffset,
  207. afdBuffer->DataLength,
  208. &bytesReceived
  209. );
  210. } else {
  211. if ( afdBuffer->DataLength == 0 ) {
  212. status = STATUS_SUCCESS;
  213. } else {
  214. status = STATUS_BUFFER_OVERFLOW;
  215. }
  216. bytesReceived = 0;
  217. }
  218. ASSERT( status == STATUS_SUCCESS || status == STATUS_BUFFER_OVERFLOW );
  219. ASSERT( afdBuffer->PartialMessage == TRUE || afdBuffer->PartialMessage == FALSE );
  220. completeMessage = !afdBuffer->PartialMessage;
  221. //
  222. // If this wasn't a peek IRP, update information on the
  223. // connection based on whether the entire buffer of data was
  224. // taken.
  225. //
  226. if ( !peek ) {
  227. //
  228. // If all the data in the buffer was taken, remove the buffer
  229. // from the connection's list and return it to the buffer pool.
  230. //
  231. if (status == STATUS_SUCCESS) {
  232. ASSERT(afdBuffer->DataLength == bytesReceived);
  233. //
  234. // Update the counts of bytes bufferred on the connection.
  235. //
  236. if ( afdBuffer->ExpeditedData ) {
  237. ASSERT( connection->VcBufferredExpeditedBytes >= bytesReceived );
  238. ASSERT( connection->VcBufferredExpeditedCount > 0 );
  239. connection->VcBufferredExpeditedBytes -= bytesReceived;
  240. connection->VcBufferredExpeditedCount -= 1;
  241. afdBuffer->ExpeditedData = FALSE;
  242. } else {
  243. ASSERT( connection->VcBufferredReceiveBytes >= bytesReceived );
  244. ASSERT( connection->VcBufferredReceiveCount > 0 );
  245. connection->VcBufferredReceiveBytes -= bytesReceived;
  246. connection->VcBufferredReceiveCount -= 1;
  247. }
  248. RemoveEntryList( &afdBuffer->BufferListEntry );
  249. DEBUG afdBuffer->BufferListEntry.Flink = NULL;
  250. if (afdBuffer->RefCount==1 || // Can't change once off the list
  251. InterlockedDecrement (&afdBuffer->RefCount)==0) {
  252. AfdReturnBuffer( afdBuffer, connection->OwningProcess );
  253. }
  254. //
  255. // Reset the afdBuffer local so that we know that the
  256. // buffer is gone.
  257. //
  258. afdBuffer = NULL;
  259. } else {
  260. //
  261. // Update the counts of bytes bufferred on the connection.
  262. //
  263. if ( afdBuffer->ExpeditedData ) {
  264. ASSERT( connection->VcBufferredExpeditedBytes >= bytesReceived );
  265. connection->VcBufferredExpeditedBytes -= bytesReceived;
  266. } else {
  267. ASSERT( connection->VcBufferredReceiveBytes >= bytesReceived );
  268. connection->VcBufferredReceiveBytes -= bytesReceived;
  269. }
  270. //
  271. // Not all of the buffer's data was taken. Update the
  272. // counters in the AFD buffer structure to reflect the
  273. // amount of data that was actually received.
  274. //
  275. ASSERT(afdBuffer->DataLength > bytesReceived);
  276. afdBuffer->DataOffset += bytesReceived;
  277. afdBuffer->DataLength -= bytesReceived;
  278. ASSERT( afdBuffer->BufferLength==AfdBufferTagSize
  279. || afdBuffer->DataOffset < afdBuffer->BufferLength );
  280. }
  281. //
  282. // If there is indicated but unreceived data in the TDI
  283. // provider, and we have available buffer space, fire off an
  284. // IRP to receive the data.
  285. //
  286. if ( connection->VcReceiveBytesInTransport > 0
  287. &&
  288. connection->VcBufferredReceiveBytes <
  289. connection->MaxBufferredReceiveBytes
  290. ) {
  291. ULONG bytesToReceive;
  292. ASSERT (connection->RcvInitiated==FALSE);
  293. //
  294. // Remember the count of data that we're going to
  295. // receive, then reset the fields in the connection
  296. // where we keep track of how much data is available in
  297. // the transport. We reset it here before releasing the
  298. // lock so that another thread doesn't try to receive
  299. // the data at the same time as us.
  300. //
  301. if ( connection->VcReceiveBytesInTransport > AfdLargeBufferSize ) {
  302. bytesToReceive = connection->VcReceiveBytesInTransport;
  303. } else {
  304. bytesToReceive = AfdLargeBufferSize;
  305. }
  306. //
  307. // Get an AFD buffer structure to hold the data.
  308. //
  309. ASSERT (newAfdBuffer==NULL);
  310. newAfdBuffer = AfdGetBuffer(
  311. endpoint,
  312. bytesToReceive, 0,
  313. connection->OwningProcess );
  314. if ( newAfdBuffer != NULL) {
  315. connection->VcReceiveBytesInTransport = 0;
  316. connection->RcvInitiated = TRUE;
  317. ASSERT (InterlockedDecrement (&connection->VcReceiveIrpsInTransport)==-1);
  318. //
  319. // We need to remember the connection in the AFD buffer
  320. // because we'll need to access it in the completion
  321. // routine.
  322. //
  323. newAfdBuffer->Context = connection;
  324. //
  325. // Acquire connection reference to be released in completion routine
  326. //
  327. REFERENCE_CONNECTION (connection);
  328. //
  329. // Finish building the receive IRP to give to the TDI
  330. // provider.
  331. //
  332. TdiBuildReceive(
  333. newAfdBuffer->Irp,
  334. connection->DeviceObject,
  335. connection->FileObject,
  336. AfdRestartBufferReceive,
  337. newAfdBuffer,
  338. newAfdBuffer->Mdl,
  339. TDI_RECEIVE_NORMAL,
  340. bytesToReceive
  341. );
  342. //
  343. // Wait to hand off the IRP until we can safely release
  344. // the endpoint lock.
  345. //
  346. }
  347. else {
  348. if (connection->VcBufferredReceiveBytes == 0 &&
  349. !connection->OnLRList) {
  350. //
  351. // Since we do not have any data buffered, application
  352. // is not notified and will never call with recv.
  353. // We will have to put this on low resource list
  354. // and attempt to allocate memory and pull the data
  355. // later.
  356. //
  357. connection->OnLRList = TRUE;
  358. REFERENCE_CONNECTION (connection);
  359. AfdLRListAddItem (&connection->LRListItem, AfdLRRepostReceive);
  360. }
  361. }
  362. }
  363. }
  364. //
  365. // Update the count of bytes we've received so far into the IRP,
  366. // and see if we can get another buffer of data to continue.
  367. //
  368. IrpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength += bytesReceived;
  369. afdBuffer = AfdGetReceiveBuffer( connection, RecvFlags, afdBuffer );
  370. //
  371. // We've set up all return information. If we got a full
  372. // message OR if we can complete with a partial message OR if
  373. // the IRP is full of data, clean up and complete the IRP.
  374. //
  375. if ( IS_MESSAGE_ENDPOINT (endpoint) && completeMessage
  376. ||
  377. status == STATUS_BUFFER_OVERFLOW
  378. ||
  379. (partialReceivePossible
  380. &&
  381. ((RecvLength==IrpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength)
  382. ||
  383. (afdBuffer==NULL))
  384. )
  385. ) {
  386. if( RecvFlags & TDI_RECEIVE_NORMAL ) {
  387. if (IS_DATA_ON_CONNECTION( connection )) {
  388. ASSERT (endpoint->DisableFastIoRecv==FALSE);
  389. AfdIndicateEventSelectEvent(
  390. endpoint,
  391. AFD_POLL_RECEIVE,
  392. STATUS_SUCCESS
  393. );
  394. }
  395. else {
  396. //
  397. // Disable fast IO path to avoid performance penalty
  398. // of unneccessarily going through it.
  399. //
  400. if (!endpoint->NonBlocking)
  401. endpoint->DisableFastIoRecv = TRUE;
  402. }
  403. }
  404. if( ( RecvFlags & TDI_RECEIVE_EXPEDITED ) &&
  405. IS_EXPEDITED_DATA_ON_CONNECTION( connection ) ) {
  406. AfdIndicateEventSelectEvent(
  407. endpoint,
  408. endpoint->InLine
  409. ? AFD_POLL_RECEIVE
  410. : AFD_POLL_RECEIVE_EXPEDITED,
  411. STATUS_SUCCESS
  412. );
  413. }
  414. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  415. //
  416. // For stream type endpoints, it does not make sense to return
  417. // STATUS_BUFFER_OVERFLOW. That status is only sensible for
  418. // message-oriented transports for which we convert it
  419. // to partial receive status to properly set the flags
  420. //
  421. if ( !IS_MESSAGE_ENDPOINT(endpoint) ) {
  422. status = STATUS_SUCCESS;
  423. }
  424. else if (status==STATUS_BUFFER_OVERFLOW || !completeMessage) {
  425. if (RecvFlags & TDI_RECEIVE_EXPEDITED)
  426. status = STATUS_RECEIVE_PARTIAL_EXPEDITED;
  427. else
  428. status = STATUS_RECEIVE_PARTIAL;
  429. }
  430. Irp->IoStatus.Information = IrpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength;
  431. UPDATE_CONN2 (connection, "Irp receive, 0x%lX bytes", (ULONG)Irp->IoStatus.Information);
  432. goto complete;
  433. }
  434. }
  435. //
  436. // We should have copied all buffered data of appropriate type
  437. // to the apps's buffer.
  438. //
  439. ASSERT ((!(RecvFlags & TDI_RECEIVE_NORMAL) || (connection->VcBufferredReceiveBytes == 0)) &&
  440. (!(RecvFlags & TDI_RECEIVE_EXPEDITED) || (connection->VcBufferredExpeditedBytes == 0)));
  441. //
  442. // There must be some more space in the buffer if we are here
  443. // or it could also be a 0-byte recv.
  444. //
  445. ASSERT ((RecvLength>IrpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength)
  446. || (RecvLength==0));
  447. //
  448. // Also, if we could complete with partial data we should have done so.
  449. //
  450. ASSERT (IrpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength==0 ||
  451. !partialReceivePossible);
  452. //
  453. // We'll have to pend the IRP. Remember the receive flags in the
  454. // IoControlCode field of our IO stack location and make sure
  455. // we have the length field set (it is no longer done by the IO
  456. // system because we use METHOD_NEITHER and WSABUFs to pass recv
  457. // parameters). Initialize adjusted length in case we need to advance
  458. // the MDL to receive next part of the message
  459. //
  460. IrpSp->Parameters.AfdRestartRecvInfo.AfdRecvFlags = RecvFlags;
  461. IrpSp->Parameters.AfdRestartRecvInfo.AfdOriginalLength = RecvLength;
  462. IrpSp->Parameters.AfdRestartRecvInfo.AfdAdjustedLength = (PVOID)0;
  463. //
  464. // If there was no data bufferred on the endpoint and the connection
  465. // has been disconnected by the remote end, complete the receive
  466. // with 0 bytes read if this is a stream endpoint, or a failure
  467. // code if this is a message endpoint.
  468. //
  469. if ( IrpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength == 0 &&
  470. connection->DisconnectIndicated ) {
  471. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  472. ASSERT (newAfdBuffer==NULL);
  473. if ( !IS_MESSAGE_ENDPOINT(endpoint) ) {
  474. status = STATUS_SUCCESS;
  475. } else {
  476. status = STATUS_GRACEFUL_DISCONNECT;
  477. }
  478. goto complete;
  479. }
  480. //
  481. // If this is a nonblocking endpoint and the request was a normal
  482. // receive (as opposed to a read IRP), fail the request. We don't
  483. // fail reads under the asumption that if the application is doing
  484. // reads they don't want nonblocking behavior.
  485. //
  486. if ( IrpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength == 0 &&
  487. endpoint->NonBlocking && !( AfdFlags & AFD_OVERLAPPED ) ) {
  488. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  489. ASSERT (newAfdBuffer==NULL);
  490. status = STATUS_DEVICE_NOT_READY;
  491. goto complete;
  492. }
  493. //
  494. // Place the IRP on the connection's list of pended receive IRPs and
  495. // mark the IRP ad pended.
  496. //
  497. InsertTailList(
  498. &connection->VcReceiveIrpListHead,
  499. &Irp->Tail.Overlay.ListEntry
  500. );
  501. Irp->IoStatus.Status = STATUS_SUCCESS;
  502. //
  503. // Set up the cancellation routine in the IRP. If the IRP has already
  504. // been cancelled, just call the cancellation routine here.
  505. //
  506. IoSetCancelRoutine( Irp, AfdCancelReceive );
  507. if ( Irp->Cancel ) {
  508. RemoveEntryList( &Irp->Tail.Overlay.ListEntry );
  509. if (IoSetCancelRoutine( Irp, NULL ) != NULL) {
  510. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  511. if (IrpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength == 0 ||
  512. endpoint->EndpointCleanedUp) {
  513. status = STATUS_CANCELLED;
  514. goto complete;
  515. }
  516. else {
  517. //
  518. // We cannot set STATUS_CANCELLED
  519. // since we loose data already placed in the IRP.
  520. //
  521. Irp->IoStatus.Information = IrpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength;
  522. UPDATE_CONN2(connection, "Cancelled receive, 0x%lX bytes", (ULONG)Irp->IoStatus.Information);
  523. status = STATUS_SUCCESS;
  524. goto complete;
  525. }
  526. }
  527. else {
  528. //
  529. // This IRP is about to be canceled. Set the Flink to NULL
  530. // so the cancel routine knows it is not on the list.
  531. Irp->Tail.Overlay.ListEntry.Flink = NULL;
  532. }
  533. //
  534. // The cancel routine will run and complete the irp.
  535. //
  536. }
  537. IoMarkIrpPending( Irp );
  538. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  539. //
  540. // If there was data bufferred in the transport, fire off the IRP to
  541. // receive it. We have to wait until here because it is not legal
  542. // to do an IoCallDriver() while holding a spin lock.
  543. //
  544. if ( newAfdBuffer != NULL ) {
  545. (VOID)IoCallDriver( connection->DeviceObject, newAfdBuffer->Irp );
  546. }
  547. return STATUS_PENDING;
  548. complete:
  549. //
  550. // If there was data bufferred in the transport, fire off
  551. // the IRP to receive it.
  552. //
  553. if ( newAfdBuffer != NULL ) {
  554. (VOID)IoCallDriver( connection->DeviceObject, newAfdBuffer->Irp );
  555. }
  556. Irp->IoStatus.Status = status;
  557. if (!NT_SUCCESS (status)) {
  558. UPDATE_CONN2 (connection, "Receive failed, status: 0x%lX", Irp->IoStatus.Status);
  559. }
  560. IoCompleteRequest( Irp, AfdPriorityBoost );
  561. return status;
  562. } // AfdBReceive
  563. NTSTATUS
  564. AfdBChainedReceiveEventHandler(
  565. IN PVOID TdiEventContext,
  566. IN CONNECTION_CONTEXT ConnectionContext,
  567. IN ULONG ReceiveFlags,
  568. IN ULONG ReceiveLength,
  569. IN ULONG StartingOffset,
  570. IN PMDL Tsdu,
  571. IN PVOID TsduDescriptor
  572. )
  573. /*++
  574. Routine Description:
  575. Handles chained receive events for nonbufferring transports.
  576. Arguments:
  577. Return Value:
  578. --*/
  579. {
  580. AFD_LOCK_QUEUE_HANDLE lockHandle;
  581. PAFD_ENDPOINT endpoint;
  582. PAFD_CONNECTION connection;
  583. PAFD_BUFFER_TAG afdBufferTag;
  584. LIST_ENTRY completeIrpListHead;
  585. PIRP irp;
  586. PIO_STACK_LOCATION irpSp;
  587. NTSTATUS status;
  588. ULONG offset;
  589. BOOLEAN result;
  590. UNREFERENCED_PARAMETER (TdiEventContext);
  591. #if DBG
  592. {
  593. PMDL tstMdl = Tsdu;
  594. ULONG count = 0;
  595. while (tstMdl) {
  596. count += MmGetMdlByteCount (tstMdl);
  597. tstMdl = tstMdl->Next;
  598. }
  599. ASSERT (count>=StartingOffset+ReceiveLength);
  600. }
  601. #endif
  602. connection = (PAFD_CONNECTION)ConnectionContext;
  603. ASSERT( connection != NULL );
  604. CHECK_REFERENCE_CONNECTION2 (connection,"AfdBChainedReceiveEventHandler, receive length: 0x%lX", ReceiveLength, result );
  605. if (!result) {
  606. return STATUS_DATA_NOT_ACCEPTED;
  607. }
  608. ASSERT( connection->Type == AfdBlockTypeConnection );
  609. ASSERT( !connection->DisconnectIndicated );
  610. endpoint = connection->Endpoint;
  611. if (endpoint==NULL) {
  612. //
  613. // Indication after connection reuse, ignore.
  614. //
  615. DEREFERENCE_CONNECTION (connection);
  616. return STATUS_DATA_NOT_ACCEPTED;
  617. }
  618. ASSERT( !IS_TDI_BUFFERRING(endpoint) );
  619. #if AFD_PERF_DBG
  620. AfdFullReceiveIndications++;
  621. #endif
  622. IF_DEBUG (RECEIVE) {
  623. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  624. "AfdBChainedReceiveEventHandler>>: Connection %p, TdsuDescr: %p, Length: %ld.\n",
  625. connection, TsduDescriptor, ReceiveLength));
  626. }
  627. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  628. //
  629. // Do following ASSERT check under lock
  630. //
  631. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting ||
  632. endpoint->Type == AfdBlockTypeVcListening ||
  633. endpoint->Type == AfdBlockTypeVcBoth );
  634. //
  635. // Check if connection was accepted and use accept endpoint instead
  636. // of the listening. Note that accept cannot happen while we are
  637. // holding listening endpoint spinlock, nor can endpoint change after
  638. // the accept, so it is safe to release listening spinlock if
  639. // we discover that endpoint was accepted.
  640. //
  641. if (((endpoint->Type & AfdBlockTypeVcListening) == AfdBlockTypeVcListening)
  642. && (connection->Endpoint != endpoint)) {
  643. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  644. endpoint = connection->Endpoint;
  645. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting );
  646. ASSERT( !IS_TDI_BUFFERRING(endpoint) );
  647. ASSERT( IS_VC_ENDPOINT (endpoint) );
  648. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  649. }
  650. //
  651. // If the receive side of the endpoint has been shut down, tell the
  652. // provider that we took all the data and reset the connection.
  653. // Same if we are shutting down.
  654. //
  655. if ((endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_RECEIVE) != 0 ||
  656. endpoint->EndpointCleanedUp ) {
  657. IF_DEBUG (RECEIVE) {
  658. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  659. "AfdBChainedReceiveEventHandler: receive shutdown, "
  660. "%ld bytes, aborting endp %p\n",
  661. ReceiveLength, endpoint ));
  662. }
  663. //
  664. // Abort the connection. Note that if the abort attempt fails
  665. // we can't do anything about it.
  666. //
  667. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  668. (VOID)AfdBeginAbort( connection );
  669. DEREFERENCE_CONNECTION (connection);
  670. return STATUS_SUCCESS;
  671. }
  672. if (ReceiveFlags & TDI_RECEIVE_EXPEDITED) {
  673. //
  674. // We're being indicated with expedited data. Buffer it and
  675. // complete any pended IRPs in the restart routine. We always
  676. // buffer expedited data to save complexity and because expedited
  677. // data is not an important performance case.
  678. //
  679. // !!! do we need to perform flow control with expedited data?
  680. //
  681. PAFD_BUFFER afdBuffer;
  682. if (connection->VcBufferredExpeditedCount==MAXUSHORT ||
  683. (afdBuffer=AfdGetBuffer (endpoint, ReceiveLength, 0, connection->OwningProcess))==NULL) {
  684. //
  685. // If we couldn't get a buffer, abort the connection. This is
  686. // pretty brutal, but the only alternative is to attempt to
  687. // receive the data sometime later, which is very complicated to
  688. // implement.
  689. //
  690. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  691. (VOID)AfdBeginAbort( connection );
  692. DEREFERENCE_CONNECTION (connection);
  693. return STATUS_SUCCESS;
  694. }
  695. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  696. status = TdiCopyMdlToBuffer (Tsdu,
  697. StartingOffset,
  698. afdBuffer->Buffer,
  699. 0,
  700. afdBuffer->BufferLength,
  701. &ReceiveLength);
  702. ASSERT (status==STATUS_SUCCESS);
  703. //
  704. // We need to remember the connection in the AFD buffer because
  705. // we'll need to access it in the completion routine.
  706. //
  707. afdBuffer->Context = connection;
  708. //
  709. // Remember the type of data that we're receiving.
  710. //
  711. afdBuffer->ExpeditedData = TRUE;
  712. afdBuffer->PartialMessage = (BOOLEAN)((ReceiveFlags & TDI_RECEIVE_ENTIRE_MESSAGE) == 0);
  713. afdBuffer->Irp->IoStatus.Status = status;
  714. afdBuffer->Irp->IoStatus.Information = ReceiveLength;
  715. status = AfdRestartBufferReceive (AfdDeviceObject, afdBuffer->Irp, afdBuffer);
  716. ASSERT (status==STATUS_MORE_PROCESSING_REQUIRED);
  717. return STATUS_SUCCESS;
  718. }
  719. if (connection->RcvInitiated) {
  720. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  721. "AFD: Indication with outstanding receive on connection %p, 0x%x bytes\n",
  722. connection, ReceiveLength));
  723. //
  724. // We have initiated receive to the transport.
  725. // Let the transport find and complete it first
  726. // to preserve ordering.
  727. //
  728. connection->VcReceiveBytesInTransport = ReceiveLength;
  729. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  730. DEREFERENCE_CONNECTION (connection);
  731. return STATUS_DATA_NOT_ACCEPTED;
  732. }
  733. //
  734. // If we are indicated data, we need to reset our record
  735. // of amount of data buffered by the transport.
  736. //
  737. connection->VcReceiveBytesInTransport = 0;
  738. RetryReceive:
  739. InitializeListHead( &completeIrpListHead );
  740. offset = AfdBFillPendingIrps (
  741. connection,
  742. Tsdu,
  743. StartingOffset,
  744. ReceiveLength,
  745. (ReceiveFlags & TDI_RECEIVE_ENTIRE_MESSAGE) |
  746. AFD_RECEIVE_CHAINED |
  747. (!IS_MESSAGE_ENDPOINT(endpoint) ?
  748. AFD_RECEIVE_STREAM : 0),
  749. &completeIrpListHead
  750. );
  751. if (offset==(ULONG)-1) {
  752. //
  753. // If the IRP had more space than in this packet and this
  754. // was not set a complete message, we will pass the IRP to
  755. // the transport and refuse the indicated data (the transport
  756. // can fill the rest of the IRP).
  757. //
  758. //
  759. // This receive indication cannot be expedited or a complete message
  760. // becuase it does not make sense to pass the IRP back in such
  761. // cases.
  762. //
  763. ASSERT (!IsListEmpty (&completeIrpListHead));
  764. ASSERT ((ReceiveFlags &
  765. (TDI_RECEIVE_EXPEDITED|TDI_RECEIVE_ENTIRE_MESSAGE))==0);
  766. ASSERT (!AfdIgnorePushBitOnReceives);
  767. irp = CONTAINING_RECORD (completeIrpListHead.Flink,
  768. IRP,
  769. Tail.Overlay.ListEntry);
  770. irpSp = IoGetCurrentIrpStackLocation (irp);
  771. ASSERT (irpSp->Parameters.AfdRestartRecvInfo.AfdOriginalLength-
  772. irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength >
  773. ReceiveLength);
  774. //
  775. // Reference connection (to be released in restart routine).
  776. // Keep reference added in the beginning of this routine.
  777. // REFERENCE_CONNECTION (connection);
  778. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  779. //
  780. // Note that we have outstanding user IRP in transport.
  781. //
  782. ASSERT (InterlockedIncrement (&connection->VcReceiveIrpsInTransport)==1);
  783. //
  784. // IRP is already partially filled.
  785. //
  786. if (irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength>0) {
  787. irp->MdlAddress = AfdAdvanceMdlChain (
  788. irp->MdlAddress,
  789. irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength
  790. - PtrToUlong(irpSp->Parameters.AfdRestartRecvInfo.AfdAdjustedLength)
  791. );
  792. ASSERT (irp->MdlAddress!=NULL);
  793. //
  794. // Remeber the length by which we adjusted MDL, so we know where
  795. // to start next time.
  796. //
  797. irpSp->Parameters.AfdRestartRecvInfo.AfdAdjustedLength =
  798. UlongToPtr(irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength);
  799. }
  800. //
  801. // Build the receive IRP to give to the TDI provider.
  802. //
  803. TdiBuildReceive(
  804. irp,
  805. connection->DeviceObject,
  806. connection->FileObject,
  807. AfdRestartBufferReceiveWithUserIrp,
  808. connection,
  809. irp->MdlAddress,
  810. irpSp->Parameters.AfdRestartRecvInfo.AfdRecvFlags & TDI_RECEIVE_EITHER,
  811. irpSp->Parameters.AfdRestartRecvInfo.AfdOriginalLength -
  812. irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength
  813. );
  814. #ifdef _AFD_VARIABLE_STACK_
  815. if ((irp=AfdCheckStackSizeAndRecordOutstandingIrp (
  816. endpoint,
  817. connection->DeviceObject,
  818. irp))!=NULL) {
  819. #else //_AFD_VARIABLE_STACK_
  820. if (AfdRecordOutstandingIrp (endpoint, connection->DeviceObject, irp)) {
  821. #endif // _AFD_VARIABLE_STACK_
  822. (VOID)IoCallDriver(connection->DeviceObject, irp );
  823. }
  824. else {
  825. //
  826. // On debug build or in case that transport driver needed more stack locations that were
  827. // available, AFD might have completed this IRP if it could not allocate
  828. // new IRP and/or tracking structure. In this case the transport does not
  829. // get a call and as the result does not restart indications. Also, the data
  830. // already placed in the IRP gets lost.
  831. //
  832. // To avoid this, we retry the indication ourselves.
  833. //
  834. CHECK_REFERENCE_CONNECTION (connection, result);
  835. if (result) {
  836. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  837. goto RetryReceive;
  838. }
  839. }
  840. return STATUS_DATA_NOT_ACCEPTED;
  841. }
  842. ASSERT (offset-StartingOffset<=ReceiveLength);
  843. //
  844. // If there is any data left, place the buffer at the end of the
  845. // connection's list of bufferred data and update counts of data on
  846. // the connection.
  847. //
  848. if (ReceiveLength > offset-StartingOffset) {
  849. //
  850. // If offset is not zero we should not have had anything buffered.
  851. //
  852. ASSERT (offset==StartingOffset || connection->VcBufferredReceiveCount==0);
  853. if ( offset>StartingOffset ||
  854. (connection->VcBufferredReceiveBytes <=
  855. connection->MaxBufferredReceiveBytes &&
  856. connection->VcBufferredReceiveCount<MAXUSHORT) ){
  857. //
  858. // We should attempt to buffer the data.
  859. //
  860. afdBufferTag = AfdGetBufferTag (0, connection->OwningProcess);
  861. }
  862. else {
  863. ASSERT (offset==StartingOffset);
  864. //
  865. // We are over the limit, don't take the data.
  866. //
  867. afdBufferTag = NULL;
  868. }
  869. if (afdBufferTag!=NULL) {
  870. AFD_VERIFY_MDL (connection, Tsdu, StartingOffset, ReceiveLength);
  871. afdBufferTag->Mdl = Tsdu;
  872. afdBufferTag->DataLength = ReceiveLength - (offset-StartingOffset);
  873. afdBufferTag->DataOffset = offset;
  874. afdBufferTag->RefCount = 1;
  875. afdBufferTag->Context = TsduDescriptor;
  876. afdBufferTag->NdisPacket = TRUE;
  877. afdBufferTag->PartialMessage = (BOOLEAN)((ReceiveFlags & TDI_RECEIVE_ENTIRE_MESSAGE) == 0);
  878. InsertTailList(
  879. &connection->VcReceiveBufferListHead,
  880. &afdBufferTag->BufferListEntry
  881. );
  882. connection->VcBufferredReceiveBytes += afdBufferTag->DataLength;
  883. ASSERT (connection->VcBufferredReceiveCount<MAXUSHORT);
  884. connection->VcBufferredReceiveCount += 1;
  885. endpoint->DisableFastIoRecv = FALSE;
  886. // Make sure connection was accepted/connected to prevent
  887. // indication on listening endpoint
  888. //
  889. if (connection->State==AfdConnectionStateConnected) {
  890. ASSERT (endpoint->Type & AfdBlockTypeVcConnecting);
  891. AfdIndicateEventSelectEvent(
  892. endpoint,
  893. AFD_POLL_RECEIVE,
  894. STATUS_SUCCESS
  895. );
  896. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  897. AfdIndicatePollEvent(
  898. endpoint,
  899. AFD_POLL_RECEIVE,
  900. STATUS_SUCCESS
  901. );
  902. }
  903. else {
  904. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  905. }
  906. status = STATUS_PENDING;
  907. }
  908. else {
  909. if (offset==StartingOffset) {
  910. //
  911. // If no IRPs were pending on the endpoint just remember the
  912. // amount of data that is available. When application
  913. // reposts the receive, we'll actually pull this data.
  914. //
  915. connection->VcReceiveBytesInTransport += ReceiveLength;
  916. if (connection->VcBufferredReceiveBytes == 0 &&
  917. !connection->OnLRList) {
  918. //
  919. // Since we do not have any data buffered, application
  920. // is not notified and will never call with recv.
  921. // We will have to put this on low resource list
  922. // and attempt to allocate memory and pull the data
  923. // later.
  924. //
  925. connection->OnLRList = TRUE;
  926. REFERENCE_CONNECTION (connection);
  927. AfdLRListAddItem (&connection->LRListItem, AfdLRRepostReceive);
  928. }
  929. else {
  930. UPDATE_CONN (connection);
  931. }
  932. }
  933. else {
  934. PLIST_ENTRY listEntry;
  935. //
  936. // We need to put back the IRPs that we were going to complete
  937. //
  938. listEntry = completeIrpListHead.Blink;
  939. while ( listEntry!=&completeIrpListHead ) {
  940. irp = CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry );
  941. listEntry = listEntry->Blink;
  942. // Set up the cancellation routine back in the IRP.
  943. //
  944. IoSetCancelRoutine( irp, AfdCancelReceive );
  945. if ( !irp->Cancel ) {
  946. RemoveEntryList (&irp->Tail.Overlay.ListEntry);
  947. InsertHeadList (&connection->VcReceiveIrpListHead,
  948. &irp->Tail.Overlay.ListEntry);
  949. }
  950. else if (IoSetCancelRoutine( irp, NULL ) != NULL) {
  951. //
  952. // The cancel routine was never called.
  953. // Have to handle cancellation here, just let the
  954. // IRP remain in completed list and set the
  955. // status appropriately keeping in mind that
  956. // we cannot complete IRP as cancelled if it
  957. // already has some data in it.
  958. //
  959. irpSp = IoGetCurrentIrpStackLocation (irp);
  960. if (irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength!=0) {
  961. ASSERT (!endpoint->EndpointCleanedUp); // checked above.
  962. irp->IoStatus.Status = STATUS_SUCCESS;
  963. irp->IoStatus.Information = irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength;
  964. }
  965. else {
  966. irp->IoStatus.Status = STATUS_CANCELLED;
  967. }
  968. }
  969. else {
  970. RemoveEntryList (&irp->Tail.Overlay.ListEntry);
  971. //
  972. // The cancel routine is about to be run.
  973. // Set the Flink to NULL so the cancel routine knows
  974. // it is not on the list
  975. //
  976. irp->Tail.Overlay.ListEntry.Flink = NULL;
  977. }
  978. }
  979. UPDATE_CONN (connection);
  980. }
  981. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  982. status = STATUS_DATA_NOT_ACCEPTED;
  983. }
  984. }
  985. else {
  986. AFD_VERIFY_MDL (connection, Tsdu, StartingOffset, offset-StartingOffset);
  987. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  988. status = STATUS_SUCCESS;
  989. }
  990. while ( !IsListEmpty( &completeIrpListHead ) ) {
  991. PLIST_ENTRY listEntry;
  992. listEntry = RemoveHeadList( &completeIrpListHead );
  993. irp = CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry );
  994. irpSp = IoGetCurrentIrpStackLocation (irp);
  995. //
  996. // Copy the data into the IRP if it is not errored out and
  997. // we accepted the data.
  998. //
  999. if (status!=STATUS_DATA_NOT_ACCEPTED && !NT_ERROR (irp->IoStatus.Status)) {
  1000. ULONG bytesCopied;
  1001. if (irp->MdlAddress!=NULL) {
  1002. #if DBG
  1003. NTSTATUS status1 =
  1004. #endif
  1005. AfdCopyMdlChainToMdlChain(
  1006. irp->MdlAddress,
  1007. irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength
  1008. - PtrToUlong(irpSp->Parameters.AfdRestartRecvInfo.AfdAdjustedLength),
  1009. Tsdu,
  1010. StartingOffset,
  1011. ReceiveLength,
  1012. &bytesCopied
  1013. );
  1014. ASSERT (status1==STATUS_SUCCESS ||
  1015. status1==STATUS_BUFFER_OVERFLOW);
  1016. ASSERT (irpSp->Parameters.AfdRestartRecvInfo.AfdOriginalLength-
  1017. irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength>=bytesCopied);
  1018. irp->IoStatus.Information =
  1019. irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength + bytesCopied;
  1020. }
  1021. else {
  1022. bytesCopied = 0;
  1023. ASSERT (irp->IoStatus.Information == 0);
  1024. ASSERT (irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength==0);
  1025. ASSERT (irpSp->Parameters.AfdRestartRecvInfo.AfdOriginalLength==0);
  1026. }
  1027. if ((irpSp->Parameters.AfdRestartRecvInfo.AfdRecvFlags& TDI_RECEIVE_PEEK) == 0) {
  1028. StartingOffset += bytesCopied;
  1029. ReceiveLength -= bytesCopied;
  1030. }
  1031. }
  1032. else {
  1033. //
  1034. // Either we failing the irp or we already filled in some data
  1035. // or this irp was for 0 bytes to begin with in which case
  1036. // we just succeed it.
  1037. //
  1038. ASSERT (NT_ERROR (irp->IoStatus.Status) ||
  1039. irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength!=0||
  1040. irpSp->Parameters.AfdRestartRecvInfo.AfdOriginalLength==0);
  1041. }
  1042. IF_DEBUG (RECEIVE) {
  1043. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1044. "AfdBChainedReceiveEventHandler: endpoint: %p, completing IRP: %p, status %lx, info: %ld.\n",
  1045. endpoint,
  1046. irp,
  1047. irp->IoStatus.Status,
  1048. irp->IoStatus.Information));
  1049. }
  1050. UPDATE_CONN2(connection, "Completing chained receive with error/bytes read: 0x%lX",
  1051. (!NT_ERROR(irp->IoStatus.Status)
  1052. ? (ULONG)irp->IoStatus.Information
  1053. : (ULONG)irp->IoStatus.Status));
  1054. IoCompleteRequest( irp, AfdPriorityBoost );
  1055. }
  1056. DEREFERENCE_CONNECTION (connection);
  1057. IF_DEBUG (RECEIVE) {
  1058. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1059. "AfdBChainedReceiveEventHandler<<: %ld\n", status));
  1060. }
  1061. return status;
  1062. }
  1063. NTSTATUS
  1064. AfdBReceiveEventHandler (
  1065. IN PVOID TdiEventContext,
  1066. IN CONNECTION_CONTEXT ConnectionContext,
  1067. IN ULONG ReceiveFlags,
  1068. IN ULONG BytesIndicated,
  1069. IN ULONG BytesAvailable,
  1070. OUT ULONG *BytesTaken,
  1071. IN PVOID Tsdu,
  1072. OUT PIRP *IoRequestPacket
  1073. )
  1074. /*++
  1075. Routine Description:
  1076. Handles receive events for nonbufferring transports.
  1077. Arguments:
  1078. Return Value:
  1079. --*/
  1080. {
  1081. AFD_LOCK_QUEUE_HANDLE lockHandle;
  1082. PAFD_ENDPOINT endpoint;
  1083. PAFD_CONNECTION connection;
  1084. PAFD_BUFFER afdBuffer;
  1085. PIRP irp;
  1086. PLIST_ENTRY listEntry;
  1087. ULONG requiredAfdBufferSize;
  1088. NTSTATUS status;
  1089. ULONG receiveLength;
  1090. BOOLEAN expedited;
  1091. BOOLEAN completeMessage, result;
  1092. UNREFERENCED_PARAMETER (TdiEventContext);
  1093. DEBUG receiveLength = 0xFFFFFFFF;
  1094. connection = (PAFD_CONNECTION)ConnectionContext;
  1095. ASSERT( connection != NULL );
  1096. CHECK_REFERENCE_CONNECTION2 (connection,"AfdBReceiveEventHandler, bytes available: 0x%lX", BytesAvailable, result );
  1097. if (!result) {
  1098. return STATUS_DATA_NOT_ACCEPTED;
  1099. }
  1100. ASSERT( connection->Type == AfdBlockTypeConnection );
  1101. ASSERT( !connection->DisconnectIndicated );
  1102. endpoint = connection->Endpoint;
  1103. if (endpoint==NULL) {
  1104. //
  1105. // Indication after connection reuse, ignore.
  1106. //
  1107. DEREFERENCE_CONNECTION (connection);
  1108. return STATUS_DATA_NOT_ACCEPTED;
  1109. }
  1110. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting ||
  1111. endpoint->Type == AfdBlockTypeVcListening ||
  1112. endpoint->Type == AfdBlockTypeVcBoth );
  1113. ASSERT( !IS_TDI_BUFFERRING(endpoint) );
  1114. ASSERT( IS_VC_ENDPOINT (endpoint) );
  1115. *BytesTaken = 0;
  1116. #if AFD_PERF_DBG
  1117. if ( BytesAvailable == BytesIndicated ) {
  1118. AfdFullReceiveIndications++;
  1119. } else {
  1120. AfdPartialReceiveIndications++;
  1121. }
  1122. #endif
  1123. //
  1124. // Figure out whether this is a receive indication for normal
  1125. // or expedited data, and whether this is a complete message.
  1126. //
  1127. expedited = (BOOLEAN)( (ReceiveFlags & TDI_RECEIVE_EXPEDITED) != 0 );
  1128. completeMessage = (BOOLEAN)((ReceiveFlags & TDI_RECEIVE_ENTIRE_MESSAGE) != 0);
  1129. //
  1130. // If the receive side of the endpoint has been shut down, tell the
  1131. // provider that we took all the data and reset the connection.
  1132. // Also, account for these bytes in our count of bytes taken from
  1133. // the transport.
  1134. //
  1135. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  1136. //
  1137. // Check if connection was accepted and use accept endpoint instead
  1138. // of the listening. Note that accept cannot happen while we are
  1139. // holding listening endpoint spinlock, nor can endpoint change after
  1140. // the accept and while connection is referenced, so it is safe to
  1141. // release listening spinlock if we discover that endpoint was accepted.
  1142. //
  1143. if (((endpoint->Type & AfdBlockTypeVcListening) == AfdBlockTypeVcListening)
  1144. && (connection->Endpoint != endpoint)) {
  1145. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  1146. endpoint = connection->Endpoint;
  1147. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting );
  1148. ASSERT( !IS_TDI_BUFFERRING(endpoint) );
  1149. ASSERT( IS_VC_ENDPOINT (endpoint) );
  1150. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  1151. }
  1152. if ( (endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_RECEIVE) != 0 ||
  1153. endpoint->EndpointCleanedUp ) {
  1154. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  1155. "AfdBReceiveEventHandler: receive shutdown, "
  1156. "%ld bytes, aborting endp %p\n",
  1157. BytesAvailable, endpoint ));
  1158. *BytesTaken = BytesAvailable;
  1159. //
  1160. // Abort the connection. Note that if the abort attempt fails
  1161. // we can't do anything about it.
  1162. //
  1163. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  1164. (VOID)AfdBeginAbort( connection );
  1165. DEREFERENCE_CONNECTION (connection);
  1166. return STATUS_SUCCESS;
  1167. }
  1168. //
  1169. // Check whether there are any IRPs waiting on the connection. If
  1170. // there is such an IRP and normal data is being indicated, use the
  1171. // IRP to receive the data.
  1172. //
  1173. if ( !expedited ) {
  1174. if (connection->RcvInitiated) {
  1175. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  1176. "AFD: Indication with outstanding receive on connection %p, 0x%x bytes available\n",
  1177. connection, BytesAvailable));
  1178. //
  1179. // We have initiated receive to the transport.
  1180. // Let the transport find and complete it first
  1181. // to preserve ordering.
  1182. //
  1183. connection->VcReceiveBytesInTransport = BytesAvailable;
  1184. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  1185. DEREFERENCE_CONNECTION (connection);
  1186. return STATUS_DATA_NOT_ACCEPTED;
  1187. }
  1188. //
  1189. // If we are indicated data, we need to reset our record
  1190. // of amount of data buffered by the transport.
  1191. //
  1192. connection->VcReceiveBytesInTransport = 0;
  1193. while (!IsListEmpty( &connection->VcReceiveIrpListHead )) {
  1194. PIO_STACK_LOCATION irpSp;
  1195. ASSERT( *BytesTaken == 0 );
  1196. listEntry = RemoveHeadList( &connection->VcReceiveIrpListHead );
  1197. //
  1198. // Get a pointer to the IRP and our stack location in it
  1199. //
  1200. irp = CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry );
  1201. irpSp = IoGetCurrentIrpStackLocation( irp );
  1202. receiveLength = irpSp->Parameters.AfdRestartRecvInfo.AfdOriginalLength-
  1203. irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength;
  1204. //
  1205. // If the IRP is not large enough to hold the available data, or
  1206. // if it is a peek or expedited (exclusively, not both normal and
  1207. // expedited) receive IRP, then we'll just buffer the
  1208. // data manually and complete the IRP in the receive completion
  1209. // routine.
  1210. //
  1211. if ( (receiveLength>=BytesAvailable) &&
  1212. ((irpSp->Parameters.AfdRestartRecvInfo.AfdRecvFlags
  1213. & TDI_RECEIVE_PEEK) == 0) &&
  1214. ((irpSp->Parameters.AfdRestartRecvInfo.AfdRecvFlags
  1215. & TDI_RECEIVE_NORMAL) != 0)) {
  1216. if ( IoSetCancelRoutine( irp, NULL ) == NULL ) {
  1217. //
  1218. // This IRP is about to be canceled. Look for another in the
  1219. // list. Set the Flink to NULL so the cancel routine knows
  1220. // it is not on the list.
  1221. //
  1222. irp->Tail.Overlay.ListEntry.Flink = NULL;
  1223. continue;
  1224. }
  1225. //
  1226. // If all of the data was indicated to us here AND this is a
  1227. // complete message in and of itself, then just copy the
  1228. // data to the IRP and complete the IRP.
  1229. //
  1230. if ( completeMessage &&
  1231. (BytesIndicated == BytesAvailable)) {
  1232. AFD_VERIFY_BUFFER (connection, Tsdu, BytesAvailable);
  1233. //
  1234. // The IRP is off the endpoint's list and is no longer
  1235. // cancellable. We can release the locks we hold.
  1236. //
  1237. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  1238. //
  1239. // Copy the data to the IRP.
  1240. //
  1241. if ( irp->MdlAddress != NULL ) {
  1242. status = AfdMapMdlChain (irp->MdlAddress);
  1243. if (NT_SUCCESS (status)) {
  1244. status = TdiCopyBufferToMdl(
  1245. Tsdu,
  1246. 0,
  1247. BytesAvailable,
  1248. irp->MdlAddress,
  1249. irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength
  1250. - PtrToUlong(irpSp->Parameters.AfdRestartRecvInfo.AfdAdjustedLength),
  1251. &receiveLength
  1252. );
  1253. irp->IoStatus.Information =
  1254. receiveLength + irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength;
  1255. ASSERT (status == STATUS_SUCCESS);
  1256. }
  1257. else {
  1258. irp->IoStatus.Status = status;
  1259. irp->IoStatus.Information = 0;
  1260. UPDATE_CONN(connection);
  1261. IoCompleteRequest (irp, AfdPriorityBoost);
  1262. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  1263. continue;
  1264. }
  1265. } else {
  1266. ASSERT (irpSp->Parameters.AfdRestartRecvInfo.AfdOriginalLength==0);
  1267. ASSERT ( BytesAvailable == 0 );
  1268. irp->IoStatus.Information = irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength;
  1269. }
  1270. //
  1271. // We have already set up the status field of the IRP
  1272. // when we pended the IRP, so there's no need to
  1273. // set it again here.
  1274. //
  1275. ASSERT( irp->IoStatus.Status == STATUS_SUCCESS );
  1276. //
  1277. // Complete the IRP.
  1278. //
  1279. IF_DEBUG (RECEIVE) {
  1280. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1281. "AfdBReceiveEventHandler: endpoint: %p, completing IRP: %p, status %lx, info: %ld.\n",
  1282. endpoint,
  1283. irp,
  1284. irp->IoStatus.Status,
  1285. irp->IoStatus.Information));
  1286. }
  1287. UPDATE_CONN2(connection, "Completing receive with error/bytes: 0x%lX",
  1288. (!NT_ERROR(irp->IoStatus.Status)
  1289. ? (ULONG)irp->IoStatus.Information
  1290. : (ULONG)irp->IoStatus.Status));
  1291. IoCompleteRequest( irp, AfdPriorityBoost );
  1292. DEREFERENCE_CONNECTION (connection);
  1293. //
  1294. // Set BytesTaken to tell the provider that we have taken all the data.
  1295. //
  1296. *BytesTaken = BytesAvailable;
  1297. return STATUS_SUCCESS;
  1298. }
  1299. //
  1300. // Some of the data was not indicated, so remember that we
  1301. // want to pass back this IRP to the TDI provider. Passing
  1302. // back this IRP directly is good because it avoids having
  1303. // to copy the data from one of our buffers into the user's
  1304. // buffer.
  1305. //
  1306. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  1307. ASSERT (InterlockedIncrement (&connection->VcReceiveIrpsInTransport)==1);
  1308. requiredAfdBufferSize = 0;
  1309. if (AfdIgnorePushBitOnReceives ||
  1310. IS_TDI_MESSAGE_MODE(endpoint)) {
  1311. receiveLength = BytesAvailable;
  1312. }
  1313. if (irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength>0) {
  1314. irp->MdlAddress = AfdAdvanceMdlChain (irp->MdlAddress,
  1315. irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength
  1316. -PtrToUlong(irpSp->Parameters.AfdRestartRecvInfo.AfdAdjustedLength)
  1317. );
  1318. ASSERT (irp->MdlAddress!=NULL);
  1319. irpSp->Parameters.AfdRestartRecvInfo.AfdAdjustedLength =
  1320. UlongToPtr(irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength);
  1321. }
  1322. TdiBuildReceive(
  1323. irp,
  1324. connection->DeviceObject,
  1325. connection->FileObject,
  1326. AfdRestartBufferReceiveWithUserIrp,
  1327. connection,
  1328. irp->MdlAddress,
  1329. ReceiveFlags & TDI_RECEIVE_EITHER,
  1330. receiveLength
  1331. );
  1332. #ifdef _AFD_VARIABLE_STACK_
  1333. if ((irp=AfdCheckStackSizeAndRecordOutstandingIrp (
  1334. endpoint,
  1335. connection->DeviceObject,
  1336. irp))!=NULL) {
  1337. #else // _AFD_VARIABLE_STACK_
  1338. if (AfdRecordOutstandingIrp (endpoint,
  1339. connection->DeviceObject,
  1340. irp)) {
  1341. #endif // _AFD_VARIABLE_STACK_
  1342. //
  1343. // Make the next stack location current. Normally IoCallDriver would
  1344. // do this, but since we're bypassing that, we do it directly.
  1345. //
  1346. IoSetNextIrpStackLocation( irp );
  1347. *IoRequestPacket = irp;
  1348. ASSERT (*BytesTaken == 0);
  1349. //
  1350. // Keep connection reference to be released in IRP completion routine
  1351. //
  1352. return STATUS_MORE_PROCESSING_REQUIRED;
  1353. }
  1354. else {
  1355. //
  1356. // Could not allocate substitute IRP or tracking info
  1357. // The IRP has aready been completed, go and try another one.
  1358. // Add extra reference to the connection to compensate for
  1359. // the one released in the completion routine.
  1360. //
  1361. CHECK_REFERENCE_CONNECTION (connection,result);
  1362. if (result) {
  1363. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  1364. continue;
  1365. }
  1366. else
  1367. return STATUS_DATA_NOT_ACCEPTED;
  1368. }
  1369. }
  1370. //
  1371. // The first pended IRP is too tiny to hold all the
  1372. // available data or else it is a peek or expedited receive
  1373. // IRP. Put the IRP back on the head of the list and buffer
  1374. // the data and complete the IRP in the restart routine.
  1375. //
  1376. InsertHeadList(
  1377. &connection->VcReceiveIrpListHead,
  1378. &irp->Tail.Overlay.ListEntry
  1379. );
  1380. break;
  1381. }
  1382. //
  1383. // Check whether we've already bufferred the maximum amount of
  1384. // data that we'll allow ourselves to buffer for this
  1385. // connection. If we're at the limit, then we need to exert
  1386. // back pressure by not accepting this indicated data (flow
  1387. // control).
  1388. //
  1389. // Note that we have no flow control mechanisms for expedited
  1390. // data. We always accept any expedited data that is indicated
  1391. // to us.
  1392. //
  1393. if ( connection->VcBufferredReceiveBytes >=
  1394. connection->MaxBufferredReceiveBytes ||
  1395. connection->VcBufferredReceiveCount==MAXUSHORT
  1396. ) {
  1397. //
  1398. // Just remember the amount of data that is available. When
  1399. // buffer space frees up, we'll actually receive this data.
  1400. //
  1401. connection->VcReceiveBytesInTransport += BytesAvailable;
  1402. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  1403. DEREFERENCE_CONNECTION (connection);
  1404. return STATUS_DATA_NOT_ACCEPTED;
  1405. }
  1406. // There were no prepended IRPs, we'll have to buffer the data
  1407. // here in AFD. If all of the available data is being indicated
  1408. // to us AND this is a complete message, just copy the data
  1409. // here.
  1410. //
  1411. if ( completeMessage &&
  1412. BytesIndicated == BytesAvailable &&
  1413. IsListEmpty (&connection->VcReceiveIrpListHead)) {
  1414. afdBuffer = AfdGetBuffer( endpoint, BytesAvailable, 0,
  1415. connection->OwningProcess );
  1416. if (afdBuffer!=NULL) {
  1417. AFD_VERIFY_BUFFER (connection, Tsdu, BytesAvailable);
  1418. //
  1419. // Use the special function to copy the data instead of
  1420. // RtlCopyMemory in case the data is coming from a special
  1421. // place (DMA, etc.) which cannot work with RtlCopyMemory.
  1422. //
  1423. TdiCopyLookaheadData(
  1424. afdBuffer->Buffer,
  1425. Tsdu,
  1426. BytesAvailable,
  1427. ReceiveFlags
  1428. );
  1429. //
  1430. // Store the data length and set the offset to 0.
  1431. //
  1432. afdBuffer->DataLength = BytesAvailable;
  1433. afdBuffer->DataOffset = 0;
  1434. afdBuffer->RefCount = 1;
  1435. afdBuffer->PartialMessage = FALSE;
  1436. //
  1437. // Place the buffer on this connection's list of bufferred data
  1438. // and update the count of data bytes on the connection.
  1439. //
  1440. InsertTailList(
  1441. &connection->VcReceiveBufferListHead,
  1442. &afdBuffer->BufferListEntry
  1443. );
  1444. connection->VcBufferredReceiveBytes += BytesAvailable;
  1445. ASSERT (connection->VcBufferredReceiveCount<MAXUSHORT);
  1446. connection->VcBufferredReceiveCount += 1;
  1447. //
  1448. // All done. Release the lock and tell the provider that we
  1449. // took all the data.
  1450. //
  1451. *BytesTaken = BytesAvailable;
  1452. //
  1453. // Indicate that it is possible to receive on the endpoint now.
  1454. //
  1455. endpoint->DisableFastIoRecv = FALSE;
  1456. // Make sure connection was accepted/connected to prevent
  1457. // indication on listening endpoint
  1458. //
  1459. if (connection->State==AfdConnectionStateConnected) {
  1460. ASSERT (endpoint->Type & AfdBlockTypeVcConnecting);
  1461. AfdIndicateEventSelectEvent(
  1462. endpoint,
  1463. AFD_POLL_RECEIVE,
  1464. STATUS_SUCCESS
  1465. );
  1466. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  1467. AfdIndicatePollEvent(
  1468. endpoint,
  1469. AFD_POLL_RECEIVE,
  1470. STATUS_SUCCESS
  1471. );
  1472. }
  1473. else {
  1474. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  1475. }
  1476. DEREFERENCE_CONNECTION (connection);
  1477. return STATUS_SUCCESS;
  1478. }
  1479. }
  1480. else {
  1481. //
  1482. // There were no prepended IRPs and not all of the data was
  1483. // indicated to us. We'll have to buffer it by handing an IRP
  1484. // back to the TDI privider.
  1485. //
  1486. // Note that in this case we sometimes hand a large buffer to
  1487. // the TDI provider. We do this so that it can hold off
  1488. // completion of our IRP until it gets EOM or the buffer is
  1489. // filled. This reduces the number of receive indications that
  1490. // the TDI provider has to perform and also reduces the number
  1491. // of kernel/user transitions the application will perform
  1492. // because we'll tend to complete receives with larger amounts
  1493. // of data.
  1494. //
  1495. // We do not hand back a "large" AFD buffer if the indicated data
  1496. // is greater than the large buffer size or if the TDI provider
  1497. // is message mode. The reason for not giving big buffers back
  1498. // to message providers is that they will hold on to the buffer
  1499. // until a full message is received and this would be incorrect
  1500. // behavior on a SOCK_STREAM.
  1501. //
  1502. if ( AfdLargeBufferSize >= BytesAvailable &&
  1503. !AfdIgnorePushBitOnReceives &&
  1504. !IS_TDI_MESSAGE_MODE(endpoint) ) {
  1505. requiredAfdBufferSize = AfdLargeBufferSize;
  1506. receiveLength = AfdLargeBufferSize;
  1507. } else {
  1508. requiredAfdBufferSize = BytesAvailable;
  1509. receiveLength = BytesAvailable;
  1510. }
  1511. //
  1512. // We're able to buffer the data. First acquire a buffer of
  1513. // appropriate size.
  1514. //
  1515. afdBuffer = AfdGetBuffer( endpoint, requiredAfdBufferSize, 0,
  1516. connection->OwningProcess );
  1517. if ( afdBuffer != NULL ) {
  1518. //
  1519. // Note that we posted our own receive IRP to transport,
  1520. // so that user IRPs do not get forwarded there
  1521. //
  1522. ASSERT (InterlockedDecrement (&connection->VcReceiveIrpsInTransport)==-1);
  1523. goto FormatReceive;
  1524. }
  1525. }
  1526. // We failed to allocate the buffer.
  1527. // Just remember the amount of data that is available. When
  1528. // buffer space frees up, we'll actually receive this data.
  1529. //
  1530. connection->VcReceiveBytesInTransport += BytesAvailable;
  1531. if (connection->VcBufferredReceiveBytes == 0 &&
  1532. !connection->OnLRList) {
  1533. //
  1534. // Since we do not have any data buffered, application
  1535. // is not notified and will never call with recv.
  1536. // We will have to put this on low resource list
  1537. // and attempt to allocate memory and pull the data
  1538. // later.
  1539. //
  1540. connection->OnLRList = TRUE;
  1541. REFERENCE_CONNECTION (connection);
  1542. AfdLRListAddItem (&connection->LRListItem, AfdLRRepostReceive);
  1543. }
  1544. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  1545. DEREFERENCE_CONNECTION (connection);
  1546. return STATUS_DATA_NOT_ACCEPTED;
  1547. } else {
  1548. //
  1549. // We're being indicated with expedited data. Buffer it and
  1550. // complete any pended IRPs in the restart routine. We always
  1551. // buffer expedited data to save complexity and because expedited
  1552. // data is not an important performance case.
  1553. //
  1554. // !!! do we need to perform flow control with expedited data?
  1555. //
  1556. requiredAfdBufferSize = BytesAvailable;
  1557. receiveLength = BytesAvailable;
  1558. //
  1559. // We're able to buffer the data. First acquire a buffer of
  1560. // appropriate size.
  1561. //
  1562. if ( connection->VcBufferredExpeditedCount==MAXUSHORT ||
  1563. (afdBuffer=AfdGetBuffer (endpoint, requiredAfdBufferSize, 0,
  1564. connection->OwningProcess))== NULL ) {
  1565. // If we couldn't get a buffer, abort the connection. This is
  1566. // pretty brutal, but the only alternative is to attempt to
  1567. // receive the data sometime later, which is very complicated to
  1568. // implement.
  1569. //
  1570. AfdBeginAbort( connection );
  1571. *BytesTaken = BytesAvailable;
  1572. DEREFERENCE_CONNECTION (connection);
  1573. return STATUS_SUCCESS;
  1574. }
  1575. }
  1576. FormatReceive:
  1577. //
  1578. // We'll have to format up an IRP and give it to the provider to
  1579. // handle. We don't need any locks to do this--the restart routine
  1580. // will check whether new receive IRPs were pended on the endpoint.
  1581. //
  1582. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  1583. ASSERT (afdBuffer!=NULL);
  1584. //
  1585. // Use the IRP in the AFD buffer if appropriate. If userIrp is
  1586. // TRUE, then the local variable irp will already point to the
  1587. // user's IRP which we'll use for this IO.
  1588. //
  1589. irp = afdBuffer->Irp;
  1590. ASSERT( afdBuffer->Mdl == irp->MdlAddress );
  1591. //
  1592. // We need to remember the connection in the AFD buffer because
  1593. // we'll need to access it in the completion routine.
  1594. //
  1595. afdBuffer->Context = connection;
  1596. //
  1597. // Remember the type of data that we're receiving.
  1598. //
  1599. afdBuffer->ExpeditedData = expedited;
  1600. afdBuffer->PartialMessage = !completeMessage;
  1601. TdiBuildReceive(
  1602. irp,
  1603. connection->DeviceObject,
  1604. connection->FileObject,
  1605. AfdRestartBufferReceive,
  1606. afdBuffer,
  1607. irp->MdlAddress,
  1608. ReceiveFlags & TDI_RECEIVE_EITHER,
  1609. receiveLength
  1610. );
  1611. //
  1612. // Finish building the receive IRP to give to the TDI provider.
  1613. //
  1614. ASSERT( receiveLength != 0xFFFFFFFF );
  1615. //
  1616. // Make the next stack location current. Normally IoCallDriver would
  1617. // do this, but since we're bypassing that, we do it directly.
  1618. //
  1619. IoSetNextIrpStackLocation( irp );
  1620. *IoRequestPacket = irp;
  1621. ASSERT (*BytesTaken == 0);
  1622. //
  1623. // Keep connection reference to be released in IRP completion routine
  1624. //
  1625. return STATUS_MORE_PROCESSING_REQUIRED;
  1626. } // AfdBReceiveEventHandler
  1627. NTSTATUS
  1628. AfdBReceiveExpeditedEventHandler (
  1629. IN PVOID TdiEventContext,
  1630. IN CONNECTION_CONTEXT ConnectionContext,
  1631. IN ULONG ReceiveFlags,
  1632. IN ULONG BytesIndicated,
  1633. IN ULONG BytesAvailable,
  1634. OUT ULONG *BytesTaken,
  1635. IN PVOID Tsdu,
  1636. OUT PIRP *IoRequestPacket
  1637. )
  1638. /*++
  1639. Routine Description:
  1640. Handles receive expedited events for nonbufferring transports.
  1641. Arguments:
  1642. Return Value:
  1643. --*/
  1644. {
  1645. return AfdBReceiveEventHandler (
  1646. TdiEventContext,
  1647. ConnectionContext,
  1648. ReceiveFlags | TDI_RECEIVE_EXPEDITED,
  1649. BytesIndicated,
  1650. BytesAvailable,
  1651. BytesTaken,
  1652. Tsdu,
  1653. IoRequestPacket
  1654. );
  1655. } // AfdBReceiveExpeditedEventHandler
  1656. NTSTATUS
  1657. AfdRestartBufferReceiveWithUserIrp (
  1658. IN PDEVICE_OBJECT DeviceObject,
  1659. IN PIRP Irp,
  1660. IN PVOID Context
  1661. )
  1662. /*++
  1663. Routine Description:
  1664. Handles completion of bufferred receives that were started in the
  1665. receive indication handler or receive routine with application
  1666. IRP passed directly to the transport.
  1667. Arguments:
  1668. DeviceObject - not used.
  1669. Irp - the IRP that is completing.
  1670. Context - connection on which we receive the data
  1671. Return Value:
  1672. STATUS_SUCCESS if user IRP is completed,
  1673. STATUS_MORE_PROCESSING_REQUIRED if we can't complete it.
  1674. --*/
  1675. {
  1676. PAFD_ENDPOINT endpoint;
  1677. PAFD_CONNECTION connection;
  1678. AFD_LOCK_QUEUE_HANDLE lockHandle;
  1679. PIO_STACK_LOCATION irpSp;
  1680. UNREFERENCED_PARAMETER (DeviceObject);
  1681. //
  1682. // The IRP being completed is actually a user's IRP, set it up
  1683. // for completion and allow IO completion to finish.
  1684. //
  1685. irpSp = IoGetCurrentIrpStackLocation( Irp );
  1686. connection = Context;
  1687. ASSERT( connection->Type == AfdBlockTypeConnection );
  1688. endpoint = connection->Endpoint;
  1689. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting ||
  1690. endpoint->Type == AfdBlockTypeVcBoth);
  1691. ASSERT( IS_VC_ENDPOINT(endpoint) );
  1692. ASSERT( !IS_TDI_BUFFERRING(endpoint) );
  1693. AfdCompleteOutstandingIrp (endpoint, Irp);
  1694. //
  1695. // We could not have any buffered data if we are completing user
  1696. // IRP
  1697. //
  1698. ASSERT( !(irpSp->Parameters.AfdRestartRecvInfo.AfdRecvFlags&TDI_RECEIVE_NORMAL)
  1699. || !IS_DATA_ON_CONNECTION( connection ));
  1700. ASSERT( !(irpSp->Parameters.AfdRestartRecvInfo.AfdRecvFlags&TDI_RECEIVE_EXPEDITED)
  1701. || !IS_EXPEDITED_DATA_ON_CONNECTION( connection ));
  1702. AFD_VERIFY_MDL (connection, Irp->MdlAddress, 0, Irp->IoStatus.Information);
  1703. ASSERT (InterlockedDecrement (&connection->VcReceiveIrpsInTransport)>=0);
  1704. //
  1705. // If pending has be returned for this IRP then mark the current
  1706. // stack as pending.
  1707. //
  1708. if ( Irp->PendingReturned ) {
  1709. IoMarkIrpPending( Irp );
  1710. }
  1711. UPDATE_CONN2 (connection, "Completing user receive with error/bytes: 0x%lX",
  1712. !NT_ERROR (Irp->IoStatus.Status)
  1713. ? (ULONG)Irp->IoStatus.Information
  1714. : (ULONG)Irp->IoStatus.Status);
  1715. if (connection->RcvInitiated) {
  1716. //
  1717. // Completion of receive initiated by AFD in low memory
  1718. // conditions (as opposed to IRP returned to the
  1719. // transport in the indication handler).
  1720. //
  1721. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  1722. connection->RcvInitiated = FALSE;
  1723. ASSERT (connection->OnLRList == FALSE);
  1724. ASSERT (connection->VcBufferredReceiveBytes==0);
  1725. if (!NT_ERROR (Irp->IoStatus.Status)) {
  1726. ASSERT (connection->VcReceiveBytesInTransport>0 || connection->Aborted);
  1727. if (connection->VcReceiveBytesInTransport > Irp->IoStatus.Information) {
  1728. connection->VcReceiveBytesInTransport -= (ULONG)Irp->IoStatus.Information;
  1729. }
  1730. else {
  1731. connection->VcReceiveBytesInTransport = 0;
  1732. }
  1733. }
  1734. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  1735. "AFD: Completing LR initiated user receive on connection %p, bytes/error: 0x%lx, 0x%x remains\n",
  1736. connection,
  1737. NT_SUCCESS (Irp->IoStatus.Status)
  1738. ? (ULONG)Irp->IoStatus.Information
  1739. : Irp->IoStatus.Status,
  1740. connection->VcReceiveBytesInTransport));
  1741. //
  1742. // We need to keep retreiving data from the transport
  1743. // if we know there is still something in there.
  1744. //
  1745. if (connection->VcReceiveBytesInTransport>0 &&
  1746. !connection->Aborted &&
  1747. !connection->DisconnectIndicated &&
  1748. (endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_RECEIVE) == 0 &&
  1749. !endpoint->EndpointCleanedUp &&
  1750. !connection->OnLRList) {
  1751. connection->OnLRList = TRUE;
  1752. REFERENCE_CONNECTION (connection);
  1753. AfdLRListAddItem (&connection->LRListItem, AfdLRRepostReceive);
  1754. }
  1755. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  1756. }
  1757. //
  1758. // If transport cancelled the IRP and we already had some data
  1759. // in it, do not complete with STATUS_CANCELLED since this will
  1760. // result in data loss.
  1761. //
  1762. if (Irp->IoStatus.Status==STATUS_CANCELLED &&
  1763. irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength>0 &&
  1764. !endpoint->EndpointCleanedUp) {
  1765. Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
  1766. }
  1767. else if (!NT_ERROR (Irp->IoStatus.Status)) {
  1768. Irp->IoStatus.Information += irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength;
  1769. }
  1770. if (Irp->IoStatus.Status==STATUS_BUFFER_OVERFLOW ||
  1771. Irp->IoStatus.Status == STATUS_RECEIVE_PARTIAL ||
  1772. Irp->IoStatus.Status == STATUS_RECEIVE_PARTIAL_EXPEDITED) {
  1773. if (!IS_MESSAGE_ENDPOINT(endpoint)) {
  1774. //
  1775. // For stream endpoint partial message does not make
  1776. // sense (unless this is the special hack for transports that
  1777. // terminate the connection when we cancel IRPs), ignore it.
  1778. //
  1779. Irp->IoStatus.Status = STATUS_SUCCESS;
  1780. }
  1781. else if ((Irp->IoStatus.Information
  1782. <irpSp->Parameters.AfdRestartRecvInfo.AfdOriginalLength) &&
  1783. ((irpSp->Parameters.AfdRestartRecvInfo.AfdRecvFlags & TDI_RECEIVE_PARTIAL) == 0 )) {
  1784. NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED;
  1785. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  1786. //
  1787. // Reset the status to success if we need to complete the IRP
  1788. // This is not entirely correct for message endpoints since
  1789. // we should not be completing the IRP unless we received the
  1790. // entire message. However, the only way this can happen is
  1791. // when the part of the message was received as IRP is cancelled
  1792. // and the only other this we possibly do is to try to copy data
  1793. // in our own buffer and reinsert it back to the queue.
  1794. //
  1795. Irp->IoStatus.Status = STATUS_SUCCESS;
  1796. //
  1797. // Set up the cancellation routine back in the IRP.
  1798. //
  1799. IoSetCancelRoutine( Irp, AfdCancelReceive );
  1800. if ( Irp->Cancel ) {
  1801. if (IoSetCancelRoutine( Irp, NULL ) != NULL) {
  1802. //
  1803. // Completion routine has not been reset,
  1804. // let the system complete the IRP on return
  1805. //
  1806. status = STATUS_SUCCESS;
  1807. }
  1808. else {
  1809. //
  1810. // The cancel routine is about to be run.
  1811. // Set the Flink to NULL so the cancel routine knows
  1812. // it is not on the list and tell the system
  1813. // not to touch the irp
  1814. //
  1815. Irp->Tail.Overlay.ListEntry.Flink = NULL;
  1816. }
  1817. }
  1818. else {
  1819. //
  1820. // Reinset IRP back in the list if partial completion
  1821. // is impossible and tell the system not to touch it
  1822. //
  1823. irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength = (ULONG)Irp->IoStatus.Information;
  1824. InsertHeadList (&connection->VcReceiveIrpListHead,
  1825. &Irp->Tail.Overlay.ListEntry);
  1826. }
  1827. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  1828. //
  1829. // Release connection reference acquired when we handed IRP to transport
  1830. //
  1831. DEREFERENCE_CONNECTION (connection);
  1832. return status;
  1833. }
  1834. }
  1835. IF_DEBUG (RECEIVE) {
  1836. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1837. "AfdRestartBufferReceiveWithUserIrp: endpoint: %p, letting IRP: %p, status %lx, info: %ld.\n",
  1838. endpoint,
  1839. Irp,
  1840. Irp->IoStatus.Status,
  1841. Irp->IoStatus.Information));
  1842. }
  1843. //
  1844. // Release connection reference acquired when we handed IRP to transport
  1845. //
  1846. DEREFERENCE_CONNECTION (connection);
  1847. //
  1848. // Tell the IO system that it is OK to continue with IO
  1849. // completion.
  1850. //
  1851. return STATUS_SUCCESS;
  1852. } //AfdRestartBufferReceiveWithUserIrp
  1853. NTSTATUS
  1854. AfdRestartBufferReceive (
  1855. IN PDEVICE_OBJECT DeviceObject,
  1856. IN PIRP Irp,
  1857. IN PVOID Context
  1858. )
  1859. /*++
  1860. Routine Description:
  1861. Handles completion of bufferred receives that were started in the
  1862. receive indication handler or AfdBReceive using Afds buffer and
  1863. associated IRP.
  1864. Arguments:
  1865. DeviceObject - not used.
  1866. Irp - the IRP that is completing.
  1867. Context - AfdBuffer in which we receive the data.
  1868. Return Value:
  1869. NTSTATUS - this is our IRP, so we always return
  1870. STATUS_MORE_PROCESSING_REQUIRED to indicate to the IO system that we
  1871. own the IRP and the IO system should stop processing the it.
  1872. --*/
  1873. {
  1874. PAFD_ENDPOINT endpoint;
  1875. PAFD_CONNECTION connection;
  1876. AFD_LOCK_QUEUE_HANDLE lockHandle;
  1877. PAFD_BUFFER afdBuffer;
  1878. PLIST_ENTRY listEntry;
  1879. LIST_ENTRY completeIrpListHead;
  1880. PIRP userIrp;
  1881. BOOLEAN expedited;
  1882. NTSTATUS irpStatus;
  1883. UNREFERENCED_PARAMETER (DeviceObject);
  1884. afdBuffer = Context;
  1885. ASSERT (IS_VALID_AFD_BUFFER (afdBuffer));
  1886. irpStatus = Irp->IoStatus.Status;
  1887. //
  1888. // We treat STATUS_BUFFER_OVERFLOW just like STATUS_RECEIVE_PARTIAL.
  1889. //
  1890. if ( irpStatus == STATUS_BUFFER_OVERFLOW )
  1891. irpStatus = STATUS_RECEIVE_PARTIAL;
  1892. connection = afdBuffer->Context;
  1893. ASSERT( connection->Type == AfdBlockTypeConnection );
  1894. endpoint = connection->Endpoint;
  1895. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting ||
  1896. endpoint->Type == AfdBlockTypeVcListening ||
  1897. endpoint->Type == AfdBlockTypeVcBoth );
  1898. ASSERT( !IS_TDI_BUFFERRING(endpoint) );
  1899. ASSERT( IS_VC_ENDPOINT (endpoint) );
  1900. if ( !NT_SUCCESS(irpStatus) ) {
  1901. afdBuffer->Mdl->ByteCount = afdBuffer->BufferLength;
  1902. AfdReturnBuffer( &afdBuffer->Header, connection->OwningProcess );
  1903. if (connection->RcvInitiated) {
  1904. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  1905. connection->RcvInitiated = FALSE;
  1906. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  1907. }
  1908. (VOID)AfdBeginAbort (connection);
  1909. DEREFERENCE_CONNECTION (connection);
  1910. return STATUS_MORE_PROCESSING_REQUIRED;
  1911. }
  1912. AFD_VERIFY_MDL (connection, Irp->MdlAddress, 0, Irp->IoStatus.Information);
  1913. //
  1914. // Remember the length of the received data.
  1915. //
  1916. afdBuffer->DataLength = (ULONG)Irp->IoStatus.Information;
  1917. //
  1918. // Initialize the local list we'll use to complete any receive IRPs.
  1919. // We use a list like this because we may need to complete multiple
  1920. // IRPs and we usually cannot complete IRPs at any random point due
  1921. // to any locks we might hold.
  1922. //
  1923. InitializeListHead( &completeIrpListHead );
  1924. //
  1925. // If there are any pended IRPs on the connection, complete as
  1926. // appropriate with the new information. Note that we'll try to
  1927. // complete as many pended IRPs as possible with this new buffer of
  1928. // data.
  1929. //
  1930. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  1931. //
  1932. // Check if connection was accepted and use accept endpoint instead
  1933. // of the listening. Note that accept cannot happen while we are
  1934. // holding listening endpoint spinlock, nor can endpoint change after
  1935. // the accept and while connections is referenced, so it is safe to
  1936. // release listening spinlock if we discover that endpoint was accepted.
  1937. //
  1938. if (((endpoint->Type & AfdBlockTypeVcListening) == AfdBlockTypeVcListening)
  1939. && (connection->Endpoint != endpoint)) {
  1940. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  1941. endpoint = connection->Endpoint;
  1942. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting );
  1943. ASSERT( !IS_TDI_BUFFERRING(endpoint) );
  1944. ASSERT( IS_VC_ENDPOINT (endpoint) );
  1945. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  1946. }
  1947. if (connection->RcvInitiated) {
  1948. connection->RcvInitiated = FALSE;
  1949. ASSERT (afdBuffer->ExpeditedData == FALSE);
  1950. ASSERT (connection->OnLRList == FALSE);
  1951. if (connection->VcReceiveBytesInTransport > afdBuffer->DataLength) {
  1952. connection->VcReceiveBytesInTransport -= afdBuffer->DataLength;
  1953. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  1954. "AFD: Completing LR initiated AFD receive on connection %p, bytes: 0x%lx, 0x%x remains\n",
  1955. connection,
  1956. afdBuffer->DataLength,
  1957. connection->VcReceiveBytesInTransport));
  1958. }
  1959. else {
  1960. connection->VcReceiveBytesInTransport = 0;
  1961. }
  1962. }
  1963. expedited = afdBuffer->ExpeditedData;
  1964. //
  1965. // Note that there are no more of our own receive IRPs in transport
  1966. // and we can start forwarding application IRPs if necessary.
  1967. //
  1968. ASSERT (expedited || InterlockedIncrement (&connection->VcReceiveIrpsInTransport)==0);
  1969. afdBuffer->DataOffset = AfdBFillPendingIrps (
  1970. connection,
  1971. afdBuffer->Mdl,
  1972. 0,
  1973. afdBuffer->DataLength,
  1974. (expedited ? TDI_RECEIVE_EXPEDITED : 0) |
  1975. ((irpStatus==STATUS_SUCCESS) ? TDI_RECEIVE_ENTIRE_MESSAGE : 0) |
  1976. (!IS_MESSAGE_ENDPOINT(endpoint) ? AFD_RECEIVE_STREAM : 0),
  1977. &completeIrpListHead
  1978. );
  1979. ASSERT (afdBuffer->DataOffset<=afdBuffer->DataLength);
  1980. afdBuffer->DataLength -= afdBuffer->DataOffset;
  1981. //
  1982. // If there is any data left, place the buffer at the end of the
  1983. // connection's list of bufferred data and update counts of data on
  1984. // the connection.
  1985. //
  1986. if (afdBuffer->DataLength>0) {
  1987. afdBuffer->RefCount = 1;
  1988. InsertTailList(
  1989. &connection->VcReceiveBufferListHead,
  1990. &afdBuffer->BufferListEntry
  1991. );
  1992. if ( expedited ) {
  1993. connection->VcBufferredExpeditedBytes += afdBuffer->DataLength;
  1994. ASSERT (connection->VcBufferredExpeditedCount<MAXUSHORT);
  1995. connection->VcBufferredExpeditedCount += 1;
  1996. } else {
  1997. connection->VcBufferredReceiveBytes += afdBuffer->DataLength;
  1998. ASSERT (connection->VcBufferredReceiveCount<MAXUSHORT);
  1999. connection->VcBufferredReceiveCount += 1;
  2000. }
  2001. //
  2002. // Remember whether we got a full or partial receive in the
  2003. // AFD buffer.
  2004. //
  2005. if ( irpStatus == STATUS_RECEIVE_PARTIAL ||
  2006. irpStatus == STATUS_RECEIVE_PARTIAL_EXPEDITED ) {
  2007. afdBuffer->PartialMessage = TRUE;
  2008. } else {
  2009. afdBuffer->PartialMessage = FALSE;
  2010. }
  2011. //
  2012. // We queued the buffer and thus we can't use it after releasing
  2013. // the spinlock. This will also signify the fact that we do not
  2014. // need to free the buffer.
  2015. //
  2016. afdBuffer = NULL;
  2017. if (connection->State==AfdConnectionStateConnected) {
  2018. endpoint->DisableFastIoRecv = FALSE;
  2019. if ( expedited && !endpoint->InLine ) {
  2020. AfdIndicateEventSelectEvent(
  2021. endpoint,
  2022. AFD_POLL_RECEIVE_EXPEDITED,
  2023. STATUS_SUCCESS
  2024. );
  2025. } else {
  2026. AfdIndicateEventSelectEvent(
  2027. endpoint,
  2028. AFD_POLL_RECEIVE,
  2029. STATUS_SUCCESS
  2030. );
  2031. }
  2032. }
  2033. }
  2034. else if (connection->VcReceiveBytesInTransport>0 &&
  2035. !connection->Aborted &&
  2036. !connection->DisconnectIndicated &&
  2037. (endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_RECEIVE) == 0 &&
  2038. !endpoint->EndpointCleanedUp &&
  2039. !connection->OnLRList) {
  2040. //
  2041. // More data even after buffer completed.
  2042. // We must be completed an LR initiated small receive.
  2043. // Continue LR processing.
  2044. //
  2045. connection->OnLRList = TRUE;
  2046. REFERENCE_CONNECTION (connection);
  2047. AfdLRListAddItem (&connection->LRListItem, AfdLRRepostReceive);
  2048. }
  2049. //
  2050. // Release locks and indicate that there is bufferred data on the
  2051. // endpoint.
  2052. //
  2053. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  2054. //
  2055. // If there was leftover data (we queued the buffer), complete polls
  2056. // as necessary. Indicate expedited data if the endpoint is not
  2057. // InLine and expedited data was received; otherwise, indicate normal data.
  2058. //
  2059. if ( afdBuffer==NULL ) {
  2060. // Make sure connection was accepted/connected to prevent
  2061. // indication on listening endpoint
  2062. //
  2063. if (connection->State==AfdConnectionStateConnected) {
  2064. ASSERT (endpoint->Type & AfdBlockTypeVcConnecting);
  2065. if ( expedited && !endpoint->InLine ) {
  2066. AfdIndicatePollEvent(
  2067. endpoint,
  2068. AFD_POLL_RECEIVE_EXPEDITED,
  2069. STATUS_SUCCESS
  2070. );
  2071. } else {
  2072. AfdIndicatePollEvent(
  2073. endpoint,
  2074. AFD_POLL_RECEIVE,
  2075. STATUS_SUCCESS
  2076. );
  2077. }
  2078. }
  2079. }
  2080. else {
  2081. ASSERT (afdBuffer->DataLength==0);
  2082. afdBuffer->ExpeditedData = FALSE;
  2083. AfdReturnBuffer (&afdBuffer->Header, connection->OwningProcess);
  2084. }
  2085. //
  2086. // Complete IRPs as necessary.
  2087. //
  2088. while ( !IsListEmpty( &completeIrpListHead ) ) {
  2089. listEntry = RemoveHeadList( &completeIrpListHead );
  2090. userIrp = CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry );
  2091. IF_DEBUG (RECEIVE) {
  2092. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  2093. "AfdRestartBufferReceive: endpoint: %p, completing IRP: %p, status %lx, info: %ld.\n",
  2094. endpoint,
  2095. userIrp,
  2096. userIrp->IoStatus.Status,
  2097. userIrp->IoStatus.Information));
  2098. }
  2099. UPDATE_CONN2(connection, "Completing buffered receive with error/bytes: 0x%lX",
  2100. (!NT_ERROR(userIrp->IoStatus.Status)
  2101. ? (ULONG)userIrp->IoStatus.Information
  2102. : (ULONG)userIrp->IoStatus.Status));
  2103. IoCompleteRequest( userIrp, AfdPriorityBoost );
  2104. }
  2105. //
  2106. // Release connection reference acquired when we handed IRP to transport
  2107. //
  2108. DEREFERENCE_CONNECTION (connection);
  2109. //
  2110. // Tell the IO system to stop processing the AFD IRP, since we now
  2111. // own it as part of the AFD buffer.
  2112. //
  2113. return STATUS_MORE_PROCESSING_REQUIRED;
  2114. } // AfdRestartBufferReceive
  2115. ULONG
  2116. AfdBFillPendingIrps (
  2117. PAFD_CONNECTION Connection,
  2118. PMDL Mdl,
  2119. ULONG DataOffset,
  2120. ULONG DataLength,
  2121. ULONG Flags,
  2122. PLIST_ENTRY CompleteIrpListHead
  2123. ) {
  2124. PIRP userIrp;
  2125. NTSTATUS status;
  2126. BOOLEAN expedited = (BOOLEAN)((Flags & TDI_RECEIVE_EXPEDITED)!=0);
  2127. while ((DataLength>0)
  2128. && (userIrp = AfdGetPendedReceiveIrp(
  2129. Connection,
  2130. expedited )) != NULL ) {
  2131. PIO_STACK_LOCATION irpSp;
  2132. ULONG receiveFlags;
  2133. ULONG spaceInIrp;
  2134. ULONG bytesCopied=(ULONG)-1;
  2135. BOOLEAN peek;
  2136. BOOLEAN partialReceivePossible;
  2137. if ( IoSetCancelRoutine( userIrp, NULL ) == NULL ) {
  2138. //
  2139. // This IRP is about to be canceled. Look for another in the
  2140. // list. Set the Flink to NULL so the cancel routine knows
  2141. // it is not on the list.
  2142. //
  2143. userIrp->Tail.Overlay.ListEntry.Flink = NULL;
  2144. continue;
  2145. }
  2146. //
  2147. // Set up some locals.
  2148. //
  2149. irpSp = IoGetCurrentIrpStackLocation( userIrp );
  2150. receiveFlags = (ULONG)irpSp->Parameters.AfdRestartRecvInfo.AfdRecvFlags;
  2151. spaceInIrp = irpSp->Parameters.AfdRestartRecvInfo.AfdOriginalLength-
  2152. irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength;
  2153. peek = (BOOLEAN)( (receiveFlags & TDI_RECEIVE_PEEK) != 0 );
  2154. if ( (Flags & AFD_RECEIVE_STREAM) ||
  2155. (receiveFlags & TDI_RECEIVE_PARTIAL) != 0 ) {
  2156. partialReceivePossible = TRUE;
  2157. } else {
  2158. partialReceivePossible = FALSE;
  2159. }
  2160. //
  2161. // If we were not indicated a entire message and the first
  2162. // IRP has more space, do not take the data, instead pass
  2163. // it back to the transport to wait for a push bit and fill
  2164. // as much as possible. Non-chained receive handles this case
  2165. // outside of this routine.
  2166. // Note that endpoint must be of stream type or the IRP
  2167. // should not allow partial receive.
  2168. // Also, peek and expedited receive are not eligible for this
  2169. // performance optimization.
  2170. //
  2171. if (!peek &&
  2172. (Flags & AFD_RECEIVE_CHAINED) &&
  2173. ((Flags & (TDI_RECEIVE_EXPEDITED|TDI_RECEIVE_ENTIRE_MESSAGE))==0) &&
  2174. ((Flags & AFD_RECEIVE_STREAM) || ((receiveFlags & TDI_RECEIVE_PARTIAL)==0)) &&
  2175. (DataLength<spaceInIrp) &&
  2176. IsListEmpty (CompleteIrpListHead) &&
  2177. !AfdIgnorePushBitOnReceives) {
  2178. InsertTailList (CompleteIrpListHead, &userIrp->Tail.Overlay.ListEntry);
  2179. return (ULONG)-1;
  2180. }
  2181. //
  2182. // Copy data to the user's IRP.
  2183. //
  2184. if ( userIrp->MdlAddress != NULL ) {
  2185. status = AfdMapMdlChain (userIrp->MdlAddress);
  2186. if (NT_SUCCESS (status)) {
  2187. if (Flags & AFD_RECEIVE_CHAINED) {
  2188. status = (DataLength<=spaceInIrp)
  2189. ? STATUS_SUCCESS
  2190. : STATUS_BUFFER_OVERFLOW;
  2191. }
  2192. else {
  2193. status = AfdCopyMdlChainToMdlChain(
  2194. userIrp->MdlAddress,
  2195. irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength
  2196. - PtrToUlong(irpSp->Parameters.AfdRestartRecvInfo.AfdAdjustedLength),
  2197. Mdl,
  2198. DataOffset,
  2199. DataLength,
  2200. &bytesCopied
  2201. );
  2202. userIrp->IoStatus.Information =
  2203. irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength + bytesCopied;
  2204. }
  2205. }
  2206. else {
  2207. ASSERT (irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength==0);
  2208. userIrp->IoStatus.Status = status;
  2209. userIrp->IoStatus.Information = 0;
  2210. //
  2211. // Add the IRP to the list of IRPs we'll need to complete once we
  2212. // can release locks.
  2213. //
  2214. InsertTailList(
  2215. CompleteIrpListHead,
  2216. &userIrp->Tail.Overlay.ListEntry
  2217. );
  2218. continue;
  2219. }
  2220. } else {
  2221. status = STATUS_BUFFER_OVERFLOW;
  2222. userIrp->IoStatus.Information = 0;
  2223. }
  2224. ASSERT( status == STATUS_SUCCESS || status == STATUS_BUFFER_OVERFLOW );
  2225. //
  2226. // For stream type endpoints, it does not make sense to return
  2227. // STATUS_BUFFER_OVERFLOW. That status is only sensible for
  2228. // message-oriented transports. We have already set up the
  2229. // status field of the IRP when we pended it, so we don't
  2230. // need to do it again here.
  2231. //
  2232. if ( Flags & AFD_RECEIVE_STREAM ) {
  2233. ASSERT( userIrp->IoStatus.Status == STATUS_SUCCESS );
  2234. } else {
  2235. userIrp->IoStatus.Status = status;
  2236. }
  2237. //
  2238. // We can complete the IRP under any of the following
  2239. // conditions:
  2240. //
  2241. // - the buffer contains a complete message of data.
  2242. //
  2243. // - it is OK to complete the IRP with a partial message.
  2244. //
  2245. // - the IRP is already full of data.
  2246. //
  2247. if ( (Flags & TDI_RECEIVE_ENTIRE_MESSAGE)
  2248. ||
  2249. partialReceivePossible
  2250. ||
  2251. status == STATUS_BUFFER_OVERFLOW ) {
  2252. //
  2253. // Convert overflow status for message endpoints
  2254. // (either we overflowed the buffer or transport
  2255. // indicated us incomplete message. For the latter
  2256. // we have already decided that we can complete the
  2257. // receive - partialReceivePossible).
  2258. //
  2259. if (!(Flags & AFD_RECEIVE_STREAM) &&
  2260. ((status==STATUS_BUFFER_OVERFLOW) ||
  2261. ((Flags & TDI_RECEIVE_ENTIRE_MESSAGE)==0))) {
  2262. userIrp->IoStatus.Status =
  2263. (receiveFlags & TDI_RECEIVE_EXPEDITED)
  2264. ? STATUS_RECEIVE_PARTIAL_EXPEDITED
  2265. : STATUS_RECEIVE_PARTIAL;
  2266. }
  2267. //
  2268. // Add the IRP to the list of IRPs we'll need to complete once we
  2269. // can release locks.
  2270. //
  2271. InsertTailList(
  2272. CompleteIrpListHead,
  2273. &userIrp->Tail.Overlay.ListEntry
  2274. );
  2275. } else {
  2276. //
  2277. // Set up the cancellation routine back in the IRP. If the IRP
  2278. // has already been cancelled, continue with the next one.
  2279. //
  2280. IoSetCancelRoutine( userIrp, AfdCancelReceive );
  2281. if ( userIrp->Cancel ) {
  2282. if (IoSetCancelRoutine( userIrp, NULL ) != NULL) {
  2283. //
  2284. // Completion routine has not been reset,
  2285. // we have to complete it ourselves, so add it
  2286. // to our completion list.
  2287. //
  2288. if (irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength==0 ||
  2289. Connection->Endpoint->EndpointCleanedUp) {
  2290. userIrp->IoStatus.Status = STATUS_CANCELLED;
  2291. }
  2292. else {
  2293. //
  2294. // We cannot set STATUS_CANCELLED
  2295. // since we loose data already placed in the IRP.
  2296. //
  2297. userIrp->IoStatus.Information = irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength;
  2298. userIrp->IoStatus.Status = STATUS_SUCCESS;
  2299. }
  2300. InsertTailList(
  2301. CompleteIrpListHead,
  2302. &userIrp->Tail.Overlay.ListEntry
  2303. );
  2304. }
  2305. else {
  2306. //
  2307. // The cancel routine is about to be run.
  2308. // Set the Flink to NULL so the cancel routine knows
  2309. // it is not on the list.
  2310. //
  2311. userIrp->Tail.Overlay.ListEntry.Flink = NULL;
  2312. }
  2313. continue;
  2314. }
  2315. else {
  2316. if (Flags & AFD_RECEIVE_CHAINED) {
  2317. status = AfdCopyMdlChainToMdlChain(
  2318. userIrp->MdlAddress,
  2319. irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength
  2320. - PtrToUlong(irpSp->Parameters.AfdRestartRecvInfo.AfdAdjustedLength),
  2321. Mdl,
  2322. DataOffset,
  2323. DataLength,
  2324. &bytesCopied
  2325. );
  2326. }
  2327. ASSERT (status==STATUS_SUCCESS);
  2328. ASSERT (bytesCopied<=spaceInIrp);
  2329. //
  2330. // Update the count of data placed into the IRP thus far.
  2331. //
  2332. irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength += bytesCopied;
  2333. //
  2334. // Put the IRP back on the connection's list of pended IRPs.
  2335. //
  2336. InsertHeadList(
  2337. &Connection->VcReceiveIrpListHead,
  2338. &userIrp->Tail.Overlay.ListEntry
  2339. );
  2340. }
  2341. }
  2342. //
  2343. // If the IRP was not a peek IRP, update the AFD buffer
  2344. // accordingly. If it was a peek IRP then the data should be
  2345. // reread, so keep it around.
  2346. //
  2347. if ( !peek ) {
  2348. //
  2349. // If we copied all of the data from the buffer to the IRP,
  2350. // free the AFD buffer structure.
  2351. //
  2352. if ( status == STATUS_SUCCESS ) {
  2353. DataOffset += DataLength;
  2354. DataLength = 0;
  2355. } else {
  2356. //
  2357. // There is more data left in the buffer. Update counts in
  2358. // the AFD buffer structure.
  2359. //
  2360. ASSERT(DataLength > spaceInIrp);
  2361. DataOffset += spaceInIrp;
  2362. DataLength -= spaceInIrp;
  2363. }
  2364. }
  2365. if (Connection->VcReceiveIrpListHead.Flink
  2366. ==&userIrp->Tail.Overlay.ListEntry)
  2367. //
  2368. // We reinserted IRP back on pending list, so
  2369. // stop processing this buffer for now.
  2370. //
  2371. // !!! This could cause a problem if there is a regular
  2372. // receive pended behind a peek IRP! But that is a
  2373. // pretty unlikely scenario.
  2374. //
  2375. break;
  2376. }
  2377. return DataOffset;
  2378. }
  2379. VOID
  2380. AfdCancelReceive (
  2381. IN PDEVICE_OBJECT DeviceObject,
  2382. IN PIRP Irp
  2383. )
  2384. /*++
  2385. Routine Description:
  2386. Cancels a receive IRP that is pended in AFD.
  2387. Arguments:
  2388. DeviceObject - not used.
  2389. Irp - the IRP to cancel.
  2390. Return Value:
  2391. None.
  2392. --*/
  2393. {
  2394. PIO_STACK_LOCATION irpSp;
  2395. PAFD_ENDPOINT endpoint;
  2396. AFD_LOCK_QUEUE_HANDLE lockHandle;
  2397. UNREFERENCED_PARAMETER (DeviceObject);
  2398. //
  2399. // Get the endpoint pointer from our IRP stack location and the
  2400. // connection pointer from the endpoint.
  2401. //
  2402. irpSp = IoGetCurrentIrpStackLocation( Irp );
  2403. endpoint = irpSp->FileObject->FsContext;
  2404. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting ||
  2405. endpoint->Type == AfdBlockTypeVcBoth );
  2406. //
  2407. // Remove the IRP from the endpoint's IRP list, synchronizing with
  2408. // the endpoint lock which protects the lists. Note that the
  2409. // IRP *must* be on one of the endpoint's lists or the Flink is NULL
  2410. // if we are getting called here--anybody that removes the IRP from
  2411. // the list must reset the cancel routine to NULL and set the
  2412. // Flink to NULL before releasing the endpoint spin lock.
  2413. //
  2414. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  2415. if ( Irp->Tail.Overlay.ListEntry.Flink != NULL ) {
  2416. RemoveEntryList( &Irp->Tail.Overlay.ListEntry );
  2417. }
  2418. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  2419. //
  2420. // Release the cancel spin lock and complete the IRP with a
  2421. // cancellation status code.
  2422. //
  2423. IoReleaseCancelSpinLock( Irp->CancelIrql );
  2424. if (irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength==0 ||
  2425. endpoint->EndpointCleanedUp) {
  2426. Irp->IoStatus.Information = 0;
  2427. Irp->IoStatus.Status = STATUS_CANCELLED;
  2428. UPDATE_CONN(endpoint->Common.VcConnecting.Connection);
  2429. }
  2430. else {
  2431. //
  2432. // There was some data in the IRP, do not complete with
  2433. // STATUS_CANCELLED, since this will result in data loss
  2434. //
  2435. Irp->IoStatus.Information = irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength;
  2436. Irp->IoStatus.Status = STATUS_SUCCESS;
  2437. UPDATE_CONN2 (endpoint->Common.VcConnecting.Connection,
  2438. "Completing cancelled irp with 0x%lX bytes",
  2439. (ULONG)Irp->IoStatus.Information);
  2440. }
  2441. IoCompleteRequest( Irp, AfdPriorityBoost );
  2442. return;
  2443. } // AfdCancelReceive
  2444. PAFD_BUFFER_HEADER
  2445. AfdGetReceiveBuffer (
  2446. IN PAFD_CONNECTION Connection,
  2447. IN ULONG ReceiveFlags,
  2448. IN PAFD_BUFFER_HEADER StartingAfdBuffer OPTIONAL
  2449. )
  2450. /*++
  2451. Routine Description:
  2452. Returns a pointer to a receive data buffer that contains the
  2453. appropriate type of data. Note that this routine DOES NOT remove
  2454. the buffer structure from the list it is on.
  2455. This routine MUST be called with the connection's endpoint lock
  2456. held!
  2457. Arguments:
  2458. Connection - a pointer to the connection to search for data.
  2459. ReceiveFlags - the type of receive data to look for.
  2460. StartingAfdBuffer - if non-NULL, start looking for a buffer AFTER
  2461. this buffer.
  2462. Return Value:
  2463. PAFD_BUFFER - a pointer to an AFD buffer of the appropriate data type,
  2464. or NULL if there was no appropriate buffer on the connection.
  2465. --*/
  2466. {
  2467. PLIST_ENTRY listEntry;
  2468. PAFD_BUFFER_HEADER afdBuffer;
  2469. ASSERT( KeGetCurrentIrql( ) == DISPATCH_LEVEL );
  2470. //
  2471. // Start with the first AFD buffer on the connection.
  2472. //
  2473. listEntry = Connection->VcReceiveBufferListHead.Flink;
  2474. afdBuffer = CONTAINING_RECORD( listEntry, AFD_BUFFER_HEADER, BufferListEntry );
  2475. //
  2476. // If a starting AFD buffer was specified, walk past that buffer in
  2477. // the connection list.
  2478. //
  2479. if ( ARGUMENT_PRESENT( StartingAfdBuffer ) ) {
  2480. while ( TRUE ) {
  2481. if ( afdBuffer == StartingAfdBuffer ) {
  2482. listEntry = listEntry->Flink;
  2483. afdBuffer = CONTAINING_RECORD( listEntry, AFD_BUFFER_HEADER, BufferListEntry );
  2484. //
  2485. // Don't mix expedited and non-expedited data.
  2486. //
  2487. if (afdBuffer->ExpeditedData!=StartingAfdBuffer->ExpeditedData)
  2488. return NULL;
  2489. break;
  2490. }
  2491. listEntry = listEntry->Flink;
  2492. afdBuffer = CONTAINING_RECORD( listEntry, AFD_BUFFER_HEADER, BufferListEntry );
  2493. ASSERT( listEntry != &Connection->VcReceiveBufferListHead );
  2494. }
  2495. }
  2496. //
  2497. // Act based on the type of data we're trying to get.
  2498. //
  2499. switch ( ReceiveFlags & TDI_RECEIVE_EITHER ) {
  2500. case TDI_RECEIVE_NORMAL:
  2501. //
  2502. // Walk the connection's list of data buffers until we find the
  2503. // first data buffer that is of the appropriate type.
  2504. //
  2505. while ( listEntry != &Connection->VcReceiveBufferListHead &&
  2506. afdBuffer->ExpeditedData ) {
  2507. listEntry = afdBuffer->BufferListEntry.Flink;
  2508. afdBuffer = CONTAINING_RECORD( listEntry, AFD_BUFFER_HEADER, BufferListEntry );
  2509. }
  2510. if ( listEntry != &Connection->VcReceiveBufferListHead ) {
  2511. return afdBuffer;
  2512. } else {
  2513. return NULL;
  2514. }
  2515. case TDI_RECEIVE_EITHER :
  2516. //
  2517. // Just return the first buffer, if there is one.
  2518. //
  2519. if ( listEntry != &Connection->VcReceiveBufferListHead ) {
  2520. return afdBuffer;
  2521. } else {
  2522. return NULL;
  2523. }
  2524. case TDI_RECEIVE_EXPEDITED:
  2525. if ( Connection->VcBufferredExpeditedCount == 0 ) {
  2526. return NULL;
  2527. }
  2528. //
  2529. // Walk the connection's list of data buffers until we find the
  2530. // first data buffer that is of the appropriate type.
  2531. //
  2532. while ( listEntry != &Connection->VcReceiveBufferListHead &&
  2533. !afdBuffer->ExpeditedData ) {
  2534. listEntry = afdBuffer->BufferListEntry.Flink;
  2535. afdBuffer = CONTAINING_RECORD( listEntry, AFD_BUFFER_HEADER, BufferListEntry );
  2536. }
  2537. if ( listEntry != &Connection->VcReceiveBufferListHead ) {
  2538. return afdBuffer;
  2539. } else {
  2540. return NULL;
  2541. }
  2542. default:
  2543. ASSERT( !"Invalid ReceiveFlags" );
  2544. return NULL;
  2545. }
  2546. } // AfdGetReceiveBuffer
  2547. PIRP
  2548. AfdGetPendedReceiveIrp (
  2549. IN PAFD_CONNECTION Connection,
  2550. IN BOOLEAN Expedited
  2551. )
  2552. /*++
  2553. Routine Description:
  2554. Removes a receive IRP from the connection's list of receive IRPs.
  2555. Only returns an IRP which is valid for the specified type of
  2556. data, normal or expedited. If there are no IRPs pended or only
  2557. IRPs of the wrong type, returns NULL.
  2558. This routine MUST be called with the connection's endpoint lock
  2559. held!
  2560. Arguments:
  2561. Connection - a pointer to the connection to search for an IRP.
  2562. Expedited - TRUE if this routine should return a receive IRP which
  2563. can receive expedited data.
  2564. Return Value:
  2565. PIRP - a pointer to an IRP which can receive data of the specified
  2566. type. The IRP IS removed from the connection's list of pended
  2567. receive IRPs.
  2568. --*/
  2569. {
  2570. PIRP irp;
  2571. PIO_STACK_LOCATION irpSp;
  2572. ULONG receiveFlags;
  2573. PLIST_ENTRY listEntry;
  2574. ASSERT( KeGetCurrentIrql( ) == DISPATCH_LEVEL );
  2575. //
  2576. // Walk the list of pended receive IRPs looking for one which can
  2577. // be completed with the specified type of data.
  2578. //
  2579. for ( listEntry = Connection->VcReceiveIrpListHead.Flink;
  2580. listEntry != &Connection->VcReceiveIrpListHead;
  2581. listEntry = listEntry->Flink ) {
  2582. //
  2583. // Get a pointer to the IRP and our stack location in the IRP.
  2584. //
  2585. irp = CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry );
  2586. irpSp = IoGetCurrentIrpStackLocation( irp );
  2587. //
  2588. // Determine whether this IRP can receive the data type we need.
  2589. //
  2590. receiveFlags = irpSp->Parameters.AfdRestartRecvInfo.AfdRecvFlags;
  2591. receiveFlags &= TDI_RECEIVE_EITHER;
  2592. ASSERT( receiveFlags != 0 );
  2593. if ( receiveFlags == TDI_RECEIVE_NORMAL && !Expedited ) {
  2594. //
  2595. // We have a normal receive and normal data. Remove this
  2596. // IRP from the connection's list and return it.
  2597. //
  2598. RemoveEntryList( listEntry );
  2599. return irp;
  2600. }
  2601. if ( receiveFlags == TDI_RECEIVE_EITHER ) {
  2602. //
  2603. // This is an "either" receive. It can take the data
  2604. // regardless of the data type.
  2605. //
  2606. RemoveEntryList( listEntry );
  2607. return irp;
  2608. }
  2609. if ( receiveFlags == TDI_RECEIVE_EXPEDITED && Expedited ) {
  2610. //
  2611. // We have an expedited receive and expedited data. Remove
  2612. // this IRP from the connection's list and return it.
  2613. //
  2614. RemoveEntryList( listEntry );
  2615. return irp;
  2616. }
  2617. //
  2618. // This IRP did not meet our criteria. Continue scanning the
  2619. // connection's list of pended IRPs for a good IRP.
  2620. //
  2621. }
  2622. //
  2623. // There were no IRPs which could be completed with the specified
  2624. // type of data.
  2625. //
  2626. return NULL;
  2627. } // AfdGetPendedReceiveIrp
  2628. BOOLEAN
  2629. AfdLRRepostReceive (
  2630. PAFD_LR_LIST_ITEM Item
  2631. )
  2632. /*++
  2633. Routine Description:
  2634. Attempts to restart receive on a connection where AFD returned
  2635. STATUS_DATA_NO_ACCEPTED to the transport due to low resource condition.
  2636. Arguments:
  2637. Connection - connection of interest
  2638. Return Value:
  2639. TRUE - was able to restart receives (or connection is gone)
  2640. FALSE - still problem with resources
  2641. --*/
  2642. {
  2643. AFD_LOCK_QUEUE_HANDLE lockHandle;
  2644. PAFD_ENDPOINT endpoint;
  2645. PAFD_CONNECTION connection;
  2646. PAFD_BUFFER afdBuffer;
  2647. ULONG receiveLength;
  2648. connection = CONTAINING_RECORD (Item, AFD_CONNECTION, LRListItem);
  2649. ASSERT( connection->Type == AfdBlockTypeConnection );
  2650. endpoint = connection->Endpoint;
  2651. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting ||
  2652. endpoint->Type == AfdBlockTypeVcListening ||
  2653. endpoint->Type == AfdBlockTypeVcBoth );
  2654. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  2655. ASSERT (connection->OnLRList == TRUE);
  2656. //
  2657. // Check if connection was accepted and use accept endpoint instead
  2658. // of the listening. Note that accept cannot happen while we are
  2659. // holding listening endpoint spinlock, nor can endpoint change after
  2660. // the accept, so it is safe to release listening spinlock if
  2661. // we discover that endpoint was accepted.
  2662. //
  2663. if (((endpoint->Type & AfdBlockTypeVcListening) == AfdBlockTypeVcListening)
  2664. && (connection->Endpoint != endpoint)) {
  2665. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  2666. endpoint = connection->Endpoint;
  2667. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting );
  2668. ASSERT( !IS_TDI_BUFFERRING(endpoint) );
  2669. ASSERT( IS_VC_ENDPOINT (endpoint) );
  2670. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  2671. }
  2672. //
  2673. // Check if connection is still alive.
  2674. //
  2675. if (connection->Aborted ||
  2676. connection->DisconnectIndicated ||
  2677. ((endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_RECEIVE) != 0) ||
  2678. endpoint->EndpointCleanedUp ||
  2679. (connection->VcReceiveBytesInTransport == 0) ||
  2680. (connection->VcBufferredReceiveBytes >= connection->MaxBufferredReceiveBytes)) {
  2681. connection->OnLRList = FALSE;
  2682. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  2683. DEREFERENCE_CONNECTION (connection);
  2684. return TRUE;
  2685. }
  2686. ASSERT (connection->RcvInitiated==FALSE);
  2687. receiveLength = connection->VcReceiveBytesInTransport;
  2688. //
  2689. // Attempt to allocate receive buffer for the amount that the
  2690. // transport indicated to us last.
  2691. //
  2692. afdBuffer = AfdGetBuffer (endpoint, receiveLength, 0, connection->OwningProcess);
  2693. if (afdBuffer!=NULL) {
  2694. connection->VcReceiveBytesInTransport = 0;
  2695. }
  2696. else {
  2697. //
  2698. // Try smaller buffer if we can.
  2699. //
  2700. if (connection->VcReceiveBytesInTransport>AfdSmallBufferSize &&
  2701. !IS_MESSAGE_ENDPOINT (endpoint)) {
  2702. receiveLength = AfdSmallBufferSize;
  2703. afdBuffer = AfdGetBuffer (endpoint, receiveLength, 0, connection->OwningProcess);
  2704. }
  2705. if (afdBuffer!=NULL) {
  2706. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  2707. "AFD: Initiating small LR recieve on connection %p, bytes: 0x%lx, 0x%x remains\n",
  2708. connection,
  2709. receiveLength,
  2710. connection->VcReceiveBytesInTransport));
  2711. }
  2712. else {
  2713. //
  2714. // Try use application IRPs
  2715. //
  2716. while (!IsListEmpty(&connection->VcReceiveIrpListHead)) {
  2717. PIRP irp;
  2718. PIO_STACK_LOCATION irpSp;
  2719. //
  2720. // Get a pointer to the IRP and our stack location in it
  2721. //
  2722. irp = CONTAINING_RECORD( connection->VcReceiveIrpListHead.Flink,
  2723. IRP,
  2724. Tail.Overlay.ListEntry );
  2725. irpSp = IoGetCurrentIrpStackLocation( irp );
  2726. receiveLength = irpSp->Parameters.AfdRestartRecvInfo.AfdOriginalLength-
  2727. irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength;
  2728. //
  2729. // If the IRP is not large enough to hold the available data, or
  2730. // if it is a peek or expedited (exclusively, not both normal and
  2731. // expedited) receive IRP, then we'll just buffer the
  2732. // data manually and complete the IRP in the receive completion
  2733. // routine.
  2734. //
  2735. if ( (receiveLength>=connection->VcReceiveBytesInTransport ||
  2736. !IS_MESSAGE_ENDPOINT (endpoint) ||
  2737. (irpSp->Parameters.AfdRestartRecvInfo.AfdRecvFlags
  2738. & TDI_RECEIVE_PARTIAL) != 0 ) &&
  2739. ((irpSp->Parameters.AfdRestartRecvInfo.AfdRecvFlags
  2740. & TDI_RECEIVE_PEEK) == 0) &&
  2741. ((irpSp->Parameters.AfdRestartRecvInfo.AfdRecvFlags
  2742. & TDI_RECEIVE_NORMAL) != 0)) {
  2743. connection->OnLRList = FALSE;
  2744. connection->RcvInitiated = TRUE;
  2745. RemoveEntryList(&irp->Tail.Overlay.ListEntry);
  2746. if (IoSetCancelRoutine(irp, NULL) == NULL) {
  2747. //
  2748. // This IRP is about to be canceled. Look for another in the
  2749. // list. Set the Flink to NULL so the cancel routine knows
  2750. // it is not on the list.
  2751. //
  2752. irp->Tail.Overlay.ListEntry.Flink = NULL;
  2753. continue;
  2754. }
  2755. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  2756. "AFD: Initiating user LR recieve on connection %p, bytes: 0x%lx, 0x%x remains\n",
  2757. connection,
  2758. receiveLength,
  2759. connection->VcReceiveBytesInTransport));
  2760. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  2761. ASSERT (InterlockedIncrement (&connection->VcReceiveIrpsInTransport)==1);
  2762. if (irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength>0) {
  2763. irp->MdlAddress = AfdAdvanceMdlChain (irp->MdlAddress,
  2764. irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength
  2765. -PtrToUlong(irpSp->Parameters.AfdRestartRecvInfo.AfdAdjustedLength)
  2766. );
  2767. ASSERT (irp->MdlAddress!=NULL);
  2768. irpSp->Parameters.AfdRestartRecvInfo.AfdAdjustedLength =
  2769. UlongToPtr(irpSp->Parameters.AfdRestartRecvInfo.AfdCurrentLength);
  2770. }
  2771. TdiBuildReceive(
  2772. irp,
  2773. connection->DeviceObject,
  2774. connection->FileObject,
  2775. AfdRestartBufferReceiveWithUserIrp,
  2776. connection,
  2777. irp->MdlAddress,
  2778. irpSp->Parameters.AfdRestartRecvInfo.AfdRecvFlags & TDI_RECEIVE_EITHER,
  2779. receiveLength
  2780. );
  2781. #ifdef _AFD_VARIABLE_STACK_
  2782. if ((irp=AfdCheckStackSizeAndRecordOutstandingIrp (
  2783. endpoint,
  2784. connection->DeviceObject,
  2785. irp))!=NULL) {
  2786. #else //_AFD_VARIABLE_STACK_
  2787. if (AfdRecordOutstandingIrp (
  2788. endpoint,
  2789. connection->DeviceObject,
  2790. irp)) {
  2791. #endif //_AFD_VARIABLE_STACK_
  2792. IoCallDriver (connection->DeviceObject, irp);
  2793. return TRUE;
  2794. } else {
  2795. //
  2796. // Could not allocate substitute IRP or tracking info.
  2797. // This connection is referenced by its position on the LRList,
  2798. // and the completion routine will be invoked as the IRP is
  2799. // completed by AfdRecordOutstandingIrpDebug(). Because we're
  2800. // not actually off the LRList yet, we need to add an extra
  2801. // reference to the connection to compensate. The IRP is
  2802. // completed by AfdRecordOutstandingIrpDebug().
  2803. //
  2804. REFERENCE_CONNECTION(connection);
  2805. //
  2806. // We're going to loop around and try another user IRP.
  2807. //
  2808. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  2809. connection->OnLRList = TRUE;
  2810. ASSERT (connection->RcvInitiated == FALSE); // reset in completion routine.
  2811. }
  2812. } else {
  2813. //
  2814. // We can't use the first user IRP either, no more options to recover.
  2815. //
  2816. break;
  2817. }
  2818. } // while (!IsListEmpty(&connection->VcReceiveIrpListHead))
  2819. //
  2820. // The caller will automatically put this connection back on LR list
  2821. //
  2822. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  2823. UPDATE_CONN (connection);
  2824. return FALSE;
  2825. }
  2826. }
  2827. //
  2828. // Finish building the receive IRP to give to the TDI
  2829. // provider.
  2830. //
  2831. TdiBuildReceive(
  2832. afdBuffer->Irp,
  2833. connection->DeviceObject,
  2834. connection->FileObject,
  2835. AfdRestartBufferReceive,
  2836. afdBuffer,
  2837. afdBuffer->Mdl,
  2838. TDI_RECEIVE_NORMAL,
  2839. receiveLength
  2840. );
  2841. //
  2842. // Acquire connection reference to be released in completion routine
  2843. // We already have one by virtue of being here
  2844. // REFERENCE_CONNECTION (connection);
  2845. UPDATE_CONN2 (connection, "Reposting LR receive for 0x%lX bytes",
  2846. receiveLength);
  2847. ASSERT (InterlockedDecrement (&connection->VcReceiveIrpsInTransport)==-1);
  2848. //
  2849. // We need to remember the connection in the AFD buffer
  2850. // because we'll need to access it in the completion
  2851. // routine.
  2852. //
  2853. afdBuffer->Context = connection;
  2854. connection->OnLRList = FALSE;
  2855. connection->RcvInitiated = TRUE;
  2856. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  2857. IoCallDriver (connection->DeviceObject, afdBuffer->Irp);
  2858. return TRUE;
  2859. }