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.

3284 lines
100 KiB

  1. /*++
  2. Copyright (c) 1989-1999 Microsoft Corporation
  3. Module Name:
  4. accept.c
  5. Abstract:
  6. This module contains the handling code for IOCTL_AFD_ACCEPT.
  7. as well as IOCTL_AFD_SUPER_ACCEPT
  8. Author:
  9. David Treadwell (davidtr) 21-Feb-1992
  10. Revision History:
  11. Vadim Eydelman (vadime) 1999 - No spinlock performance path in super accept,
  12. general code restructuring.
  13. --*/
  14. #include "afdp.h"
  15. VOID
  16. AfdDoListenBacklogReplenish (
  17. IN PVOID Context
  18. );
  19. NTSTATUS
  20. AfdReplenishListenBacklog (
  21. IN PAFD_ENDPOINT Endpoint
  22. );
  23. VOID
  24. AfdReportConnectionAllocationFailure (
  25. PAFD_ENDPOINT Endpoint,
  26. NTSTATUS Status
  27. );
  28. NTSTATUS
  29. AfdContinueSuperAccept (
  30. IN PIRP Irp,
  31. PAFD_CONNECTION Connection
  32. );
  33. NTSTATUS
  34. AfdRestartSuperAcceptGetAddress (
  35. IN PDEVICE_OBJECT DeviceObject,
  36. IN PIRP Irp,
  37. IN PVOID Context
  38. );
  39. NTSTATUS
  40. AfdRestartSuperAcceptReceive (
  41. IN PDEVICE_OBJECT DeviceObject,
  42. IN PIRP Irp,
  43. IN PVOID Context
  44. );
  45. NTSTATUS
  46. AfdRestartDelayedAccept (
  47. IN PDEVICE_OBJECT DeviceObject,
  48. IN PIRP Irp,
  49. IN PVOID Context
  50. );
  51. VOID
  52. AfdSuperAcceptApcKernelRoutine (
  53. IN struct _KAPC *Apc,
  54. IN OUT PKNORMAL_ROUTINE *NormalRoutine,
  55. IN OUT PVOID *NormalContext,
  56. IN OUT PVOID *SystemArgument1,
  57. IN OUT PVOID *SystemArgument2
  58. );
  59. VOID
  60. AfdSuperAcceptApcRundownRoutine (
  61. IN struct _KAPC *Apc
  62. );
  63. #ifdef ALLOC_PRAGMA
  64. #pragma alloc_text( PAGEAFD, AfdAccept )
  65. #pragma alloc_text( PAGEAFD, AfdSuperAccept )
  66. #pragma alloc_text( PAGEAFD, AfdDeferAccept )
  67. #pragma alloc_text( PAGEAFD, AfdDoListenBacklogReplenish )
  68. #pragma alloc_text( PAGEAFD, AfdSetupAcceptEndpoint )
  69. #pragma alloc_text( PAGE, AfdReplenishListenBacklog )
  70. #pragma alloc_text( PAGEAFD, AfdReportConnectionAllocationFailure )
  71. #pragma alloc_text( PAGEAFD, AfdInitiateListenBacklogReplenish )
  72. #pragma alloc_text( PAGEAFD, AfdRestartSuperAccept )
  73. #pragma alloc_text( PAGEAFD, AfdRestartSuperAcceptListen )
  74. #pragma alloc_text( PAGEAFD, AfdContinueSuperAccept )
  75. #pragma alloc_text( PAGEAFD, AfdServiceSuperAccept )
  76. #pragma alloc_text( PAGEAFD, AfdRestartSuperAcceptGetAddress )
  77. #pragma alloc_text( PAGEAFD, AfdRestartSuperAcceptReceive )
  78. #pragma alloc_text( PAGE, AfdSuperAcceptApcKernelRoutine )
  79. #pragma alloc_text( PAGE, AfdSuperAcceptApcRundownRoutine )
  80. #pragma alloc_text( PAGEAFD, AfdCancelSuperAccept )
  81. #pragma alloc_text( PAGEAFD, AfdCleanupSuperAccept )
  82. #pragma alloc_text( PAGEAFD, AfdRestartDelayedAccept)
  83. #pragma alloc_text( PAGEAFD, AfdRestartDelayedSuperAccept)
  84. #endif
  85. //
  86. // Macros to make the super accept restart code more maintainable.
  87. //
  88. #define AfdRestartSuperAcceptInfo DeviceIoControl
  89. // Used while IRP is in AFD queue (otherwise AfdAcceptFileObject
  90. // is stored as completion routine context).
  91. #define AfdAcceptFileObject Type3InputBuffer
  92. // Used when IRP is passed to the transport (otherwise MdlAddress
  93. // is stored in the IRP itself).
  94. #define AfdMdlAddress Type3InputBuffer
  95. #define AfdReceiveDataLength OutputBufferLength
  96. #define AfdRemoteAddressLength InputBufferLength
  97. #define AfdLocalAddressLength IoControlCode
  98. //
  99. // Similar macros for delayed accept restart code.
  100. //
  101. #define AfdRestartDelayedAcceptInfo DeviceIoControl
  102. #define AfdSystemBuffer Type3InputBuffer
  103. NTSTATUS
  104. FASTCALL
  105. AfdAccept (
  106. IN PIRP Irp,
  107. IN PIO_STACK_LOCATION IrpSp
  108. )
  109. /*++
  110. Routine Description:
  111. Accepts an incoming connection. The connection is identified by the
  112. sequence number returned in the wait for listen IRP, and then
  113. associated with the endpoint specified in this request. When this
  114. request completes, the connection is fully established and ready for
  115. data transfer.
  116. Arguments:
  117. Irp - a pointer to a transmit file IRP.
  118. IrpSp - Our stack location for this IRP.
  119. Return Value:
  120. STATUS_SUCCESS if the request was completed successfully, or a
  121. failure status code if there was an error.
  122. --*/
  123. {
  124. NTSTATUS status;
  125. PAFD_ACCEPT_INFO acceptInfo;
  126. PAFD_ENDPOINT listenEndpoint;
  127. PFILE_OBJECT acceptFileObject;
  128. PAFD_ENDPOINT acceptEndpoint;
  129. PAFD_CONNECTION connection;
  130. //
  131. // Set up local variables.
  132. //
  133. listenEndpoint = IrpSp->FileObject->FsContext;
  134. Irp->IoStatus.Information = 0;
  135. #ifdef _WIN64
  136. if (IoIs32bitProcess (Irp)) {
  137. PAFD_ACCEPT_INFO newSystemBuffer;
  138. PAFD_ACCEPT_INFO32 oldSystemBuffer = Irp->AssociatedIrp.SystemBuffer;
  139. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  140. sizeof(AFD_ACCEPT_INFO32) ) {
  141. status = STATUS_INVALID_PARAMETER;
  142. goto complete;
  143. }
  144. try {
  145. newSystemBuffer = ExAllocatePoolWithQuotaTag (
  146. NonPagedPool|POOL_RAISE_IF_ALLOCATION_FAILURE,
  147. sizeof (AFD_ACCEPT_INFO),
  148. AFD_SYSTEM_BUFFER_POOL_TAG);
  149. }
  150. except (EXCEPTION_EXECUTE_HANDLER) {
  151. status = GetExceptionCode ();
  152. goto complete;
  153. }
  154. newSystemBuffer->SanActive = oldSystemBuffer->SanActive;
  155. newSystemBuffer->AcceptHandle = oldSystemBuffer->AcceptHandle;
  156. newSystemBuffer->Sequence = oldSystemBuffer->Sequence;
  157. ExFreePool (Irp->AssociatedIrp.SystemBuffer);
  158. Irp->AssociatedIrp.SystemBuffer = newSystemBuffer;
  159. IrpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof (AFD_ACCEPT_INFO);
  160. }
  161. #endif // _WIN64
  162. acceptInfo = Irp->AssociatedIrp.SystemBuffer;
  163. //
  164. // Make sure that this request is valid.
  165. //
  166. if ( !listenEndpoint->Listening ||
  167. IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  168. sizeof(AFD_ACCEPT_INFO) ||
  169. Irp->MdlAddress!=NULL) {
  170. status = STATUS_INVALID_PARAMETER;
  171. goto complete;
  172. }
  173. ASSERT ((listenEndpoint->Type & AfdBlockTypeVcListening)==AfdBlockTypeVcListening);
  174. //
  175. // Check for if the caller is unaware of the SAN
  176. // provider activation and report the error.
  177. //
  178. if (!acceptInfo->SanActive && AfdSanServiceHelper!=NULL) {
  179. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  180. "AFD: Process %p is being told to enable SAN on accept\n",
  181. PsGetCurrentProcessId ()));
  182. status = STATUS_INVALID_PARAMETER_12;
  183. goto complete;
  184. }
  185. //
  186. // Add another free connection to replace the one we're accepting.
  187. // Also, add extra to account for past failures in calls to
  188. // AfdAddFreeConnection().
  189. //
  190. InterlockedIncrement(
  191. &listenEndpoint->Common.VcListening.FailedConnectionAdds
  192. );
  193. AfdReplenishListenBacklog( listenEndpoint );
  194. //
  195. // Obtain a pointer to the endpoint on which we're going to
  196. // accept the connection.
  197. //
  198. status = ObReferenceObjectByHandle(
  199. acceptInfo->AcceptHandle,
  200. (IrpSp->Parameters.DeviceIoControl.IoControlCode>>14) & 3,
  201. // DesiredAccess
  202. *IoFileObjectType,
  203. Irp->RequestorMode,
  204. (PVOID *)&acceptFileObject,
  205. NULL
  206. );
  207. if ( !NT_SUCCESS(status) ) {
  208. goto complete;
  209. }
  210. //
  211. // We may have a file object that is not an AFD endpoint. Make sure
  212. // that this is an actual AFD endpoint.
  213. //
  214. if ( acceptFileObject->DeviceObject!=AfdDeviceObject) {
  215. status = STATUS_INVALID_HANDLE;
  216. goto complete_deref;
  217. }
  218. acceptEndpoint = acceptFileObject->FsContext;
  219. if (acceptEndpoint->TransportInfo!=listenEndpoint->TransportInfo) {
  220. status = STATUS_INVALID_PARAMETER;
  221. goto complete_deref;
  222. }
  223. ASSERT( InterlockedIncrement( &acceptEndpoint->ObReferenceBias ) > 0 );
  224. IF_DEBUG(ACCEPT) {
  225. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  226. "AfdAccept: file object %p, accept endpoint %p, listen endpoint %p\n",
  227. acceptFileObject, acceptEndpoint, listenEndpoint ));
  228. }
  229. if (AFD_START_STATE_CHANGE (acceptEndpoint, AfdEndpointStateConnected)) {
  230. if (acceptEndpoint->State!=AfdEndpointStateOpen ||
  231. acceptEndpoint->TransportInfo!=listenEndpoint->TransportInfo ||
  232. acceptEndpoint->SecurityDescriptor!=NULL) {
  233. status = STATUS_INVALID_PARAMETER;
  234. }
  235. else {
  236. AFD_LOCK_QUEUE_HANDLE lockHandle;
  237. AfdAcquireSpinLock (&listenEndpoint->SpinLock, &lockHandle);
  238. connection = AfdGetReturnedConnection (listenEndpoint,
  239. acceptInfo->Sequence);
  240. if (connection==NULL) {
  241. AfdReleaseSpinLock (&listenEndpoint->SpinLock, &lockHandle);
  242. status = STATUS_INVALID_PARAMETER;
  243. }
  244. else if (connection->SanConnection) {
  245. Irp->Tail.Overlay.DriverContext[3] = acceptInfo->AcceptHandle;
  246. IrpSp->Parameters.AfdRestartSuperAcceptInfo.AfdAcceptFileObject = acceptFileObject;
  247. IrpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength = 0;
  248. IrpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength = 0;
  249. IrpSp->Parameters.AfdRestartSuperAcceptInfo.AfdRemoteAddressLength = 0;
  250. status = AfdSanAcceptCore (Irp, acceptFileObject, connection, &lockHandle);
  251. if (status==STATUS_PENDING) {
  252. return STATUS_PENDING;
  253. }
  254. }
  255. else {
  256. status = AfdAcceptCore (Irp, acceptEndpoint, connection);
  257. AfdReleaseSpinLock (&listenEndpoint->SpinLock, &lockHandle);
  258. AFD_RETURN_REMOTE_ADDRESS (
  259. connection->RemoteAddress,
  260. connection->RemoteAddressLength
  261. );
  262. connection->RemoteAddress = NULL;
  263. if (status==STATUS_SUCCESS) {
  264. NOTHING;
  265. }
  266. else if (status==STATUS_PENDING) {
  267. //
  268. // Remember that a TDI accept has started on this endpoint.
  269. //
  270. InterlockedIncrement(
  271. &listenEndpoint->Common.VcListening.TdiAcceptPendingCount
  272. );
  273. IrpSp->Parameters.AfdRestartDelayedAcceptInfo.AfdSystemBuffer =
  274. Irp->AssociatedIrp.SystemBuffer;
  275. Irp->AssociatedIrp.SystemBuffer = NULL;
  276. ASSERT (Irp->MdlAddress==NULL);
  277. IoSetCompletionRoutine(
  278. Irp,
  279. AfdRestartDelayedAccept,
  280. acceptFileObject,
  281. TRUE,
  282. TRUE,
  283. TRUE
  284. );
  285. AfdIoCallDriver (
  286. acceptEndpoint,
  287. connection->DeviceObject,
  288. Irp
  289. );
  290. return STATUS_PENDING;
  291. }
  292. else {
  293. AfdAbortConnection (connection);
  294. ASSERT (status==STATUS_CANCELLED);
  295. }
  296. }
  297. }
  298. AFD_END_STATE_CHANGE (acceptEndpoint);
  299. }
  300. else {
  301. status = STATUS_INVALID_PARAMETER;
  302. }
  303. ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
  304. complete_deref:
  305. ObDereferenceObject( acceptFileObject );
  306. complete:
  307. Irp->IoStatus.Status = status;
  308. ASSERT( Irp->CancelRoutine == NULL );
  309. IoCompleteRequest( Irp, AfdPriorityBoost );
  310. return status;
  311. } // AfdAccept
  312. NTSTATUS
  313. AfdAcceptCore (
  314. IN PIRP AcceptIrp,
  315. IN PAFD_ENDPOINT AcceptEndpoint,
  316. IN PAFD_CONNECTION Connection
  317. )
  318. /*++
  319. Routine Description:
  320. Performs the key functions of associating a connection accepted
  321. on a listening endpoint with a new endpoint.
  322. Arguments:
  323. AcceptIrp - Irp used for accept operation
  324. AcceptEndpoint - the new endpoint with which to associate the
  325. connectuion.
  326. Connection - the connection being accepted.
  327. Return Value:
  328. STATUS_SUCCESS if the operation was completed successfully,
  329. STATUS_PENDING if IRP was passed further to the transport
  330. failure status code if there was an error.
  331. --*/
  332. {
  333. PAFD_ENDPOINT listenEndpoint;
  334. NTSTATUS status;
  335. PIO_STACK_LOCATION irpSp;
  336. AFD_LOCK_QUEUE_HANDLE lockHandle;
  337. irpSp = IoGetCurrentIrpStackLocation (AcceptIrp);
  338. listenEndpoint = irpSp->FileObject->FsContext;
  339. //
  340. // Reenable the accept event bit, and if there are additional
  341. // unaccepted connections on the endpoint, post another event.
  342. //
  343. listenEndpoint->EventsActive &= ~AFD_POLL_ACCEPT;
  344. IF_DEBUG(EVENT_SELECT) {
  345. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  346. "AfdAcceptCore: Endp %08lX, Active %08lX\n",
  347. listenEndpoint,
  348. listenEndpoint->EventsActive
  349. ));
  350. }
  351. if( !IsListEmpty( &listenEndpoint->Common.VcListening.UnacceptedConnectionListHead ) ) {
  352. AfdIndicateEventSelectEvent(
  353. listenEndpoint,
  354. AFD_POLL_ACCEPT,
  355. STATUS_SUCCESS
  356. );
  357. }
  358. //
  359. // Do not release the listening endpoint spinlock here.
  360. // We are going to be chaning connection object which assumes
  361. // protection from listening endpoint spinlock until it is associated
  362. // with accept endpoint (this plugs nasty racing conditions when
  363. // receive is indicated rigth before connection object is updated, so
  364. // it takes listening endpoint spinlock, and rigth before it queues
  365. // the buffer to the connection object, it gets associated with accept
  366. // endpoint and AcceptEx'es receive does not notice the buffer because
  367. // it takes accept endpoint spinlock)
  368. //
  369. // AfdReleaseSpinLock( &ListenEndpoint->SpinLock, &lockHandle );
  370. //
  371. // Check the state of the accepting endpoint under the guard
  372. // of the endpoint's spinlock.
  373. //
  374. AfdAcquireSpinLockAtDpcLevel( &AcceptEndpoint->SpinLock, &lockHandle);
  375. status = AfdSetupAcceptEndpoint (listenEndpoint, AcceptEndpoint, Connection);
  376. if (status==STATUS_SUCCESS) {
  377. if (IS_DELAYED_ACCEPTANCE_ENDPOINT (listenEndpoint)) {
  378. PTDI_CONNECTION_INFORMATION requestConnectionInformation;
  379. if( Connection->ConnectDataBuffers != NULL ) {
  380. //
  381. // We allocated extra space at the end of the connect data
  382. // buffers structure. We'll use this for the
  383. // TDI_CONNECTION_INFORMATION structure that holds response
  384. // connect data and options. Not pretty, but the fastest
  385. // and easiest way to accomplish this.
  386. //
  387. requestConnectionInformation =
  388. &Connection->ConnectDataBuffers->RequestConnectionInfo;
  389. RtlZeroMemory(
  390. requestConnectionInformation,
  391. sizeof(*requestConnectionInformation)
  392. );
  393. requestConnectionInformation->UserData =
  394. Connection->ConnectDataBuffers->SendConnectData.Buffer;
  395. requestConnectionInformation->UserDataLength =
  396. Connection->ConnectDataBuffers->SendConnectData.BufferLength;
  397. requestConnectionInformation->Options =
  398. Connection->ConnectDataBuffers->SendConnectOptions.Buffer;
  399. requestConnectionInformation->OptionsLength =
  400. Connection->ConnectDataBuffers->SendConnectOptions.BufferLength;
  401. } else {
  402. requestConnectionInformation = NULL;
  403. }
  404. TdiBuildAccept(
  405. AcceptIrp,
  406. Connection->DeviceObject,
  407. Connection->FileObject,
  408. NULL,
  409. NULL,
  410. requestConnectionInformation,
  411. NULL
  412. );
  413. status = STATUS_PENDING;
  414. }
  415. else {
  416. //
  417. // Set the endpoint to the connected state.
  418. //
  419. AcceptEndpoint->State = AfdEndpointStateConnected;
  420. Connection->State = AfdConnectionStateConnected;
  421. //
  422. // Set events active field base on data accumulated on the connection.
  423. //
  424. if( IS_DATA_ON_CONNECTION( Connection ) ||
  425. ( AcceptEndpoint->InLine &&
  426. IS_EXPEDITED_DATA_ON_CONNECTION( Connection ) ) ) {
  427. AcceptEndpoint->EventsActive |= AFD_POLL_RECEIVE;
  428. }
  429. if( !AcceptEndpoint->InLine &&
  430. IS_EXPEDITED_DATA_ON_CONNECTION( Connection ) ) {
  431. AcceptEndpoint->EventsActive |= AFD_POLL_RECEIVE_EXPEDITED;
  432. }
  433. AcceptEndpoint->EventsActive |= AFD_POLL_SEND;
  434. if( Connection->DisconnectIndicated ) {
  435. AcceptEndpoint->EventsActive |= AFD_POLL_DISCONNECT;
  436. }
  437. if( Connection->Aborted ) {
  438. AcceptEndpoint->EventsActive |= AFD_POLL_ABORT;
  439. }
  440. IF_DEBUG(EVENT_SELECT) {
  441. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  442. "AfdAcceptCore: Endp %08lX, Active %08lX\n",
  443. AcceptEndpoint,
  444. AcceptEndpoint->EventsActive
  445. ));
  446. }
  447. status = STATUS_SUCCESS;
  448. }
  449. }
  450. AfdReleaseSpinLockFromDpcLevel( &AcceptEndpoint->SpinLock, &lockHandle);
  451. return status;
  452. } // AfdAcceptCore
  453. VOID
  454. AfdInitiateListenBacklogReplenish (
  455. IN PAFD_ENDPOINT Endpoint
  456. )
  457. /*++
  458. Routine Description:
  459. Queues a work item to begin replenishing the listen backlog
  460. on a listening endpoint.
  461. Arguments:
  462. Endpoint - the listening endpoint on which to replenish the
  463. backlog.
  464. Return Value:
  465. None.
  466. --*/
  467. {
  468. AFD_LOCK_QUEUE_HANDLE lockHandle;
  469. //
  470. // Check if backlog replenish is active already.
  471. //
  472. AfdAcquireSpinLock (&Endpoint->SpinLock, &lockHandle);
  473. if (!Endpoint->Common.VcListening.BacklogReplenishActive) {
  474. Endpoint->Common.VcListening.BacklogReplenishActive = TRUE;
  475. //
  476. // Reference the endpoint so that it won't go away until we're
  477. // done with it.
  478. //
  479. REFERENCE_ENDPOINT( Endpoint );
  480. AfdQueueWorkItem(
  481. AfdDoListenBacklogReplenish,
  482. &Endpoint->WorkItem
  483. );
  484. }
  485. AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle);
  486. return;
  487. } // AfdInitiateListenBacklogReplenish
  488. VOID
  489. AfdDoListenBacklogReplenish (
  490. IN PVOID Context
  491. )
  492. /*++
  493. Routine Description:
  494. The worker routine for replenishing the listen backlog on a
  495. listening endpoint. This routine only runs in the context of
  496. an executive worker thread.
  497. Arguments:
  498. Context - Points to an AFD_WORK_ITEM structure. The Context field
  499. of this structure points to the endpoint on which to replenish
  500. the listen backlog.
  501. Return Value:
  502. None.
  503. --*/
  504. {
  505. PAFD_ENDPOINT endpoint;
  506. NTSTATUS status;
  507. AFD_LOCK_QUEUE_HANDLE lockHandle;
  508. endpoint = CONTAINING_RECORD(
  509. Context,
  510. AFD_ENDPOINT,
  511. WorkItem
  512. );
  513. ASSERT( endpoint->Type == AfdBlockTypeVcListening ||
  514. endpoint->Type == AfdBlockTypeVcBoth );
  515. ASSERT (endpoint->Common.VcListening.BacklogReplenishActive == TRUE);
  516. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  517. endpoint->Common.VcListening.BacklogReplenishActive = FALSE;
  518. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  519. //
  520. // Fill up the free connection backlog.
  521. //
  522. status = AfdReplenishListenBacklog( endpoint );
  523. if (!NT_SUCCESS (status)) {
  524. //
  525. // If we failed, try to notify application
  526. //
  527. AfdReportConnectionAllocationFailure (endpoint, status);
  528. }
  529. //
  530. // Clean up and return.
  531. //
  532. DEREFERENCE_ENDPOINT( endpoint );
  533. return;
  534. } // AfdDoListenBacklogReplenish
  535. NTSTATUS
  536. AfdReplenishListenBacklog (
  537. IN PAFD_ENDPOINT Endpoint
  538. )
  539. /*++
  540. Routine Description:
  541. Does the actual work of filling up the listen backlog on a listening
  542. endpoint.
  543. Arguments:
  544. Endpoint - the listening endpoint on which to replenish the
  545. listen backlog.
  546. Return Value:
  547. STATUS_SUCCESS - if new connection was allocated or we already
  548. had enough
  549. status of conneciton allocation failure otherwise
  550. --*/
  551. {
  552. NTSTATUS status;
  553. LONG result;
  554. PAGED_CODE( );
  555. ASSERT( Endpoint->Type == AfdBlockTypeVcListening ||
  556. Endpoint->Type == AfdBlockTypeVcBoth );
  557. //
  558. // Decrement the count of failed connection additions.
  559. //
  560. result = InterlockedDecrement(
  561. &Endpoint->Common.VcListening.FailedConnectionAdds
  562. );
  563. //
  564. // Continue opening new free conections until we've hit the
  565. // backlog or a connection open fails.
  566. //
  567. // If the result of the decrement is negative, then we are either
  568. // all set on the connection count or else have available extra
  569. // connection objects on the listening endpoint. These connections
  570. // have been reused from prior connections which have now
  571. // terminated.
  572. //
  573. while ( result >= 0 ) {
  574. status = AfdAddFreeConnection( Endpoint );
  575. if ( !NT_SUCCESS(status) ) {
  576. InterlockedIncrement(
  577. &Endpoint->Common.VcListening.FailedConnectionAdds
  578. );
  579. IF_DEBUG(LISTEN) {
  580. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  581. "AfdReplenishListenBacklog: AfdAddFreeConnection failed: %X, fail count = %ld\n", status,
  582. Endpoint->Common.VcListening.FailedConnectionAdds ));
  583. }
  584. //
  585. // Return connection allocation failure to the application
  586. // if it cares to know (posted accept request).
  587. //
  588. return status;
  589. }
  590. result = InterlockedDecrement(
  591. &Endpoint->Common.VcListening.FailedConnectionAdds
  592. );
  593. }
  594. //
  595. // Correct the counter to reflect the number of connections
  596. // we have available. Then just return from here.
  597. //
  598. InterlockedIncrement(
  599. &Endpoint->Common.VcListening.FailedConnectionAdds
  600. );
  601. return STATUS_SUCCESS;
  602. } // AfdReplenishListenBacklog
  603. VOID
  604. AfdReportConnectionAllocationFailure (
  605. PAFD_ENDPOINT Endpoint,
  606. NTSTATUS Status
  607. )
  608. /*++
  609. Routine Description:
  610. Reports connection allocation failure to the application by
  611. failing then first wait for listen irp in the queue (if application
  612. has AcceptEx or blockin accept outstanding, it will get this notification).
  613. Arguments:
  614. Endpoint - the listening endpoint on which to report an error
  615. Status - status code to report
  616. Return Value:
  617. None
  618. --*/
  619. {
  620. AFD_LOCK_QUEUE_HANDLE lockHandle;
  621. AfdAcquireSpinLock (&Endpoint->SpinLock, &lockHandle);
  622. if ((Endpoint->Common.VcListening.FailedConnectionAdds>0) &&
  623. IsListEmpty (&Endpoint->Common.VcListening.UnacceptedConnectionListHead) &&
  624. !IsListEmpty (&Endpoint->Common.VcListening.ListeningIrpListHead)) {
  625. PIRP irp;
  626. PIO_STACK_LOCATION irpSp;
  627. irp = CONTAINING_RECORD (Endpoint->Common.VcListening.ListeningIrpListHead.Flink,
  628. IRP,
  629. Tail.Overlay.ListEntry);
  630. irpSp = IoGetCurrentIrpStackLocation (irp);
  631. RemoveEntryList (&irp->Tail.Overlay.ListEntry);
  632. irp->Tail.Overlay.ListEntry.Flink = NULL;
  633. AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle);
  634. if (IoSetCancelRoutine (irp, NULL)==NULL) {
  635. KIRQL cancelIrql;
  636. //
  637. // If the cancel routine was NULL then cancel routine
  638. // may be running. Wait on the cancel spinlock until
  639. // the cancel routine is done.
  640. //
  641. // Note: The cancel routine will not find the IRP
  642. // since it is not in the list.
  643. //
  644. IoAcquireCancelSpinLock( &cancelIrql );
  645. ASSERT( irp->Cancel );
  646. IoReleaseCancelSpinLock( cancelIrql );
  647. }
  648. if (irpSp->MajorFunction==IRP_MJ_INTERNAL_DEVICE_CONTROL) {
  649. AfdCleanupSuperAccept (irp, Status);
  650. }
  651. else {
  652. irp->IoStatus.Status = Status;
  653. irp->IoStatus.Information = 0;
  654. }
  655. IoCompleteRequest (irp, AfdPriorityBoost);
  656. }
  657. else {
  658. AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle);
  659. }
  660. }
  661. NTSTATUS
  662. FASTCALL
  663. AfdSuperAccept (
  664. IN PIRP Irp,
  665. IN PIO_STACK_LOCATION IrpSp
  666. )
  667. /*++
  668. Routine Description:
  669. Initial entrypoint for handling super accept IRPs. A super accept
  670. combines several operations for high-performance connection
  671. acceptance. The combined operations are waiting for an incoming
  672. connection, accepting it, retrieving the local and remote socket
  673. addresses, and receiving the first chunk of data on the connection.
  674. This routine verifies parameters, initializes data structures to be
  675. used for the request, and initiates the I/O.
  676. Arguments:
  677. Irp - a pointer to a transmit file IRP.
  678. IrpSp - Our stack location for this IRP.
  679. Return Value:
  680. STATUS_PENDING if the request was initiated successfully, or a
  681. failure status code if there was an error.
  682. --*/
  683. {
  684. PAFD_ENDPOINT listenEndpoint;
  685. PAFD_ENDPOINT acceptEndpoint;
  686. PFILE_OBJECT acceptFileObject;
  687. HANDLE acceptHandle;
  688. ULONG receiveDataLength, localAddressLength, remoteAddressLength;
  689. BOOLEAN sanActive;
  690. #ifndef i386
  691. BOOLEAN fixAddressAlignment;
  692. #endif
  693. NTSTATUS status;
  694. ULONG totalLength;
  695. PSLIST_ENTRY listEntry;
  696. PAFD_CONNECTION connection;
  697. AFD_LOCK_QUEUE_HANDLE lockHandle;
  698. //
  699. // Set up local variables.
  700. //
  701. listenEndpoint = IrpSp->FileObject->FsContext;
  702. acceptFileObject = NULL;
  703. acceptEndpoint = NULL;
  704. #ifdef _WIN64
  705. if (IoIs32bitProcess (Irp)) {
  706. PAFD_SUPER_ACCEPT_INFO32 superAcceptInfo32;
  707. superAcceptInfo32 = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  708. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  709. sizeof(AFD_SUPER_ACCEPT_INFO32) ) {
  710. status = STATUS_INVALID_PARAMETER;
  711. goto complete;
  712. }
  713. AFD_W4_INIT status = STATUS_SUCCESS;
  714. try {
  715. if (Irp->RequestorMode!=KernelMode) {
  716. ProbeForReadSmallStructure (superAcceptInfo32,
  717. sizeof (*superAcceptInfo32),
  718. PROBE_ALIGNMENT32 (AFD_SUPER_ACCEPT_INFO32));
  719. }
  720. acceptHandle = superAcceptInfo32->AcceptHandle;
  721. receiveDataLength = superAcceptInfo32->ReceiveDataLength;
  722. localAddressLength = superAcceptInfo32->LocalAddressLength;
  723. remoteAddressLength = superAcceptInfo32->RemoteAddressLength;
  724. sanActive = superAcceptInfo32->SanActive;
  725. fixAddressAlignment = superAcceptInfo32->FixAddressAlignment;
  726. }
  727. except (AFD_EXCEPTION_FILTER (status)) {
  728. ASSERT (NT_ERROR (status));
  729. goto complete;
  730. }
  731. }
  732. else
  733. #endif // _WIN64
  734. {
  735. PAFD_SUPER_ACCEPT_INFO superAcceptInfo;
  736. superAcceptInfo = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  737. AFD_W4_INIT status = STATUS_SUCCESS;
  738. try {
  739. if (Irp->RequestorMode!=KernelMode) {
  740. ProbeForReadSmallStructure (superAcceptInfo,
  741. sizeof (*superAcceptInfo),
  742. PROBE_ALIGNMENT (AFD_SUPER_ACCEPT_INFO));
  743. }
  744. acceptHandle = superAcceptInfo->AcceptHandle;
  745. receiveDataLength = superAcceptInfo->ReceiveDataLength;
  746. localAddressLength = superAcceptInfo->LocalAddressLength;
  747. remoteAddressLength = superAcceptInfo->RemoteAddressLength;
  748. sanActive = superAcceptInfo->SanActive;
  749. #ifndef i386
  750. fixAddressAlignment = superAcceptInfo->FixAddressAlignment;
  751. #endif
  752. }
  753. except (AFD_EXCEPTION_FILTER (status)) {
  754. ASSERT (NT_ERROR (status));
  755. goto complete;
  756. }
  757. }
  758. //
  759. // Check for if the caller is unaware of the SAN
  760. // provider activation and report the error.
  761. //
  762. if (!sanActive && AfdSanServiceHelper!=NULL) {
  763. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  764. "AFD: Process %p is being told to enable SAN on AcceptEx\n",
  765. PsGetCurrentProcessId ()));
  766. status = STATUS_INVALID_PARAMETER_12;
  767. goto complete;
  768. }
  769. //
  770. // Validate the input information. The input buffer must be large
  771. // enough to hold all the input information, plus some extra to use
  772. // here to hold the local address. The output buffer must be
  773. // non-NULL and large enough to hold the specified information.
  774. //
  775. //
  776. if ( !listenEndpoint->Listening
  777. ||
  778. remoteAddressLength < (ULONG)FIELD_OFFSET (TRANSPORT_ADDRESS,
  779. Address[0].Address)
  780. ||
  781. //
  782. // Do the check in such a manner that integer overflow
  783. // (which is not enabled by the compiler) does not
  784. // affect the validity of the result.
  785. //
  786. (totalLength=IrpSp->Parameters.DeviceIoControl.OutputBufferLength)<
  787. receiveDataLength
  788. ||
  789. (totalLength-=receiveDataLength) < localAddressLength
  790. ||
  791. (totalLength-=localAddressLength) < remoteAddressLength
  792. ) {
  793. if( !listenEndpoint->Listening ) {
  794. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  795. "AfdSuperAccept: non-listening endpoint @ %08lX\n",
  796. listenEndpoint
  797. ));
  798. status = STATUS_INVALID_PARAMETER;
  799. }
  800. else {
  801. status = STATUS_BUFFER_TOO_SMALL;
  802. }
  803. goto complete;
  804. }
  805. AFD_W4_INIT ASSERT (status == STATUS_SUCCESS);
  806. try {
  807. if (IoAllocateMdl(Irp->UserBuffer,
  808. IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  809. FALSE, // Secondary buffer
  810. TRUE, // Charge quota
  811. Irp
  812. )==NULL) {
  813. status = STATUS_INSUFFICIENT_RESOURCES;
  814. goto complete;
  815. }
  816. MmProbeAndLockPages (Irp->MdlAddress, Irp->RequestorMode, IoWriteAccess);
  817. }
  818. __except (AFD_EXCEPTION_FILTER (status)) {
  819. ASSERT (NT_ERROR (status));
  820. goto complete;
  821. }
  822. ASSERT ((listenEndpoint->Type & AfdBlockTypeVcListening) == AfdBlockTypeVcListening);
  823. //
  824. // Obtain a pointer to the endpoint on which we're going to
  825. // accept the connection.
  826. //
  827. status = ObReferenceObjectByHandle(
  828. acceptHandle,
  829. (IrpSp->Parameters.DeviceIoControl.IoControlCode>>14) & 3,
  830. // DesiredAccess
  831. *IoFileObjectType,
  832. Irp->RequestorMode,
  833. &acceptFileObject,
  834. NULL
  835. );
  836. if ( !NT_SUCCESS(status) ) {
  837. goto complete;
  838. }
  839. //
  840. // We may have a file object that is not an AFD endpoint. Make sure
  841. // that this is an actual AFD endpoint.
  842. //
  843. if (acceptFileObject->DeviceObject!= AfdDeviceObject) {
  844. status = STATUS_INVALID_HANDLE;
  845. goto complete;
  846. }
  847. acceptEndpoint = acceptFileObject->FsContext;
  848. ASSERT( InterlockedIncrement( &acceptEndpoint->ObReferenceBias ) > 0 );
  849. if (!AFD_START_STATE_CHANGE (acceptEndpoint, AfdEndpointStateConnected)) {
  850. status = STATUS_INVALID_PARAMETER;
  851. goto complete;
  852. }
  853. if (acceptEndpoint->TransportInfo!=listenEndpoint->TransportInfo ||
  854. acceptEndpoint->State != AfdEndpointStateOpen ||
  855. acceptEndpoint->SecurityDescriptor!=NULL) {
  856. status = STATUS_INVALID_PARAMETER;
  857. goto complete_state_change;
  858. }
  859. #ifndef i386
  860. acceptEndpoint->Common.VcConnecting.FixAddressAlignment = fixAddressAlignment;
  861. #endif
  862. Irp->Tail.Overlay.DriverContext[3] = acceptHandle;
  863. //
  864. // Save common IRP parameters in our stack location so
  865. // we can retreive them when necessary
  866. //
  867. IrpSp->Parameters.AfdRestartSuperAcceptInfo.AfdAcceptFileObject = acceptFileObject;
  868. IrpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength = receiveDataLength;
  869. IrpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength = localAddressLength;
  870. IrpSp->Parameters.AfdRestartSuperAcceptInfo.AfdRemoteAddressLength = remoteAddressLength;
  871. //
  872. // Add another free connection to replace the one we're accepting.
  873. // Also, add extra to account for past failures in calls to
  874. // AfdAddFreeConnection().
  875. //
  876. InterlockedIncrement(
  877. &listenEndpoint->Common.VcListening.FailedConnectionAdds
  878. );
  879. status = AfdReplenishListenBacklog( listenEndpoint );
  880. //
  881. // Save the IRP, so that accept enpoint cleanup can find it.
  882. // Note, that even if found, the cleanup won't touch the IRP
  883. // until cancel routine is set in it.
  884. //
  885. ASSERT (acceptEndpoint->Irp==NULL);
  886. acceptEndpoint->Irp = Irp;
  887. //
  888. // Get free connection from the list, if none is available,
  889. // or direct super accept is disabled, go through the regular
  890. // listen-accept path.
  891. //
  892. if (AfdDisableDirectSuperAccept ||
  893. IS_DELAYED_ACCEPTANCE_ENDPOINT (listenEndpoint) ||
  894. ExQueryDepthSList (&listenEndpoint->Common.VcListening.PreacceptedConnectionsListHead)
  895. > AFD_MAXIMUM_FREE_CONNECTIONS ||
  896. ((listEntry = InterlockedPopEntrySList (
  897. &listenEndpoint->Common.VcListening.FreeConnectionListHead
  898. ))==NULL)) {
  899. //
  900. // Setup super accept IRP to be put into the wait for
  901. // listen queue. Internal device control distinguishes this
  902. // from the regular wait for listen IRPs that come directly
  903. // from the application.
  904. //
  905. IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  906. //
  907. // Mark this IRP as pending since we are going to return
  908. // STATUS_PENDING no matter what (sometimes the actual
  909. // status is hidden very deep inside the call stack and
  910. // it is impossible to propagate it all the way up).
  911. //
  912. IoMarkIrpPending (Irp);
  913. AfdWaitForListen (Irp, IrpSp);
  914. //
  915. // If connection allocation failed above, we need to report
  916. // this to application. We delay this call in case there is
  917. // already a preaccepted connection, so the allocation failure
  918. // is not important.
  919. //
  920. if (!NT_SUCCESS (status)) {
  921. AfdReportConnectionAllocationFailure (listenEndpoint, status);
  922. }
  923. return STATUS_PENDING;
  924. }
  925. //
  926. // Get connection object of the list entry
  927. //
  928. connection = CONTAINING_RECORD(
  929. listEntry,
  930. AFD_CONNECTION,
  931. SListEntry
  932. );
  933. //
  934. // Stuff special constant into the connection object accept IRP
  935. // pointer, so that cancel routine does not complete the IRP
  936. // while we are still looking at it, but in the same time we
  937. // can detect that the IRP was cancelled (cancel routine will
  938. // replace the -1 with NULL to indicate that it has been ran).
  939. // This technique avoids extra spinlock acquire/release and
  940. // associated IRQL raise/lower on an extremely performance-sensitive
  941. // code path.
  942. //
  943. connection->AcceptIrp = (PIRP)-1;
  944. Irp->Tail.Overlay.DriverContext[0] = connection;
  945. //
  946. // We are going to pend this Irp, so mark it as pending
  947. // and set up the cancel routine.
  948. //
  949. IoMarkIrpPending (Irp);
  950. IoSetCancelRoutine( Irp, AfdCancelSuperAccept );
  951. //
  952. // Check if the IRP has already been canceled.
  953. // If the cancel routine ran, it just reset the connection
  954. // object accept pointer to NULL (instead of -1 that we stuffed
  955. // in it above), but it did not complete the IRP.
  956. //
  957. if ( !Irp->Cancel &&
  958. (InterlockedCompareExchangePointer (
  959. (PVOID *)&connection->AcceptIrp,
  960. Irp,
  961. (PVOID)-1)==(PVOID)-1)) {
  962. //
  963. // Can't touch the IRP after this point since it may have already
  964. // been canceled.
  965. //
  966. DEBUG Irp = NULL;
  967. //
  968. // Push the connection and associated Irp/endpoint
  969. // onto preaccepted connection list.
  970. //
  971. if (InterlockedPushEntrySList(
  972. &listenEndpoint->Common.VcListening.PreacceptedConnectionsListHead,
  973. &connection->SListEntry
  974. )==NULL) {
  975. //
  976. // This is the first Irp in the list, we need to check
  977. // if there are any unaccepted connections that we
  978. // can use to satisfy super accept.
  979. //
  980. AfdAcquireSpinLock (&listenEndpoint->SpinLock, &lockHandle);
  981. if (!listenEndpoint->EndpointCleanedUp) {
  982. LIST_ENTRY irpList;
  983. InitializeListHead (&irpList);
  984. //
  985. // First see if there is an unaccepted connection
  986. //
  987. while (!IsListEmpty (&listenEndpoint->Common.VcListening.UnacceptedConnectionListHead)) {
  988. connection = CONTAINING_RECORD(
  989. listenEndpoint->Common.VcListening.UnacceptedConnectionListHead.Flink,
  990. AFD_CONNECTION,
  991. ListEntry
  992. );
  993. RemoveEntryList (&connection->ListEntry);
  994. //
  995. // Now make sure we still have super accept irp
  996. //
  997. if (AfdServiceSuperAccept (listenEndpoint, connection, &lockHandle, &irpList)) {
  998. //
  999. // The routine has found and completed super accept IRP
  1000. // Reaquire a spinlock and continue searching for more.
  1001. //
  1002. AfdAcquireSpinLock (&listenEndpoint->SpinLock, &lockHandle);
  1003. }
  1004. else {
  1005. //
  1006. // No super accept Irps, put connection back onto the list
  1007. // while we are still holding the lock and bail out.
  1008. //
  1009. InsertHeadList (&listenEndpoint->Common.VcListening.UnacceptedConnectionListHead,
  1010. &connection->ListEntry);
  1011. break;
  1012. }
  1013. }
  1014. AfdReleaseSpinLock (&listenEndpoint->SpinLock, &lockHandle);
  1015. //
  1016. // Complete failed super accept IRPs (if any)
  1017. //
  1018. if (!IsListEmpty (&irpList)) {
  1019. KIRQL cancelIrql;
  1020. //
  1021. // Make sure cancel routines will
  1022. // not access the completed IRPs
  1023. //
  1024. IoAcquireCancelSpinLock (&cancelIrql);
  1025. IoReleaseCancelSpinLock (cancelIrql);
  1026. while (!IsListEmpty (&irpList)) {
  1027. PIRP irp;
  1028. irp = CONTAINING_RECORD (irpList.Flink, IRP, Tail.Overlay.ListEntry);
  1029. RemoveEntryList (&irp->Tail.Overlay.ListEntry);
  1030. IoCompleteRequest (irp, AfdPriorityBoost);
  1031. }
  1032. }
  1033. }
  1034. else {
  1035. AfdReleaseSpinLock (&listenEndpoint->SpinLock, &lockHandle);
  1036. AfdFreeQueuedConnections (listenEndpoint);
  1037. }
  1038. }
  1039. else {
  1040. USHORT depth =
  1041. ExQueryDepthSList (&listenEndpoint->Common.VcListening.PreacceptedConnectionsListHead);
  1042. if (depth > listenEndpoint->Common.VcListening.MaxExtraConnections) {
  1043. //
  1044. // Update under the lock, so we do not corrupt
  1045. // other fields in the same memory access granularity unit.
  1046. // This should be infrequent operation anyway.
  1047. //
  1048. AfdAcquireSpinLock (&listenEndpoint->SpinLock, &lockHandle);
  1049. listenEndpoint->Common.VcListening.MaxExtraConnections = depth;
  1050. AfdReleaseSpinLock (&listenEndpoint->SpinLock, &lockHandle);
  1051. }
  1052. }
  1053. }
  1054. else {
  1055. //
  1056. // Reset and call the cancel routine, since
  1057. // even if cancel routine ran, it could not complete
  1058. // the irp because it was not set in the connection
  1059. // object. Note that cancel routine is done with the IRP
  1060. // once it releases cancel spinlock which we acquire here.
  1061. //
  1062. AfdCleanupSuperAccept (Irp, STATUS_CANCELLED);
  1063. if (IoSetCancelRoutine (Irp, NULL)==NULL) {
  1064. KIRQL cancelIrql;
  1065. IoAcquireCancelSpinLock (&cancelIrql);
  1066. IoReleaseCancelSpinLock (cancelIrql);
  1067. }
  1068. IoCompleteRequest (Irp, AfdPriorityBoost);
  1069. //
  1070. // We have to return pending because we have already
  1071. // marked the Irp as pending.
  1072. //
  1073. }
  1074. return STATUS_PENDING;
  1075. complete_state_change:
  1076. AFD_END_STATE_CHANGE (acceptEndpoint);
  1077. complete:
  1078. if ( acceptFileObject != NULL ) {
  1079. if (acceptEndpoint!=NULL) {
  1080. ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
  1081. }
  1082. ObDereferenceObject( acceptFileObject );
  1083. }
  1084. //
  1085. // Free MDL here as IO system can't do it if it is
  1086. // not locked.
  1087. //
  1088. if (Irp->MdlAddress!=NULL) {
  1089. if (Irp->MdlAddress->MdlFlags & MDL_PAGES_LOCKED) {
  1090. MmUnlockPages (Irp->MdlAddress);
  1091. }
  1092. IoFreeMdl (Irp->MdlAddress);
  1093. Irp->MdlAddress = NULL;
  1094. }
  1095. Irp->IoStatus.Information = 0;
  1096. Irp->IoStatus.Status = status;
  1097. IoCompleteRequest( Irp, 0 );
  1098. return status;
  1099. } // AfdSuperAccept
  1100. NTSTATUS
  1101. AfdRestartSuperAccept (
  1102. IN PDEVICE_OBJECT DeviceObject,
  1103. IN PIRP Irp,
  1104. IN PVOID Context
  1105. )
  1106. /*++
  1107. Routine Description:
  1108. The completion routine for the AFD wait for listen IRP portion
  1109. of a super accept.
  1110. Arguments:
  1111. DeviceObject - the devoce object on which the request is completing.
  1112. Irp - The super accept IRP.
  1113. Context - points to accept file object.
  1114. Return Value:
  1115. STATUS_SUCCESS if the I/O system should complete the super accept
  1116. request, or STATUS_MORE_PROCESSING_REQUIRED if the super accept
  1117. request is still being processed.
  1118. --*/
  1119. {
  1120. PAFD_ENDPOINT listenEndpoint;
  1121. PFILE_OBJECT acceptFileObject;
  1122. PAFD_ENDPOINT acceptEndpoint;
  1123. PAFD_CONNECTION connection;
  1124. PIO_STACK_LOCATION irpSp;
  1125. AFD_LOCK_QUEUE_HANDLE lockHandle;
  1126. UNREFERENCED_PARAMETER (DeviceObject);
  1127. //
  1128. // Initialize some locals.
  1129. //
  1130. irpSp = IoGetCurrentIrpStackLocation( Irp );
  1131. listenEndpoint = irpSp->FileObject->FsContext;
  1132. acceptFileObject = Context;
  1133. acceptEndpoint = acceptFileObject->FsContext;
  1134. ASSERT (IS_AFD_ENDPOINT_TYPE (acceptEndpoint));
  1135. connection = acceptEndpoint->Common.VcConnecting.Connection;
  1136. ASSERT (connection->Type==AfdBlockTypeConnection);
  1137. ASSERT (connection->Endpoint==acceptEndpoint);
  1138. //
  1139. // Overwrite listen file object with accept file object
  1140. // since we won't be using listen file object anymore,
  1141. // while we still need to deference accept file object
  1142. // upon IRP completion.
  1143. //
  1144. irpSp->FileObject = acceptFileObject;
  1145. //
  1146. // Fix up the MDL pointer in the IRP.
  1147. //
  1148. ASSERT (Irp->MdlAddress==NULL);
  1149. Irp->MdlAddress = irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdMdlAddress;
  1150. //
  1151. // If pending has been returned for this irp then mark the current
  1152. // stack as pending.
  1153. //
  1154. if ( Irp->PendingReturned ) {
  1155. IoMarkIrpPending( Irp );
  1156. }
  1157. //
  1158. // Remember that a TDI accept has completed on this endpoint.
  1159. //
  1160. InterlockedDecrement(
  1161. &listenEndpoint->Common.VcListening.TdiAcceptPendingCount
  1162. );
  1163. connection->ConnectTime = KeQueryInterruptTime();
  1164. if ( NT_SUCCESS(Irp->IoStatus.Status)) {
  1165. //
  1166. // Set the endpoint to the connected state.
  1167. //
  1168. AfdAcquireSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
  1169. acceptEndpoint->State = AfdEndpointStateConnected;
  1170. connection->State = AfdConnectionStateConnected;
  1171. acceptEndpoint->EventsActive |= AFD_POLL_SEND;
  1172. //
  1173. // Remove the TDI accept IRP reference to the connection.
  1174. // Combine with reference below to optimize.
  1175. //
  1176. // DEREFERENCE_CONNECTION( connection );
  1177. //
  1178. // Reference connection to prevent it from going away during
  1179. // accept process as the result of transmit file completion.
  1180. // (transmit file can now occur at any time since we
  1181. // marked the endpoint as connected and about to end state change)
  1182. //
  1183. // REFERENCE_CONNECTION (connection);
  1184. AfdReleaseSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
  1185. AFD_END_STATE_CHANGE(acceptEndpoint);
  1186. return AfdContinueSuperAccept (Irp, connection);
  1187. }
  1188. else {
  1189. //
  1190. // If the accept failed, treat it like an abortive disconnect.
  1191. // This way the application still gets a new endpoint, but it gets
  1192. // told about the reset.
  1193. //
  1194. AFD_END_STATE_CHANGE(acceptEndpoint);
  1195. AfdDisconnectEventHandler(
  1196. NULL,
  1197. connection,
  1198. 0,
  1199. NULL,
  1200. 0,
  1201. NULL,
  1202. TDI_DISCONNECT_ABORT
  1203. );
  1204. ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
  1205. ObDereferenceObject( acceptFileObject );
  1206. //
  1207. // Check if we have secondary MDL for local address query and
  1208. // free it.
  1209. //
  1210. if (Irp->MdlAddress->Next!=NULL) {
  1211. //
  1212. // We never lock pages for this one (they are locked
  1213. // as part of main MDL).
  1214. //
  1215. ASSERT (irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength>0);
  1216. ASSERT ((Irp->MdlAddress->Next->MdlFlags & MDL_PAGES_LOCKED)==0);
  1217. IoFreeMdl (Irp->MdlAddress->Next);
  1218. Irp->MdlAddress->Next = NULL;
  1219. }
  1220. //
  1221. // Remove the TDI accept IRP reference to the connection.
  1222. //
  1223. DEREFERENCE_CONNECTION( connection );
  1224. return STATUS_SUCCESS;
  1225. }
  1226. } // AfdRestartSuperAccept
  1227. VOID
  1228. AfdRestartSuperAcceptListen (
  1229. IN PIRP Irp,
  1230. IN PAFD_CONNECTION Connection
  1231. )
  1232. /*++
  1233. Routine Description:
  1234. The completion routine for the AFD wait for listen IRP portion
  1235. of a super accept.
  1236. Arguments:
  1237. Irp - The super accept IRP.
  1238. Connection - points to the connection object
  1239. Return Value:
  1240. None
  1241. --*/
  1242. {
  1243. PAFD_ENDPOINT acceptEndpoint;
  1244. PIO_STACK_LOCATION irpSp;
  1245. NTSTATUS status;
  1246. //
  1247. // Initialize some locals.
  1248. //
  1249. irpSp = IoGetCurrentIrpStackLocation( Irp );
  1250. acceptEndpoint = irpSp->FileObject->FsContext;
  1251. ASSERT (IS_AFD_ENDPOINT_TYPE (acceptEndpoint));
  1252. AFD_END_STATE_CHANGE(acceptEndpoint);
  1253. //
  1254. // Fix up the system buffer and MDL pointers in the IRP.
  1255. //
  1256. ASSERT (Irp->MdlAddress==NULL);
  1257. ASSERT (Irp->AssociatedIrp.SystemBuffer == NULL);
  1258. Irp->MdlAddress = irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdMdlAddress;
  1259. //
  1260. // This routine shouldn't have been called if accept failed
  1261. //
  1262. ASSERT ( NT_SUCCESS(Irp->IoStatus.Status) );
  1263. //
  1264. // Reference connection to prevent it from going away during
  1265. // accept process as the result of transmit file completion.
  1266. // (transmit file can now occur at any time since we
  1267. // marked the endpoint as connected and about to end state change)
  1268. //
  1269. REFERENCE_CONNECTION (Connection);
  1270. status = AfdContinueSuperAccept (Irp, Connection);
  1271. //
  1272. // If completion routine return anything other
  1273. // than STATUS_MORE_PROCESSING_REQUIRED, the IRP
  1274. // is ready to be completed. Otherwise, is was
  1275. // reused to call transport driver and will be completed
  1276. // by the driver. Note that in the latter case
  1277. // the IRP cannot be touched because
  1278. // it could have been completed inside of the
  1279. // completion routine or by the driver before the
  1280. // completion routine returned.
  1281. //
  1282. if (status!=STATUS_MORE_PROCESSING_REQUIRED) {
  1283. IoCompleteRequest (Irp, AfdPriorityBoost);
  1284. }
  1285. } // AfdRestartSuperAcceptListen
  1286. NTSTATUS
  1287. AfdRestartDelayedSuperAccept (
  1288. IN PDEVICE_OBJECT DeviceObject,
  1289. IN PIRP Irp,
  1290. IN PVOID Context
  1291. )
  1292. /*++
  1293. Routine Description:
  1294. The completion routine for the AFD wait for delayed accept IRP portion
  1295. of a super accept.
  1296. Arguments:
  1297. DeviceObject - the devoce object on which the request is completing.
  1298. Irp - The super accept IRP.
  1299. Context - points to accept file object
  1300. Return Value:
  1301. STATUS_SUCCESS if the I/O system should complete the super accept
  1302. request, or STATUS_MORE_PROCESSING_REQUIRED if the super accept
  1303. request is still being processed.
  1304. --*/
  1305. {
  1306. PAFD_ENDPOINT listenEndpoint;
  1307. PFILE_OBJECT acceptFileObject;
  1308. PAFD_ENDPOINT acceptEndpoint;
  1309. PAFD_CONNECTION connection;
  1310. PIO_STACK_LOCATION irpSp;
  1311. AFD_LOCK_QUEUE_HANDLE lockHandle;
  1312. UNREFERENCED_PARAMETER (DeviceObject);
  1313. //
  1314. // Initialize some locals.
  1315. //
  1316. irpSp = IoGetCurrentIrpStackLocation( Irp );
  1317. listenEndpoint = irpSp->FileObject->FsContext;
  1318. acceptFileObject = Context;
  1319. acceptEndpoint = acceptFileObject->FsContext;
  1320. ASSERT (IS_AFD_ENDPOINT_TYPE (acceptEndpoint));
  1321. //
  1322. // Overwrite listen file object with accept file object
  1323. // since we won't be using listen file object anymore,
  1324. // while we still need to deference accept file object
  1325. // upon IRP completion.
  1326. //
  1327. irpSp->FileObject = acceptFileObject;
  1328. //
  1329. // Fix up the MDL pointer in the IRP.
  1330. //
  1331. ASSERT (Irp->MdlAddress==NULL);
  1332. Irp->MdlAddress = irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdMdlAddress;
  1333. AfdCompleteOutstandingIrp (acceptEndpoint, Irp);
  1334. //
  1335. // If pending has been returned for this irp then mark the current
  1336. // stack as pending.
  1337. //
  1338. if ( Irp->PendingReturned ) {
  1339. IoMarkIrpPending( Irp );
  1340. }
  1341. //
  1342. // Remember that a TDI accept has completed on this endpoint.
  1343. //
  1344. InterlockedDecrement(
  1345. &listenEndpoint->Common.VcListening.TdiAcceptPendingCount
  1346. );
  1347. AfdAcquireSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
  1348. //
  1349. // The AFD connection object should now be in the endpoiont.
  1350. //
  1351. connection = AFD_CONNECTION_FROM_ENDPOINT( acceptEndpoint );
  1352. if (connection!=NULL) {
  1353. //
  1354. // If the IRP failed, quit processing.
  1355. //
  1356. if ( NT_SUCCESS(Irp->IoStatus.Status) ) {
  1357. acceptEndpoint->State = AfdEndpointStateConnected;
  1358. connection->State = AfdConnectionStateConnected;
  1359. acceptEndpoint->EventsActive |= AFD_POLL_SEND;
  1360. //
  1361. // Reference connection to prevent it from going away during
  1362. // accept process as the result of transmit file completion.
  1363. // (transmit file can now occur at any time since we
  1364. // marked the endpoint as connected and about to end state change)
  1365. //
  1366. REFERENCE_CONNECTION (connection);
  1367. AfdReleaseSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
  1368. AFD_END_STATE_CHANGE(acceptEndpoint);
  1369. return AfdContinueSuperAccept (Irp, connection);
  1370. }
  1371. else {
  1372. //
  1373. // If the accept failed, treat it like an abortive disconnect.
  1374. // This way the application still gets a new endpoint, but it gets
  1375. // told about the reset.
  1376. //
  1377. AfdReleaseSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
  1378. AFD_END_STATE_CHANGE(acceptEndpoint);
  1379. AfdDisconnectEventHandler(
  1380. NULL,
  1381. connection,
  1382. 0,
  1383. NULL,
  1384. 0,
  1385. NULL,
  1386. TDI_DISCONNECT_ABORT
  1387. );
  1388. ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
  1389. ObDereferenceObject( acceptFileObject );
  1390. //
  1391. // After dereferencing file object we shouldn't be accessing it
  1392. // or associated endpoint structure
  1393. //
  1394. }
  1395. }
  1396. else {
  1397. // this could happed if transmit file cleaned up the object
  1398. // really quickly somehow,
  1399. AfdReleaseSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
  1400. ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
  1401. ObDereferenceObject( acceptFileObject );
  1402. //
  1403. // After dereferencing file object we shouldn't be accessing it
  1404. // or associated endpoint structure
  1405. //
  1406. }
  1407. //
  1408. // Check if we have secondary MDL for local address query and
  1409. // free it.
  1410. //
  1411. if (Irp->MdlAddress->Next!=NULL) {
  1412. //
  1413. // We never lock pages for this one (they are locked
  1414. // as part of main MDL).
  1415. //
  1416. ASSERT (irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength>0);
  1417. ASSERT ((Irp->MdlAddress->Next->MdlFlags & MDL_PAGES_LOCKED)==0);
  1418. IoFreeMdl (Irp->MdlAddress->Next);
  1419. Irp->MdlAddress->Next = NULL;
  1420. }
  1421. return STATUS_SUCCESS;
  1422. } // AfdRestartDelayedSuperAccept
  1423. NTSTATUS
  1424. AfdContinueSuperAccept (
  1425. IN PIRP Irp,
  1426. PAFD_CONNECTION Connection
  1427. )
  1428. /*++
  1429. Routine Description:
  1430. Continues super accept IRP processing after the initial accept
  1431. phase by requesting local address and/or first portion of the
  1432. received data.
  1433. Arguments:
  1434. Irp - a pointer to the super accept IRP
  1435. Connection - pointer to the accepted connection
  1436. Return Value:
  1437. STATUS_SUCCESS if Irp processing is completed
  1438. STATUS_MORE_PROCESSING_REQUIRED if it submits another request
  1439. and processing will ocurr in the completion routine.
  1440. --*/
  1441. {
  1442. PAFD_ENDPOINT acceptEndpoint;
  1443. PIO_STACK_LOCATION irpSp;
  1444. ULONG length;
  1445. //
  1446. // Initialize locals
  1447. //
  1448. irpSp = IoGetCurrentIrpStackLocation (Irp);
  1449. acceptEndpoint = irpSp->FileObject->FsContext;
  1450. //
  1451. // See if we need to get local address.
  1452. //
  1453. if (irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength>0) {
  1454. ASSERT (Irp->MdlAddress->Next!=NULL);
  1455. //
  1456. // Get the MDL that describes local address part of the user buffer
  1457. // The oritinal mdl chain address is safe in our stack location
  1458. //
  1459. Irp->MdlAddress = Irp->MdlAddress->Next;
  1460. //
  1461. // Unchain the address MDL from the receive MDL - we will
  1462. // free it upon completion of the address query operation
  1463. //
  1464. ((PMDL)irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdMdlAddress)->Next = NULL;
  1465. ASSERT (irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength
  1466. == MmGetMdlByteCount (Irp->MdlAddress));
  1467. IoBuildPartialMdl (
  1468. irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdMdlAddress,
  1469. Irp->MdlAddress,
  1470. MmGetMdlVirtualAddress (Irp->MdlAddress),
  1471. MmGetMdlByteCount (Irp->MdlAddress)
  1472. );
  1473. TdiBuildQueryInformation(
  1474. Irp,
  1475. Connection->DeviceObject,
  1476. Connection->FileObject,
  1477. AfdRestartSuperAcceptGetAddress,
  1478. Connection,
  1479. TDI_QUERY_ADDRESS_INFO,
  1480. Irp->MdlAddress
  1481. );
  1482. //
  1483. // Perform the local address query. We'll continue processing from
  1484. // the completion routine.
  1485. //
  1486. AfdIoCallDriver( acceptEndpoint, Connection->DeviceObject, Irp );
  1487. return STATUS_MORE_PROCESSING_REQUIRED;
  1488. }
  1489. //
  1490. // See if want to get first portion of the data
  1491. //
  1492. else if (irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength>0) {
  1493. PIO_STACK_LOCATION nextIrpSp;
  1494. ASSERT (Irp->MdlAddress->Next==NULL);
  1495. //
  1496. // Get the length of the receive portion of the buffer
  1497. // and save the length of the MDL to restore in the completion routine
  1498. // Set the length of the MDL to match that of the receive request
  1499. //
  1500. length = irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength;
  1501. irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength =
  1502. MmGetMdlByteCount (Irp->MdlAddress);
  1503. Irp->MdlAddress->ByteCount = length;
  1504. //
  1505. // Prepare the IRP to be used to receive the first chunk of data on
  1506. // the connection.
  1507. //
  1508. // Also note that we send ourselves an IRP_MJ_READ IRP because
  1509. // the I/O subsystem has already probed & locked the output buffer,
  1510. // which just happens to look just like an IRP_MJ_READ IRP.
  1511. //
  1512. nextIrpSp = IoGetNextIrpStackLocation( Irp );
  1513. nextIrpSp->FileObject = irpSp->FileObject;
  1514. nextIrpSp->DeviceObject = IoGetRelatedDeviceObject( nextIrpSp->FileObject );
  1515. nextIrpSp->MajorFunction = IRP_MJ_READ;
  1516. nextIrpSp->Parameters.Read.Length = length;
  1517. nextIrpSp->Parameters.Read.Key = 0;
  1518. nextIrpSp->Parameters.Read.ByteOffset.QuadPart = 0;
  1519. IoSetCompletionRoutine(
  1520. Irp,
  1521. AfdRestartSuperAcceptReceive,
  1522. Connection,
  1523. TRUE,
  1524. TRUE,
  1525. TRUE
  1526. );
  1527. //
  1528. // Perform the receive. We'll continue processing from
  1529. // the completion routine.
  1530. //
  1531. AfdIoCallDriver( acceptEndpoint, nextIrpSp->DeviceObject, Irp );
  1532. return STATUS_MORE_PROCESSING_REQUIRED;
  1533. }
  1534. Irp->IoStatus.Information = 0;
  1535. if (Connection->Aborted && NT_SUCCESS (Irp->IoStatus.Status)) {
  1536. Irp->IoStatus.Status = STATUS_CONNECTION_RESET;
  1537. }
  1538. if (NT_SUCCESS (Irp->IoStatus.Status) &&
  1539. (Connection->RemoteAddress!=NULL) &&
  1540. (KeInitializeApc (&acceptEndpoint->Common.VcConnecting.Apc,
  1541. PsGetThreadTcb (Irp->Tail.Overlay.Thread),
  1542. Irp->ApcEnvironment,
  1543. AfdSuperAcceptApcKernelRoutine,
  1544. AfdSuperAcceptApcRundownRoutine,
  1545. (PKNORMAL_ROUTINE)NULL,
  1546. KernelMode,
  1547. NULL
  1548. ),
  1549. KeInsertQueueApc (&acceptEndpoint->Common.VcConnecting.Apc,
  1550. Irp,
  1551. Connection,
  1552. AfdPriorityBoost))) {
  1553. return STATUS_MORE_PROCESSING_REQUIRED;
  1554. }
  1555. else {
  1556. //
  1557. // Dereference the accept file object and tell IO to complete this IRP.
  1558. //
  1559. ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
  1560. ObDereferenceObject( irpSp->FileObject );
  1561. //
  1562. // After dereferencing file object we shouldn't be accessing it
  1563. // or associated endpoint structure
  1564. //
  1565. DEREFERENCE_CONNECTION (Connection);
  1566. return STATUS_SUCCESS;
  1567. }
  1568. }
  1569. NTSTATUS
  1570. AfdRestartSuperAcceptGetAddress (
  1571. IN PDEVICE_OBJECT DeviceObject,
  1572. IN PIRP Irp,
  1573. IN PVOID Context
  1574. )
  1575. /*++
  1576. Routine Description:
  1577. The completion routine for the AFD wait for query local address
  1578. portion of a super accept.
  1579. Arguments:
  1580. DeviceObject - the devoce object on which the request is completing.
  1581. Irp - The super accept IRP.
  1582. Context - points to the accepted connection
  1583. Return Value:
  1584. STATUS_SUCCESS if the I/O system should complete the super accept
  1585. request, or STATUS_MORE_PROCESSING_REQUIRED if the super accept
  1586. request is still being processed.
  1587. --*/
  1588. {
  1589. PAFD_ENDPOINT acceptEndpoint;
  1590. PAFD_CONNECTION connection;
  1591. PIO_STACK_LOCATION irpSp;
  1592. UNREFERENCED_PARAMETER (DeviceObject);
  1593. //
  1594. // Initialize some locals.
  1595. //
  1596. irpSp = IoGetCurrentIrpStackLocation (Irp);
  1597. acceptEndpoint = irpSp->FileObject->FsContext;
  1598. ASSERT (IS_AFD_ENDPOINT_TYPE (acceptEndpoint));
  1599. connection = Context;
  1600. ASSERT (connection->Type==AfdBlockTypeConnection);
  1601. ASSERT (connection->Endpoint==acceptEndpoint);
  1602. AfdCompleteOutstandingIrp (acceptEndpoint, Irp);
  1603. //
  1604. // If pending has been returned for this irp then mark the current
  1605. // stack as pending.
  1606. //
  1607. if ( Irp->PendingReturned ) {
  1608. IoMarkIrpPending( Irp );
  1609. }
  1610. ASSERT (Irp->MdlAddress->MdlFlags & MDL_PARTIAL);
  1611. IoFreeMdl( Irp->MdlAddress );
  1612. //
  1613. // Fix up the MDL pointer in the IRP and set local address length
  1614. // to 0 to use the common routine for receive part of the super
  1615. // accept Irp
  1616. //
  1617. Irp->MdlAddress = irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdMdlAddress;
  1618. if (NT_SUCCESS (Irp->IoStatus.Status)) {
  1619. #ifndef i386
  1620. if (acceptEndpoint->Common.VcConnecting.FixAddressAlignment) {
  1621. PTDI_ADDRESS_INFO addressInfo = (PVOID)
  1622. ((PUCHAR)MmGetSystemAddressForMdl(Irp->MdlAddress)
  1623. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength);
  1624. USHORT addressLength = addressInfo->Address.Address[0].AddressLength+sizeof(USHORT);
  1625. USHORT UNALIGNED *pAddrLength = (PVOID)
  1626. ((PUCHAR)addressInfo
  1627. +irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength
  1628. -sizeof(USHORT));
  1629. RtlMoveMemory (addressInfo,
  1630. &addressInfo->Address.Address[0].AddressType,
  1631. addressLength);
  1632. *pAddrLength = addressLength;
  1633. }
  1634. #endif // ifndef i386
  1635. irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength = 0;
  1636. return AfdContinueSuperAccept (Irp, connection);
  1637. }
  1638. else {
  1639. //
  1640. // Dereference the accept file object and tell IO to complete this IRP.
  1641. //
  1642. ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
  1643. ObDereferenceObject( irpSp->FileObject );
  1644. //
  1645. // After dereferencing file object we shouldn't be accessing it
  1646. // or associated endpoint structure
  1647. //
  1648. DEREFERENCE_CONNECTION (connection);
  1649. return STATUS_SUCCESS;
  1650. }
  1651. } // AfdRestartSuperAcceptGetAddress
  1652. NTSTATUS
  1653. AfdRestartSuperAcceptReceive (
  1654. IN PDEVICE_OBJECT DeviceObject,
  1655. IN PIRP Irp,
  1656. IN PVOID Context
  1657. )
  1658. /*++
  1659. Routine Description:
  1660. The completion routine for the AFD receive portion of a super accept.
  1661. Arguments:
  1662. DeviceObject - the devoce object on which the request is completing.
  1663. Irp - The super accept IRP.
  1664. Context - points to the accepted connection
  1665. Return Value:
  1666. STATUS_SUCCESS if the I/O system should complete the super accept
  1667. request, or STATUS_MORE_PROCESSING_REQUIRED if the super accept
  1668. request is still being processed.
  1669. --*/
  1670. {
  1671. PAFD_ENDPOINT acceptEndpoint;
  1672. PAFD_CONNECTION connection;
  1673. PIO_STACK_LOCATION irpSp;
  1674. UNREFERENCED_PARAMETER (DeviceObject);
  1675. //
  1676. // Initialize some locals.
  1677. //
  1678. irpSp = IoGetCurrentIrpStackLocation (Irp);
  1679. acceptEndpoint = irpSp->FileObject->FsContext;
  1680. ASSERT (IS_AFD_ENDPOINT_TYPE (acceptEndpoint));
  1681. connection = Context;
  1682. ASSERT (connection->Type == AfdBlockTypeConnection);
  1683. ASSERT (connection->Endpoint==acceptEndpoint);
  1684. AfdCompleteOutstandingIrp (acceptEndpoint, Irp);
  1685. //
  1686. // Restore MDL length so that IO system can properly unmap
  1687. // and unlock it when it completes the IRP
  1688. //
  1689. ASSERT (Irp->MdlAddress!=NULL);
  1690. ASSERT (Irp->MdlAddress->Next==NULL);
  1691. Irp->MdlAddress->ByteCount =
  1692. irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength;
  1693. //
  1694. // If pending has been returned for this irp then mark the current
  1695. // stack as pending.
  1696. //
  1697. if ( Irp->PendingReturned ) {
  1698. IoMarkIrpPending( Irp );
  1699. }
  1700. if (NT_SUCCESS (Irp->IoStatus.Status) &&
  1701. (connection->RemoteAddress!=NULL) &&
  1702. (KeInitializeApc (&acceptEndpoint->Common.VcConnecting.Apc,
  1703. PsGetThreadTcb (Irp->Tail.Overlay.Thread),
  1704. Irp->ApcEnvironment,
  1705. AfdSuperAcceptApcKernelRoutine,
  1706. AfdSuperAcceptApcRundownRoutine,
  1707. (PKNORMAL_ROUTINE)NULL,
  1708. KernelMode,
  1709. NULL
  1710. ),
  1711. KeInsertQueueApc (&acceptEndpoint->Common.VcConnecting.Apc,
  1712. Irp,
  1713. connection,
  1714. AfdPriorityBoost))) {
  1715. return STATUS_MORE_PROCESSING_REQUIRED;
  1716. }
  1717. else {
  1718. //
  1719. // Dereference the accept file object and tell IO to complete this IRP.
  1720. //
  1721. ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
  1722. ObDereferenceObject( irpSp->FileObject );
  1723. //
  1724. // After dereferencing file object we shouldn't be accessing it
  1725. // or associated endpoint structure
  1726. //
  1727. DEREFERENCE_CONNECTION (connection);
  1728. return STATUS_SUCCESS;
  1729. }
  1730. } // AfdRestartSuperAcceptReceive
  1731. VOID
  1732. AfdSuperAcceptApcKernelRoutine (
  1733. IN struct _KAPC *Apc,
  1734. IN OUT PKNORMAL_ROUTINE *NormalRoutine,
  1735. IN OUT PVOID *NormalContext,
  1736. IN OUT PVOID *SystemArgument1,
  1737. IN OUT PVOID *SystemArgument2
  1738. )
  1739. {
  1740. PIRP irp;
  1741. PIO_STACK_LOCATION irpSp;
  1742. PAFD_ENDPOINT endpoint;
  1743. PAFD_CONNECTION connection;
  1744. PVOID context;
  1745. PAGED_CODE ();
  1746. UNREFERENCED_PARAMETER (NormalContext);
  1747. #if DBG
  1748. try {
  1749. ASSERT (*NormalRoutine == NULL);
  1750. #else
  1751. UNREFERENCED_PARAMETER (NormalRoutine);
  1752. #endif
  1753. endpoint = CONTAINING_RECORD (Apc, AFD_ENDPOINT, Common.VcConnecting.Apc);
  1754. ASSERT (IS_AFD_ENDPOINT_TYPE (endpoint));
  1755. irp = *SystemArgument1;
  1756. irpSp = IoGetCurrentIrpStackLocation( irp );
  1757. ASSERT (irpSp->FileObject->FsContext==endpoint);
  1758. connection = *SystemArgument2;
  1759. ASSERT( connection->Type == AfdBlockTypeConnection );
  1760. ASSERT (connection->Endpoint==endpoint);
  1761. //
  1762. // Copy remote address to the user mode context
  1763. //
  1764. context = AfdLockEndpointContext (endpoint);
  1765. if ( (((CLONG)(endpoint->Common.VcConnecting.RemoteSocketAddressOffset+
  1766. endpoint->Common.VcConnecting.RemoteSocketAddressLength)) <
  1767. endpoint->ContextLength) &&
  1768. (endpoint->Common.VcConnecting.RemoteSocketAddressLength >=
  1769. connection->RemoteAddress->Address[0].AddressLength +
  1770. sizeof(u_short))) {
  1771. RtlMoveMemory ((PUCHAR)context +
  1772. endpoint->Common.VcConnecting.RemoteSocketAddressOffset,
  1773. &connection->RemoteAddress->Address[0].AddressType,
  1774. connection->RemoteAddress->Address[0].AddressLength +
  1775. sizeof(u_short));
  1776. }
  1777. else {
  1778. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_WARNING_LEVEL,
  1779. "AfdSuperAcceptApcKernelRoutine: Could not copy remote address for AcceptEx on endpoint: %p, process: %p\n",
  1780. endpoint, endpoint->OwningProcess));
  1781. }
  1782. AfdUnlockEndpointContext (endpoint, context);
  1783. AFD_RETURN_REMOTE_ADDRESS (
  1784. connection->RemoteAddress,
  1785. connection->RemoteAddressLength
  1786. );
  1787. connection->RemoteAddress = NULL;
  1788. //
  1789. // Dereference the accept file object and tell IO to complete this IRP.
  1790. //
  1791. ASSERT( InterlockedDecrement( &endpoint->ObReferenceBias ) >= 0 );
  1792. ObDereferenceObject( irpSp->FileObject );
  1793. //
  1794. // After dereferencing file object we shouldn't be accessing it
  1795. // or associated endpoint structure
  1796. //
  1797. DEREFERENCE_CONNECTION (connection);
  1798. IoCompleteRequest (irp, AfdPriorityBoost);
  1799. #if DBG
  1800. }
  1801. except (AfdApcExceptionFilter (
  1802. GetExceptionInformation(),
  1803. (LPSTR)__FILE__,
  1804. (LONG)__LINE__)) {
  1805. DbgBreakPoint ();
  1806. }
  1807. #endif
  1808. }
  1809. VOID
  1810. AfdSuperAcceptApcRundownRoutine (
  1811. IN struct _KAPC *Apc
  1812. )
  1813. {
  1814. PIRP irp;
  1815. PIO_STACK_LOCATION irpSp;
  1816. PAFD_ENDPOINT endpoint;
  1817. PAFD_CONNECTION connection;
  1818. PAGED_CODE ();
  1819. endpoint = CONTAINING_RECORD (Apc, AFD_ENDPOINT, Common.VcConnecting.Apc);
  1820. ASSERT (IS_AFD_ENDPOINT_TYPE (endpoint));
  1821. irp = Apc->SystemArgument1;
  1822. irpSp = IoGetCurrentIrpStackLocation( irp );
  1823. ASSERT (irpSp->FileObject->FsContext==endpoint);
  1824. connection = Apc->SystemArgument2;
  1825. ASSERT( connection->Type == AfdBlockTypeConnection );
  1826. ASSERT (connection->Endpoint==endpoint);
  1827. //
  1828. // Dereference the accept file object and tell IO to complete this IRP.
  1829. //
  1830. ASSERT( InterlockedDecrement( &endpoint->ObReferenceBias ) >= 0 );
  1831. ObDereferenceObject( irpSp->FileObject );
  1832. //
  1833. // After dereferencing file object we shouldn't be accessing it
  1834. // or associated endpoint structure
  1835. //
  1836. DEREFERENCE_CONNECTION (connection);
  1837. IoCompleteRequest (irp, AfdPriorityBoost);
  1838. }
  1839. NTSTATUS
  1840. FASTCALL
  1841. AfdDeferAccept (
  1842. IN PIRP Irp,
  1843. IN PIO_STACK_LOCATION IrpSp
  1844. )
  1845. /*++
  1846. Routine Description:
  1847. Defers acceptance of an incoming connection for which an
  1848. AFD_WAIT_FOR_LISTEN IOCTL has already completed. The caller
  1849. may specify that the connection be deferred for later acceptance
  1850. or rejected totally.
  1851. Arguments:
  1852. Irp - a pointer to a transmit file IRP.
  1853. IrpSp - Our stack location for this IRP.
  1854. Return Value:
  1855. STATUS_SUCCESS if the request was completed successfully, or a
  1856. failure status code if there was an error.
  1857. --*/
  1858. {
  1859. NTSTATUS status;
  1860. PAFD_DEFER_ACCEPT_INFO deferAcceptInfo;
  1861. PAFD_ENDPOINT endpoint;
  1862. PAFD_CONNECTION connection;
  1863. AFD_LOCK_QUEUE_HANDLE lockHandle;
  1864. //
  1865. // Set up local variables.
  1866. //
  1867. endpoint = IrpSp->FileObject->FsContext;
  1868. deferAcceptInfo = Irp->AssociatedIrp.SystemBuffer;
  1869. Irp->IoStatus.Information = 0;
  1870. //
  1871. // Make sure that this request is valid.
  1872. //
  1873. if( !endpoint->Listening ||
  1874. IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  1875. sizeof(AFD_DEFER_ACCEPT_INFO) ) {
  1876. status = STATUS_INVALID_PARAMETER;
  1877. goto complete;
  1878. }
  1879. ASSERT ((endpoint->Type & AfdBlockTypeVcListening) == AfdBlockTypeVcListening);
  1880. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  1881. //
  1882. // Find the specified connection. If it cannot be found, then this
  1883. // is a bogus request.
  1884. //
  1885. connection = AfdGetReturnedConnection(
  1886. endpoint,
  1887. deferAcceptInfo->Sequence
  1888. );
  1889. if( connection == NULL ) {
  1890. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  1891. status = STATUS_INVALID_PARAMETER;
  1892. goto complete;
  1893. }
  1894. ASSERT( connection->Type == AfdBlockTypeConnection );
  1895. //
  1896. // If this is a request to reject the accepted connection, then
  1897. // abort the connection. Otherwise (this is a request to defer
  1898. // acceptance until later) then insert the connection at the *head*
  1899. // of the endpoint's unaccepted connection queue.
  1900. //
  1901. if( deferAcceptInfo->Reject ) {
  1902. //
  1903. // Reenable the accept event bit, and if there are additional
  1904. // unaccepted connections on the endpoint, post another event.
  1905. //
  1906. endpoint->EventsActive &= ~AFD_POLL_ACCEPT;
  1907. IF_DEBUG(EVENT_SELECT) {
  1908. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1909. "AfdDeferAccept: Endp %08lX, Active %08lX\n",
  1910. endpoint,
  1911. endpoint->EventsActive
  1912. ));
  1913. }
  1914. if( !IsListEmpty( &endpoint->Common.VcListening.UnacceptedConnectionListHead ) ) {
  1915. AfdIndicateEventSelectEvent(
  1916. endpoint,
  1917. AFD_POLL_ACCEPT,
  1918. STATUS_SUCCESS
  1919. );
  1920. }
  1921. //
  1922. // Special handling for SAN connections
  1923. //
  1924. if (connection->SanConnection) {
  1925. PIRP connectIrp;
  1926. //
  1927. // Snag the connect indication IRP
  1928. //
  1929. connectIrp = connection->ConnectIrp;
  1930. ASSERT (connectIrp!=NULL);
  1931. connection->ConnectIrp = NULL;
  1932. //
  1933. // We can now release listen endpoint spinlock
  1934. // The cancel routine will not find IRP in the connection
  1935. //
  1936. if (IoSetCancelRoutine (connectIrp, NULL)==NULL) {
  1937. KIRQL cancelIrql;
  1938. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  1939. //
  1940. // Cancel routine is running, make sure
  1941. // it finishes before proceeding further
  1942. //
  1943. IoAcquireCancelSpinLock (&cancelIrql);
  1944. IoReleaseCancelSpinLock (cancelIrql);
  1945. connectIrp->IoStatus.Status = STATUS_CANCELLED;
  1946. }
  1947. else {
  1948. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  1949. connectIrp->IoStatus.Status = STATUS_CONNECTION_REFUSED;
  1950. }
  1951. //
  1952. // Return the connection and complete SAN provider IRP
  1953. //
  1954. connection->Endpoint = NULL;
  1955. connection->SanConnection = FALSE;
  1956. AfdSanReleaseConnection (endpoint, connection, FALSE);
  1957. DEREFERENCE_ENDPOINT (endpoint);
  1958. connectIrp->IoStatus.Information = 0;
  1959. IoCompleteRequest (connectIrp, AfdPriorityBoost);
  1960. }
  1961. else {
  1962. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  1963. //
  1964. // Abort the connection.
  1965. //
  1966. AfdAbortConnection( connection );
  1967. //
  1968. // Add another free connection to replace the one we're rejecting.
  1969. // Also, add extra to account for past failures in calls to
  1970. // AfdAddFreeConnection().
  1971. //
  1972. InterlockedIncrement(
  1973. &endpoint->Common.VcListening.FailedConnectionAdds
  1974. );
  1975. AfdReplenishListenBacklog( endpoint );
  1976. }
  1977. } else {
  1978. //
  1979. // Restore the connection's state before putting it back
  1980. // on the queue.
  1981. //
  1982. connection->State = AfdConnectionStateUnaccepted;
  1983. InsertHeadList(
  1984. &endpoint->Common.VcListening.UnacceptedConnectionListHead,
  1985. &connection->ListEntry
  1986. );
  1987. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  1988. }
  1989. status = STATUS_SUCCESS;
  1990. complete:
  1991. Irp->IoStatus.Status = status;
  1992. ASSERT( Irp->CancelRoutine == NULL );
  1993. IoCompleteRequest( Irp, AfdPriorityBoost );
  1994. return status;
  1995. } // AfdDeferAccept
  1996. NTSTATUS
  1997. AfdRestartDelayedAccept (
  1998. IN PDEVICE_OBJECT DeviceObject,
  1999. IN PIRP Irp,
  2000. IN PVOID Context
  2001. )
  2002. /*++
  2003. Routine Description:
  2004. The completion routine for the AFD wait for delayed accept IRP portion
  2005. of an accept.
  2006. Arguments:
  2007. DeviceObject - the devoce object on which the request is completing.
  2008. Irp - The accept IRP.
  2009. Context - points to accept file object
  2010. Return Value:
  2011. STATUS_SUCCESS if the I/O system should complete the super accept
  2012. request, or STATUS_MORE_PROCESSING_REQUIRED if the super accept
  2013. request is still being processed.
  2014. --*/
  2015. {
  2016. PIO_STACK_LOCATION irpSp;
  2017. PFILE_OBJECT acceptFileObject;
  2018. PAFD_ENDPOINT acceptEndpoint;
  2019. PAFD_CONNECTION connection;
  2020. PAFD_ENDPOINT listenEndpoint;
  2021. AFD_LOCK_QUEUE_HANDLE lockHandle;
  2022. UNREFERENCED_PARAMETER (DeviceObject);
  2023. acceptFileObject = Context;
  2024. acceptEndpoint = acceptFileObject->FsContext;
  2025. irpSp = IoGetCurrentIrpStackLocation (Irp);
  2026. listenEndpoint = irpSp->FileObject->FsContext;
  2027. //
  2028. // Remember that a TDI accept has completed on this endpoint.
  2029. //
  2030. InterlockedDecrement(
  2031. &listenEndpoint->Common.VcListening.TdiAcceptPendingCount
  2032. );
  2033. AfdCompleteOutstandingIrp (acceptEndpoint, Irp);
  2034. if ( Irp->PendingReturned ) {
  2035. IoMarkIrpPending( Irp );
  2036. }
  2037. AfdAcquireSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
  2038. //
  2039. // The AFD connection object should now be in the endpoiont.
  2040. //
  2041. connection = AFD_CONNECTION_FROM_ENDPOINT( acceptEndpoint );
  2042. if (connection!=NULL) {
  2043. if (NT_SUCCESS (Irp->IoStatus.Status)) {
  2044. acceptEndpoint->State = AfdEndpointStateConnected;
  2045. connection->State = AfdConnectionStateConnected;
  2046. acceptEndpoint->EventsActive |= AFD_POLL_SEND;
  2047. acceptEndpoint->EnableSendEvent = TRUE;
  2048. AfdReleaseSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
  2049. AFD_END_STATE_CHANGE (acceptEndpoint);
  2050. }
  2051. else {
  2052. //
  2053. // If the accept failed, treat it like an abortive disconnect.
  2054. // This way the application still gets a new endpoint, but it gets
  2055. // told about the reset.
  2056. //
  2057. REFERENCE_CONNECTION (connection);
  2058. AfdReleaseSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
  2059. AFD_END_STATE_CHANGE (acceptEndpoint);
  2060. AfdDisconnectEventHandler(
  2061. NULL,
  2062. connection,
  2063. 0,
  2064. NULL,
  2065. 0,
  2066. NULL,
  2067. TDI_DISCONNECT_ABORT
  2068. );
  2069. DEREFERENCE_CONNECTION (connection);
  2070. }
  2071. }
  2072. ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
  2073. ObDereferenceObject( acceptFileObject );
  2074. Irp->AssociatedIrp.SystemBuffer = irpSp->Parameters.AfdRestartDelayedAcceptInfo.AfdSystemBuffer;
  2075. return STATUS_SUCCESS;
  2076. }
  2077. VOID
  2078. AfdCleanupSuperAccept (
  2079. IN PIRP Irp,
  2080. IN NTSTATUS Status
  2081. )
  2082. /*++
  2083. Routine Description:
  2084. Cleans up a super accept IRP and prepeares it for completion
  2085. Arguments:
  2086. Irp - the IRP to cleanup.
  2087. Status - failure status
  2088. Return Value:
  2089. None.
  2090. --*/
  2091. {
  2092. PAFD_ENDPOINT listenEndpoint;
  2093. PFILE_OBJECT acceptFileObject;
  2094. PAFD_ENDPOINT acceptEndpoint;
  2095. PIO_STACK_LOCATION irpSp;
  2096. AFD_LOCK_QUEUE_HANDLE lockHandle;
  2097. ASSERT (!NT_SUCCESS (Status));
  2098. //
  2099. // Initialize some locals.
  2100. //
  2101. irpSp = IoGetCurrentIrpStackLocation (Irp);
  2102. listenEndpoint = irpSp->FileObject->FsContext;
  2103. //
  2104. // Reduce the count of failed connection adds on the listening
  2105. // endpoint to account for this connection object which we're
  2106. // adding back onto the queue once it is pulled from pre-accepted connection
  2107. // list.
  2108. //
  2109. InterlockedDecrement (&listenEndpoint->Common.VcListening.FailedConnectionAdds);
  2110. acceptFileObject = irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdAcceptFileObject;
  2111. acceptEndpoint = acceptFileObject->FsContext;
  2112. ASSERT (IS_AFD_ENDPOINT_TYPE (acceptEndpoint));
  2113. //
  2114. // Cleanup super accept IRP out of endpoint.
  2115. //
  2116. AfdAcquireSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
  2117. ASSERT (acceptEndpoint->Irp==Irp); // May need to remove this assert
  2118. // in the future.
  2119. acceptEndpoint->Irp = NULL;
  2120. AfdReleaseSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
  2121. //
  2122. // Mark the end of state change letting the endpoint
  2123. // to be used again in state change operation (e.g. accept).
  2124. //
  2125. AFD_END_STATE_CHANGE (acceptEndpoint);
  2126. //
  2127. // Dereference accept file object
  2128. //
  2129. ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
  2130. ObDereferenceObject( acceptFileObject );
  2131. //
  2132. // Check if we have secondary MDL for local address query and
  2133. // free it.
  2134. //
  2135. if (Irp->MdlAddress->Next!=NULL) {
  2136. //
  2137. // We never lock pages for this one (they are locked
  2138. // as part of main MDL).
  2139. //
  2140. ASSERT (irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength>0);
  2141. ASSERT ((Irp->MdlAddress->Next->MdlFlags & MDL_PAGES_LOCKED)==0);
  2142. IoFreeMdl (Irp->MdlAddress->Next);
  2143. Irp->MdlAddress->Next = NULL;
  2144. }
  2145. //
  2146. // Set the status specified in the IRP and return
  2147. // The caller will eventually complete it.
  2148. //
  2149. Irp->IoStatus.Status = Status;
  2150. Irp->IoStatus.Information = 0;
  2151. return;
  2152. }
  2153. VOID
  2154. AfdCancelSuperAccept (
  2155. IN PDEVICE_OBJECT DeviceObject,
  2156. IN PIRP Irp
  2157. )
  2158. /*++
  2159. Routine Description:
  2160. Cancels a super accept IRP that is pended in AFD.
  2161. Arguments:
  2162. DeviceObject - not used.
  2163. Irp - the IRP to cancel.
  2164. Return Value:
  2165. None.
  2166. --*/
  2167. {
  2168. PAFD_CONNECTION connection;
  2169. UNREFERENCED_PARAMETER (DeviceObject);
  2170. connection = Irp->Tail.Overlay.DriverContext[0];
  2171. ASSERT (connection->Type==AfdBlockTypeConnection);
  2172. ASSERT (connection->Endpoint==NULL);
  2173. //
  2174. // If IRP is in the connection object, cleanup and complete it
  2175. //
  2176. if (InterlockedExchangePointer (
  2177. (PVOID *)&connection->AcceptIrp,
  2178. NULL)==Irp) {
  2179. IoReleaseCancelSpinLock( Irp->CancelIrql );
  2180. AfdCleanupSuperAccept (Irp, STATUS_CANCELLED);
  2181. IoCompleteRequest( Irp, AfdPriorityBoost );
  2182. }
  2183. else {
  2184. IoReleaseCancelSpinLock( Irp->CancelIrql );
  2185. }
  2186. return;
  2187. }
  2188. BOOLEAN
  2189. AfdServiceSuperAccept (
  2190. IN PAFD_ENDPOINT Endpoint,
  2191. IN PAFD_CONNECTION Connection,
  2192. IN PAFD_LOCK_QUEUE_HANDLE LockHandle,
  2193. OUT PLIST_ENTRY AcceptIrpList
  2194. )
  2195. /*++
  2196. Routine Description:
  2197. Attemts to satisfy super accept irp using the incoming
  2198. connection. This routine must be called with listening endpoint
  2199. spinlock held.
  2200. Arguments:
  2201. Endpoint - listening endpoint on which connection is
  2202. being accepted
  2203. Connection - connection being accepted.
  2204. AcceptIrpList - returns a list of accept Irps which were failed and
  2205. need to be completed after listening endpoint spinlock
  2206. is released.
  2207. Return Value:
  2208. TRUE - the super accept IRP was found and is in the head of the list
  2209. FALSE - no usable super accept IRP exists.
  2210. --*/
  2211. {
  2212. PSLIST_ENTRY listEntry;
  2213. PIRP acceptIrp;
  2214. PAFD_CONNECTION oldConnection;
  2215. //
  2216. // Keep removing super accept IRPs while there are any there
  2217. //
  2218. while ((listEntry = InterlockedPopEntrySList (
  2219. &Endpoint->Common.VcListening.PreacceptedConnectionsListHead
  2220. ))!=NULL) {
  2221. NTSTATUS status;
  2222. //
  2223. // Find the connection pointer from the list entry and return a
  2224. // pointer to the connection object.
  2225. //
  2226. oldConnection = CONTAINING_RECORD(
  2227. listEntry,
  2228. AFD_CONNECTION,
  2229. SListEntry
  2230. );
  2231. acceptIrp = InterlockedExchangePointer ((PVOID *)&oldConnection->AcceptIrp, NULL);
  2232. //
  2233. // Check if there is accept irp associated with
  2234. // this connection, if not just put it back on the free list
  2235. // (the IRP must have been cancelled)
  2236. //
  2237. if (acceptIrp!=NULL) {
  2238. if (IoSetCancelRoutine (acceptIrp, NULL)!=NULL) {
  2239. PFILE_OBJECT acceptFileObject;
  2240. PAFD_ENDPOINT acceptEndpoint;
  2241. PIO_STACK_LOCATION irpSp;
  2242. //
  2243. // Initialize some locals.
  2244. //
  2245. irpSp = IoGetCurrentIrpStackLocation (acceptIrp);
  2246. acceptFileObject = irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdAcceptFileObject;
  2247. acceptEndpoint = acceptFileObject->FsContext;
  2248. ASSERT (IS_AFD_ENDPOINT_TYPE (acceptEndpoint));
  2249. //
  2250. // Check if super accept Irp has enough space for
  2251. // the remote address
  2252. //
  2253. if (Connection->RemoteAddressLength>
  2254. irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdRemoteAddressLength) {
  2255. status = STATUS_BUFFER_TOO_SMALL;
  2256. }
  2257. //
  2258. // Check if we have enough system PTE's to map
  2259. // the buffer.
  2260. //
  2261. else if ((status = AfdMapMdlChain (acceptIrp->MdlAddress)),
  2262. !NT_SUCCESS (status)) {
  2263. NOTHING;
  2264. }
  2265. else if (Connection->SanConnection) {
  2266. status = AfdSanAcceptCore (acceptIrp, acceptFileObject, Connection, LockHandle);
  2267. if (status==STATUS_PENDING) {
  2268. //
  2269. // Accept IRP is pending waiting for Switch
  2270. // completion notification
  2271. // Release old connection object
  2272. //
  2273. ASSERT (oldConnection->Endpoint==NULL);
  2274. InterlockedPushEntrySList (
  2275. &Endpoint->Common.VcListening.FreeConnectionListHead,
  2276. &oldConnection->SListEntry);
  2277. }
  2278. else {
  2279. //
  2280. // Something failed, we need to complete accept IRP
  2281. //
  2282. ASSERT (NT_ERROR (status));
  2283. AfdCleanupSuperAccept (acceptIrp, status);
  2284. IoCompleteRequest (acceptIrp, AfdPriorityBoost);
  2285. //
  2286. // This connection has already been diassociated from endpoint.
  2287. // If backlog is below the level we need, put it on the free
  2288. // list, otherwise, get rid of it.
  2289. //
  2290. ASSERT (oldConnection->Endpoint==NULL);
  2291. if (InterlockedIncrement (&Endpoint->Common.VcListening.FailedConnectionAdds)>0) {
  2292. InterlockedDecrement (&Endpoint->Common.VcListening.FailedConnectionAdds);
  2293. InterlockedPushEntrySList (
  2294. &Endpoint->Common.VcListening.FreeConnectionListHead,
  2295. &oldConnection->SListEntry);
  2296. }
  2297. else {
  2298. DEREFERENCE_CONNECTION (oldConnection);
  2299. }
  2300. }
  2301. //
  2302. // Complete previously failed accept irps if any.
  2303. //
  2304. while (!IsListEmpty (AcceptIrpList)) {
  2305. PIRP irp;
  2306. irp = CONTAINING_RECORD (AcceptIrpList->Flink, IRP, Tail.Overlay.ListEntry);
  2307. RemoveEntryList (&irp->Tail.Overlay.ListEntry);
  2308. IoCompleteRequest (irp, AfdPriorityBoost);
  2309. }
  2310. return TRUE;
  2311. }
  2312. //
  2313. // Allocate MDL for local address query if requested
  2314. //
  2315. else if ((irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength>0) &&
  2316. (IoAllocateMdl ((PUCHAR)acceptIrp->UserBuffer+irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength,
  2317. irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength,
  2318. TRUE,
  2319. FALSE,
  2320. acceptIrp)==NULL)){
  2321. status = STATUS_INSUFFICIENT_RESOURCES;
  2322. }
  2323. else {
  2324. //
  2325. // Copy over the address information to the user's buffer.
  2326. //
  2327. #ifndef i386
  2328. if (acceptEndpoint->Common.VcConnecting.FixAddressAlignment) {
  2329. USHORT addressLength =
  2330. Connection->RemoteAddress->Address[0].AddressLength
  2331. + sizeof (USHORT);
  2332. USHORT UNALIGNED *pAddrLength = (PVOID)
  2333. ((PUCHAR)MmGetSystemAddressForMdl (acceptIrp->MdlAddress)
  2334. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength
  2335. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength
  2336. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdRemoteAddressLength
  2337. - sizeof (USHORT));
  2338. RtlMoveMemory (
  2339. (PUCHAR)MmGetSystemAddressForMdl (acceptIrp->MdlAddress)
  2340. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength
  2341. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength,
  2342. &Connection->RemoteAddress->Address[0].AddressType,
  2343. addressLength);
  2344. *pAddrLength = addressLength;
  2345. }
  2346. else
  2347. #endif
  2348. {
  2349. RtlMoveMemory (
  2350. (PUCHAR)MmGetSystemAddressForMdl (acceptIrp->MdlAddress)
  2351. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength
  2352. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength,
  2353. Connection->RemoteAddress,
  2354. Connection->RemoteAddressLength);
  2355. }
  2356. status = AfdAcceptCore (acceptIrp, acceptEndpoint, Connection);
  2357. if (status==STATUS_SUCCESS) {
  2358. AfdReleaseSpinLock (&Endpoint->SpinLock, LockHandle);
  2359. //
  2360. // Decrement counter to account for connection being
  2361. // returned to the free pool. No need to do this because
  2362. // we are picking up a connection from the free pool
  2363. // InterlockedDecrement (&Endpoint->Common.VcListening.FailedConnectionAdds);
  2364. //
  2365. ASSERT (oldConnection->Endpoint==NULL);
  2366. InterlockedPushEntrySList (
  2367. &Endpoint->Common.VcListening.FreeConnectionListHead,
  2368. &oldConnection->SListEntry);
  2369. //
  2370. // Complete previously failed accept irps if any.
  2371. //
  2372. while (!IsListEmpty (AcceptIrpList)) {
  2373. PIRP irp;
  2374. irp = CONTAINING_RECORD (AcceptIrpList->Flink, IRP, Tail.Overlay.ListEntry);
  2375. RemoveEntryList (&irp->Tail.Overlay.ListEntry);
  2376. IoCompleteRequest (irp, AfdPriorityBoost);
  2377. }
  2378. //
  2379. // Make irp look like it is completed by the
  2380. // transport.
  2381. //
  2382. acceptIrp->IoStatus.Status = STATUS_SUCCESS;
  2383. irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdMdlAddress = acceptIrp->MdlAddress;
  2384. acceptIrp->MdlAddress = NULL;
  2385. irpSp->FileObject = acceptFileObject;
  2386. //
  2387. // Call completion routine directly to simulate
  2388. // completion by the transport stack
  2389. //
  2390. AfdRestartSuperAcceptListen (acceptIrp, Connection);
  2391. return TRUE;
  2392. }
  2393. else {
  2394. ASSERT (status!=STATUS_PENDING);
  2395. }
  2396. }
  2397. }
  2398. else { // if (IoSetCancelRoutine (accpetIrp, NULL)!=NULL)
  2399. status = STATUS_CANCELLED;
  2400. }
  2401. //
  2402. // Cleanup the IRP and insert it into the completion list
  2403. //
  2404. AfdCleanupSuperAccept (acceptIrp, status);
  2405. InsertTailList (AcceptIrpList,
  2406. &acceptIrp->Tail.Overlay.ListEntry);
  2407. } // if (acceptIrp!=NULL)
  2408. else {
  2409. status = STATUS_CANCELLED;
  2410. }
  2411. //
  2412. // This connection has already been diassociated from endpoint.
  2413. // If backlog is below the level we need, put it on the free
  2414. // list, otherwise, get rid of it.
  2415. //
  2416. ASSERT (oldConnection->Endpoint==NULL);
  2417. if (Endpoint->Common.VcListening.FailedConnectionAdds>=0 &&
  2418. status!=STATUS_INSUFFICIENT_RESOURCES &&
  2419. ExQueryDepthSList (&Endpoint->Common.VcListening.FreeConnectionListHead)<AFD_MAXIMUM_FREE_CONNECTIONS) {
  2420. InterlockedPushEntrySList (
  2421. &Endpoint->Common.VcListening.FreeConnectionListHead,
  2422. &oldConnection->SListEntry);
  2423. }
  2424. else {
  2425. InterlockedIncrement (&Endpoint->Common.VcListening.FailedConnectionAdds);
  2426. DEREFERENCE_CONNECTION (oldConnection);
  2427. }
  2428. }
  2429. return FALSE;
  2430. }
  2431. NTSTATUS
  2432. AfdSetupAcceptEndpoint (
  2433. PAFD_ENDPOINT ListenEndpoint,
  2434. PAFD_ENDPOINT AcceptEndpoint,
  2435. PAFD_CONNECTION Connection
  2436. )
  2437. /*++
  2438. Routine Description:
  2439. Sets up the accept endpoint to get ready to accept connection
  2440. (copies parameters of the listening endpoint on which connection
  2441. was indicated)
  2442. Arguments:
  2443. ListenEndpoint - endpoint on which connection was indicated
  2444. AcceptEndpoint - endpoint on which to accept the connection
  2445. Connection - connection to accept
  2446. Return Value:
  2447. STATUS_SUCCESS - endpoint state/parameters adjusted OK
  2448. STATUS_CANCELLED - endpoint has already been cleaned up.
  2449. Note:
  2450. Accepting endpoint spinlock must be held when calling this routine.
  2451. Listen endpoint spinlock needs to be held only if connection has already
  2452. been accepted (transport was told to accept it). This is necessary
  2453. to synchronize with receive indication handler since it uses endpoint
  2454. spinlock pointed to by the connection structure and we switch this pointer
  2455. inside this routine.
  2456. --*/
  2457. {
  2458. //
  2459. // Check the state of the accepting endpoint.
  2460. //
  2461. if ( AcceptEndpoint->EndpointCleanedUp ) {
  2462. return STATUS_CANCELLED;
  2463. }
  2464. //
  2465. // Note that the returned connection structure already has a
  2466. // referenced pointer to the listening endpoint. Rather than
  2467. // removing the reference here, only to re-add it later, we'll
  2468. // just not touch the reference count.
  2469. //
  2470. ASSERT( Connection->Endpoint == ListenEndpoint );
  2471. //
  2472. // Set up the accept endpoint. Note that we already have a reference to
  2473. // the endpoint by the virtue of its file object
  2474. //
  2475. //
  2476. // Place the connection on the endpoint we'll accept it on. It is
  2477. // still referenced from when it was created.
  2478. //
  2479. AcceptEndpoint->Common.VcConnecting.Connection = Connection;
  2480. //
  2481. // Remove super accept IRP from the endpoint
  2482. //
  2483. AcceptEndpoint->Irp = NULL;
  2484. //
  2485. // Set up the accept endpoint's type, and remember blocking
  2486. // characteristics of the TDI provider.
  2487. //
  2488. AcceptEndpoint->Type = AfdBlockTypeVcConnecting;
  2489. AcceptEndpoint->TdiServiceFlags = ListenEndpoint->TdiServiceFlags;
  2490. ASSERT (AcceptEndpoint->TransportInfo == ListenEndpoint->TransportInfo);
  2491. ASSERT (AcceptEndpoint->TransportInfo->ReferenceCount>0);
  2492. //
  2493. // Set up a referenced pointer to the listening endpoint. This is
  2494. // necessary so that the endpoint does not go away until all
  2495. // accepted endpoints have gone away. Without this, a connect
  2496. // indication could occur on a TDI address object held open
  2497. // by an accepted endpoint after the listening endpoint has
  2498. // been closed and the memory for it deallocated.
  2499. //
  2500. // Note that, since we didn't remove the reference above, we don't
  2501. // need to add it here.
  2502. //
  2503. AcceptEndpoint->Common.VcConnecting.ListenEndpoint = ListenEndpoint;
  2504. //
  2505. // Set up a referenced pointer in the accepted endpoint to the
  2506. // TDI address object.
  2507. //
  2508. ObReferenceObject( ListenEndpoint->AddressFileObject );
  2509. AfdRecordAddrRef();
  2510. AcceptEndpoint->AddressFileObject = ListenEndpoint->AddressFileObject;
  2511. AcceptEndpoint->AddressDeviceObject = ListenEndpoint->AddressDeviceObject;
  2512. //
  2513. // Copy the pointer to the local address. Because we keep listen
  2514. // endpoint alive for as long as any of its connection is
  2515. // active, we can rely on the fact that address structure won't go
  2516. // away as well.
  2517. //
  2518. AcceptEndpoint->LocalAddress = ListenEndpoint->LocalAddress;
  2519. AcceptEndpoint->LocalAddressLength = ListenEndpoint->LocalAddressLength;
  2520. //
  2521. // Set up a referenced pointer from the connection to the accept
  2522. // endpoint.
  2523. //
  2524. REFERENCE_ENDPOINT( AcceptEndpoint );
  2525. Connection->Endpoint = AcceptEndpoint;
  2526. return STATUS_SUCCESS;
  2527. }