Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1564 lines
52 KiB

  1. /*++
  2. Copyright (c) 1989-1999 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. Vadim Eydelman (vadime)
  12. 1998-1999 Minimal NT5.0 changes (keep in sync with rest)
  13. --*/
  14. #include "afdp.h"
  15. NTSTATUS
  16. AfdRestartReceive (
  17. IN PDEVICE_OBJECT DeviceObject,
  18. IN PIRP Irp,
  19. IN PVOID Context
  20. );
  21. #ifdef ALLOC_PRAGMA
  22. #pragma alloc_text( PAGEAFD, AfdReceive )
  23. #pragma alloc_text( PAGEAFD, AfdRestartReceive )
  24. #pragma alloc_text( PAGEAFD, AfdReceiveEventHandler )
  25. #pragma alloc_text( PAGEAFD, AfdReceiveExpeditedEventHandler )
  26. #pragma alloc_text( PAGEAFD, AfdQueryReceiveInformation )
  27. #endif
  28. NTSTATUS
  29. FASTCALL
  30. AfdReceive (
  31. IN PIRP Irp,
  32. IN PIO_STACK_LOCATION IrpSp
  33. )
  34. {
  35. NTSTATUS status;
  36. AFD_LOCK_QUEUE_HANDLE lockHandle;
  37. PAFD_ENDPOINT endpoint;
  38. PAFD_CONNECTION connection;
  39. PTDI_REQUEST_RECEIVE receiveRequest;
  40. BOOLEAN allocatedReceiveRequest = FALSE;
  41. BOOLEAN peek;
  42. LARGE_INTEGER bytesExpected;
  43. BOOLEAN isDataOnConnection;
  44. BOOLEAN isExpeditedDataOnConnection;
  45. ULONG recvFlags;
  46. ULONG afdFlags;
  47. ULONG recvLength;
  48. ULONG bufferCount;
  49. //
  50. // Make sure that the endpoint is in the correct state.
  51. //
  52. endpoint = IrpSp->FileObject->FsContext;
  53. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  54. //
  55. // Datagram endpoints can be received on event if they are just bound
  56. // Connection oriented endpoints must be connected.
  57. //
  58. if ( (endpoint->State != AfdEndpointStateConnected ) &&
  59. (!IS_DGRAM_ENDPOINT(endpoint) || (endpoint->State!= AfdEndpointStateBound))) {
  60. if (IS_DGRAM_ENDPOINT(endpoint))
  61. status = STATUS_INVALID_PARAMETER;
  62. else
  63. status = STATUS_INVALID_CONNECTION;
  64. goto complete;
  65. }
  66. //
  67. // If receive has been shut down or the endpoint aborted, fail.
  68. //
  69. if ( (endpoint->DisconnectMode & AFD_ABORTIVE_DISCONNECT) ) {
  70. status = STATUS_LOCAL_DISCONNECT;
  71. goto complete;
  72. }
  73. if ( (endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_RECEIVE) ) {
  74. status = STATUS_PIPE_DISCONNECTED;
  75. goto complete;
  76. }
  77. //
  78. // If this is an IOCTL_AFD_RECEIVE, then grab the parameters from the
  79. // supplied AFD_RECV_INFO structure, build an MDL chain describing
  80. // the WSABUF array, and attach the MDL chain to the IRP.
  81. //
  82. // If this is an IRP_MJ_READ IRP, just grab the length from the IRP
  83. // and set the flags to zero.
  84. //
  85. if ( IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL ) {
  86. #ifdef _WIN64
  87. if (IoIs32bitProcess (Irp)) {
  88. PAFD_RECV_INFO32 recvInfo32;
  89. LPWSABUF32 bufferArray32;
  90. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
  91. sizeof(*recvInfo32) ) {
  92. try {
  93. //
  94. // Validate the input structure if it comes from the user mode
  95. // application
  96. //
  97. recvInfo32 = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  98. if( Irp->RequestorMode != KernelMode ) {
  99. ProbeForRead(
  100. recvInfo32,
  101. sizeof(*recvInfo32),
  102. PROBE_ALIGNMENT32(AFD_RECV_INFO32)
  103. );
  104. }
  105. //
  106. // Make local copies of the embeded pointer and parameters
  107. // that we will be using more than once in case malicios
  108. // application attempts to change them while we are
  109. // validating
  110. //
  111. recvFlags = recvInfo32->TdiFlags;
  112. afdFlags = recvInfo32->AfdFlags;
  113. bufferArray32 = recvInfo32->BufferArray;
  114. bufferCount = recvInfo32->BufferCount;
  115. //
  116. // Validate the receive flags & WSABUF parameters.
  117. // Note that either TDI_RECEIVE_NORMAL or
  118. // TDI_RECEIVE_EXPEDITED (but not both) must be set
  119. // in the receive flags. And expedited can only
  120. // be set if transport supports expedited data and
  121. // endpoint is not set to inline mode.
  122. //
  123. if ( ( recvFlags & TDI_RECEIVE_EITHER ) == 0 ||
  124. ( recvFlags & TDI_RECEIVE_EITHER ) == TDI_RECEIVE_EITHER
  125. ) {
  126. //
  127. // Invalid receive flags
  128. //
  129. status = STATUS_INVALID_PARAMETER;
  130. }
  131. else if (( recvFlags & TDI_RECEIVE_EXPEDITED) != 0 &&
  132. (!IS_TDI_EXPEDITED( endpoint )
  133. || endpoint->InLine )) {
  134. if (endpoint->InLine) {
  135. //
  136. // Endpoint set inline, OOB data is reported as
  137. // normal.
  138. //
  139. status = STATUS_INVALID_PARAMETER;
  140. }
  141. else {
  142. //
  143. // Transport does not support expedited data
  144. //
  145. status = STATUS_NOT_SUPPORTED;
  146. }
  147. }
  148. else {
  149. //
  150. // Create the MDL chain describing the WSABUF array.
  151. // This will also validate the buffer array and individual
  152. // buffers
  153. //
  154. status = AfdAllocateMdlChain32(
  155. Irp, // Requestor mode passed along
  156. bufferArray32,
  157. bufferCount,
  158. IoWriteAccess,
  159. &recvLength
  160. );
  161. }
  162. } except ( AFD_EXCEPTION_FILTER(&status) ) {
  163. //
  164. // Exception accessing input structure.
  165. //
  166. }
  167. } else {
  168. //
  169. // Invalid input buffer length.
  170. //
  171. status = STATUS_INVALID_PARAMETER;
  172. }
  173. }
  174. else
  175. #endif // _WIN64
  176. {
  177. PAFD_RECV_INFO recvInfo;
  178. LPWSABUF bufferArray;
  179. //
  180. // Sanity check.
  181. //
  182. ASSERT( IrpSp->Parameters.DeviceIoControl.IoControlCode==IOCTL_AFD_RECEIVE );
  183. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
  184. sizeof(*recvInfo) ) {
  185. try {
  186. //
  187. // Validate the input structure if it comes from the user mode
  188. // application
  189. //
  190. recvInfo = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  191. if( Irp->RequestorMode != KernelMode ) {
  192. ProbeForRead(
  193. recvInfo,
  194. sizeof(*recvInfo),
  195. PROBE_ALIGNMENT(AFD_RECV_INFO)
  196. );
  197. }
  198. //
  199. // Make local copies of the embeded pointer and parameters
  200. // that we will be using more than once in case malicios
  201. // application attempts to change them while we are
  202. // validating
  203. //
  204. recvFlags = recvInfo->TdiFlags;
  205. afdFlags = recvInfo->AfdFlags;
  206. bufferArray = recvInfo->BufferArray;
  207. bufferCount = recvInfo->BufferCount;
  208. //
  209. // Validate the receive flags & WSABUF parameters.
  210. // Note that either TDI_RECEIVE_NORMAL or
  211. // TDI_RECEIVE_EXPEDITED (but not both) must be set
  212. // in the receive flags. And expedited can only
  213. // be set if transport supports expedited data and
  214. // endpoint is not set to inline mode.
  215. //
  216. if ( ( recvFlags & TDI_RECEIVE_EITHER ) == 0 ||
  217. ( recvFlags & TDI_RECEIVE_EITHER ) == TDI_RECEIVE_EITHER
  218. ) {
  219. //
  220. // Invalid receive flags
  221. //
  222. status = STATUS_INVALID_PARAMETER;
  223. }
  224. else if (( recvFlags & TDI_RECEIVE_EXPEDITED) != 0 &&
  225. (!IS_TDI_EXPEDITED( endpoint )
  226. || endpoint->InLine )) {
  227. if (endpoint->InLine) {
  228. //
  229. // Endpoint set inline, OOB data is reported as
  230. // normal.
  231. //
  232. status = STATUS_INVALID_PARAMETER;
  233. }
  234. else {
  235. //
  236. // Transport does not support expedited data
  237. //
  238. status = STATUS_NOT_SUPPORTED;
  239. }
  240. }
  241. else {
  242. //
  243. // Create the MDL chain describing the WSABUF array.
  244. // This will also validate the buffer array and individual
  245. // buffers
  246. //
  247. status = AfdAllocateMdlChain(
  248. Irp, // Requestor mode passed along
  249. bufferArray,
  250. bufferCount,
  251. IoWriteAccess,
  252. &recvLength
  253. );
  254. }
  255. } except ( AFD_EXCEPTION_FILTER(&status) ) {
  256. //
  257. // Exception accessing input structure.
  258. //
  259. }
  260. } else {
  261. //
  262. // Invalid input buffer length.
  263. //
  264. status = STATUS_INVALID_PARAMETER;
  265. }
  266. }
  267. if( !NT_SUCCESS(status) ) {
  268. goto complete;
  269. }
  270. if (IS_SAN_ENDPOINT(endpoint)) {
  271. IrpSp->MajorFunction = IRP_MJ_READ;
  272. IrpSp->Parameters.Read.Length = recvLength;
  273. return AfdSanRedirectRequest (Irp, IrpSp);
  274. }
  275. } else {
  276. ASSERT( IrpSp->MajorFunction == IRP_MJ_READ );
  277. recvFlags = TDI_RECEIVE_NORMAL;
  278. afdFlags = AFD_OVERLAPPED;
  279. recvLength = IrpSp->Parameters.Read.Length;
  280. ASSERT( FIELD_OFFSET( IO_STACK_LOCATION, Parameters.Read.Length ) ==
  281. FIELD_OFFSET( IO_STACK_LOCATION, Parameters.DeviceIoControl.OutputBufferLength ) );
  282. }
  283. //
  284. // If this is a datagram endpoint, format up a receive datagram request
  285. // and pass it on to the TDI provider.
  286. //
  287. if ( IS_DGRAM_ENDPOINT(endpoint) ) {
  288. AFD_RECV_INFO recvInfo;
  289. recvInfo.TdiFlags = recvFlags;
  290. recvInfo.AfdFlags = afdFlags;
  291. IrpSp->Parameters.DeviceIoControl.InputBufferLength = recvLength;
  292. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = &recvInfo;
  293. return AfdReceiveDatagram( Irp, IrpSp);
  294. }
  295. //
  296. // If this is an endpoint on a nonbufferring transport, use another
  297. // routine to handle the request.
  298. //
  299. if ( !IS_TDI_BUFFERRING(endpoint) ) {
  300. return AfdBReceive( Irp, IrpSp, recvFlags, afdFlags, recvLength );
  301. }
  302. //
  303. // Allocate a buffer for the receive request structure.
  304. //
  305. try {
  306. receiveRequest = AFD_ALLOCATE_POOL_WITH_QUOTA (
  307. NonPagedPool,
  308. sizeof(TDI_REQUEST_RECEIVE),
  309. AFD_TDI_POOL_TAG
  310. );
  311. // AFD_ALLOCATE_POOL_WITH_QUOTA macro sets POOL_RAISE_IF_ALLOCATION_FAILURE
  312. }
  313. except (EXCEPTION_EXECUTE_HANDLER) {
  314. status = GetExceptionCode ();
  315. receiveRequest = NULL;
  316. goto complete;
  317. }
  318. allocatedReceiveRequest = TRUE;
  319. //
  320. // Set up the receive request structure.
  321. //
  322. RtlZeroMemory(
  323. receiveRequest,
  324. sizeof(*receiveRequest)
  325. );
  326. receiveRequest->ReceiveFlags = (USHORT)recvFlags;
  327. //
  328. // If this endpoint is set up for inline reception of expedited data,
  329. // change the receive flags to use either normal or expedited data.
  330. //
  331. if ( endpoint->InLine ) {
  332. receiveRequest->ReceiveFlags |= TDI_RECEIVE_EITHER;
  333. }
  334. //
  335. // Determine whether this is a request to just peek at the data.
  336. //
  337. peek = (BOOLEAN)( (receiveRequest->ReceiveFlags & TDI_RECEIVE_PEEK) != 0 );
  338. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  339. //
  340. // Check if endpoint was cleaned-up and cancel the request.
  341. //
  342. if (endpoint->EndpointCleanedUp) {
  343. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  344. status = STATUS_CANCELLED;
  345. goto complete;
  346. }
  347. connection = endpoint->Common.VcConnecting.Connection;
  348. if (connection==NULL) {
  349. //
  350. // connection might have been cleaned up by transmit file.
  351. //
  352. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  353. status = STATUS_INVALID_CONNECTION;
  354. goto complete;
  355. }
  356. ASSERT( connection->Type == AfdBlockTypeConnection );
  357. if ( endpoint->NonBlocking ) {
  358. isDataOnConnection = IS_DATA_ON_CONNECTION( connection );
  359. isExpeditedDataOnConnection = IS_EXPEDITED_DATA_ON_CONNECTION( connection );
  360. }
  361. if ( endpoint->InLine ) {
  362. //
  363. // If the endpoint is nonblocking, check whether the receive can
  364. // be performed immediately. Note that if the endpoint is set
  365. // up for inline reception of expedited data we don't fail just
  366. // yet--there may be expedited data available to be read.
  367. //
  368. if ( endpoint->NonBlocking && !( afdFlags & AFD_OVERLAPPED ) ) {
  369. if ( !isDataOnConnection &&
  370. !isExpeditedDataOnConnection &&
  371. !connection->AbortIndicated &&
  372. !connection->DisconnectIndicated ) {
  373. IF_DEBUG(RECEIVE) {
  374. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  375. "AfdReceive: failing nonblocking IL receive, ind %ld, "
  376. "taken %ld, out %ld\n",
  377. connection->Common.Bufferring.ReceiveBytesIndicated.LowPart,
  378. connection->Common.Bufferring.ReceiveBytesTaken.LowPart,
  379. connection->Common.Bufferring.ReceiveBytesOutstanding.LowPart ));
  380. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  381. " EXP ind %ld, taken %ld, out %ld\n",
  382. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.LowPart,
  383. connection->Common.Bufferring.ReceiveExpeditedBytesTaken.LowPart,
  384. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.LowPart ));
  385. }
  386. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  387. status = STATUS_DEVICE_NOT_READY;
  388. goto complete;
  389. }
  390. }
  391. //
  392. // If this is a nonblocking endpoint for a message-oriented
  393. // transport, limit the number of bytes that can be received to the
  394. // amount that has been indicated. This prevents the receive
  395. // from blocking in the case where only part of a message has been
  396. // received.
  397. //
  398. if ( IS_MESSAGE_ENDPOINT(endpoint) && endpoint->NonBlocking ) {
  399. LARGE_INTEGER expBytesExpected;
  400. bytesExpected.QuadPart =
  401. connection->Common.Bufferring.ReceiveBytesIndicated.QuadPart -
  402. (connection->Common.Bufferring.ReceiveBytesTaken.QuadPart +
  403. connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart);
  404. ASSERT( bytesExpected.HighPart == 0 );
  405. expBytesExpected.QuadPart =
  406. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.QuadPart -
  407. (connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart +
  408. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart);
  409. ASSERT( expBytesExpected.HighPart == 0 );
  410. IF_DEBUG(RECEIVE) {
  411. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  412. "AfdReceive: %lx normal bytes expected, %ld exp bytes expected",
  413. bytesExpected.LowPart, expBytesExpected.LowPart ));
  414. }
  415. //
  416. // If expedited data exists on the connection, use the lower
  417. // count between the available expedited and normal receive
  418. // data.
  419. //
  420. if ( (isExpeditedDataOnConnection &&
  421. bytesExpected.LowPart > expBytesExpected.LowPart) ||
  422. !isDataOnConnection ) {
  423. bytesExpected = expBytesExpected;
  424. }
  425. //
  426. // If the request is for more bytes than are available, cut back
  427. // the number of bytes requested to what we know is actually
  428. // available.
  429. //
  430. if ( recvLength > bytesExpected.LowPart ) {
  431. recvLength = bytesExpected.LowPart;
  432. }
  433. }
  434. //
  435. // Increment the count of posted receive bytes outstanding.
  436. // This count is used for polling and nonblocking receives.
  437. // Note that we do not increment this count if this is only
  438. // a PEEK receive, since peeks do not actually take any data
  439. // they should not affect whether data is available to be read
  440. // on the endpoint.
  441. //
  442. IF_DEBUG(RECEIVE) {
  443. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  444. "AfdReceive: conn %p for %ld bytes, ind %ld, "
  445. "taken %ld, out %ld %s\n",
  446. connection,
  447. recvLength,
  448. connection->Common.Bufferring.ReceiveBytesIndicated.LowPart,
  449. connection->Common.Bufferring.ReceiveBytesTaken.LowPart,
  450. connection->Common.Bufferring.ReceiveBytesOutstanding.LowPart,
  451. peek ? "PEEK" : "" ));
  452. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  453. " EXP ind %ld, taken %ld, out %ld\n",
  454. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.LowPart,
  455. connection->Common.Bufferring.ReceiveExpeditedBytesTaken.LowPart,
  456. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.LowPart ));
  457. }
  458. if ( !peek ) {
  459. connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart =
  460. connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart +
  461. recvLength;
  462. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart =
  463. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart +
  464. recvLength;
  465. }
  466. }
  467. if ( !endpoint->InLine &&
  468. (receiveRequest->ReceiveFlags & TDI_RECEIVE_NORMAL) != 0 ) {
  469. //
  470. // If the endpoint is nonblocking, check whether the receive can
  471. // be performed immediately.
  472. //
  473. if ( endpoint->NonBlocking && !( afdFlags & AFD_OVERLAPPED ) ) {
  474. if ( !isDataOnConnection &&
  475. !connection->AbortIndicated &&
  476. !connection->DisconnectIndicated ) {
  477. IF_DEBUG(RECEIVE) {
  478. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  479. "AfdReceive: failing nonblocking receive, ind %ld, "
  480. "taken %ld, out %ld\n",
  481. connection->Common.Bufferring.ReceiveBytesIndicated.LowPart,
  482. connection->Common.Bufferring.ReceiveBytesTaken.LowPart,
  483. connection->Common.Bufferring.ReceiveBytesOutstanding.LowPart ));
  484. }
  485. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  486. status = STATUS_DEVICE_NOT_READY;
  487. goto complete;
  488. }
  489. }
  490. //
  491. // If this is a nonblocking endpoint for a message-oriented
  492. // transport, limit the number of bytes that can be received to the
  493. // amount that has been indicated. This prevents the receive
  494. // from blocking in the case where only part of a message has been
  495. // received.
  496. //
  497. if ( IS_MESSAGE_ENDPOINT(endpoint) && endpoint->NonBlocking ) {
  498. bytesExpected.QuadPart =
  499. connection->Common.Bufferring.ReceiveBytesIndicated.QuadPart -
  500. (connection->Common.Bufferring.ReceiveBytesTaken.QuadPart +
  501. connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart);
  502. ASSERT( bytesExpected.HighPart == 0 );
  503. //
  504. // If the request is for more bytes than are available, cut back
  505. // the number of bytes requested to what we know is actually
  506. // available.
  507. //
  508. if ( recvLength > bytesExpected.LowPart ) {
  509. recvLength = bytesExpected.LowPart;
  510. }
  511. }
  512. //
  513. // Increment the count of posted receive bytes outstanding.
  514. // This count is used for polling and nonblocking receives.
  515. // Note that we do not increment this count if this is only
  516. // a PEEK receive, since peeks do not actually take any data
  517. // they should not affect whether data is available to be read
  518. // on the endpoint.
  519. //
  520. IF_DEBUG(RECEIVE) {
  521. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  522. "AfdReceive: conn %p for %ld bytes, ind %ld, "
  523. "taken %ld, out %ld %s\n",
  524. connection,
  525. recvLength,
  526. connection->Common.Bufferring.ReceiveBytesIndicated.LowPart,
  527. connection->Common.Bufferring.ReceiveBytesTaken.LowPart,
  528. connection->Common.Bufferring.ReceiveBytesOutstanding.LowPart,
  529. peek ? "PEEK" : "" ));
  530. }
  531. if ( !peek ) {
  532. connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart =
  533. connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart +
  534. recvLength;
  535. }
  536. }
  537. if ( !endpoint->InLine &&
  538. (receiveRequest->ReceiveFlags & TDI_RECEIVE_EXPEDITED) != 0 ) {
  539. if ( endpoint->NonBlocking && !( afdFlags & AFD_OVERLAPPED ) &&
  540. !isExpeditedDataOnConnection &&
  541. !connection->AbortIndicated &&
  542. !connection->DisconnectIndicated ) {
  543. IF_DEBUG(RECEIVE) {
  544. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  545. "AfdReceive: failing nonblocking EXP receive, ind %ld, "
  546. "taken %ld, out %ld\n",
  547. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.LowPart,
  548. connection->Common.Bufferring.ReceiveExpeditedBytesTaken.LowPart,
  549. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.LowPart ));
  550. }
  551. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  552. status = STATUS_DEVICE_NOT_READY;
  553. goto complete;
  554. }
  555. //
  556. // If this is a nonblocking endpoint for a message-oriented
  557. // transport, limit the number of bytes that can be received to the
  558. // amount that has been indicated. This prevents the receive
  559. // from blocking in the case where only part of a message has been
  560. // received.
  561. //
  562. if ( IS_MESSAGE_ENDPOINT(endpoint) &&
  563. endpoint->NonBlocking &&
  564. IS_EXPEDITED_DATA_ON_CONNECTION( connection ) ) {
  565. bytesExpected.QuadPart =
  566. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.QuadPart -
  567. (connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart +
  568. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart);
  569. ASSERT( bytesExpected.HighPart == 0 );
  570. ASSERT( bytesExpected.LowPart != 0 );
  571. //
  572. // If the request is for more bytes than are available, cut back
  573. // the number of bytes requested to what we know is actually
  574. // available.
  575. //
  576. if ( recvLength > bytesExpected.LowPart ) {
  577. recvLength = bytesExpected.LowPart;
  578. }
  579. }
  580. //
  581. // Increment the count of posted expedited receive bytes
  582. // outstanding. This count is used for polling and nonblocking
  583. // receives. Note that we do not increment this count if this
  584. // is only a PEEK receive.
  585. //
  586. IF_DEBUG(RECEIVE) {
  587. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  588. "AfdReceive: conn %p for %ld bytes, ind %ld, "
  589. "taken %ld, out %ld EXP %s\n",
  590. connection,
  591. recvLength,
  592. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.LowPart,
  593. connection->Common.Bufferring.ReceiveExpeditedBytesTaken.LowPart,
  594. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.LowPart,
  595. peek ? "PEEK" : "" ));
  596. }
  597. if ( !peek ) {
  598. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart =
  599. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart +
  600. recvLength;
  601. }
  602. }
  603. //
  604. // Reference the connection so it can't go away
  605. // even if transmit file tries to clean it up
  606. //
  607. REFERENCE_CONNECTION (connection);
  608. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  609. //
  610. // Build the TDI receive request.
  611. //
  612. TdiBuildReceive(
  613. Irp,
  614. connection->DeviceObject,
  615. connection->FileObject,
  616. AfdRestartReceive,
  617. connection,
  618. Irp->MdlAddress,
  619. receiveRequest->ReceiveFlags,
  620. recvLength
  621. );
  622. //
  623. // Save a pointer to the receive request structure so that we
  624. // can free it in our restart routine.
  625. //
  626. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = receiveRequest;
  627. IrpSp->Parameters.DeviceIoControl.OutputBufferLength = recvLength;
  628. //
  629. // Call the transport to actually perform the connect operation.
  630. //
  631. return AfdIoCallDriver( endpoint, connection->DeviceObject, Irp );
  632. complete:
  633. if ( allocatedReceiveRequest ) {
  634. AFD_FREE_POOL(
  635. receiveRequest,
  636. AFD_TDI_POOL_TAG
  637. );
  638. }
  639. Irp->IoStatus.Information = 0;
  640. Irp->IoStatus.Status = status;
  641. IoCompleteRequest( Irp, AfdPriorityBoost );
  642. return status;
  643. } // AfdReceive
  644. NTSTATUS
  645. AfdRestartReceive (
  646. IN PDEVICE_OBJECT DeviceObject,
  647. IN PIRP Irp,
  648. IN PVOID Context
  649. )
  650. {
  651. PAFD_ENDPOINT endpoint;
  652. PAFD_CONNECTION connection;
  653. PIO_STACK_LOCATION irpSp;
  654. LARGE_INTEGER actualBytes;
  655. LARGE_INTEGER requestedBytes;
  656. AFD_LOCK_QUEUE_HANDLE lockHandle;
  657. ULONG receiveFlags;
  658. ULONG eventMask;
  659. BOOLEAN expedited;
  660. PTDI_REQUEST_RECEIVE receiveRequest;
  661. connection = Context;
  662. ASSERT( connection->Type == AfdBlockTypeConnection );
  663. endpoint = connection->Endpoint;
  664. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting ||
  665. endpoint->Type == AfdBlockTypeVcBoth );
  666. ASSERT( IS_TDI_BUFFERRING(endpoint) );
  667. irpSp = IoGetCurrentIrpStackLocation( Irp );
  668. AfdCompleteOutstandingIrp( endpoint, Irp );
  669. actualBytes.QuadPart = Irp->IoStatus.Information;
  670. requestedBytes.QuadPart = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  671. //
  672. // Determine whether we received normal or expedited data.
  673. //
  674. receiveRequest = irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  675. receiveFlags = receiveRequest->ReceiveFlags;
  676. if ( Irp->IoStatus.Status == STATUS_RECEIVE_EXPEDITED ||
  677. Irp->IoStatus.Status == STATUS_RECEIVE_PARTIAL_EXPEDITED ) {
  678. expedited = TRUE;
  679. } else {
  680. expedited = FALSE;
  681. }
  682. //
  683. // Free the receive request structure.
  684. //
  685. AFD_FREE_POOL(
  686. receiveRequest,
  687. AFD_TDI_POOL_TAG
  688. );
  689. //
  690. // If this was a PEEK receive, don't update the counts of received
  691. // data, just return.
  692. //
  693. if ( (receiveFlags & TDI_RECEIVE_PEEK) != 0 ) {
  694. IF_DEBUG(RECEIVE) {
  695. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  696. "AfdRestartReceive: IRP %p, endpoint %p, conn %p, "
  697. "status %X\n",
  698. Irp, endpoint, endpoint->Common.VcConnecting.Connection,
  699. Irp->IoStatus.Status ));
  700. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  701. " %s data, PEEKed only.\n",
  702. expedited ? "expedited" : "normal" ));
  703. }
  704. DEREFERENCE_CONNECTION (connection);
  705. return STATUS_SUCCESS;
  706. }
  707. //
  708. // Update the count of bytes actually received on the connection.
  709. //
  710. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  711. if( expedited ) {
  712. eventMask = endpoint->InLine
  713. ? (ULONG)~AFD_POLL_RECEIVE
  714. : (ULONG)~AFD_POLL_RECEIVE_EXPEDITED;
  715. } else {
  716. eventMask = (ULONG)~AFD_POLL_RECEIVE;
  717. }
  718. endpoint->EventsActive &= eventMask;
  719. IF_DEBUG(EVENT_SELECT) {
  720. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  721. "AfdReceive: Endp %p, Active %lx\n",
  722. endpoint,
  723. endpoint->EventsActive
  724. ));
  725. }
  726. if ( !expedited ) {
  727. if ( actualBytes.LowPart == 0 ) {
  728. ASSERT( actualBytes.HighPart == 0 );
  729. connection->VcZeroByteReceiveIndicated = FALSE;
  730. } else {
  731. connection->Common.Bufferring.ReceiveBytesTaken.QuadPart =
  732. actualBytes.QuadPart +
  733. connection->Common.Bufferring.ReceiveBytesTaken.QuadPart;
  734. }
  735. //
  736. // If the number taken exceeds the number indicated, then this
  737. // receive got some unindicated bytes because the receive was
  738. // posted when the indication arrived. If this is the case, set
  739. // the amount indicated equal to the amount received.
  740. //
  741. if ( connection->Common.Bufferring.ReceiveBytesTaken.QuadPart >
  742. connection->Common.Bufferring.ReceiveBytesIndicated.QuadPart ) {
  743. connection->Common.Bufferring.ReceiveBytesIndicated =
  744. connection->Common.Bufferring.ReceiveBytesTaken;
  745. }
  746. //
  747. // Decrement the count of outstanding receive bytes on this connection
  748. // by the receive size that was requested.
  749. //
  750. connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart =
  751. connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart -
  752. requestedBytes.QuadPart;
  753. //
  754. // If the endpoint is inline, decrement the count of outstanding
  755. // expedited bytes.
  756. //
  757. if ( endpoint->InLine ) {
  758. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart =
  759. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart -
  760. requestedBytes.QuadPart;
  761. }
  762. if( connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart > 0 ||
  763. ( endpoint->InLine &&
  764. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart > 0 ) ) {
  765. AfdIndicateEventSelectEvent(
  766. endpoint,
  767. AFD_POLL_RECEIVE,
  768. STATUS_SUCCESS
  769. );
  770. }
  771. IF_DEBUG(RECEIVE) {
  772. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  773. "AfdRestartReceive: IRP %p, endpoint %p, conn %p, "
  774. "status %lx\n",
  775. Irp, endpoint, connection,
  776. Irp->IoStatus.Status ));
  777. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  778. " req. bytes %ld, actual %ld, ind %ld, "
  779. " taken %ld, out %ld\n",
  780. requestedBytes.LowPart, actualBytes.LowPart,
  781. connection->Common.Bufferring.ReceiveBytesIndicated.LowPart,
  782. connection->Common.Bufferring.ReceiveBytesTaken.LowPart,
  783. connection->Common.Bufferring.ReceiveBytesOutstanding.LowPart
  784. ));
  785. }
  786. } else {
  787. connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart =
  788. actualBytes.QuadPart +
  789. connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart;
  790. //
  791. // If the number taken exceeds the number indicated, then this
  792. // receive got some unindicated bytes because the receive was
  793. // posted when the indication arrived. If this is the case, set
  794. // the amount indicated equal to the amount received.
  795. //
  796. if ( connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart >
  797. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.QuadPart ) {
  798. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated =
  799. connection->Common.Bufferring.ReceiveExpeditedBytesTaken;
  800. }
  801. //
  802. // Decrement the count of outstanding receive bytes on this connection
  803. // by the receive size that was requested.
  804. //
  805. ASSERT( connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.LowPart > 0 ||
  806. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.HighPart > 0 ||
  807. requestedBytes.LowPart == 0 );
  808. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart =
  809. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart -
  810. requestedBytes.QuadPart;
  811. //
  812. // If the endpoint is inline, decrement the count of outstanding
  813. // normal bytes.
  814. //
  815. if ( endpoint->InLine ) {
  816. connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart =
  817. connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart -
  818. requestedBytes.QuadPart;
  819. if( connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart > 0 ||
  820. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart > 0 ) {
  821. AfdIndicateEventSelectEvent(
  822. endpoint,
  823. AFD_POLL_RECEIVE,
  824. STATUS_SUCCESS
  825. );
  826. }
  827. } else {
  828. if( connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart > 0 ) {
  829. AfdIndicateEventSelectEvent(
  830. endpoint,
  831. AFD_POLL_RECEIVE_EXPEDITED,
  832. STATUS_SUCCESS
  833. );
  834. }
  835. }
  836. IF_DEBUG(RECEIVE) {
  837. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  838. "AfdRestartReceive: (exp) IRP %p, endpoint %p, conn %p, "
  839. "status %X\n",
  840. Irp, endpoint, connection,
  841. Irp->IoStatus.Status ));
  842. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  843. " req. bytes %ld, actual %ld, ind %ld, "
  844. " taken %ld, out %ld\n",
  845. requestedBytes.LowPart, actualBytes.LowPart,
  846. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.LowPart,
  847. connection->Common.Bufferring.ReceiveExpeditedBytesTaken.LowPart,
  848. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.LowPart
  849. ));
  850. }
  851. }
  852. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  853. DEREFERENCE_CONNECTION (connection);
  854. //
  855. // If pending has be returned for this irp then mark the current
  856. // stack as pending.
  857. //
  858. if ( Irp->PendingReturned ) {
  859. IoMarkIrpPending(Irp);
  860. }
  861. return STATUS_SUCCESS;
  862. } // AfdRestartReceive
  863. NTSTATUS
  864. AfdReceiveEventHandler (
  865. IN PVOID TdiEventContext,
  866. IN CONNECTION_CONTEXT ConnectionContext,
  867. IN ULONG ReceiveFlags,
  868. IN ULONG BytesIndicated,
  869. IN ULONG BytesAvailable,
  870. OUT ULONG *BytesTaken,
  871. IN PVOID Tsdu,
  872. OUT PIRP *IoRequestPacket
  873. )
  874. {
  875. PAFD_CONNECTION connection;
  876. PAFD_ENDPOINT endpoint;
  877. AFD_LOCK_QUEUE_HANDLE lockHandle;
  878. BOOLEAN result;
  879. connection = (PAFD_CONNECTION)ConnectionContext;
  880. ASSERT( connection != NULL );
  881. CHECK_REFERENCE_CONNECTION (connection,result);
  882. if (!result) {
  883. return STATUS_DATA_NOT_ACCEPTED;
  884. }
  885. ASSERT( connection->Type == AfdBlockTypeConnection );
  886. endpoint = connection->Endpoint;
  887. ASSERT( endpoint != NULL );
  888. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting ||
  889. endpoint->Type == AfdBlockTypeVcListening ||
  890. endpoint->Type == AfdBlockTypeVcBoth);
  891. ASSERT( !connection->DisconnectIndicated );
  892. ASSERT( !connection->AbortIndicated );
  893. ASSERT( IS_TDI_BUFFERRING(endpoint) );
  894. //
  895. // Bump the count of bytes indicated on the connection to account for
  896. // the bytes indicated by this event.
  897. //
  898. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  899. //
  900. // Check if connection was accepted and use accept endpoint instead
  901. // of the listening. Note that accept cannot happen while we are
  902. // holding listening endpoint spinlock, nor can endpoint change after
  903. // the accept, so it is safe to release listening spinlock if
  904. // we discover that endpoint was accepted.
  905. //
  906. if (((endpoint->Type & AfdBlockTypeVcListening) == AfdBlockTypeVcListening)
  907. && (connection->Endpoint != endpoint)) {
  908. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  909. endpoint = connection->Endpoint;
  910. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting );
  911. ASSERT( !IS_TDI_BUFFERRING(endpoint) );
  912. ASSERT( !IS_VC_ENDPOINT (endpoint) );
  913. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  914. }
  915. if ( BytesAvailable == 0 ) {
  916. connection->VcZeroByteReceiveIndicated = TRUE;
  917. } else {
  918. connection->Common.Bufferring.ReceiveBytesIndicated.QuadPart =
  919. connection->Common.Bufferring.ReceiveBytesIndicated.QuadPart +
  920. BytesAvailable;
  921. }
  922. IF_DEBUG(RECEIVE) {
  923. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  924. "AfdReceiveEventHandler: conn %p, bytes %ld, "
  925. "ind %ld, taken %ld, out %ld\n",
  926. connection, BytesAvailable,
  927. connection->Common.Bufferring.ReceiveBytesIndicated.LowPart,
  928. connection->Common.Bufferring.ReceiveBytesTaken.LowPart,
  929. connection->Common.Bufferring.ReceiveBytesOutstanding.LowPart ));
  930. }
  931. //
  932. // If the receive side of the endpoint has been shut down, tell the
  933. // provider that we took all the data and reset the connection.
  934. // Also, account for these bytes in our count of bytes taken from
  935. // the transport.
  936. //
  937. if ( (endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_RECEIVE) != 0 ) {
  938. #if DBG
  939. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  940. "AfdReceiveEventHandler: receive shutdown, "
  941. "%ld bytes, aborting endp %p\n",
  942. BytesAvailable, endpoint ));
  943. #endif
  944. connection->Common.Bufferring.ReceiveBytesTaken.QuadPart =
  945. connection->Common.Bufferring.ReceiveBytesTaken.QuadPart +
  946. BytesAvailable;
  947. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  948. *BytesTaken = BytesAvailable;
  949. //
  950. // Abort the connection. Note that if the abort attempt fails
  951. // we can't do anything about it.
  952. //
  953. (VOID)AfdBeginAbort( connection );
  954. DEREFERENCE_CONNECTION (connection);
  955. return STATUS_SUCCESS;
  956. } else {
  957. // Make sure connection was accepted/connected to prevent
  958. // indication on listening endpoint
  959. //
  960. if (connection->State==AfdConnectionStateConnected) {
  961. ASSERT (endpoint->Type & AfdBlockTypeVcConnecting);
  962. AfdIndicateEventSelectEvent(
  963. endpoint,
  964. AFD_POLL_RECEIVE,
  965. STATUS_SUCCESS
  966. );
  967. }
  968. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  969. //
  970. // Note to the TDI provider that we didn't take any of the data here.
  971. //
  972. // !!! needs bufferring for non-bufferring transports!
  973. *BytesTaken = 0;
  974. //
  975. // If there are any outstanding poll IRPs for this endpoint/
  976. // event, complete them.
  977. //
  978. // Make sure connection was accepted/connected to prevent
  979. // indication on listening endpoint
  980. //
  981. if (connection->State==AfdConnectionStateConnected) {
  982. ASSERT (endpoint->Type & AfdBlockTypeVcConnecting);
  983. AfdIndicatePollEvent(
  984. endpoint,
  985. AFD_POLL_RECEIVE,
  986. STATUS_SUCCESS
  987. );
  988. }
  989. DEREFERENCE_CONNECTION (connection);
  990. return STATUS_DATA_NOT_ACCEPTED;
  991. }
  992. } // AfdReceiveEventHandler
  993. NTSTATUS
  994. AfdReceiveExpeditedEventHandler (
  995. IN PVOID TdiEventContext,
  996. IN CONNECTION_CONTEXT ConnectionContext,
  997. IN ULONG ReceiveFlags,
  998. IN ULONG BytesIndicated,
  999. IN ULONG BytesAvailable,
  1000. OUT ULONG *BytesTaken,
  1001. IN PVOID Tsdu,
  1002. OUT PIRP *IoRequestPacket
  1003. )
  1004. {
  1005. PAFD_CONNECTION connection;
  1006. PAFD_ENDPOINT endpoint;
  1007. AFD_LOCK_QUEUE_HANDLE lockHandle;
  1008. BOOLEAN result;
  1009. connection = (PAFD_CONNECTION)ConnectionContext;
  1010. ASSERT( connection != NULL );
  1011. CHECK_REFERENCE_CONNECTION (connection, result);
  1012. if (!result) {
  1013. return STATUS_DATA_NOT_ACCEPTED;
  1014. }
  1015. ASSERT( connection->Type == AfdBlockTypeConnection );
  1016. endpoint = connection->Endpoint;
  1017. ASSERT( endpoint != NULL );
  1018. //
  1019. // Bump the count of bytes indicated on the connection to account for
  1020. // the expedited bytes indicated by this event.
  1021. //
  1022. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  1023. //
  1024. // Check if connection was accepted and use accept endpoint instead
  1025. // of the listening. Note that accept cannot happen while we are
  1026. // holding listening endpoint spinlock, nor can endpoint change after
  1027. // the accept, so it is safe to release listening spinlock if
  1028. // we discover that endpoint was accepted.
  1029. //
  1030. if (((endpoint->Type & AfdBlockTypeVcListening) == AfdBlockTypeVcListening)
  1031. && (connection->Endpoint != endpoint)) {
  1032. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  1033. endpoint = connection->Endpoint;
  1034. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting );
  1035. ASSERT( !IS_TDI_BUFFERRING(endpoint) );
  1036. ASSERT( !IS_VC_ENDPOINT (endpoint) );
  1037. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  1038. }
  1039. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.QuadPart =
  1040. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.QuadPart +
  1041. BytesAvailable;
  1042. IF_DEBUG(RECEIVE) {
  1043. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1044. "AfdReceiveExpeditedEventHandler: conn %p, bytes %ld, "
  1045. "ind %ld, taken %ld, out %ld, offset %ld\n",
  1046. connection, BytesAvailable,
  1047. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.LowPart,
  1048. connection->Common.Bufferring.ReceiveExpeditedBytesTaken.LowPart,
  1049. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.LowPart ));
  1050. }
  1051. //
  1052. // If the receive side of the endpoint has been shut down, tell
  1053. // the provider that we took all the data. Also, account for these
  1054. // bytes in our count of bytes taken from the transport.
  1055. //
  1056. //
  1057. if ( (endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_RECEIVE) != 0 ) {
  1058. IF_DEBUG(RECEIVE) {
  1059. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1060. "AfdReceiveExpeditedEventHandler: receive shutdown, "
  1061. "%ld bytes dropped.\n", BytesAvailable ));
  1062. }
  1063. connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart =
  1064. connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart +
  1065. BytesAvailable;
  1066. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  1067. *BytesTaken = BytesAvailable;
  1068. //
  1069. // Abort the connection. Note that if the abort attempt fails
  1070. // we can't do anything about it.
  1071. //
  1072. (VOID)AfdBeginAbort( connection );
  1073. } else {
  1074. if (connection->State==AfdConnectionStateConnected) {
  1075. ASSERT (endpoint->Type & AfdBlockTypeVcConnecting);
  1076. AfdIndicateEventSelectEvent(
  1077. endpoint,
  1078. endpoint->InLine
  1079. ? AFD_POLL_RECEIVE
  1080. : AFD_POLL_RECEIVE_EXPEDITED,
  1081. STATUS_SUCCESS
  1082. );
  1083. }
  1084. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  1085. //
  1086. // Note to the TDI provider that we didn't take any of the data here.
  1087. //
  1088. // !!! needs bufferring for non-bufferring transports!
  1089. *BytesTaken = 0;
  1090. //
  1091. // If there are any outstanding poll IRPs for this endpoint/
  1092. // event, complete them. Indicate this data as normal data if
  1093. // this endpoint is set up for inline reception of expedited
  1094. // data.
  1095. //
  1096. // Make sure connection was accepted/connected to prevent
  1097. // indication on listening endpoint
  1098. //
  1099. if (connection->State==AfdConnectionStateConnected) {
  1100. ASSERT (endpoint->Type & AfdBlockTypeVcConnecting);
  1101. AfdIndicatePollEvent(
  1102. endpoint,
  1103. endpoint->InLine
  1104. ? AFD_POLL_RECEIVE
  1105. : AFD_POLL_RECEIVE_EXPEDITED,
  1106. STATUS_SUCCESS
  1107. );
  1108. }
  1109. }
  1110. DEREFERENCE_CONNECTION (connection);
  1111. return STATUS_DATA_NOT_ACCEPTED;
  1112. } // AfdReceiveExpeditedEventHandler
  1113. NTSTATUS
  1114. AfdQueryReceiveInformation (
  1115. IN PFILE_OBJECT FileObject,
  1116. IN ULONG IoctlCode,
  1117. IN KPROCESSOR_MODE RequestorMode,
  1118. IN PVOID InputBuffer,
  1119. IN ULONG InputBufferLength,
  1120. IN PVOID OutputBuffer,
  1121. IN ULONG OutputBufferLength,
  1122. OUT PUINT_PTR Information
  1123. )
  1124. {
  1125. AFD_RECEIVE_INFORMATION receiveInformation;
  1126. PAFD_ENDPOINT endpoint;
  1127. AFD_LOCK_QUEUE_HANDLE lockHandle;
  1128. LARGE_INTEGER result;
  1129. PAFD_CONNECTION connection;
  1130. NTSTATUS status;
  1131. *Information = 0;
  1132. //
  1133. // Make sure that the output buffer is large enough.
  1134. //
  1135. if ( OutputBufferLength < sizeof(receiveInformation) ) {
  1136. return STATUS_BUFFER_TOO_SMALL;
  1137. }
  1138. //
  1139. // If this endpoint has a connection block, use the connection block's
  1140. // information, else use the information from the endpoint itself.
  1141. //
  1142. endpoint = FileObject->FsContext;
  1143. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  1144. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  1145. connection = AFD_CONNECTION_FROM_ENDPOINT( endpoint );
  1146. if ( connection != NULL ) {
  1147. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting ||
  1148. endpoint->Type == AfdBlockTypeVcBoth );
  1149. ASSERT( connection->Type == AfdBlockTypeConnection );
  1150. if ( !IS_TDI_BUFFERRING(endpoint) ) {
  1151. receiveInformation.BytesAvailable =
  1152. connection->VcBufferredReceiveBytes;
  1153. receiveInformation.ExpeditedBytesAvailable =
  1154. connection->VcBufferredExpeditedBytes;
  1155. } else {
  1156. //
  1157. // Determine the number of bytes available to be read.
  1158. //
  1159. result.QuadPart =
  1160. connection->Common.Bufferring.ReceiveBytesIndicated.QuadPart -
  1161. (connection->Common.Bufferring.ReceiveBytesTaken.QuadPart +
  1162. connection->Common.Bufferring.ReceiveBytesOutstanding.QuadPart);
  1163. ASSERT( result.HighPart == 0 );
  1164. receiveInformation.BytesAvailable = result.LowPart;
  1165. //
  1166. // Determine the number of expedited bytes available to be read.
  1167. //
  1168. result.QuadPart =
  1169. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated.QuadPart -
  1170. (connection->Common.Bufferring.ReceiveExpeditedBytesTaken.QuadPart +
  1171. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding.QuadPart);
  1172. ASSERT( result.HighPart == 0 );
  1173. receiveInformation.ExpeditedBytesAvailable = result.LowPart;
  1174. }
  1175. } else {
  1176. //
  1177. // Determine the number of bytes available to be read.
  1178. //
  1179. if ( IS_DGRAM_ENDPOINT(endpoint) ) {
  1180. //
  1181. // Return the amount of bytes of datagrams that are
  1182. // bufferred on the endpoint.
  1183. //
  1184. if (endpoint->DgBufferredReceiveBytes>0) {
  1185. receiveInformation.BytesAvailable = endpoint->DgBufferredReceiveBytes;
  1186. }
  1187. else { // Report one byte to the application to prompt it to
  1188. // read the data if zero-sized datagrams are available.
  1189. receiveInformation.BytesAvailable = endpoint->DgBufferredReceiveCount>0 ? 1 : 0;
  1190. }
  1191. } else {
  1192. //
  1193. // This is an unconnected endpoint, hence no bytes are
  1194. // available to be read.
  1195. //
  1196. receiveInformation.BytesAvailable = 0;
  1197. }
  1198. //
  1199. // Whether this is a datagram endpoint or just unconnected,
  1200. // there are no expedited bytes available.
  1201. //
  1202. receiveInformation.ExpeditedBytesAvailable = 0;
  1203. }
  1204. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  1205. try {
  1206. //
  1207. // Validate the output structure if it comes from the user mode
  1208. // application
  1209. //
  1210. if (RequestorMode != KernelMode ) {
  1211. ProbeForWrite (OutputBuffer,
  1212. sizeof (receiveInformation),
  1213. PROBE_ALIGNMENT (AFD_RECEIVE_INFORMATION));
  1214. }
  1215. //
  1216. // Copy parameters back to application's memory
  1217. //
  1218. *((PAFD_RECEIVE_INFORMATION)OutputBuffer) = receiveInformation;
  1219. } except( AFD_EXCEPTION_FILTER(&status) ) {
  1220. return status;
  1221. }
  1222. *Information = sizeof(AFD_RECEIVE_INFORMATION);
  1223. return STATUS_SUCCESS;
  1224. } // AfdQueryReceiveInformation