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.

1245 lines
39 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. receive.c
  5. Abstract:
  6. This module contains the code for passing on receive IRPs to
  7. TDI providers.
  8. Author:
  9. David Treadwell (davidtr) 13-Mar-1992
  10. Revision History:
  11. --*/
  12. #include "afdp.h"
  13. NTSTATUS
  14. AfdRestartReceive (
  15. IN PDEVICE_OBJECT DeviceObject,
  16. IN PIRP Irp,
  17. IN PVOID Context
  18. );
  19. #ifdef ALLOC_PRAGMA
  20. #pragma alloc_text( PAGEAFD, AfdReceive )
  21. #pragma alloc_text( PAGEAFD, AfdRestartReceive )
  22. #pragma alloc_text( PAGEAFD, AfdReceiveEventHandler )
  23. #pragma alloc_text( PAGEAFD, AfdReceiveExpeditedEventHandler )
  24. #pragma alloc_text( PAGEAFD, AfdQueryReceiveInformation )
  25. #endif
  26. NTSTATUS
  27. AfdReceive (
  28. IN PIRP Irp,
  29. IN PIO_STACK_LOCATION IrpSp
  30. )
  31. {
  32. NTSTATUS status;
  33. KIRQL oldIrql;
  34. PAFD_ENDPOINT endpoint;
  35. PAFD_CONNECTION connection;
  36. PTDI_REQUEST_RECEIVE receiveRequest;
  37. BOOLEAN allocatedReceiveRequest = FALSE;
  38. BOOLEAN peek;
  39. LARGE_INTEGER bytesExpected;
  40. BOOLEAN isDataOnConnection;
  41. BOOLEAN isExpeditedDataOnConnection;
  42. PAFD_RECV_INFO recvInfo;
  43. ULONG recvFlags;
  44. ULONG afdFlags;
  45. ULONG recvLength;
  46. //
  47. // Make sure that the endpoint is in the correct state.
  48. //
  49. endpoint = IrpSp->FileObject->FsContext;
  50. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  51. if ( endpoint->State != AfdEndpointStateConnected ) {
  52. status = STATUS_INVALID_CONNECTION;
  53. goto complete;
  54. }
  55. //
  56. // If receive has been shut down or the endpoint aborted, fail.
  57. //
  58. if ( (endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_RECEIVE) ) {
  59. status = STATUS_PIPE_DISCONNECTED;
  60. goto complete;
  61. }
  62. if ( (endpoint->DisconnectMode & AFD_ABORTIVE_DISCONNECT) ) {
  63. status = STATUS_LOCAL_DISCONNECT;
  64. goto complete;
  65. }
  66. //
  67. // If this is an IOCTL_AFD_RECEIVE, then grab the parameters from the
  68. // supplied AFD_RECV_INFO structure, build an MDL chain describing
  69. // the WSABUF array, and attach the MDL chain to the IRP.
  70. //
  71. // If this is an IRP_MJ_READ IRP, just grab the length from the IRP
  72. // and set the flags to zero.
  73. //
  74. if ( IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL ) {
  75. //
  76. // Sanity check.
  77. //
  78. ASSERT( IrpSp->Parameters.DeviceIoControl.IoControlCode ==
  79. IOCTL_AFD_RECEIVE );
  80. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
  81. sizeof(*recvInfo) ) {
  82. try {
  83. //
  84. // Probe the input structure.
  85. //
  86. recvInfo = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  87. if( Irp->RequestorMode != KernelMode ) {
  88. ProbeForRead(
  89. recvInfo,
  90. sizeof(*recvInfo),
  91. sizeof(ULONG)
  92. );
  93. }
  94. //
  95. // Snag the receive flags.
  96. //
  97. recvFlags = recvInfo->TdiFlags;
  98. afdFlags = recvInfo->AfdFlags;
  99. //
  100. // Validate the receive flags & WSABUF parameters.
  101. // Note that either TDI_RECEIVE_NORMAL or
  102. // TDI_RECEIVE_EXPEDITED (but not both) must be set
  103. // in the receive flags.
  104. //
  105. if ( ( recvFlags & TDI_RECEIVE_EITHER ) != 0 &&
  106. ( recvFlags & TDI_RECEIVE_EITHER ) != TDI_RECEIVE_EITHER &&
  107. recvInfo->BufferArray != NULL &&
  108. recvInfo->BufferCount > 0 ) {
  109. //
  110. // Create the MDL chain describing the WSABUF array.
  111. //
  112. status = AfdAllocateMdlChain(
  113. Irp,
  114. recvInfo->BufferArray,
  115. recvInfo->BufferCount,
  116. IoWriteAccess,
  117. &recvLength
  118. );
  119. } else {
  120. //
  121. // Invalid receive flags, BufferArray, or
  122. // BufferCount fields.
  123. //
  124. status = STATUS_INVALID_PARAMETER;
  125. }
  126. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  127. //
  128. // Exception accessing input structure.
  129. //
  130. status = GetExceptionCode();
  131. }
  132. } else {
  133. //
  134. // Invalid input buffer length.
  135. //
  136. status = STATUS_INVALID_PARAMETER;
  137. }
  138. if( !NT_SUCCESS(status) ) {
  139. goto complete;
  140. }
  141. } else {
  142. ASSERT( IrpSp->MajorFunction == IRP_MJ_READ );
  143. recvFlags = TDI_RECEIVE_NORMAL;
  144. afdFlags = AFD_OVERLAPPED;
  145. recvLength = IrpSp->Parameters.Read.Length;
  146. //
  147. // Convert this stack location to a proper one for a receive
  148. // request.
  149. //
  150. IrpSp->Parameters.DeviceIoControl.OutputBufferLength =
  151. IrpSp->Parameters.Read.Length;
  152. IrpSp->Parameters.DeviceIoControl.InputBufferLength =
  153. sizeof(*receiveRequest);
  154. }
  155. //
  156. // If this is a datagram endpoint, format up a receive datagram request
  157. // and pass it on to the TDI provider.
  158. //
  159. if ( IS_DGRAM_ENDPOINT(endpoint) ) {
  160. return AfdReceiveDatagram( Irp, IrpSp, recvFlags, afdFlags );
  161. }
  162. //
  163. // If this is an endpoint on a nonbufferring transport, use another
  164. // routine to handle the request.
  165. //
  166. if ( !endpoint->TdiBufferring ) {
  167. return AfdBReceive( Irp, IrpSp, recvFlags, afdFlags, recvLength );
  168. }
  169. //
  170. // Allocate a buffer for the receive request structure.
  171. //
  172. receiveRequest = AFD_ALLOCATE_POOL(
  173. NonPagedPool,
  174. sizeof(TDI_REQUEST_RECEIVE),
  175. AFD_TDI_POOL_TAG
  176. );
  177. if ( receiveRequest == NULL ) {
  178. status = STATUS_INSUFFICIENT_RESOURCES;
  179. goto complete;
  180. }
  181. allocatedReceiveRequest = TRUE;
  182. //
  183. // Set up the receive request structure.
  184. //
  185. RtlZeroMemory(
  186. receiveRequest,
  187. sizeof(*receiveRequest)
  188. );
  189. receiveRequest->ReceiveFlags = (USHORT)recvFlags;
  190. connection = endpoint->Common.VcConnecting.Connection;
  191. ASSERT( connection != NULL );
  192. ASSERT( connection->Type == AfdBlockTypeConnection );
  193. //
  194. // If this endpoint is set up for inline reception of expedited data,
  195. // change the receive flags to use either normal or expedited data.
  196. //
  197. if ( endpoint->InLine ) {
  198. receiveRequest->ReceiveFlags |= TDI_RECEIVE_EITHER;
  199. }
  200. //
  201. // Determine whether this is a request to just peek at the data.
  202. //
  203. peek = (BOOLEAN)( (receiveRequest->ReceiveFlags & TDI_RECEIVE_PEEK) != 0 );
  204. AfdAcquireSpinLock( &AfdSpinLock, &oldIrql );
  205. if ( endpoint->NonBlocking ) {
  206. isDataOnConnection = IS_DATA_ON_CONNECTION( connection );
  207. isExpeditedDataOnConnection = IS_EXPEDITED_DATA_ON_CONNECTION( connection );
  208. }
  209. if ( endpoint->InLine ) {
  210. //
  211. // If the endpoint is nonblocking, check whether the receive can
  212. // be performed immediately. Note that if the endpoint is set
  213. // up for inline reception of expedited data we don't fail just
  214. // yet--there may be expedited data available to be read.
  215. //
  216. if ( endpoint->NonBlocking && !( afdFlags & AFD_OVERLAPPED ) ) {
  217. if ( !isDataOnConnection &&
  218. !isExpeditedDataOnConnection &&
  219. !connection->AbortIndicated &&
  220. !connection->DisconnectIndicated ) {
  221. IF_DEBUG(RECEIVE) {
  222. KdPrint(( "AfdReceive: failing nonblocking IL receive, ind %ld, "
  223. "taken %ld, out %ld\n",
  224. connection->Common.Bufferring.ReceiveBytesIndicated.LowPart,
  225. connection->Common.Bufferring.ReceiveBytesTaken.LowPart,
  226. connection->Common.Bufferring.ReceiveBytesOutstanding.LowPart ));
  227. KdPrint(( " EXP ind %ld, taken %ld, out %ld\n",
  228. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.LowPart,
  229. connection->Common.Bufferring.ReceiveExpeditedBytesTaken.LowPart,
  230. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.LowPart ));
  231. }
  232. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  233. status = STATUS_DEVICE_NOT_READY;
  234. goto complete;
  235. }
  236. }
  237. //
  238. // If this is a nonblocking endpoint for a message-oriented
  239. // transport, limit the number of bytes that can be received to the
  240. // amount that has been indicated. This prevents the receive
  241. // from blocking in the case where only part of a message has been
  242. // received.
  243. //
  244. if ( endpoint->EndpointType != AfdEndpointTypeStream &&
  245. endpoint->NonBlocking ) {
  246. LARGE_INTEGER expBytesExpected;
  247. bytesExpected.QuadPart =
  248. connection->Common.Bufferring.ReceiveBytesIndicated.QuadPart -
  249. (connection->Common.Bufferring.ReceiveBytesTaken.QuadPart +
  250. connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart);
  251. ASSERT( bytesExpected.HighPart == 0 );
  252. expBytesExpected.QuadPart =
  253. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.QuadPart -
  254. (connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart +
  255. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart);
  256. ASSERT( expBytesExpected.HighPart == 0 );
  257. IF_DEBUG(RECEIVE) {
  258. KdPrint(( "AfdReceive: %lx normal bytes expected, %ld exp bytes expected",
  259. bytesExpected.LowPart, expBytesExpected.LowPart ));
  260. }
  261. //
  262. // If expedited data exists on the connection, use the lower
  263. // count between the available expedited and normal receive
  264. // data.
  265. //
  266. if ( (isExpeditedDataOnConnection &&
  267. bytesExpected.LowPart > expBytesExpected.LowPart) ||
  268. !isDataOnConnection ) {
  269. bytesExpected = expBytesExpected;
  270. }
  271. //
  272. // If the request is for more bytes than are available, cut back
  273. // the number of bytes requested to what we know is actually
  274. // available.
  275. //
  276. if ( recvLength > bytesExpected.LowPart ) {
  277. recvLength = bytesExpected.LowPart;
  278. }
  279. }
  280. //
  281. // Increment the count of posted receive bytes outstanding.
  282. // This count is used for polling and nonblocking receives.
  283. // Note that we do not increment this count if this is only
  284. // a PEEK receive, since peeks do not actually take any data
  285. // they should not affect whether data is available to be read
  286. // on the endpoint.
  287. //
  288. IF_DEBUG(RECEIVE) {
  289. KdPrint(( "AfdReceive: conn %lx for %ld bytes, ind %ld, "
  290. "taken %ld, out %ld %s\n",
  291. connection,
  292. recvLength,
  293. connection->Common.Bufferring.ReceiveBytesIndicated.LowPart,
  294. connection->Common.Bufferring.ReceiveBytesTaken.LowPart,
  295. connection->Common.Bufferring.ReceiveBytesOutstanding.LowPart,
  296. peek ? "PEEK" : "" ));
  297. KdPrint(( " EXP ind %ld, taken %ld, out %ld\n",
  298. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.LowPart,
  299. connection->Common.Bufferring.ReceiveExpeditedBytesTaken.LowPart,
  300. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.LowPart ));
  301. }
  302. if ( !peek ) {
  303. connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart =
  304. connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart +
  305. recvLength;
  306. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart =
  307. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart +
  308. recvLength;
  309. }
  310. }
  311. if ( !endpoint->InLine &&
  312. (receiveRequest->ReceiveFlags & TDI_RECEIVE_NORMAL) != 0 ) {
  313. //
  314. // If the endpoint is nonblocking, check whether the receive can
  315. // be performed immediately.
  316. //
  317. if ( endpoint->NonBlocking && !( afdFlags & AFD_OVERLAPPED ) ) {
  318. if ( !isDataOnConnection &&
  319. !connection->AbortIndicated &&
  320. !connection->DisconnectIndicated ) {
  321. IF_DEBUG(RECEIVE) {
  322. KdPrint(( "AfdReceive: failing nonblocking receive, ind %ld, "
  323. "taken %ld, out %ld\n",
  324. connection->Common.Bufferring.ReceiveBytesIndicated.LowPart,
  325. connection->Common.Bufferring.ReceiveBytesTaken.LowPart,
  326. connection->Common.Bufferring.ReceiveBytesOutstanding.LowPart ));
  327. }
  328. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  329. status = STATUS_DEVICE_NOT_READY;
  330. goto complete;
  331. }
  332. }
  333. //
  334. // If this is a nonblocking endpoint for a message-oriented
  335. // transport, limit the number of bytes that can be received to the
  336. // amount that has been indicated. This prevents the receive
  337. // from blocking in the case where only part of a message has been
  338. // received.
  339. //
  340. if ( endpoint->EndpointType != AfdEndpointTypeStream &&
  341. endpoint->NonBlocking ) {
  342. bytesExpected.QuadPart =
  343. connection->Common.Bufferring.ReceiveBytesIndicated.QuadPart -
  344. (connection->Common.Bufferring.ReceiveBytesTaken.QuadPart +
  345. connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart);
  346. ASSERT( bytesExpected.HighPart == 0 );
  347. //
  348. // If the request is for more bytes than are available, cut back
  349. // the number of bytes requested to what we know is actually
  350. // available.
  351. //
  352. if ( recvLength > bytesExpected.LowPart ) {
  353. recvLength = bytesExpected.LowPart;
  354. }
  355. }
  356. //
  357. // Increment the count of posted receive bytes outstanding.
  358. // This count is used for polling and nonblocking receives.
  359. // Note that we do not increment this count if this is only
  360. // a PEEK receive, since peeks do not actually take any data
  361. // they should not affect whether data is available to be read
  362. // on the endpoint.
  363. //
  364. IF_DEBUG(RECEIVE) {
  365. KdPrint(( "AfdReceive: conn %lx for %ld bytes, ind %ld, "
  366. "taken %ld, out %ld %s\n",
  367. connection,
  368. recvLength,
  369. connection->Common.Bufferring.ReceiveBytesIndicated.LowPart,
  370. connection->Common.Bufferring.ReceiveBytesTaken.LowPart,
  371. connection->Common.Bufferring.ReceiveBytesOutstanding.LowPart,
  372. peek ? "PEEK" : "" ));
  373. }
  374. if ( !peek ) {
  375. connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart =
  376. connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart +
  377. recvLength;
  378. }
  379. }
  380. if ( !endpoint->InLine &&
  381. (receiveRequest->ReceiveFlags & TDI_RECEIVE_EXPEDITED) != 0 ) {
  382. if ( endpoint->NonBlocking && !( afdFlags & AFD_OVERLAPPED ) &&
  383. !isExpeditedDataOnConnection &&
  384. !connection->AbortIndicated &&
  385. !connection->DisconnectIndicated ) {
  386. IF_DEBUG(RECEIVE) {
  387. KdPrint(( "AfdReceive: failing nonblocking EXP receive, ind %ld, "
  388. "taken %ld, out %ld\n",
  389. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.LowPart,
  390. connection->Common.Bufferring.ReceiveExpeditedBytesTaken.LowPart,
  391. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.LowPart ));
  392. }
  393. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  394. status = STATUS_DEVICE_NOT_READY;
  395. goto complete;
  396. }
  397. //
  398. // If this is a nonblocking endpoint for a message-oriented
  399. // transport, limit the number of bytes that can be received to the
  400. // amount that has been indicated. This prevents the receive
  401. // from blocking in the case where only part of a message has been
  402. // received.
  403. //
  404. if ( endpoint->EndpointType != AfdEndpointTypeStream &&
  405. endpoint->NonBlocking &&
  406. IS_EXPEDITED_DATA_ON_CONNECTION( connection ) ) {
  407. bytesExpected.QuadPart =
  408. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.QuadPart -
  409. (connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart +
  410. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart);
  411. ASSERT( bytesExpected.HighPart == 0 );
  412. ASSERT( bytesExpected.LowPart != 0 );
  413. //
  414. // If the request is for more bytes than are available, cut back
  415. // the number of bytes requested to what we know is actually
  416. // available.
  417. //
  418. if ( recvLength > bytesExpected.LowPart ) {
  419. recvLength = bytesExpected.LowPart;
  420. }
  421. }
  422. //
  423. // Increment the count of posted expedited receive bytes
  424. // outstanding. This count is used for polling and nonblocking
  425. // receives. Note that we do not increment this count if this
  426. // is only a PEEK receive.
  427. //
  428. IF_DEBUG(RECEIVE) {
  429. KdPrint(( "AfdReceive: conn %lx for %ld bytes, ind %ld, "
  430. "taken %ld, out %ld EXP %s\n",
  431. connection,
  432. recvLength,
  433. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.LowPart,
  434. connection->Common.Bufferring.ReceiveExpeditedBytesTaken.LowPart,
  435. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.LowPart,
  436. peek ? "PEEK" : "" ));
  437. }
  438. if ( !peek ) {
  439. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart =
  440. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart +
  441. recvLength;
  442. }
  443. }
  444. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  445. //
  446. // Build the TDI receive request.
  447. //
  448. TdiBuildReceive(
  449. Irp,
  450. connection->DeviceObject,
  451. connection->FileObject,
  452. AfdRestartReceive,
  453. endpoint,
  454. Irp->MdlAddress,
  455. receiveRequest->ReceiveFlags,
  456. recvLength
  457. );
  458. //
  459. // Save a pointer to the receive request structure so that we
  460. // can free it in our restart routine.
  461. //
  462. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = receiveRequest;
  463. IrpSp->Parameters.DeviceIoControl.OutputBufferLength = recvLength;
  464. //
  465. // Call the transport to actually perform the connect operation.
  466. //
  467. return AfdIoCallDriver( endpoint, connection->DeviceObject, Irp );
  468. complete:
  469. if ( allocatedReceiveRequest ) {
  470. AFD_FREE_POOL(
  471. receiveRequest,
  472. AFD_TDI_POOL_TAG
  473. );
  474. }
  475. Irp->IoStatus.Information = 0;
  476. Irp->IoStatus.Status = status;
  477. IoCompleteRequest( Irp, AfdPriorityBoost );
  478. return status;
  479. } // AfdReceive
  480. NTSTATUS
  481. AfdRestartReceive (
  482. IN PDEVICE_OBJECT DeviceObject,
  483. IN PIRP Irp,
  484. IN PVOID Context
  485. )
  486. {
  487. PAFD_ENDPOINT endpoint = Context;
  488. PAFD_CONNECTION connection;
  489. PIO_STACK_LOCATION irpSp;
  490. LARGE_INTEGER actualBytes;
  491. LARGE_INTEGER requestedBytes;
  492. KIRQL oldIrql1, oldIrql2;
  493. ULONG receiveFlags;
  494. ULONG eventMask;
  495. BOOLEAN expedited;
  496. PTDI_REQUEST_RECEIVE receiveRequest;
  497. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting );
  498. ASSERT( endpoint->Common.VcConnecting.Connection != NULL );
  499. ASSERT( endpoint->TdiBufferring );
  500. irpSp = IoGetCurrentIrpStackLocation( Irp );
  501. actualBytes = RtlConvertUlongToLargeInteger( Irp->IoStatus.Information );
  502. requestedBytes = RtlConvertUlongToLargeInteger(
  503. irpSp->Parameters.DeviceIoControl.OutputBufferLength
  504. );
  505. //
  506. // Determine whether we received normal or expedited data.
  507. //
  508. receiveRequest = irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  509. receiveFlags = receiveRequest->ReceiveFlags;
  510. if ( Irp->IoStatus.Status == STATUS_RECEIVE_EXPEDITED ||
  511. Irp->IoStatus.Status == STATUS_RECEIVE_PARTIAL_EXPEDITED ) {
  512. expedited = TRUE;
  513. } else {
  514. expedited = FALSE;
  515. }
  516. //
  517. // Free the receive request structure.
  518. //
  519. AFD_FREE_POOL(
  520. receiveRequest,
  521. AFD_TDI_POOL_TAG
  522. );
  523. //
  524. // If this was a PEEK receive, don't update the counts of received
  525. // data, just return.
  526. //
  527. if ( (receiveFlags & TDI_RECEIVE_PEEK) != 0 ) {
  528. IF_DEBUG(RECEIVE) {
  529. KdPrint(( "AfdRestartReceive: IRP %lx, endpoint %lx, conn %lx, "
  530. "status %X\n",
  531. Irp, endpoint, endpoint->Common.VcConnecting.Connection,
  532. Irp->IoStatus.Status ));
  533. KdPrint(( " %s data, PEEKed only.\n",
  534. expedited ? "expedited" : "normal" ));
  535. }
  536. AfdCompleteOutstandingIrp( endpoint, Irp );
  537. return STATUS_SUCCESS;
  538. }
  539. //
  540. // Update the count of bytes actually received on the connection.
  541. //
  542. AfdAcquireSpinLock( &AfdSpinLock, &oldIrql1 );
  543. AfdAcquireSpinLock( &endpoint->SpinLock, &oldIrql2 );
  544. if( expedited ) {
  545. eventMask = endpoint->InLine
  546. ? (ULONG)~AFD_POLL_RECEIVE
  547. : (ULONG)~AFD_POLL_RECEIVE_EXPEDITED;
  548. } else {
  549. eventMask = (ULONG)~AFD_POLL_RECEIVE;
  550. }
  551. endpoint->EventsActive &= eventMask;
  552. IF_DEBUG(EVENT_SELECT) {
  553. KdPrint((
  554. "AfdReceive: Endp %08lX, Active %08lX\n",
  555. endpoint,
  556. endpoint->EventsActive
  557. ));
  558. }
  559. connection = endpoint->Common.VcConnecting.Connection;
  560. ASSERT( connection->Type == AfdBlockTypeConnection );
  561. if ( !expedited ) {
  562. if ( actualBytes.LowPart == 0 ) {
  563. ASSERT( actualBytes.HighPart == 0 );
  564. connection->VcZeroByteReceiveIndicated = FALSE;
  565. } else {
  566. connection->Common.Bufferring.ReceiveBytesTaken.QuadPart =
  567. actualBytes.QuadPart +
  568. connection->Common.Bufferring.ReceiveBytesTaken.QuadPart;
  569. }
  570. //
  571. // If the number taken exceeds the number indicated, then this
  572. // receive got some unindicated bytes because the receive was
  573. // posted when the indication arrived. If this is the case, set
  574. // the amount indicated equal to the amount received.
  575. //
  576. if ( connection->Common.Bufferring.ReceiveBytesTaken.QuadPart >
  577. connection->Common.Bufferring.ReceiveBytesIndicated.QuadPart ) {
  578. connection->Common.Bufferring.ReceiveBytesIndicated =
  579. connection->Common.Bufferring.ReceiveBytesTaken;
  580. }
  581. //
  582. // Decrement the count of outstanding receive bytes on this connection
  583. // by the receive size that was requested.
  584. //
  585. connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart =
  586. connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart -
  587. requestedBytes.QuadPart;
  588. //
  589. // If the endpoint is inline, decrement the count of outstanding
  590. // expedited bytes.
  591. //
  592. if ( endpoint->InLine ) {
  593. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart =
  594. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart -
  595. requestedBytes.QuadPart;
  596. }
  597. if( connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart > 0 ||
  598. ( endpoint->InLine &&
  599. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart > 0 ) ) {
  600. AfdIndicateEventSelectEvent(
  601. endpoint,
  602. AFD_POLL_RECEIVE_BIT,
  603. STATUS_SUCCESS
  604. );
  605. }
  606. IF_DEBUG(RECEIVE) {
  607. KdPrint(( "AfdRestartReceive: IRP %lx, endpoint %lx, conn %lx, "
  608. "status %X\n",
  609. Irp, endpoint, connection,
  610. Irp->IoStatus.Status ));
  611. KdPrint(( " req. bytes %ld, actual %ld, ind %ld, "
  612. " taken %ld, out %ld\n",
  613. requestedBytes.LowPart, actualBytes.LowPart,
  614. connection->Common.Bufferring.ReceiveBytesIndicated.LowPart,
  615. connection->Common.Bufferring.ReceiveBytesTaken.LowPart,
  616. connection->Common.Bufferring.ReceiveBytesOutstanding.LowPart
  617. ));
  618. }
  619. } else {
  620. connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart =
  621. actualBytes.QuadPart +
  622. connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart;
  623. //
  624. // If the number taken exceeds the number indicated, then this
  625. // receive got some unindicated bytes because the receive was
  626. // posted when the indication arrived. If this is the case, set
  627. // the amount indicated equal to the amount received.
  628. //
  629. if ( connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart >
  630. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.QuadPart ) {
  631. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated =
  632. connection->Common.Bufferring.ReceiveExpeditedBytesTaken;
  633. }
  634. //
  635. // Decrement the count of outstanding receive bytes on this connection
  636. // by the receive size that was requested.
  637. //
  638. ASSERT( connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.LowPart > 0 ||
  639. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.HighPart > 0 ||
  640. requestedBytes.LowPart == 0 );
  641. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart =
  642. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart -
  643. requestedBytes.QuadPart;
  644. //
  645. // If the endpoint is inline, decrement the count of outstanding
  646. // normal bytes.
  647. //
  648. if ( endpoint->InLine ) {
  649. connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart =
  650. connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart -
  651. requestedBytes.QuadPart;
  652. if( connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart > 0 ||
  653. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart > 0 ) {
  654. AfdIndicateEventSelectEvent(
  655. endpoint,
  656. AFD_POLL_RECEIVE_BIT,
  657. STATUS_SUCCESS
  658. );
  659. }
  660. } else {
  661. if( connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart > 0 ) {
  662. AfdIndicateEventSelectEvent(
  663. endpoint,
  664. AFD_POLL_RECEIVE_EXPEDITED_BIT,
  665. STATUS_SUCCESS
  666. );
  667. }
  668. }
  669. IF_DEBUG(RECEIVE) {
  670. KdPrint(( "AfdRestartReceive: (exp) IRP %lx, endpoint %lx, conn %lx, "
  671. "status %X\n",
  672. Irp, endpoint, connection,
  673. Irp->IoStatus.Status ));
  674. KdPrint(( " req. bytes %ld, actual %ld, ind %ld, "
  675. " taken %ld, out %ld\n",
  676. requestedBytes.LowPart, actualBytes.LowPart,
  677. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.LowPart,
  678. connection->Common.Bufferring.ReceiveExpeditedBytesTaken.LowPart,
  679. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.LowPart
  680. ));
  681. }
  682. }
  683. AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql2 );
  684. AfdReleaseSpinLock( &AfdSpinLock, oldIrql1 );
  685. AfdCompleteOutstandingIrp( endpoint, Irp );
  686. //
  687. // If pending has be returned for this irp then mark the current
  688. // stack as pending.
  689. //
  690. if ( Irp->PendingReturned ) {
  691. IoMarkIrpPending(Irp);
  692. }
  693. return STATUS_SUCCESS;
  694. } // AfdRestartReceive
  695. NTSTATUS
  696. AfdReceiveEventHandler (
  697. IN PVOID TdiEventContext,
  698. IN CONNECTION_CONTEXT ConnectionContext,
  699. IN ULONG ReceiveFlags,
  700. IN ULONG BytesIndicated,
  701. IN ULONG BytesAvailable,
  702. OUT ULONG *BytesTaken,
  703. IN PVOID Tsdu,
  704. OUT PIRP *IoRequestPacket
  705. )
  706. {
  707. PAFD_CONNECTION connection;
  708. PAFD_ENDPOINT endpoint;
  709. KIRQL oldIrql;
  710. connection = (PAFD_CONNECTION)ConnectionContext;
  711. ASSERT( connection != NULL );
  712. endpoint = connection->Endpoint;
  713. ASSERT( endpoint != NULL );
  714. ASSERT( connection->Type == AfdBlockTypeConnection );
  715. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting ||
  716. endpoint->Type == AfdBlockTypeVcListening );
  717. ASSERT( !connection->DisconnectIndicated );
  718. ASSERT( !connection->AbortIndicated );
  719. ASSERT( endpoint->TdiBufferring );
  720. //
  721. // Bump the count of bytes indicated on the connection to account for
  722. // the bytes indicated by this event.
  723. //
  724. AfdAcquireSpinLock( &AfdSpinLock, &oldIrql );
  725. if ( BytesAvailable == 0 ) {
  726. connection->VcZeroByteReceiveIndicated = TRUE;
  727. } else {
  728. connection->Common.Bufferring.ReceiveBytesIndicated.QuadPart =
  729. connection->Common.Bufferring.ReceiveBytesIndicated.QuadPart +
  730. BytesAvailable;
  731. }
  732. IF_DEBUG(RECEIVE) {
  733. KdPrint(( "AfdReceiveEventHandler: conn %lx, bytes %ld, "
  734. "ind %ld, taken %ld, out %ld\n",
  735. connection, BytesAvailable,
  736. connection->Common.Bufferring.ReceiveBytesIndicated.LowPart,
  737. connection->Common.Bufferring.ReceiveBytesTaken.LowPart,
  738. connection->Common.Bufferring.ReceiveBytesOutstanding.LowPart ));
  739. }
  740. //
  741. // If the receive side of the endpoint has been shut down, tell the
  742. // provider that we took all the data and reset the connection.
  743. // Also, account for these bytes in our count of bytes taken from
  744. // the transport.
  745. //
  746. if ( (endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_RECEIVE) != 0 ) {
  747. #if DBG
  748. DbgPrint( "AfdReceiveEventHandler: receive shutdown, "
  749. "%ld bytes, aborting endp %lx\n",
  750. BytesAvailable, endpoint );
  751. #endif
  752. connection->Common.Bufferring.ReceiveBytesTaken.QuadPart =
  753. connection->Common.Bufferring.ReceiveBytesTaken.QuadPart +
  754. BytesAvailable;
  755. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  756. *BytesTaken = BytesAvailable;
  757. //
  758. // Abort the connection. Note that if the abort attempt fails
  759. // we can't do anything about it.
  760. //
  761. (VOID)AfdBeginAbort( connection );
  762. return STATUS_SUCCESS;
  763. } else {
  764. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  765. //
  766. // Note to the TDI provider that we didn't take any of the data here.
  767. //
  768. // !!! needs bufferring for non-bufferring transports!
  769. *BytesTaken = 0;
  770. //
  771. // If there are any outstanding poll IRPs for this endpoint/
  772. // event, complete them.
  773. //
  774. AfdIndicatePollEvent(
  775. endpoint,
  776. AFD_POLL_RECEIVE_BIT,
  777. STATUS_SUCCESS
  778. );
  779. return STATUS_DATA_NOT_ACCEPTED;
  780. }
  781. } // AfdReceiveEventHandler
  782. NTSTATUS
  783. AfdReceiveExpeditedEventHandler (
  784. IN PVOID TdiEventContext,
  785. IN CONNECTION_CONTEXT ConnectionContext,
  786. IN ULONG ReceiveFlags,
  787. IN ULONG BytesIndicated,
  788. IN ULONG BytesAvailable,
  789. OUT ULONG *BytesTaken,
  790. IN PVOID Tsdu,
  791. OUT PIRP *IoRequestPacket
  792. )
  793. {
  794. PAFD_CONNECTION connection;
  795. PAFD_ENDPOINT endpoint;
  796. KIRQL oldIrql;
  797. connection = (PAFD_CONNECTION)ConnectionContext;
  798. ASSERT( connection != NULL );
  799. endpoint = connection->Endpoint;
  800. ASSERT( endpoint != NULL );
  801. ASSERT( connection->Type == AfdBlockTypeConnection );
  802. //
  803. // Bump the count of bytes indicated on the connection to account for
  804. // the expedited bytes indicated by this event.
  805. //
  806. AfdAcquireSpinLock( &AfdSpinLock, &oldIrql );
  807. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.QuadPart =
  808. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.QuadPart +
  809. BytesAvailable;
  810. IF_DEBUG(RECEIVE) {
  811. KdPrint(( "AfdReceiveExpeditedEventHandler: conn %lx, bytes %ld, "
  812. "ind %ld, taken %ld, out %ld, offset %ld\n",
  813. connection, BytesAvailable,
  814. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.LowPart,
  815. connection->Common.Bufferring.ReceiveExpeditedBytesTaken.LowPart,
  816. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.LowPart ));
  817. }
  818. //
  819. // If the receive side of the endpoint has been shut down, tell
  820. // the provider that we took all the data. Also, account for these
  821. // bytes in our count of bytes taken from the transport.
  822. //
  823. //
  824. if ( (endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_RECEIVE) != 0 ) {
  825. IF_DEBUG(RECEIVE) {
  826. KdPrint(( "AfdReceiveExpeditedEventHandler: receive shutdown, "
  827. "%ld bytes dropped.\n", BytesAvailable ));
  828. }
  829. connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart =
  830. connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart +
  831. BytesAvailable;
  832. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  833. *BytesTaken = BytesAvailable;
  834. //
  835. // Abort the connection. Note that if the abort attempt fails
  836. // we can't do anything about it.
  837. //
  838. (VOID)AfdBeginAbort( connection );
  839. } else {
  840. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  841. //
  842. // Note to the TDI provider that we didn't take any of the data here.
  843. //
  844. // !!! needs bufferring for non-bufferring transports!
  845. *BytesTaken = 0;
  846. //
  847. // If there are any outstanding poll IRPs for this endpoint/
  848. // event, complete them. Indicate this data as normal data if
  849. // this endpoint is set up for inline reception of expedited
  850. // data.
  851. //
  852. AfdIndicatePollEvent(
  853. endpoint,
  854. endpoint->InLine
  855. ? AFD_POLL_RECEIVE_BIT
  856. : AFD_POLL_RECEIVE_EXPEDITED_BIT,
  857. STATUS_SUCCESS
  858. );
  859. }
  860. return STATUS_DATA_NOT_ACCEPTED;
  861. } // AfdReceiveExpeditedEventHandler
  862. NTSTATUS
  863. AfdQueryReceiveInformation (
  864. IN PIRP Irp,
  865. IN PIO_STACK_LOCATION IrpSp
  866. )
  867. {
  868. PAFD_RECEIVE_INFORMATION receiveInformation;
  869. PAFD_ENDPOINT endpoint;
  870. KIRQL oldIrql;
  871. LARGE_INTEGER result;
  872. PAFD_CONNECTION connection;
  873. //
  874. // Make sure that the output buffer is large enough.
  875. //
  876. if ( IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  877. sizeof(AFD_RECEIVE_INFORMATION) ) {
  878. return STATUS_BUFFER_TOO_SMALL;
  879. }
  880. //
  881. // If this endpoint has a connection block, use the connection block's
  882. // information, else use the information from the endpoint itself.
  883. //
  884. endpoint = IrpSp->FileObject->FsContext;
  885. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  886. receiveInformation = Irp->AssociatedIrp.SystemBuffer;
  887. if ( endpoint->TdiBufferring ) {
  888. AfdAcquireSpinLock( &AfdSpinLock, &oldIrql );
  889. } else {
  890. AfdAcquireSpinLock( &endpoint->SpinLock, &oldIrql );
  891. }
  892. connection = AFD_CONNECTION_FROM_ENDPOINT( endpoint );
  893. if ( connection != NULL ) {
  894. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting );
  895. ASSERT( connection->Type == AfdBlockTypeConnection );
  896. if ( !endpoint->TdiBufferring ) {
  897. receiveInformation->BytesAvailable =
  898. connection->VcBufferredReceiveBytes;
  899. receiveInformation->ExpeditedBytesAvailable =
  900. connection->VcBufferredExpeditedBytes;
  901. } else {
  902. //
  903. // Determine the number of bytes available to be read.
  904. //
  905. result.QuadPart =
  906. connection->Common.Bufferring.ReceiveBytesIndicated.QuadPart -
  907. (connection->Common.Bufferring.ReceiveBytesTaken.QuadPart +
  908. connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart);
  909. ASSERT( result.HighPart == 0 );
  910. receiveInformation->BytesAvailable = result.LowPart;
  911. //
  912. // Determine the number of expedited bytes available to be read.
  913. //
  914. result.QuadPart =
  915. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.QuadPart -
  916. (connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart +
  917. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart);
  918. ASSERT( result.HighPart == 0 );
  919. receiveInformation->ExpeditedBytesAvailable = result.LowPart;
  920. }
  921. } else {
  922. //
  923. // Determine the number of bytes available to be read.
  924. //
  925. if ( IS_DGRAM_ENDPOINT(endpoint) ) {
  926. //
  927. // Return the amount of bytes of datagrams that are
  928. // bufferred on the endpoint.
  929. //
  930. receiveInformation->BytesAvailable = endpoint->BufferredDatagramBytes;
  931. } else {
  932. //
  933. // This is an unconnected endpoint, hence no bytes are
  934. // available to be read.
  935. //
  936. receiveInformation->BytesAvailable = 0;
  937. }
  938. //
  939. // Whether this is a datagram endpoint or just unconnected,
  940. // there are no expedited bytes available.
  941. //
  942. receiveInformation->ExpeditedBytesAvailable = 0;
  943. }
  944. if ( endpoint->TdiBufferring ) {
  945. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  946. } else {
  947. AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
  948. }
  949. Irp->IoStatus.Information = sizeof(AFD_RECEIVE_INFORMATION);
  950. return STATUS_SUCCESS;
  951. } // AfdQueryReceiveInformation