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.

765 lines
27 KiB

  1. /*++
  2. Copyright (c) 1989-1999 Microsoft Corporation
  3. Module Name:
  4. close.c
  5. Abstract:
  6. This module contains code for cleanup and close IRPs.
  7. Author:
  8. David Treadwell (davidtr) 18-Mar-1992
  9. Revision History:
  10. --*/
  11. #include "afdp.h"
  12. #ifdef ALLOC_PRAGMA
  13. #pragma alloc_text( PAGE, AfdClose )
  14. #pragma alloc_text( PAGEAFD, AfdCleanup )
  15. #endif
  16. NTSTATUS
  17. FASTCALL
  18. AfdCleanup (
  19. IN PIRP Irp,
  20. IN PIO_STACK_LOCATION IrpSp
  21. )
  22. /*++
  23. Routine Description:
  24. This is the routine that handles Cleanup IRPs in AFD.
  25. Arguments:
  26. Irp - Pointer to I/O request packet.
  27. IrpSp - pointer to the IO stack location to use for this request.
  28. Return Value:
  29. NTSTATUS -- Indicates whether the request was successfully queued.
  30. --*/
  31. {
  32. NTSTATUS status;
  33. PAFD_ENDPOINT endpoint;
  34. AFD_LOCK_QUEUE_HANDLE lockHandle;
  35. PLIST_ENTRY listEntry;
  36. LARGE_INTEGER processExitTime;
  37. UNREFERENCED_PARAMETER (Irp);
  38. endpoint = IrpSp->FileObject->FsContext;
  39. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  40. IF_DEBUG(OPEN_CLOSE) {
  41. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  42. "AfdCleanup: cleanup on file object %p, endpoint %p, connection %p\n",
  43. IrpSp->FileObject,
  44. endpoint,
  45. AFD_CONNECTION_FROM_ENDPOINT( endpoint )
  46. ));
  47. }
  48. //
  49. // Get the process exit time while still at low IRQL.
  50. //
  51. processExitTime = PsGetProcessExitTime( );
  52. //
  53. // Indicate that there was a local close on this endpoint. If there
  54. // are any outstanding polls on this endpoint, they will be
  55. // completed now.
  56. //
  57. AfdIndicatePollEvent(
  58. endpoint,
  59. AFD_POLL_LOCAL_CLOSE,
  60. STATUS_SUCCESS
  61. );
  62. //
  63. // Remember that the endpoint has been cleaned up. This is important
  64. // because it allows AfdRestartAccept to know that the endpoint has
  65. // been cleaned up and that it should toss the connection.
  66. //
  67. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  68. AfdIndicateEventSelectEvent (endpoint, AFD_POLL_LOCAL_CLOSE, STATUS_SUCCESS);
  69. ASSERT( endpoint->EndpointCleanedUp == FALSE);
  70. endpoint->EndpointCleanedUp = TRUE;
  71. //
  72. // If this a datagram endpoint, cancel all IRPs and free any buffers
  73. // of data. Note that if the state of the endpoint is just "open"
  74. // (not bound, etc.) then we can't have any pended IRPs or datagrams
  75. // on the endpoint. Also, the lists of IRPs and datagrams may not
  76. // yet been initialized if the state is just open.
  77. //
  78. if ( IS_DGRAM_ENDPOINT(endpoint) ) {
  79. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  80. if ( endpoint->State == AfdEndpointStateBound ||
  81. endpoint->State == AfdEndpointStateConnected) {
  82. //
  83. // Reset the counts of datagrams bufferred on the endpoint.
  84. // This prevents anyone from thinking that there is bufferred
  85. // data on the endpoint.
  86. //
  87. endpoint->DgBufferredReceiveCount = 0;
  88. endpoint->DgBufferredReceiveBytes = 0;
  89. //
  90. // Cancel all receive datagram and peek datagram IRPs on the
  91. // endpoint.
  92. //
  93. AfdCompleteIrpList(
  94. &endpoint->ReceiveDatagramIrpListHead,
  95. endpoint,
  96. STATUS_CANCELLED,
  97. AfdCleanupReceiveDatagramIrp
  98. );
  99. AfdCompleteIrpList(
  100. &endpoint->PeekDatagramIrpListHead,
  101. endpoint,
  102. STATUS_CANCELLED,
  103. AfdCleanupReceiveDatagramIrp
  104. );
  105. }
  106. }
  107. else if (IS_SAN_ENDPOINT (endpoint)) {
  108. if (!IsListEmpty (&endpoint->Common.SanEndp.IrpList)) {
  109. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  110. AfdSanRestartRequestProcessing (endpoint, STATUS_CANCELLED);
  111. }
  112. else {
  113. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  114. }
  115. }
  116. else if (IS_SAN_HELPER (endpoint)) {
  117. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  118. if (endpoint->OwningProcess==IoGetCurrentProcess ()) {
  119. AfdSanHelperCleanup (endpoint);
  120. }
  121. else {
  122. ASSERT ((endpoint->Common.SanHlpr.PendingRequests & 1) != 0);
  123. }
  124. }
  125. else {
  126. PAFD_CONNECTION connection;
  127. connection = AFD_CONNECTION_FROM_ENDPOINT( endpoint );
  128. ASSERT( connection == NULL || connection->Type == AfdBlockTypeConnection );
  129. //
  130. // Reference the connection object so that it does not go away while
  131. // we are freeing the resources
  132. //
  133. if (connection!=NULL) {
  134. REFERENCE_CONNECTION (connection);
  135. //
  136. // If this is a connected non-datagram socket and the send side has
  137. // not been disconnected and there is no outstanding data to be
  138. // received, begin a graceful disconnect on the connection. If there
  139. // is unreceived data out outstanding IO, abort the connection.
  140. //
  141. if ( (endpoint->State == AfdEndpointStateConnected
  142. || endpoint->State==AfdEndpointStateBound
  143. || endpoint->State==AfdEndpointStateTransmitClosing)
  144. // Endpoint is in bound state when connection
  145. // request is in progress, we still need
  146. // to abort those.
  147. &&
  148. connection->ConnectedReferenceAdded
  149. &&
  150. !endpoint->afdC_Root // these are connected on bind
  151. &&
  152. ( (endpoint->DisconnectMode & AFD_ABORTIVE_DISCONNECT) == 0)
  153. &&
  154. ( (endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_SEND) == 0 ||
  155. IS_DATA_ON_CONNECTION(connection) ||
  156. IS_EXPEDITED_DATA_ON_CONNECTION(connection) ||
  157. ( !IS_TDI_BUFFERRING(endpoint) &&
  158. connection->Common.NonBufferring.ReceiveBytesInTransport > 0 ) ||
  159. endpoint->StateChangeInProgress)
  160. &&
  161. !connection->Aborted ) {
  162. ASSERT( endpoint->Type == AfdBlockTypeVcConnecting );
  163. if ( IS_DATA_ON_CONNECTION( connection )
  164. ||
  165. IS_EXPEDITED_DATA_ON_CONNECTION( connection )
  166. ||
  167. ( !IS_TDI_BUFFERRING(endpoint) &&
  168. connection->Common.NonBufferring.ReceiveBytesInTransport > 0 )
  169. ||
  170. processExitTime.QuadPart != 0
  171. ||
  172. endpoint->OutstandingIrpCount != 0
  173. ||
  174. endpoint->StateChangeInProgress
  175. ||
  176. ( !IS_TDI_BUFFERRING(endpoint) &&
  177. (!IsListEmpty( &connection->VcReceiveIrpListHead ) ||
  178. !IsListEmpty( &connection->VcSendIrpListHead )) )
  179. ) {
  180. #if DBG
  181. if ( processExitTime.QuadPart != 0 ) {
  182. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  183. "AfdCleanup: process exiting w/o closesocket, aborting endp %p\n",
  184. endpoint ));
  185. }
  186. else {
  187. if ( IS_DATA_ON_CONNECTION( connection ) ) {
  188. if (IS_TDI_BUFFERRING(endpoint)) {
  189. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  190. "AfdCleanup: unrecv'd data on endp %p, aborting. "
  191. "%ld ind, %ld taken, %ld out\n",
  192. endpoint,
  193. connection->Common.Bufferring.ReceiveBytesIndicated,
  194. connection->Common.Bufferring.ReceiveBytesTaken,
  195. connection->Common.Bufferring.ReceiveBytesOutstanding ));
  196. }
  197. else {
  198. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  199. "AfdCleanup: unrecv'd data (%ld) on endp %p, aborting.\n",
  200. connection->Common.NonBufferring.BufferredReceiveBytes,
  201. endpoint ));
  202. }
  203. }
  204. if ( IS_EXPEDITED_DATA_ON_CONNECTION( connection ) ) {
  205. if (IS_TDI_BUFFERRING(endpoint)) {
  206. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  207. "AfdCleanup: unrecv'd exp data on endp %p, aborting. "
  208. "%ld ind, %ld taken, %ld out\n",
  209. endpoint,
  210. connection->Common.Bufferring.ReceiveExpeditedBytesIndicated,
  211. connection->Common.Bufferring.ReceiveExpeditedBytesTaken,
  212. connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding ));
  213. }
  214. else {
  215. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  216. "AfdCleanup: unrecv'd exp data (%ld) on endp %p, aborting.\n",
  217. connection->Common.NonBufferring.BufferredExpeditedBytes,
  218. endpoint ));
  219. }
  220. }
  221. if ( !IS_TDI_BUFFERRING(endpoint) &&
  222. connection->Common.NonBufferring.ReceiveBytesInTransport > 0 ) {
  223. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  224. "AfdCleanup: unrecv'd data (%ld) in transport on endp %p, aborting.\n",
  225. connection->Common.NonBufferring.ReceiveBytesInTransport,
  226. endpoint));
  227. }
  228. if ( endpoint->OutstandingIrpCount != 0 ) {
  229. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  230. "AfdCleanup: %ld IRPs %s outstanding on endpoint %p, "
  231. "aborting.\n",
  232. endpoint->OutstandingIrpCount,
  233. (endpoint->StateChangeInProgress
  234. ? "(accept, connect, or transmit file)"
  235. : ""),
  236. endpoint ));
  237. }
  238. }
  239. #endif
  240. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  241. (VOID)AfdBeginAbort( connection );
  242. } else {
  243. endpoint->DisconnectMode |= AFD_PARTIAL_DISCONNECT_RECEIVE;
  244. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  245. status = AfdBeginDisconnect( endpoint, NULL, NULL );
  246. if (!NT_SUCCESS (status)) {
  247. //
  248. // If disconnect failed, we have no choice but to abort the
  249. // connection because we cannot return error from close and
  250. // have application try it again. If we don't abort, connection
  251. // ends up hanging there forever.
  252. //
  253. (VOID)AfdBeginAbort (connection);
  254. }
  255. }
  256. } else {
  257. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  258. }
  259. //
  260. // If this is a connected VC endpoint on a nonbufferring TDI provider,
  261. // cancel all outstanding send and receive IRPs.
  262. //
  263. if ( !IS_TDI_BUFFERRING(endpoint) ) {
  264. AfdCompleteIrpList(
  265. &connection->VcReceiveIrpListHead,
  266. endpoint,
  267. STATUS_CANCELLED,
  268. NULL
  269. );
  270. AfdCompleteIrpList(
  271. &connection->VcSendIrpListHead,
  272. endpoint,
  273. STATUS_CANCELLED,
  274. AfdCleanupSendIrp
  275. );
  276. }
  277. //
  278. // Remember that we have started cleanup on this connection.
  279. // We know that we'll never get a request on the connection
  280. // after we start cleanup on the connection.
  281. //
  282. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  283. connection->CleanupBegun = TRUE;
  284. //
  285. // Attempt to remove the connected reference.
  286. //
  287. AfdDeleteConnectedReference( connection, TRUE );
  288. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  289. //
  290. // Remove connection reference added in the beginning of this
  291. // function. We can't access connection object after this point
  292. // because in can be freed inside the AfdDereferenceConnection.
  293. //
  294. DEREFERENCE_CONNECTION (connection);
  295. connection = NULL;
  296. }
  297. else {
  298. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  299. }
  300. //
  301. // Complete any outstanding wait for listen IRPs on the endpoint.
  302. //
  303. if ( (endpoint->Type & AfdBlockTypeVcListening) == AfdBlockTypeVcListening ) {
  304. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  305. while ( !IsListEmpty( &endpoint->Common.VcListening.ListeningIrpListHead ) ) {
  306. PIRP waitForListenIrp;
  307. PIO_STACK_LOCATION irpSp;
  308. listEntry = RemoveHeadList( &endpoint->Common.VcListening.ListeningIrpListHead );
  309. waitForListenIrp = CONTAINING_RECORD(
  310. listEntry,
  311. IRP,
  312. Tail.Overlay.ListEntry
  313. );
  314. //
  315. // Set FLink to NULL so that cancel routine won't touch the IRP.
  316. //
  317. listEntry->Flink = NULL;
  318. irpSp = IoGetCurrentIrpStackLocation (waitForListenIrp);
  319. if (irpSp->MajorFunction==IRP_MJ_INTERNAL_DEVICE_CONTROL) {
  320. AfdCleanupSuperAccept (waitForListenIrp, STATUS_CANCELLED);
  321. }
  322. else {
  323. waitForListenIrp->IoStatus.Status = STATUS_CANCELLED;
  324. waitForListenIrp->IoStatus.Information = 0;
  325. }
  326. //
  327. // Release the AFD spin lock so that we can complete the
  328. // wait for listen IRP.
  329. //
  330. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  331. //
  332. // Cancel the IRP.
  333. //
  334. //
  335. // Reset the cancel routine in the IRP.
  336. //
  337. if ( IoSetCancelRoutine( waitForListenIrp, NULL ) == NULL ) {
  338. KIRQL cancelIrql;
  339. //
  340. // If the cancel routine was NULL then cancel routine
  341. // may be running. Wait on the cancel spinlock until
  342. // the cancel routine is done.
  343. //
  344. // Note: The cancel routine will not find the IRP
  345. // since it is not in the list.
  346. //
  347. IoAcquireCancelSpinLock( &cancelIrql );
  348. ASSERT( waitForListenIrp->Cancel );
  349. IoReleaseCancelSpinLock( cancelIrql );
  350. }
  351. IoCompleteRequest( waitForListenIrp, AfdPriorityBoost );
  352. //
  353. // Reacquire the AFD spin lock for the next pass through the
  354. // loop.
  355. //
  356. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  357. }
  358. //
  359. // Free all queued (free, unaccepted, and returned) connections
  360. // on the endpoint.
  361. //
  362. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  363. AfdFreeQueuedConnections( endpoint );
  364. endpoint->Common.VcListening.FailedConnectionAdds = 0;
  365. }
  366. }
  367. if (endpoint->RoutingQueryReferenced) {
  368. AfdCleanupRoutingChange (endpoint);
  369. }
  370. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  371. while (!IsListEmpty (&endpoint->RequestList)) {
  372. PAFD_REQUEST_CONTEXT requestCtx;
  373. listEntry = RemoveHeadList (&endpoint->RequestList);
  374. listEntry->Flink = NULL;
  375. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  376. requestCtx = CONTAINING_RECORD (listEntry,
  377. AFD_REQUEST_CONTEXT,
  378. EndpointListLink);
  379. (*requestCtx->CleanupRoutine) (endpoint, requestCtx);
  380. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  381. }
  382. if ( endpoint->Irp != NULL) {
  383. PIRP transmitIrp;
  384. KIRQL cancelIrql;
  385. //
  386. // Release the endpoint and acquire the cancel spinlock
  387. // and then the enpoint spinlock.
  388. //
  389. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  390. IoAcquireCancelSpinLock( &cancelIrql );
  391. AfdAcquireSpinLockAtDpcLevel( &endpoint->SpinLock, &lockHandle );
  392. //
  393. // Make sure there is still a transmit IRP.
  394. //
  395. transmitIrp = endpoint->Irp;
  396. if ( transmitIrp != NULL ) {
  397. PDRIVER_CANCEL cancelRoutine;
  398. // indicate that it has to be cancelled
  399. transmitIrp->Cancel = TRUE;
  400. cancelRoutine = IoSetCancelRoutine( transmitIrp, NULL );
  401. if ( cancelRoutine != NULL ) {
  402. //
  403. // The IRP needs to be canceled. Release the
  404. // endpoint spinlock. The value in endpoint->Irp can
  405. // now change, but the IRP cannot be completed while the
  406. // cancel spinlock is held since we set the cancel flag
  407. // in the IRP.
  408. //
  409. AfdReleaseSpinLockFromDpcLevel( &endpoint->SpinLock, &lockHandle );
  410. transmitIrp->CancelIrql = cancelIrql;
  411. cancelRoutine ( NULL, transmitIrp );
  412. }
  413. else {
  414. // The IRP has not been completely setup yet
  415. // and will be cancelled in the dispatch routine
  416. AfdReleaseSpinLockFromDpcLevel( &endpoint->SpinLock, &lockHandle );
  417. IoReleaseCancelSpinLock( cancelIrql );
  418. }
  419. } else {
  420. //
  421. // The IRP has been completed or canceled. Release the locks
  422. // and continue.
  423. //
  424. AfdReleaseSpinLockFromDpcLevel( &endpoint->SpinLock, &lockHandle );
  425. IoReleaseCancelSpinLock( cancelIrql );
  426. }
  427. } else {
  428. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  429. }
  430. //
  431. // Reset relevant event handlers on the endpoint. This prevents
  432. // getting indications after we free the endpoint and connection
  433. // objects. We should not be able to get new connects after this
  434. // handle has been cleaned up.
  435. //
  436. // Note that these calls can fail if, for example, DHCP changes the
  437. // host's IP address while the endpoint is active.
  438. //
  439. //
  440. if ((endpoint->AddressHandle != NULL) && (endpoint->State != AfdEndpointStateOpen)) {
  441. if (endpoint->Listening) {
  442. status = AfdSetEventHandler(
  443. endpoint->AddressFileObject,
  444. TDI_EVENT_CONNECT,
  445. NULL,
  446. NULL
  447. );
  448. // ASSERT(NT_SUCCESS(status));
  449. if (IS_TDI_ADDRESS_SECURITY(endpoint)) {
  450. status = AfdUnbind(endpoint);
  451. // ASSERT(NT_SUCCESS(status));
  452. }
  453. } else if (IS_VC_ENDPOINT(endpoint)) {
  454. //
  455. // Connection-oriented accepted endpoints cannot have address handles
  456. // in their structures because they share them with listening
  457. // endpoint. So, this is an endpoint on which connect was done.
  458. // We need to call AfdUnbind() on it to allow other endpoints to
  459. // bind to the address held by this endpoint.
  460. // We cannot wait for final dereference on address file object for
  461. // unbind to take place, because that can be delayed till all
  462. // endpoint ref counts go to 0. So, we must do explicit unbind here
  463. //
  464. if (IS_TDI_ADDRESS_SECURITY (endpoint)) {
  465. status = AfdUnbind(endpoint);
  466. // ASSERT(NT_SUCCESS(status));
  467. }
  468. } else if (IS_DGRAM_ENDPOINT(endpoint)) {
  469. status = AfdSetEventHandler(
  470. endpoint->AddressFileObject,
  471. TDI_EVENT_RECEIVE_DATAGRAM,
  472. NULL,
  473. NULL
  474. );
  475. // ASSERT(NT_SUCCESS(status));
  476. status = AfdSetEventHandler(
  477. endpoint->AddressFileObject,
  478. TDI_EVENT_ERROR_EX,
  479. NULL,
  480. NULL
  481. );
  482. // ASSERT(NT_SUCCESS(status));
  483. status = AfdSetEventHandler(
  484. endpoint->AddressFileObject,
  485. TDI_EVENT_ERROR,
  486. NULL,
  487. NULL
  488. );
  489. // ASSERT(NT_SUCCESS(status));
  490. //
  491. // We need to call AfdUnbind() on this endpoint to allow other endpoints to
  492. // bind to the address held by this endpoint.
  493. // We cannot wait for final dereference on address file object for
  494. // unbind to take place, because that can be delayed till all
  495. // endpoint ref counts go to 0. So, we must do explicit unbind here
  496. //
  497. if (IS_TDI_ADDRESS_SECURITY (endpoint)) {
  498. status = AfdUnbind(endpoint);
  499. // ASSERT(NT_SUCCESS(status));
  500. }
  501. }
  502. } // if (endpoint->State != AfdEndpointStateOpen)
  503. InterlockedIncrement(&AfdEndpointsCleanedUp);
  504. return STATUS_SUCCESS;
  505. } // AfdCleanup
  506. NTSTATUS
  507. FASTCALL
  508. AfdClose (
  509. IN PIRP Irp,
  510. IN PIO_STACK_LOCATION IrpSp
  511. )
  512. /*++
  513. Routine Description:
  514. This is the routine that handles Close IRPs in AFD. It
  515. dereferences the endpoint specified in the IRP, which will result in
  516. the endpoint being freed when all other references go away.
  517. Arguments:
  518. Irp - Pointer to I/O request packet.
  519. IrpSp - pointer to the IO stack location to use for this request.
  520. Return Value:
  521. NTSTATUS -- Indicates whether the request was successfully queued.
  522. --*/
  523. {
  524. PAFD_ENDPOINT endpoint;
  525. PAFD_CONNECTION connection;
  526. UNREFERENCED_PARAMETER (Irp);
  527. PAGED_CODE( );
  528. endpoint = IrpSp->FileObject->FsContext;
  529. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  530. IF_DEBUG(OPEN_CLOSE) {
  531. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  532. "AfdClose: closing file object %p, endpoint %p\n",
  533. IrpSp->FileObject, endpoint ));
  534. }
  535. IF_DEBUG(ENDPOINT) {
  536. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  537. "AfdClose: closing endpoint at %p\n",
  538. endpoint ));
  539. }
  540. connection = AFD_CONNECTION_FROM_ENDPOINT (endpoint);
  541. //
  542. // If there is a connection on this endpoint, dereference it here
  543. // rather than in AfdDereferenceEndpoint, because the connection
  544. // has a referenced pointer to the endpoint which must be removed
  545. // before the endpoint can dereference the connection.
  546. //
  547. if (connection != NULL) {
  548. endpoint->Common.VcConnecting.Connection = NULL;
  549. DEREFERENCE_CONNECTION (connection);
  550. //
  551. // This is to simplify debugging.
  552. // If connection is not being closed by the transport
  553. // we want to be able to find it in the debugger faster
  554. // then thru !poolfind AfdC.
  555. //
  556. endpoint->WorkItem.Context = connection;
  557. }
  558. else if (IS_SAN_ENDPOINT (endpoint) &&
  559. endpoint->Common.SanEndp.SwitchContext!=NULL) {
  560. PVOID requestCtx;
  561. endpoint->Common.SanEndp.FileObject = NULL;
  562. requestCtx = AFD_SWITCH_MAKE_REQUEST_CONTEXT(
  563. ((ULONG)0xFFFFFFFF),
  564. AFD_SWITCH_REQUEST_CLOSE);
  565. IoSetIoCompletion (
  566. endpoint->Common.SanEndp.SanHlpr->Common.SanHlpr.IoCompletionPort,// Port
  567. endpoint->Common.SanEndp.SwitchContext, // Key
  568. requestCtx, // ApcContext
  569. STATUS_SUCCESS, // Status
  570. 0, // Information
  571. FALSE // ChargeQuota
  572. );
  573. }
  574. //
  575. // Set the state of the endpoint to closing and dereference to
  576. // get rid of the active reference.
  577. //
  578. ASSERT (endpoint->State!=AfdEndpointStateClosing);
  579. endpoint->State = AfdEndpointStateClosing;
  580. //
  581. // Dereference the endpoint to get rid of the active reference.
  582. // This will result in the endpoint storage being freed as soon
  583. // as all other references go away.
  584. //
  585. DEREFERENCE_ENDPOINT( endpoint );
  586. return STATUS_SUCCESS;
  587. } // AfdClose