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

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