Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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