Windows NT 4.0 source code leak
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.

1884 lines
53 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. recvvc.c
  5. Abstract:
  6. This module contains routines for handling data receive for connection-
  7. oriented endpoints.
  8. Author:
  9. David Treadwell (davidtr) 21-Oct-1993
  10. Revision History:
  11. --*/
  12. #include "afdp.h"
  13. VOID
  14. AfdCancelReceive (
  15. IN PDEVICE_OBJECT DeviceObject,
  16. IN PIRP Irp
  17. );
  18. PIRP
  19. AfdGetPendedReceiveIrp (
  20. IN PAFD_CONNECTION Connection,
  21. IN BOOLEAN Expedited
  22. );
  23. PAFD_BUFFER
  24. AfdGetReceiveBuffer (
  25. IN PAFD_CONNECTION Connection,
  26. IN ULONG ReceiveFlags,
  27. IN PAFD_BUFFER StartingAfdBuffer OPTIONAL
  28. );
  29. #ifdef ALLOC_PRAGMA
  30. #pragma alloc_text( PAGEAFD, AfdBReceive )
  31. #pragma alloc_text( PAGEAFD, AfdBReceiveEventHandler )
  32. #pragma alloc_text( PAGEAFD, AfdBReceiveExpeditedEventHandler )
  33. #pragma alloc_text( PAGEAFD, AfdCancelReceive )
  34. #pragma alloc_text( PAGEAFD, AfdGetPendedReceiveIrp )
  35. #pragma alloc_text( PAGEAFD, AfdGetReceiveBuffer )
  36. #pragma alloc_text( PAGEAFD, AfdRestartBufferReceive )
  37. #endif
  38. NTSTATUS
  39. AfdBReceive (
  40. IN PIRP Irp,
  41. IN PIO_STACK_LOCATION IrpSp,
  42. IN ULONG RecvFlags,
  43. IN ULONG AfdFlags,
  44. IN ULONG RecvLength
  45. )
  46. {
  47. NTSTATUS status;
  48. KIRQL oldIrql;
  49. PAFD_ENDPOINT endpoint;
  50. PAFD_CONNECTION connection;
  51. ULONG bytesReceived;
  52. BOOLEAN peek;
  53. PAFD_BUFFER afdBuffer;
  54. BOOLEAN completeMessage;
  55. BOOLEAN partialReceivePossible;
  56. PAFD_BUFFER newAfdBuffer;
  57. //
  58. // Set up some local variables.
  59. //
  60. endpoint = IrpSp->FileObject->FsContext;
  61. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting );
  62. connection = endpoint->Common.VcConnecting.Connection;
  63. ASSERT( connection != NULL );
  64. ASSERT( connection->Type == AfdBlockTypeConnection );
  65. //
  66. // Determine if this is a peek operation.
  67. //
  68. ASSERT( ( RecvFlags & TDI_RECEIVE_EITHER ) != 0 );
  69. ASSERT( ( RecvFlags & TDI_RECEIVE_EITHER ) != TDI_RECEIVE_EITHER );
  70. peek = ( RecvFlags & TDI_RECEIVE_PEEK ) != 0;
  71. //
  72. // Determine whether it is legal to complete this receive with a
  73. // partial message.
  74. //
  75. if ( endpoint->EndpointType == AfdEndpointTypeStream ) {
  76. partialReceivePossible = TRUE;
  77. } else {
  78. if ( (RecvFlags & TDI_RECEIVE_PARTIAL) != 0 ) {
  79. partialReceivePossible = TRUE;
  80. } else {
  81. partialReceivePossible = FALSE;
  82. }
  83. }
  84. //
  85. // Reset the InputBufferLength field of our stack location. We'll
  86. // use this to keep track of how much data we've placed into the IRP
  87. // so far.
  88. //
  89. IrpSp->Parameters.DeviceIoControl.InputBufferLength = 0;
  90. //
  91. // If this is an inline endpoint, then either type of receive data
  92. // can be used to satisfy this receive.
  93. //
  94. if ( endpoint->InLine ) {
  95. RecvFlags |= TDI_RECEIVE_EITHER;
  96. }
  97. //
  98. // Check whether the remote end has aborted the connection, in which
  99. // case we should complete the receive.
  100. //
  101. if ( connection->AbortIndicated ) {
  102. status = STATUS_CONNECTION_RESET;
  103. goto complete;
  104. }
  105. //
  106. // Try to get data already bufferred on the connection to satisfy
  107. // this receive.
  108. //
  109. IoAcquireCancelSpinLock( &Irp->CancelIrql );
  110. AfdAcquireSpinLock( &endpoint->SpinLock, &oldIrql );
  111. if( RecvFlags & TDI_RECEIVE_EXPEDITED ) {
  112. endpoint->EventsActive &= ~AFD_POLL_RECEIVE_EXPEDITED;
  113. }
  114. if( RecvFlags & TDI_RECEIVE_NORMAL ) {
  115. endpoint->EventsActive &= ~AFD_POLL_RECEIVE;
  116. }
  117. IF_DEBUG(EVENT_SELECT) {
  118. KdPrint((
  119. "AfdBReceive: Endp %08lX, Active %08lX\n",
  120. endpoint,
  121. endpoint->EventsActive
  122. ));
  123. }
  124. newAfdBuffer = NULL;
  125. afdBuffer = NULL;
  126. afdBuffer = AfdGetReceiveBuffer( connection, RecvFlags, afdBuffer );
  127. while ( afdBuffer != NULL ) {
  128. //
  129. // Copy the data to the MDL in the IRP. Note that we do not
  130. // handle the case where, for a stream type endpoint, the
  131. // receive IRP is large enough to take multiple data buffers
  132. // worth of information. Our method works fine, albeit a little
  133. // slower. The faster, where the output buffer is filled up as
  134. // much as possible, is done in the fast path. We should only
  135. // be here if we hit a timing window between a fast path attempt
  136. // and a receive indication.
  137. //
  138. if ( Irp->MdlAddress != NULL ) {
  139. status = TdiCopyBufferToMdl(
  140. afdBuffer->Buffer,
  141. afdBuffer->DataOffset,
  142. afdBuffer->DataLength,
  143. Irp->MdlAddress,
  144. IrpSp->Parameters.DeviceIoControl.InputBufferLength,
  145. &bytesReceived
  146. );
  147. } else {
  148. if ( afdBuffer->DataLength == 0 ) {
  149. status = STATUS_SUCCESS;
  150. } else {
  151. status = STATUS_BUFFER_OVERFLOW;
  152. }
  153. bytesReceived = 0;
  154. }
  155. ASSERT( status == STATUS_SUCCESS || status == STATUS_BUFFER_OVERFLOW );
  156. ASSERT( afdBuffer->PartialMessage == TRUE || afdBuffer->PartialMessage == FALSE );
  157. completeMessage = !afdBuffer->PartialMessage;
  158. //
  159. // If this wasn't a peek IRP, update information on the
  160. // connection based on whether the entire buffer of data was
  161. // taken.
  162. //
  163. if ( !peek ) {
  164. //
  165. // If all the data in the buffer was taken, remove the buffer
  166. // from the connection's list and return it to the buffer pool.
  167. //
  168. if (status == STATUS_SUCCESS) {
  169. ASSERT(afdBuffer->DataLength == bytesReceived);
  170. //
  171. // Update the counts of bytes bufferred on the connection.
  172. //
  173. if ( afdBuffer->ExpeditedData ) {
  174. ASSERT( connection->VcBufferredExpeditedBytes >= bytesReceived );
  175. ASSERT( connection->VcBufferredExpeditedCount > 0 );
  176. connection->VcBufferredExpeditedBytes -= bytesReceived;
  177. connection->VcBufferredExpeditedCount -= 1;
  178. } else {
  179. ASSERT( connection->VcBufferredReceiveBytes >= bytesReceived );
  180. ASSERT( connection->VcBufferredReceiveCount > 0 );
  181. connection->VcBufferredReceiveBytes -= bytesReceived;
  182. connection->VcBufferredReceiveCount -= 1;
  183. }
  184. RemoveEntryList( &afdBuffer->BufferListEntry );
  185. afdBuffer->DataOffset = 0;
  186. afdBuffer->ExpeditedData = FALSE;
  187. AfdReturnBuffer( afdBuffer );
  188. //
  189. // Reset the afdBuffer local so that we know that the
  190. // buffer is gone.
  191. //
  192. afdBuffer = NULL;
  193. } else {
  194. //
  195. // Update the counts of bytes bufferred on the connection.
  196. //
  197. if ( afdBuffer->ExpeditedData ) {
  198. ASSERT( connection->VcBufferredExpeditedBytes >= bytesReceived );
  199. connection->VcBufferredExpeditedBytes -= bytesReceived;
  200. } else {
  201. ASSERT( connection->VcBufferredReceiveBytes >= bytesReceived );
  202. connection->VcBufferredReceiveBytes -= bytesReceived;
  203. }
  204. //
  205. // Not all of the buffer's data was taken. Update the
  206. // counters in the AFD buffer structure to reflect the
  207. // amount of data that was actually received.
  208. //
  209. ASSERT(afdBuffer->DataLength > bytesReceived);
  210. afdBuffer->DataOffset += bytesReceived;
  211. afdBuffer->DataLength -= bytesReceived;
  212. ASSERT( afdBuffer->DataOffset < afdBuffer->BufferLength );
  213. }
  214. //
  215. // If there is indicated but unreceived data in the TDI
  216. // provider, and we have available buffer space, fire off an
  217. // IRP to receive the data.
  218. //
  219. if ( connection->VcReceiveCountInTransport > 0
  220. &&
  221. connection->VcBufferredReceiveBytes <
  222. connection->MaxBufferredReceiveBytes
  223. &&
  224. connection->VcBufferredReceiveCount <
  225. connection->MaxBufferredReceiveCount ) {
  226. CLONG bytesToReceive;
  227. //
  228. // Remember the count of data that we're going to
  229. // receive, then reset the fields in the connection
  230. // where we keep track of how much data is available in
  231. // the transport. We reset it here before releasing the
  232. // lock so that another thread doesn't try to receive
  233. // the data at the same time as us.
  234. //
  235. if ( connection->VcReceiveBytesInTransport > AfdLargeBufferSize ) {
  236. bytesToReceive = connection->VcReceiveBytesInTransport;
  237. } else {
  238. bytesToReceive = AfdLargeBufferSize;
  239. }
  240. ASSERT( connection->VcReceiveCountInTransport == 1 );
  241. connection->VcReceiveBytesInTransport = 0;
  242. connection->VcReceiveCountInTransport = 0;
  243. //
  244. // Get an AFD buffer structure to hold the data.
  245. //
  246. newAfdBuffer = AfdGetBuffer( bytesToReceive, 0 );
  247. if ( newAfdBuffer == NULL ) {
  248. AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
  249. IoReleaseCancelSpinLock( Irp->CancelIrql );
  250. AfdBeginAbort( connection );
  251. status = STATUS_LOCAL_DISCONNECT;
  252. goto complete;
  253. }
  254. //
  255. // We need to remember the connection in the AFD buffer
  256. // because we'll need to access it in the completion
  257. // routine.
  258. //
  259. newAfdBuffer->Context = connection;
  260. //
  261. // Finish building the receive IRP to give to the TDI
  262. // provider.
  263. //
  264. TdiBuildReceive(
  265. newAfdBuffer->Irp,
  266. connection->DeviceObject,
  267. connection->FileObject,
  268. AfdRestartBufferReceive,
  269. newAfdBuffer,
  270. newAfdBuffer->Mdl,
  271. TDI_RECEIVE_NORMAL,
  272. bytesToReceive
  273. );
  274. //
  275. // Wait to hand off the IRP until we can safely release
  276. // the endpoint lock.
  277. //
  278. }
  279. }
  280. //
  281. // For stream type endpoints, it does not make sense to return
  282. // STATUS_BUFFER_OVERFLOW. That status is only sensible for
  283. // message-oriented transports.
  284. //
  285. if ( endpoint->EndpointType == AfdEndpointTypeStream ) {
  286. status = STATUS_SUCCESS;
  287. }
  288. //
  289. // We've set up all return information. If we got a full
  290. // message OR if we can complete with a partial message OR if
  291. // the IRP is full of data, clean up and complete the IRP.
  292. //
  293. if ( completeMessage || partialReceivePossible ||
  294. status == STATUS_BUFFER_OVERFLOW ) {
  295. if( ( RecvFlags & TDI_RECEIVE_NORMAL ) &&
  296. IS_DATA_ON_CONNECTION( connection ) ) {
  297. AfdIndicateEventSelectEvent(
  298. endpoint,
  299. AFD_POLL_RECEIVE_BIT,
  300. STATUS_SUCCESS
  301. );
  302. }
  303. if( ( RecvFlags & TDI_RECEIVE_EXPEDITED ) &&
  304. IS_EXPEDITED_DATA_ON_CONNECTION( connection ) ) {
  305. AfdIndicateEventSelectEvent(
  306. endpoint,
  307. endpoint->InLine
  308. ? AFD_POLL_RECEIVE_BIT
  309. : AFD_POLL_RECEIVE_EXPEDITED_BIT,
  310. STATUS_SUCCESS
  311. );
  312. }
  313. AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
  314. IoReleaseCancelSpinLock( Irp->CancelIrql );
  315. //
  316. // If there was data bufferred in the transport, fire off
  317. // the IRP to receive it.
  318. //
  319. if ( newAfdBuffer != NULL ) {
  320. (VOID)IoCallDriver( connection->DeviceObject, newAfdBuffer->Irp );
  321. }
  322. Irp->IoStatus.Status = status;
  323. Irp->IoStatus.Information = bytesReceived +
  324. IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  325. IoCompleteRequest( Irp, 0 );
  326. return status;
  327. }
  328. //
  329. // Update the count of bytes we've received so far into the IRP,
  330. // get another buffer of data, and continue.
  331. //
  332. IrpSp->Parameters.DeviceIoControl.InputBufferLength += bytesReceived;
  333. afdBuffer = AfdGetReceiveBuffer( connection, RecvFlags, afdBuffer );
  334. }
  335. //
  336. // If there was no data bufferred on the endpoint and the connection
  337. // has been disconnected by the remote end, complete the receive
  338. // with 0 bytes read if this is a stream endpoint, or a failure
  339. // code if this is a message endpoint.
  340. //
  341. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength == 0 &&
  342. connection->DisconnectIndicated ) {
  343. AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
  344. IoReleaseCancelSpinLock( Irp->CancelIrql );
  345. if ( endpoint->EndpointType == AfdEndpointTypeStream ) {
  346. status = STATUS_SUCCESS;
  347. } else {
  348. status = STATUS_GRACEFUL_DISCONNECT;
  349. }
  350. goto complete;
  351. }
  352. //
  353. // If this is a nonblocking endpoint and the request was a normal
  354. // receive (as opposed to a read IRP), fail the request. We don't
  355. // fail reads under the asumption that if the application is doing
  356. // reads they don't want nonblocking behavior.
  357. //
  358. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength == 0 &&
  359. endpoint->NonBlocking && !( AfdFlags & AFD_OVERLAPPED ) ) {
  360. AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
  361. IoReleaseCancelSpinLock( Irp->CancelIrql );
  362. status = STATUS_DEVICE_NOT_READY;
  363. goto complete;
  364. }
  365. //
  366. // We'll have to pend the IRP. Remember the receive flags in the
  367. // Type3InputBuffer field of our IO stack location.
  368. //
  369. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = (PVOID)RecvFlags;
  370. //
  371. // Place the IRP on the connection's list of pended receive IRPs and
  372. // mark the IRP ad pended.
  373. //
  374. InsertTailList(
  375. &connection->VcReceiveIrpListHead,
  376. &Irp->Tail.Overlay.ListEntry
  377. );
  378. IoMarkIrpPending( Irp );
  379. Irp->IoStatus.Status = STATUS_SUCCESS;
  380. //
  381. // Set up the cancellation routine in the IRP. If the IRP has already
  382. // been cancelled, just call the cancellation routine here.
  383. //
  384. if ( Irp->Cancel ) {
  385. AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
  386. AfdCancelReceive( IrpSp->DeviceObject, Irp );
  387. return STATUS_CANCELLED;
  388. }
  389. IoSetCancelRoutine( Irp, AfdCancelReceive );
  390. AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
  391. IoReleaseCancelSpinLock( Irp->CancelIrql );
  392. //
  393. // If there was data bufferred in the transport, fire off the IRP to
  394. // receive it. We have to wait until here because it is not legal
  395. // to do an IoCallDriver() while holding a spin lock.
  396. //
  397. if ( newAfdBuffer != NULL ) {
  398. (VOID)IoCallDriver( connection->DeviceObject, newAfdBuffer->Irp );
  399. }
  400. return STATUS_PENDING;
  401. complete:
  402. Irp->IoStatus.Status = status;
  403. Irp->IoStatus.Information = 0;
  404. IoCompleteRequest( Irp, 0 );
  405. return status;
  406. } // AfdBReceive
  407. NTSTATUS
  408. AfdBReceiveEventHandler (
  409. IN PVOID TdiEventContext,
  410. IN CONNECTION_CONTEXT ConnectionContext,
  411. IN ULONG ReceiveFlags,
  412. IN ULONG BytesIndicated,
  413. IN ULONG BytesAvailable,
  414. OUT ULONG *BytesTaken,
  415. IN PVOID Tsdu,
  416. OUT PIRP *IoRequestPacket
  417. )
  418. /*++
  419. Routine Description:
  420. Handles receive events for nonbufferring transports.
  421. Arguments:
  422. Return Value:
  423. --*/
  424. {
  425. KIRQL oldIrql;
  426. KIRQL cancelIrql;
  427. PAFD_ENDPOINT endpoint;
  428. PAFD_CONNECTION connection;
  429. PLIST_ENTRY listEntry;
  430. PAFD_BUFFER afdBuffer;
  431. PIRP irp;
  432. ULONG requiredAfdBufferSize;
  433. NTSTATUS status;
  434. ULONG receiveLength;
  435. BOOLEAN userIrp;
  436. BOOLEAN expedited;
  437. BOOLEAN completeMessage;
  438. DEBUG receiveLength = 0xFFFFFFFF;
  439. connection = (PAFD_CONNECTION)ConnectionContext;
  440. ASSERT( connection != NULL );
  441. endpoint = connection->Endpoint;
  442. ASSERT( endpoint != NULL );
  443. *BytesTaken = 0;
  444. ASSERT( connection->Type == AfdBlockTypeConnection );
  445. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting ||
  446. endpoint->Type == AfdBlockTypeVcListening );
  447. ASSERT( !connection->DisconnectIndicated );
  448. ASSERT( !endpoint->TdiBufferring );
  449. ASSERT( endpoint->EndpointType == AfdEndpointTypeStream ||
  450. endpoint->EndpointType == AfdEndpointTypeSequencedPacket ||
  451. endpoint->EndpointType == AfdEndpointTypeReliableMessage );
  452. #if AFD_PERF_DBG
  453. if ( BytesAvailable == BytesIndicated ) {
  454. AfdFullReceiveIndications++;
  455. } else {
  456. AfdPartialReceiveIndications++;
  457. }
  458. #endif
  459. //
  460. // If the receive side of the endpoint has been shut down, tell the
  461. // provider that we took all the data and reset the connection.
  462. // Also, account for these bytes in our count of bytes taken from
  463. // the transport.
  464. //
  465. IoAcquireCancelSpinLock( &cancelIrql );
  466. AfdAcquireSpinLock( &endpoint->SpinLock, &oldIrql );
  467. if ( (endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_RECEIVE) != 0 ||
  468. endpoint->EndpointCleanedUp ) {
  469. #if DBG
  470. DbgPrint( "AfdBReceiveEventHandler: receive shutdown, "
  471. "%ld bytes, aborting endp %lx\n",
  472. BytesAvailable, endpoint );
  473. #endif
  474. *BytesTaken = BytesAvailable;
  475. //
  476. // Abort the connection. Note that if the abort attempt fails
  477. // we can't do anything about it.
  478. //
  479. AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
  480. IoReleaseCancelSpinLock( cancelIrql );
  481. (VOID)AfdBeginAbort( connection );
  482. return STATUS_SUCCESS;
  483. }
  484. //
  485. // Figure out whether this is a receive indication for normal
  486. // or expedited data, and whether this is a complete message.
  487. //
  488. expedited = (BOOLEAN)( (ReceiveFlags & TDI_RECEIVE_EXPEDITED) != 0 );
  489. ASSERT( expedited || connection->VcReceiveBytesInTransport == 0 );
  490. ASSERT( expedited || connection->VcReceiveCountInTransport == 0 );
  491. completeMessage = (BOOLEAN)((ReceiveFlags & TDI_RECEIVE_ENTIRE_MESSAGE) != 0);
  492. //
  493. // Check whether there are any IRPs waiting on the connection. If
  494. // there is such an IRP and normal data is being indicated, use the
  495. // IRP to receive the data.
  496. //
  497. if ( !IsListEmpty( &connection->VcReceiveIrpListHead ) && !expedited ) {
  498. PIO_STACK_LOCATION irpSp;
  499. ASSERT( *BytesTaken == 0 );
  500. listEntry = RemoveHeadList( &connection->VcReceiveIrpListHead );
  501. //
  502. // Get a pointer to the IRP and reset the cancel routine in
  503. // the IRP. The IRP is no longer cancellable.
  504. //
  505. irp = CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry );
  506. IoSetCancelRoutine( irp, NULL );
  507. irpSp = IoGetCurrentIrpStackLocation( irp );
  508. //
  509. // If the IRP is not large enough to hold the available data, or
  510. // if it is a peek or expedited receive IRP, or if we've already
  511. // placed some data into the IRP, then we'll just buffer the
  512. // data manually and complete the IRP in the receive completion
  513. // routine.
  514. //
  515. if ( irpSp->Parameters.DeviceIoControl.OutputBufferLength >=
  516. BytesAvailable &&
  517. irpSp->Parameters.DeviceIoControl.InputBufferLength == 0 &&
  518. (ULONG)irpSp->Parameters.DeviceIoControl.Type3InputBuffer == 0 &&
  519. !endpoint->TdiMessageMode ) {
  520. //
  521. // If all of the data was indicated to us here AND this is a
  522. // complete message in and of itself, then just copy the
  523. // data to the IRP and complete the IRP.
  524. //
  525. if ( completeMessage && BytesIndicated == BytesAvailable ) {
  526. //
  527. // The IRP is off the endpoint's list and is no longer
  528. // cancellable. We can release the locks we hold.
  529. //
  530. AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
  531. IoReleaseCancelSpinLock( cancelIrql );
  532. //
  533. // Set BytesTaken to indicate that we've taken all the
  534. // data. We do it here because we already have
  535. // BytesAvailable in a register, which probably won't
  536. // be true after making function calls.
  537. //
  538. *BytesTaken = BytesAvailable;
  539. //
  540. // Copy the data to the IRP.
  541. //
  542. if ( irp->MdlAddress != NULL ) {
  543. status = TdiCopyBufferToMdl(
  544. Tsdu,
  545. 0,
  546. BytesAvailable,
  547. irp->MdlAddress,
  548. 0,
  549. &irp->IoStatus.Information
  550. );
  551. } else {
  552. ASSERT( BytesAvailable == 0 );
  553. status = STATUS_SUCCESS;
  554. irp->IoStatus.Information = 0;
  555. }
  556. //
  557. // We should never get STATUS_BUFFER_OVERFLOW from
  558. // TdiCopyBufferToMdl() because the user's buffer
  559. // should have been large enough to hold all the data.
  560. //
  561. ASSERT( status == STATUS_SUCCESS );
  562. //
  563. // We have already set up the status field of the IRP
  564. // when we pended the IRP, so there's no need to
  565. // set it again here.
  566. //
  567. ASSERT( irp->IoStatus.Status == STATUS_SUCCESS );
  568. //
  569. // Complete the IRP. We've already set BytesTaken
  570. // to tell the provider that we have taken all the data.
  571. //
  572. IoCompleteRequest( irp, AfdPriorityBoost );
  573. return STATUS_SUCCESS;
  574. }
  575. //
  576. // Some of the data was not indicated, so remember that we
  577. // want to pass back this IRP to the TDI provider. Passing
  578. // back this IRP directly is good because it avoids having
  579. // to copy the data from one of our buffers into the user's
  580. // buffer.
  581. //
  582. userIrp = TRUE;
  583. requiredAfdBufferSize = 0;
  584. receiveLength =
  585. AfdIgnorePushBitOnReceives
  586. ? BytesAvailable
  587. : irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  588. } else {
  589. //
  590. // The first pended IRP is too tiny to hold all the
  591. // available data or else it is a peek or expedited receive
  592. // IRP. Put the IRP back on the head of the list and buffer
  593. // the data and complete the IRP in the restart routine.
  594. //
  595. InsertHeadList(
  596. &connection->VcReceiveIrpListHead,
  597. &irp->Tail.Overlay.ListEntry
  598. );
  599. userIrp = FALSE;
  600. requiredAfdBufferSize = BytesAvailable;
  601. receiveLength = BytesAvailable;
  602. }
  603. } else if ( !expedited ) {
  604. ASSERT( IsListEmpty( &connection->VcReceiveIrpListHead ) );
  605. //
  606. // Check whether we've already bufferred the maximum amount of
  607. // data that we'll allow ourselves to buffer for this
  608. // connection. If we're at the limit, then we need to exert
  609. // back pressure by not accepting this indicated data (flow
  610. // control).
  611. //
  612. // Note that we have no flow control mechanisms for expedited
  613. // data. We always accept any expedited data that is indicated
  614. // to us.
  615. //
  616. if ( connection->VcBufferredReceiveBytes >=
  617. connection->MaxBufferredReceiveBytes
  618. ||
  619. connection->VcBufferredReceiveCount >=
  620. connection->MaxBufferredReceiveCount ) {
  621. ASSERT( connection->VcReceiveBytesInTransport == 0 );
  622. ASSERT( connection->VcReceiveCountInTransport == 0 );
  623. //
  624. // Just remember the amount of data that is available. When
  625. // buffer space frees up, we'll actually receive this data.
  626. //
  627. connection->VcReceiveBytesInTransport = BytesAvailable;
  628. connection->VcReceiveCountInTransport = 1;
  629. AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
  630. IoReleaseCancelSpinLock( cancelIrql );
  631. return STATUS_DATA_NOT_ACCEPTED;
  632. }
  633. //
  634. // There were no prepended IRPs. We'll have to buffer the data
  635. // here in AFD. If all of the available data is being indicated
  636. // to us AND this is a complete message, just copy the data
  637. // here.
  638. //
  639. if ( completeMessage && BytesIndicated == BytesAvailable ) {
  640. //
  641. // We don't need the cancel spin lock any more, so we can
  642. // release it. However, since we acquired the cancel spin lock
  643. // after the endpoint spin lock and we still need the endpoint
  644. // spin lock, be careful to switch the IRQLs.
  645. //
  646. IoReleaseCancelSpinLock( oldIrql );
  647. oldIrql = cancelIrql;
  648. //
  649. // Get an AFD buffer to hold the data.
  650. //
  651. afdBuffer = AfdGetBuffer( BytesAvailable, 0 );
  652. if ( afdBuffer == NULL ) {
  653. AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
  654. //
  655. // If we couldn't get a buffer, abort the connection.
  656. // This is pretty brutal, but the only alternative is
  657. // to attempt to receive the data sometime later, which
  658. // is very complicated to implement.
  659. //
  660. AfdBeginAbort( connection );
  661. *BytesTaken = BytesAvailable;
  662. return STATUS_SUCCESS;
  663. }
  664. //
  665. // Use the special function to copy the data instead of
  666. // RtlCopyMemory in case the data is coming from a special
  667. // place (DMA, etc.) which cannot work with RtlCopyMemory.
  668. //
  669. TdiCopyLookaheadData(
  670. afdBuffer->Buffer,
  671. Tsdu,
  672. BytesAvailable,
  673. ReceiveFlags
  674. );
  675. //
  676. // Store the data length and set the offset to 0.
  677. //
  678. afdBuffer->DataLength = BytesAvailable;
  679. ASSERT( afdBuffer->DataOffset == 0 );
  680. afdBuffer->PartialMessage = FALSE;
  681. //
  682. // Place the buffer on this connection's list of bufferred data
  683. // and update the count of data bytes on the connection.
  684. //
  685. InsertTailList(
  686. &connection->VcReceiveBufferListHead,
  687. &afdBuffer->BufferListEntry
  688. );
  689. connection->VcBufferredReceiveBytes += BytesAvailable;
  690. connection->VcBufferredReceiveCount += 1;
  691. //
  692. // All done. Release the lock and tell the provider that we
  693. // took all the data.
  694. //
  695. *BytesTaken = BytesAvailable;
  696. //
  697. // Indicate that it is possible to receive on the endpoint now.
  698. //
  699. AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
  700. AfdIndicatePollEvent(
  701. endpoint,
  702. AFD_POLL_RECEIVE_BIT,
  703. STATUS_SUCCESS
  704. );
  705. return STATUS_SUCCESS;
  706. }
  707. //
  708. // There were no prepended IRPs and not all of the data was
  709. // indicated to us. We'll have to buffer it by handing an IRP
  710. // back to the TDI privider.
  711. //
  712. // Note that in this case we sometimes hand a large buffer to
  713. // the TDI provider. We do this so that it can hold off
  714. // completion of our IRP until it gets EOM or the buffer is
  715. // filled. This reduces the number of receive indications that
  716. // the TDI provider has to perform and also reduces the number
  717. // of kernel/user transitions the application will perform
  718. // because we'll tend to complete receives with larger amounts
  719. // of data.
  720. //
  721. // We do not hand back a "large" AFD buffer if the indicated data
  722. // is greater than the large buffer size or if the TDI provider
  723. // is message mode. The reason for not giving big buffers back
  724. // to message providers is that they will hold on to the buffer
  725. // until a full message is received and this would be incorrect
  726. // behavior on a SOCK_STREAM.
  727. //
  728. userIrp = FALSE;
  729. if ( AfdLargeBufferSize >= BytesAvailable &&
  730. !AfdIgnorePushBitOnReceives &&
  731. !endpoint->TdiMessageMode ) {
  732. requiredAfdBufferSize = AfdLargeBufferSize;
  733. receiveLength = AfdLargeBufferSize;
  734. } else {
  735. requiredAfdBufferSize = BytesAvailable;
  736. receiveLength = BytesAvailable;
  737. }
  738. } else {
  739. //
  740. // We're being indicated with expedited data. Buffer it and
  741. // complete any pended IRPs in the restart routine. We always
  742. // buffer expedited data to save complexity and because expedited
  743. // data is not an important performance case.
  744. //
  745. // !!! do we need to perform flow control with expedited data?
  746. //
  747. userIrp = FALSE;
  748. requiredAfdBufferSize = BytesAvailable;
  749. receiveLength = BytesAvailable;
  750. }
  751. //
  752. // We're able to buffer the data. First acquire a buffer of
  753. // appropriate size.
  754. //
  755. afdBuffer = AfdGetBuffer( requiredAfdBufferSize, 0 );
  756. if ( afdBuffer == NULL ) {
  757. AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
  758. IoReleaseCancelSpinLock( cancelIrql );
  759. //
  760. // If we couldn't get a buffer, abort the connection. This is
  761. // pretty brutal, but the only alternative is to attempt to
  762. // receive the data sometime later, which is very complicated to
  763. // implement.
  764. //
  765. AfdBeginAbort( connection );
  766. *BytesTaken = BytesAvailable;
  767. return STATUS_SUCCESS;
  768. }
  769. //
  770. // We'll have to format up an IRP and give it to the provider to
  771. // handle. We don't need any locks to do this--the restart routine
  772. // will check whether new receive IRPs were pended on the endpoint.
  773. //
  774. AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
  775. IoReleaseCancelSpinLock( cancelIrql );
  776. //
  777. // Use the IRP in the AFD buffer if appropriate. If userIrp is
  778. // TRUE, then the local variable irp will already point to the
  779. // user's IRP which we'll use for this IO.
  780. //
  781. if ( !userIrp ) {
  782. irp = afdBuffer->Irp;
  783. ASSERT( afdBuffer->Mdl == irp->MdlAddress );
  784. }
  785. //
  786. // We need to remember the connection in the AFD buffer because
  787. // we'll need to access it in the completion routine.
  788. //
  789. afdBuffer->Context = connection;
  790. //
  791. // Remember the type of data that we're receiving.
  792. //
  793. afdBuffer->ExpeditedData = expedited;
  794. afdBuffer->PartialMessage = !completeMessage;
  795. //
  796. // Finish building the receive IRP to give to the TDI provider.
  797. //
  798. ASSERT( receiveLength != 0xFFFFFFFF );
  799. TdiBuildReceive(
  800. irp,
  801. connection->DeviceObject,
  802. connection->FileObject,
  803. AfdRestartBufferReceive,
  804. afdBuffer,
  805. irp->MdlAddress,
  806. ReceiveFlags & TDI_RECEIVE_EITHER,
  807. receiveLength
  808. );
  809. //
  810. // Make the next stack location current. Normally IoCallDriver would
  811. // do this, but since we're bypassing that, we do it directly.
  812. //
  813. IoSetNextIrpStackLocation( irp );
  814. *IoRequestPacket = irp;
  815. *BytesTaken = 0;
  816. return STATUS_MORE_PROCESSING_REQUIRED;
  817. } // AfdBReceiveEventHandler
  818. NTSTATUS
  819. AfdBReceiveExpeditedEventHandler (
  820. IN PVOID TdiEventContext,
  821. IN CONNECTION_CONTEXT ConnectionContext,
  822. IN ULONG ReceiveFlags,
  823. IN ULONG BytesIndicated,
  824. IN ULONG BytesAvailable,
  825. OUT ULONG *BytesTaken,
  826. IN PVOID Tsdu,
  827. OUT PIRP *IoRequestPacket
  828. )
  829. /*++
  830. Routine Description:
  831. Handles receive expedited events for nonbufferring transports.
  832. Arguments:
  833. Return Value:
  834. --*/
  835. {
  836. return AfdBReceiveEventHandler (
  837. TdiEventContext,
  838. ConnectionContext,
  839. ReceiveFlags | TDI_RECEIVE_EXPEDITED,
  840. BytesIndicated,
  841. BytesAvailable,
  842. BytesTaken,
  843. Tsdu,
  844. IoRequestPacket
  845. );
  846. } // AfdBReceiveExpeditedEventHandler
  847. NTSTATUS
  848. AfdRestartBufferReceive (
  849. IN PDEVICE_OBJECT DeviceObject,
  850. IN PIRP Irp,
  851. IN PVOID Context
  852. )
  853. /*++
  854. Routine Description:
  855. Handles completion of bufferred receives that were started in the
  856. receive indication handler.
  857. Arguments:
  858. DeviceObject - not used.
  859. Irp - the IRP that is completing.
  860. Context - the endpoint which received the data.
  861. Return Value:
  862. NTSTATUS - if this is our IRP, then always
  863. STATUS_MORE_PROCESSING_REQUIRED to indicate to the IO system that we
  864. own the IRP and the IO system should stop processing the it.
  865. If this is a user's IRP, then STATUS_SUCCESS to indicate that
  866. IO completion should continue.
  867. --*/
  868. {
  869. PAFD_ENDPOINT endpoint;
  870. PAFD_CONNECTION connection;
  871. KIRQL oldIrql;
  872. KIRQL cancelIrql;
  873. PAFD_BUFFER afdBuffer;
  874. PLIST_ENTRY listEntry;
  875. LIST_ENTRY completeIrpListHead;
  876. NTSTATUS status;
  877. PIRP userIrp;
  878. BOOLEAN expedited;
  879. NTSTATUS irpStatus;
  880. afdBuffer = Context;
  881. connection = afdBuffer->Context;
  882. endpoint = connection->Endpoint;
  883. ASSERT( connection->Type == AfdBlockTypeConnection );
  884. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting ||
  885. endpoint->Type == AfdBlockTypeVcListening );
  886. ASSERT( !endpoint->TdiBufferring );
  887. ASSERT( endpoint->EndpointType == AfdEndpointTypeStream ||
  888. endpoint->EndpointType == AfdEndpointTypeSequencedPacket ||
  889. endpoint->EndpointType == AfdEndpointTypeReliableMessage );
  890. //
  891. // If the IRP being completed is actually a user's IRP, set it up
  892. // for completion and allow IO completion to finish.
  893. //
  894. if ( Irp != afdBuffer->Irp ) {
  895. //
  896. // Free the AFD buffer we've been using to track this request.
  897. //
  898. AfdReturnBuffer( afdBuffer );
  899. //
  900. // If pending has be returned for this IRP then mark the current
  901. // stack as pending.
  902. //
  903. if ( Irp->PendingReturned ) {
  904. IoMarkIrpPending( Irp );
  905. }
  906. //
  907. // Tell the IO system that it is OK to continue with IO
  908. // completion.
  909. //
  910. return STATUS_SUCCESS;
  911. }
  912. //
  913. // If the receive failed, abort the connection.
  914. //
  915. irpStatus = Irp->IoStatus.Status;
  916. if ( !NT_SUCCESS(irpStatus) ) {
  917. //
  918. // We treat STATUS_BUFFER_OVERFLOW just like STATUS_RECEIVE_PARTIAL.
  919. //
  920. if ( irpStatus == STATUS_BUFFER_OVERFLOW ) {
  921. irpStatus = STATUS_RECEIVE_PARTIAL;
  922. } else {
  923. afdBuffer->Mdl->ByteCount = afdBuffer->BufferLength;
  924. AfdReturnBuffer( afdBuffer );
  925. //
  926. // !!! We can't abort the connection if the connection has
  927. // not yet been accepted because we'll still be pointing
  928. // at the listening endpoint. We should do something,
  929. // however. How common is this failure?
  930. //
  931. KdPrint(( "AfdRestartBufferReceive: IRP %lx failed on endp %lx\n",
  932. irpStatus, endpoint ));
  933. return STATUS_MORE_PROCESSING_REQUIRED;
  934. }
  935. }
  936. //
  937. // Remember the length of the received data.
  938. //
  939. afdBuffer->DataLength = Irp->IoStatus.Information;
  940. //
  941. // Initialize the local list we'll use to complete any receive IRPs.
  942. // We use a list like this because we may need to complete multiple
  943. // IRPs and we usually cannot complete IRPs at any random point due
  944. // to any locks we might hold.
  945. //
  946. InitializeListHead( &completeIrpListHead );
  947. //
  948. // If there are any pended IRPs on the connection, complete as
  949. // appropriate with the new information. Note that we'll try to
  950. // complete as many pended IRPs as possible with this new buffer of
  951. // data.
  952. //
  953. IoAcquireCancelSpinLock( &cancelIrql );
  954. AfdAcquireSpinLock( &endpoint->SpinLock, &oldIrql );
  955. expedited = afdBuffer->ExpeditedData;
  956. while ( afdBuffer != NULL &&
  957. (userIrp = AfdGetPendedReceiveIrp(
  958. connection,
  959. expedited )) != NULL ) {
  960. PIO_STACK_LOCATION irpSp;
  961. ULONG receiveFlags;
  962. ULONG bytesCopied = 0;
  963. BOOLEAN peek;
  964. BOOLEAN partialReceivePossible;
  965. //
  966. // Set up some locals.
  967. //
  968. irpSp = IoGetCurrentIrpStackLocation( userIrp );
  969. receiveFlags = (ULONG)irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  970. peek = (BOOLEAN)( (receiveFlags & TDI_RECEIVE_PEEK) != 0 );
  971. if ( endpoint->EndpointType == AfdEndpointTypeStream ||
  972. (receiveFlags & TDI_RECEIVE_PARTIAL) != 0 ) {
  973. partialReceivePossible = TRUE;
  974. } else {
  975. partialReceivePossible = FALSE;
  976. }
  977. //
  978. // We're about to complete the IRP, so reset its cancel routine.
  979. //
  980. IoSetCancelRoutine( userIrp, NULL );
  981. //
  982. // Copy data to the user's IRP.
  983. //
  984. if ( userIrp->MdlAddress != NULL ) {
  985. status = TdiCopyBufferToMdl(
  986. afdBuffer->Buffer,
  987. afdBuffer->DataOffset,
  988. afdBuffer->DataLength,
  989. userIrp->MdlAddress,
  990. irpSp->Parameters.DeviceIoControl.InputBufferLength,
  991. &bytesCopied
  992. );
  993. userIrp->IoStatus.Information =
  994. irpSp->Parameters.DeviceIoControl.InputBufferLength + bytesCopied;
  995. } else {
  996. if ( afdBuffer->DataLength == 0 ) {
  997. status = STATUS_SUCCESS;
  998. } else {
  999. status = STATUS_BUFFER_OVERFLOW;
  1000. }
  1001. userIrp->IoStatus.Information = 0;
  1002. }
  1003. ASSERT( status == STATUS_SUCCESS || status == STATUS_BUFFER_OVERFLOW );
  1004. //
  1005. // If the IRP was not a peek IRP, update the AFD buffer
  1006. // accordingly. If it was a peek IRP then the data should be
  1007. // reread, so keep it around.
  1008. //
  1009. if ( !peek ) {
  1010. //
  1011. // If we copied all of the data from the buffer to the IRP,
  1012. // free the AFD buffer structure.
  1013. //
  1014. if ( status == STATUS_SUCCESS ) {
  1015. ASSERT(afdBuffer->DataLength == bytesCopied);
  1016. afdBuffer->DataOffset = 0;
  1017. afdBuffer->ExpeditedData = FALSE;
  1018. AfdReturnBuffer( afdBuffer );
  1019. afdBuffer = NULL;
  1020. //
  1021. // *** NOTE THAT AFTER THIS POINT WE CANNOT TOUCH EITHER
  1022. // THE AFD BUFFER OR THE IRP!
  1023. //
  1024. } else {
  1025. //
  1026. // There is more data left in the buffer. Update counts in
  1027. // the AFD buffer structure.
  1028. //
  1029. ASSERT(afdBuffer->DataLength > bytesCopied);
  1030. afdBuffer->DataOffset += bytesCopied;
  1031. afdBuffer->DataLength -= bytesCopied;
  1032. ASSERT(afdBuffer->DataOffset < afdBuffer->BufferLength);
  1033. }
  1034. }
  1035. //
  1036. // For stream type endpoints, it does not make sense to return
  1037. // STATUS_BUFFER_OVERFLOW. That status is only sensible for
  1038. // message-oriented transports. We have already set up the
  1039. // status field of the IRP when we pended it, so we don't
  1040. // need to do it again here.
  1041. //
  1042. if ( endpoint->EndpointType == AfdEndpointTypeStream ) {
  1043. ASSERT( userIrp->IoStatus.Status == STATUS_SUCCESS );
  1044. } else {
  1045. userIrp->IoStatus.Status = status;
  1046. }
  1047. //
  1048. // We can complete the IRP under any of the following
  1049. // conditions:
  1050. //
  1051. // - the buffer contains a complete message of data.
  1052. //
  1053. // - it is OK to complete the IRP with a partial message.
  1054. //
  1055. // - the IRP is already full of data.
  1056. //
  1057. if ( irpStatus == STATUS_SUCCESS
  1058. ||
  1059. partialReceivePossible
  1060. ||
  1061. status == STATUS_BUFFER_OVERFLOW ) {
  1062. //
  1063. // Add the IRP to the list of IRPs we'll need to complete once we
  1064. // can release locks.
  1065. //
  1066. InsertTailList(
  1067. &completeIrpListHead,
  1068. &userIrp->Tail.Overlay.ListEntry
  1069. );
  1070. } else {
  1071. //
  1072. // Update the count of data placed into the IRP thus far.
  1073. //
  1074. irpSp->Parameters.DeviceIoControl.InputBufferLength += bytesCopied;
  1075. //
  1076. // Put the IRP back on the connection's list of pended IRPs.
  1077. //
  1078. InsertHeadList(
  1079. &connection->VcReceiveIrpListHead,
  1080. &userIrp->Tail.Overlay.ListEntry
  1081. );
  1082. //
  1083. // Stop processing this buffer for now.
  1084. //
  1085. // !!! This could cause a problem if there is a regular
  1086. // receive pended behind a peek IRP! But that is a
  1087. // pretty unlikely scenario.
  1088. //
  1089. break;
  1090. }
  1091. }
  1092. //
  1093. // If there is any data left, place the buffer at the end of the
  1094. // connection's list of bufferred data and update counts of data on
  1095. // the connection.
  1096. //
  1097. if ( afdBuffer != NULL ) {
  1098. InsertTailList(
  1099. &connection->VcReceiveBufferListHead,
  1100. &afdBuffer->BufferListEntry
  1101. );
  1102. if ( expedited ) {
  1103. connection->VcBufferredExpeditedBytes += afdBuffer->DataLength;
  1104. connection->VcBufferredExpeditedCount += 1;
  1105. } else {
  1106. connection->VcBufferredReceiveBytes += afdBuffer->DataLength;
  1107. connection->VcBufferredReceiveCount += 1;
  1108. }
  1109. //
  1110. // Remember whether we got a full or partial receive in the
  1111. // AFD buffer.
  1112. //
  1113. if ( irpStatus == STATUS_RECEIVE_PARTIAL ||
  1114. irpStatus == STATUS_RECEIVE_PARTIAL_EXPEDITED ) {
  1115. afdBuffer->PartialMessage = TRUE;
  1116. } else {
  1117. afdBuffer->PartialMessage = FALSE;
  1118. }
  1119. }
  1120. //
  1121. // Release locks and indicate that there is bufferred data on the
  1122. // endpoint.
  1123. //
  1124. AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
  1125. IoReleaseCancelSpinLock( cancelIrql );
  1126. //
  1127. // If there was leftover data, complete polls as necessary. Indicate
  1128. // expedited data if the endpoint is not InLine and expedited data
  1129. // was received; otherwise, indicate normal data.
  1130. //
  1131. if ( afdBuffer != NULL ) {
  1132. if ( expedited && !endpoint->InLine ) {
  1133. AfdIndicatePollEvent(
  1134. endpoint,
  1135. AFD_POLL_RECEIVE_EXPEDITED_BIT,
  1136. STATUS_SUCCESS
  1137. );
  1138. } else {
  1139. AfdIndicatePollEvent(
  1140. endpoint,
  1141. AFD_POLL_RECEIVE_BIT,
  1142. STATUS_SUCCESS
  1143. );
  1144. }
  1145. }
  1146. //
  1147. // Complete IRPs as necessary.
  1148. //
  1149. while ( !IsListEmpty( &completeIrpListHead ) ) {
  1150. listEntry = RemoveHeadList( &completeIrpListHead );
  1151. userIrp = CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry );
  1152. IoCompleteRequest( userIrp, AfdPriorityBoost );
  1153. }
  1154. //
  1155. // Tell the IO system to stop processing the AFD IRP, since we now
  1156. // own it as part of the AFD buffer.
  1157. //
  1158. return STATUS_MORE_PROCESSING_REQUIRED;
  1159. } // AfdRestartBufferReceive
  1160. VOID
  1161. AfdCancelReceive (
  1162. IN PDEVICE_OBJECT DeviceObject,
  1163. IN PIRP Irp
  1164. )
  1165. /*++
  1166. Routine Description:
  1167. Cancels a receive IRP that is pended in AFD.
  1168. Arguments:
  1169. DeviceObject - not used.
  1170. Irp - the IRP to cancel.
  1171. Return Value:
  1172. None.
  1173. --*/
  1174. {
  1175. PIO_STACK_LOCATION irpSp;
  1176. PAFD_ENDPOINT endpoint;
  1177. PAFD_CONNECTION connection;
  1178. KIRQL oldIrql;
  1179. //
  1180. // Get the endpoint pointer from our IRP stack location and the
  1181. // connection pointer from the endpoint.
  1182. //
  1183. irpSp = IoGetCurrentIrpStackLocation( Irp );
  1184. endpoint = irpSp->FileObject->FsContext;
  1185. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting );
  1186. connection = endpoint->Common.VcConnecting.Connection;
  1187. ASSERT( connection->Type == AfdBlockTypeConnection );
  1188. //
  1189. // Remove the IRP from the connection's IRP list, synchronizing with
  1190. // the endpoint lock which protects the lists. Note that the IRP
  1191. // *must* be on one of the connection's lists if we are getting
  1192. // called here--anybody that removes the IRP from the list must do
  1193. // so while holding the cancel spin lock and reset the cancel
  1194. // routine to NULL before releasing the cancel spin lock.
  1195. //
  1196. AfdAcquireSpinLock( &endpoint->SpinLock, &oldIrql );
  1197. RemoveEntryList( &Irp->Tail.Overlay.ListEntry );
  1198. AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
  1199. //
  1200. // Reset the cancel routine in the IRP.
  1201. //
  1202. IoSetCancelRoutine( Irp, NULL );
  1203. //
  1204. // Release the cancel spin lock and complete the IRP with a
  1205. // cancellation status code.
  1206. //
  1207. IoReleaseCancelSpinLock( Irp->CancelIrql );
  1208. Irp->IoStatus.Information = 0;
  1209. Irp->IoStatus.Status = STATUS_CANCELLED;
  1210. IoCompleteRequest( Irp, AfdPriorityBoost );
  1211. return;
  1212. } // AfdCancelReceive
  1213. PAFD_BUFFER
  1214. AfdGetReceiveBuffer (
  1215. IN PAFD_CONNECTION Connection,
  1216. IN ULONG ReceiveFlags,
  1217. IN PAFD_BUFFER StartingAfdBuffer OPTIONAL
  1218. )
  1219. /*++
  1220. Routine Description:
  1221. Returns a pointer to a receive data buffer that contains the
  1222. appropriate type of data. Note that this routine DOES NOT remove
  1223. the buffer structure from the list it is on.
  1224. This routine MUST be called with the connection's endpoint lock
  1225. held!
  1226. Arguments:
  1227. Connection - a pointer to the connection to search for data.
  1228. ReceiveFlags - the type of receive data to look for.
  1229. StartingAfdBuffer - if non-NULL, start looking for a buffer AFTER
  1230. this buffer.
  1231. Return Value:
  1232. PAFD_BUFFER - a pointer to an AFD buffer of the appropriate data type,
  1233. or NULL if there was no appropriate buffer on the connection.
  1234. --*/
  1235. {
  1236. PLIST_ENTRY listEntry;
  1237. PAFD_BUFFER afdBuffer;
  1238. ASSERT( KeGetCurrentIrql( ) == DISPATCH_LEVEL );
  1239. //
  1240. // Start with the first AFD buffer on the connection.
  1241. //
  1242. listEntry = Connection->VcReceiveBufferListHead.Flink;
  1243. afdBuffer = CONTAINING_RECORD( listEntry, AFD_BUFFER, BufferListEntry );
  1244. //
  1245. // If a starting AFD buffer was specified, walk past that buffer in
  1246. // the connection list.
  1247. //
  1248. if ( ARGUMENT_PRESENT( StartingAfdBuffer ) ) {
  1249. while ( TRUE ) {
  1250. if ( afdBuffer == StartingAfdBuffer ) {
  1251. listEntry = listEntry->Flink;
  1252. afdBuffer = CONTAINING_RECORD( listEntry, AFD_BUFFER, BufferListEntry );
  1253. break;
  1254. }
  1255. listEntry = listEntry->Flink;
  1256. afdBuffer = CONTAINING_RECORD( listEntry, AFD_BUFFER, BufferListEntry );
  1257. ASSERT( listEntry != &Connection->VcReceiveBufferListHead );
  1258. }
  1259. }
  1260. //
  1261. // Act based on the type of data we're trying to get.
  1262. //
  1263. switch ( ReceiveFlags & TDI_RECEIVE_EITHER ) {
  1264. case TDI_RECEIVE_NORMAL:
  1265. //
  1266. // Walk the connection's list of data buffers until we find the
  1267. // first data buffer that is of the appropriate type.
  1268. //
  1269. while ( listEntry != &Connection->VcReceiveBufferListHead &&
  1270. afdBuffer->ExpeditedData ) {
  1271. listEntry = afdBuffer->BufferListEntry.Flink;
  1272. afdBuffer = CONTAINING_RECORD( listEntry, AFD_BUFFER, BufferListEntry );
  1273. }
  1274. if ( listEntry != &Connection->VcReceiveBufferListHead ) {
  1275. return afdBuffer;
  1276. } else {
  1277. return NULL;
  1278. }
  1279. case TDI_RECEIVE_EITHER :
  1280. //
  1281. // Just return the first buffer, if there is one.
  1282. //
  1283. if ( listEntry != &Connection->VcReceiveBufferListHead ) {
  1284. return afdBuffer;
  1285. } else {
  1286. return NULL;
  1287. }
  1288. case TDI_RECEIVE_EXPEDITED:
  1289. if ( Connection->VcBufferredExpeditedCount == 0 ) {
  1290. return NULL;
  1291. }
  1292. //
  1293. // Walk the connection's list of data buffers until we find the
  1294. // first data buffer that is of the appropriate type.
  1295. //
  1296. while ( listEntry != &Connection->VcReceiveBufferListHead &&
  1297. !afdBuffer->ExpeditedData ) {
  1298. listEntry = afdBuffer->BufferListEntry.Flink;
  1299. afdBuffer = CONTAINING_RECORD( listEntry, AFD_BUFFER, BufferListEntry );
  1300. }
  1301. if ( listEntry != &Connection->VcReceiveBufferListHead ) {
  1302. return afdBuffer;
  1303. } else {
  1304. return NULL;
  1305. }
  1306. default:
  1307. ASSERT( !"Invalid ReceiveFlags" );
  1308. return NULL;
  1309. }
  1310. } // AfdGetReceiveBuffer
  1311. PIRP
  1312. AfdGetPendedReceiveIrp (
  1313. IN PAFD_CONNECTION Connection,
  1314. IN BOOLEAN Expedited
  1315. )
  1316. /*++
  1317. Routine Description:
  1318. Removes a receive IRP from the connection's list of receive IRPs.
  1319. Only returns an IRP which is valid for the specified type of
  1320. data, normal or expedited. If there are no IRPs pended or only
  1321. IRPs of the wrong type, returns NULL.
  1322. This routine MUST be called with the connection's endpoint lock
  1323. held!
  1324. Arguments:
  1325. Connection - a pointer to the connection to search for an IRP.
  1326. Expedited - TRUE if this routine should return a receive IRP which
  1327. can receive expedited data.
  1328. Return Value:
  1329. PIRP - a pointer to an IRP which can receive data of the specified
  1330. type. The IRP IS removed from the connection's list of pended
  1331. receive IRPs.
  1332. --*/
  1333. {
  1334. PIRP irp;
  1335. PIO_STACK_LOCATION irpSp;
  1336. ULONG receiveFlags;
  1337. PLIST_ENTRY listEntry;
  1338. ASSERT( KeGetCurrentIrql( ) == DISPATCH_LEVEL );
  1339. //
  1340. // Walk the list of pended receive IRPs looking for one which can
  1341. // be completed with the specified type of data.
  1342. //
  1343. for ( listEntry = Connection->VcReceiveIrpListHead.Flink;
  1344. listEntry != &Connection->VcReceiveIrpListHead;
  1345. listEntry = listEntry->Flink ) {
  1346. //
  1347. // Get a pointer to the IRP and our stack location in the IRP.
  1348. //
  1349. irp = CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry );
  1350. irpSp = IoGetCurrentIrpStackLocation( irp );
  1351. //
  1352. // Determine whether this IRP can receive the data type we need.
  1353. //
  1354. receiveFlags = (ULONG)irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  1355. receiveFlags &= TDI_RECEIVE_EITHER;
  1356. ASSERT( receiveFlags != 0 );
  1357. if ( receiveFlags == TDI_RECEIVE_NORMAL && !Expedited ) {
  1358. //
  1359. // We have a normal receive and normal data. Remove this
  1360. // IRP from the connection's list and return it.
  1361. //
  1362. RemoveEntryList( listEntry );
  1363. return irp;
  1364. }
  1365. if ( receiveFlags == TDI_RECEIVE_EITHER ) {
  1366. //
  1367. // This is an "either" receive. It can take the data
  1368. // regardless of the data type.
  1369. //
  1370. RemoveEntryList( listEntry );
  1371. return irp;
  1372. }
  1373. if ( receiveFlags == TDI_RECEIVE_EXPEDITED && Expedited ) {
  1374. //
  1375. // We have an expedited receive and expedited data. Remove
  1376. // this IRP from the connection's list and return it.
  1377. //
  1378. RemoveEntryList( listEntry );
  1379. return irp;
  1380. }
  1381. //
  1382. // This IRP did not meet our criteria. Continue scanning the
  1383. // connection's list of pended IRPs for a good IRP.
  1384. //
  1385. }
  1386. //
  1387. // There were no IRPs which could be completed with the specified
  1388. // type of data.
  1389. //
  1390. return NULL;
  1391. } // AfdGetPendedReceiveIrp