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.

1546 lines
44 KiB

  1. /*++
  2. Copyright (c) 1992-1999 Microsoft Corporation
  3. Module Name:
  4. blkendp.c
  5. Abstract:
  6. This module contains allocate, free, close, reference, and dereference
  7. routines for AFD endpoints.
  8. Author:
  9. David Treadwell (davidtr) 10-Mar-1992
  10. Revision History:
  11. Vadim Eydelman (vadime) 1999 - Don't attach to system proces, use system handles instead
  12. Delayed acceptance endpoints.
  13. --*/
  14. #include "afdp.h"
  15. VOID
  16. AfdFreeEndpointResources (
  17. PAFD_ENDPOINT endpoint
  18. );
  19. VOID
  20. AfdFreeEndpoint (
  21. IN PVOID Context
  22. );
  23. PAFD_ENDPOINT
  24. AfdReuseEndpoint (
  25. VOID
  26. );
  27. VOID
  28. AfdFreeTransportInfo (
  29. PAFD_TRANSPORT_INFO TransportInfo
  30. );
  31. #ifdef ALLOC_PRAGMA
  32. #pragma alloc_text( PAGE, AfdAllocateEndpoint )
  33. #pragma alloc_text( PAGE, AfdFreeEndpointResources )
  34. #pragma alloc_text( PAGE, AfdFreeEndpoint )
  35. #pragma alloc_text( PAGE, AfdReuseEndpoint )
  36. #pragma alloc_text( PAGE, AfdGetTransportInfo )
  37. #pragma alloc_text( PAGE, AfdFreeTransportInfo )
  38. #pragma alloc_text( PAGEAFD, AfdRefreshEndpoint )
  39. #pragma alloc_text( PAGEAFD, AfdDereferenceEndpoint )
  40. #if REFERENCE_DEBUG
  41. #pragma alloc_text( PAGEAFD, AfdReferenceEndpoint )
  42. #endif
  43. #pragma alloc_text( PAGEAFD, AfdFreeQueuedConnections )
  44. #endif
  45. NTSTATUS
  46. AfdAllocateEndpoint (
  47. OUT PAFD_ENDPOINT * NewEndpoint,
  48. IN PUNICODE_STRING TransportDeviceName,
  49. IN LONG GroupID
  50. )
  51. /*++
  52. Routine Description:
  53. Allocates and initializes a new AFD endpoint structure.
  54. Arguments:
  55. NewEndpoint - Receives a pointer to the new endpoint structure if
  56. successful.
  57. TransportDeviceName - the name of the TDI transport provider
  58. corresponding to the endpoint structure.
  59. GroupID - Identifies the group ID for the new endpoint.
  60. Return Value:
  61. NTSTATUS - The completion status.
  62. --*/
  63. {
  64. PAFD_ENDPOINT endpoint;
  65. PAFD_TRANSPORT_INFO transportInfo = NULL;
  66. NTSTATUS status;
  67. AFD_GROUP_TYPE groupType;
  68. PAGED_CODE( );
  69. DEBUG *NewEndpoint = NULL;
  70. if ( TransportDeviceName != NULL ) {
  71. //
  72. // First, make sure that the transport device name is stored globally
  73. // for AFD. Since there will typically only be a small number of
  74. // transport device names, we store the name strings once globally
  75. // for access by all endpoints.
  76. //
  77. status = AfdGetTransportInfo( TransportDeviceName, &transportInfo );
  78. //
  79. // If transport device is not activated, we'll try again during bind
  80. //
  81. if ( !NT_SUCCESS (status) &&
  82. (status!=STATUS_OBJECT_NAME_NOT_FOUND) &&
  83. (status!=STATUS_OBJECT_PATH_NOT_FOUND) &&
  84. (status!=STATUS_NO_SUCH_DEVICE) ) {
  85. //
  86. // Dereference transport info structure if one was created for us.
  87. // (Should not happen in current implementation).
  88. //
  89. ASSERT (transportInfo==NULL);
  90. return status;
  91. }
  92. ASSERT (transportInfo!=NULL);
  93. }
  94. //
  95. // Validate the incoming group ID, allocate a new one if necessary.
  96. //
  97. if( AfdGetGroup( &GroupID, &groupType ) ) {
  98. PEPROCESS process = IoGetCurrentProcess ();
  99. status = PsChargeProcessPoolQuota(
  100. process,
  101. NonPagedPool,
  102. sizeof (AFD_ENDPOINT)
  103. );
  104. if (!NT_SUCCESS (status)) {
  105. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  106. "AfdAllocateEndpoint: PsChargeProcessPoolQuota failed.\n" ));
  107. goto Cleanup;
  108. }
  109. // See if we have too many endpoins waiting to be freed and reuse one of them
  110. if ((AfdEndpointsFreeing<AFD_ENDPOINTS_FREEING_MAX)
  111. || ((endpoint = AfdReuseEndpoint ())==NULL)) {
  112. //
  113. // Allocate a buffer to hold the endpoint structure.
  114. // We use the priority version of this routine because
  115. // we are going to charge the process for this allocation
  116. // before it can make any use of it.
  117. //
  118. endpoint = AFD_ALLOCATE_POOL_PRIORITY(
  119. NonPagedPool,
  120. sizeof(AFD_ENDPOINT),
  121. AFD_ENDPOINT_POOL_TAG,
  122. NormalPoolPriority
  123. );
  124. }
  125. if ( endpoint != NULL ) {
  126. AfdRecordQuotaHistory(
  127. process,
  128. (LONG)sizeof (AFD_ENDPOINT),
  129. "CreateEndp ",
  130. endpoint
  131. );
  132. AfdRecordPoolQuotaCharged(sizeof (AFD_ENDPOINT));
  133. RtlZeroMemory( endpoint, sizeof(AFD_ENDPOINT) );
  134. //
  135. // Initialize the reference count to 2--one for the caller's
  136. // reference, one for the active reference.
  137. //
  138. endpoint->ReferenceCount = 2;
  139. //
  140. // Initialize the endpoint structure.
  141. //
  142. if ( TransportDeviceName == NULL ) {
  143. endpoint->Type = AfdBlockTypeHelper;
  144. endpoint->State = AfdEndpointStateInvalid;
  145. } else {
  146. endpoint->Type = AfdBlockTypeEndpoint;
  147. endpoint->State = AfdEndpointStateOpen;
  148. endpoint->TransportInfo = transportInfo;
  149. //
  150. // Cache service flags for quick determination of provider characteristics
  151. // such as bufferring and messaging
  152. //
  153. if (transportInfo->InfoValid) {
  154. endpoint->TdiServiceFlags = endpoint->TransportInfo->ProviderInfo.ServiceFlags;
  155. }
  156. }
  157. endpoint->GroupID = GroupID;
  158. endpoint->GroupType = groupType;
  159. AfdInitializeSpinLock( &endpoint->SpinLock );
  160. InitializeListHead (&endpoint->RoutingNotifications);
  161. InitializeListHead (&endpoint->RequestList);
  162. #if DBG
  163. InitializeListHead( &endpoint->OutstandingIrpListHead );
  164. #endif
  165. //
  166. // Remember the process which opened the endpoint. We'll use this to
  167. // charge quota to the process as necessary. Reference the process
  168. // so that it does not go away until we have returned all charged
  169. // quota to the process.
  170. //
  171. endpoint->OwningProcess = process;
  172. ObReferenceObject(endpoint->OwningProcess);
  173. //
  174. // Insert the endpoint on the global list.
  175. //
  176. AfdInsertNewEndpointInList( endpoint );
  177. //
  178. // Return a pointer to the new endpoint to the caller.
  179. //
  180. IF_DEBUG(ENDPOINT) {
  181. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  182. "AfdAllocateEndpoint: new endpoint at %p\n",
  183. endpoint ));
  184. }
  185. *NewEndpoint = endpoint;
  186. return STATUS_SUCCESS;
  187. }
  188. else {
  189. PsReturnPoolQuota(
  190. process,
  191. NonPagedPool,
  192. sizeof (AFD_ENDPOINT)
  193. );
  194. status= STATUS_INSUFFICIENT_RESOURCES;
  195. }
  196. Cleanup:
  197. if( GroupID != 0 ) {
  198. AfdDereferenceGroup( GroupID );
  199. }
  200. }
  201. else {
  202. status = STATUS_INVALID_PARAMETER;
  203. }
  204. if (transportInfo!=NULL) {
  205. if (InterlockedDecrement (&transportInfo->ReferenceCount)==0) {
  206. AfdFreeTransportInfo (transportInfo);
  207. }
  208. }
  209. return status;
  210. } // AfdAllocateEndpoint
  211. VOID
  212. AfdFreeQueuedConnections (
  213. IN PAFD_ENDPOINT Endpoint
  214. )
  215. /*++
  216. Routine Description:
  217. Frees queued connection objects on a listening AFD endpoint.
  218. Arguments:
  219. Endpoint - a pointer to the AFD endpoint structure.
  220. Return Value:
  221. None.
  222. --*/
  223. {
  224. AFD_LOCK_QUEUE_HANDLE lockHandle;
  225. KIRQL oldIrql;
  226. PAFD_CONNECTION connection;
  227. PIRP irp;
  228. ASSERT( Endpoint->Type == AfdBlockTypeVcListening ||
  229. Endpoint->Type == AfdBlockTypeVcBoth );
  230. //
  231. // Free the unaccepted connections.
  232. //
  233. // We must hold endpoint spinLock to call AfdGetUnacceptedConnection,
  234. // but we may not hold it when calling AfdDereferenceConnection.
  235. //
  236. KeRaiseIrql (DISPATCH_LEVEL, &oldIrql);
  237. AfdAcquireSpinLockAtDpcLevel( &Endpoint->SpinLock, &lockHandle );
  238. while ( (connection = AfdGetUnacceptedConnection( Endpoint )) != NULL ) {
  239. ASSERT( connection->Endpoint == Endpoint );
  240. AfdReleaseSpinLockFromDpcLevel( &Endpoint->SpinLock, &lockHandle );
  241. if (connection->SanConnection) {
  242. AfdSanAbortConnection ( connection );
  243. }
  244. else {
  245. AfdAbortConnection( connection );
  246. }
  247. AfdAcquireSpinLockAtDpcLevel( &Endpoint->SpinLock, &lockHandle );
  248. }
  249. //
  250. // Free the returned connections.
  251. //
  252. while ( (connection = AfdGetReturnedConnection( Endpoint, 0 )) != NULL ) {
  253. ASSERT( connection->Endpoint == Endpoint );
  254. AfdReleaseSpinLockFromDpcLevel( &Endpoint->SpinLock, &lockHandle );
  255. if (connection->SanConnection) {
  256. AfdSanAbortConnection ( connection );
  257. }
  258. else {
  259. AfdAbortConnection( connection );
  260. }
  261. AfdAcquireSpinLockAtDpcLevel( &Endpoint->SpinLock, &lockHandle );
  262. }
  263. if (IS_DELAYED_ACCEPTANCE_ENDPOINT (Endpoint)) {
  264. while (!IsListEmpty (&Endpoint->Common.VcListening.ListenConnectionListHead)) {
  265. PIRP listenIrp;
  266. connection = CONTAINING_RECORD (
  267. Endpoint->Common.VcListening.ListenConnectionListHead.Flink,
  268. AFD_CONNECTION,
  269. ListEntry
  270. );
  271. RemoveEntryList (&connection->ListEntry);
  272. listenIrp = InterlockedExchangePointer ((PVOID *)&connection->ListenIrp, NULL);
  273. if (listenIrp!=NULL) {
  274. IoAcquireCancelSpinLock (&listenIrp->CancelIrql);
  275. ASSERT (listenIrp->CancelIrql==DISPATCH_LEVEL);
  276. AfdReleaseSpinLockFromDpcLevel (&Endpoint->SpinLock, &lockHandle);
  277. AfdCancelIrp (listenIrp);
  278. AfdAcquireSpinLockAtDpcLevel( &Endpoint->SpinLock, &lockHandle );
  279. }
  280. }
  281. AfdReleaseSpinLockFromDpcLevel( &Endpoint->SpinLock, &lockHandle );
  282. }
  283. else {
  284. AfdReleaseSpinLockFromDpcLevel( &Endpoint->SpinLock, &lockHandle );
  285. //
  286. // And finally, purge the free connection queue.
  287. //
  288. while ( (connection = AfdGetFreeConnection( Endpoint, &irp )) != NULL ) {
  289. ASSERT( connection->Type == AfdBlockTypeConnection );
  290. if (irp!=NULL) {
  291. AfdCleanupSuperAccept (irp, STATUS_CANCELLED);
  292. if (irp->Cancel) {
  293. KIRQL cancelIrql;
  294. //
  295. // Need to sycn with cancel routine which may
  296. // have been called from AfdCleanup for accepting
  297. // endpoint
  298. //
  299. IoAcquireCancelSpinLock (&cancelIrql);
  300. IoReleaseCancelSpinLock (cancelIrql);
  301. }
  302. IoCompleteRequest (irp, AfdPriorityBoost);
  303. }
  304. DEREFERENCE_CONNECTION( connection );
  305. }
  306. }
  307. KeLowerIrql (oldIrql);
  308. return;
  309. } // AfdFreeQueuedConnections
  310. VOID
  311. AfdFreeEndpointResources (
  312. PAFD_ENDPOINT endpoint
  313. )
  314. /*++
  315. Routine Description:
  316. Does the actual work to deallocate an AFD endpoint structure and
  317. associated structures. Note that all other references to the
  318. endpoint structure must be gone before this routine is called, since
  319. it frees the endpoint and assumes that nobody else will be looking
  320. at the endpoint.
  321. Arguments:
  322. Endpoint to be cleaned up
  323. Return Value:
  324. None
  325. --*/
  326. {
  327. NTSTATUS status;
  328. PLIST_ENTRY listEntry;
  329. PAGED_CODE ();
  330. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  331. ASSERT( endpoint->ReferenceCount == 0 );
  332. ASSERT( endpoint->State == AfdEndpointStateClosing );
  333. ASSERT( endpoint->ObReferenceBias == 0 );
  334. ASSERT( KeGetCurrentIrql( ) == 0 );
  335. //
  336. // If this is a listening endpoint, then purge the endpoint of all
  337. // queued connections.
  338. //
  339. if ( (endpoint->Type & AfdBlockTypeVcListening) == AfdBlockTypeVcListening ) {
  340. AfdFreeQueuedConnections( endpoint );
  341. }
  342. //
  343. // Dereference any group ID associated with this endpoint.
  344. //
  345. if( endpoint->GroupID != 0 ) {
  346. AfdDereferenceGroup( endpoint->GroupID );
  347. }
  348. //
  349. // If this is a bufferring datagram endpoint, remove all the
  350. // bufferred datagrams from the endpoint's list and free them.
  351. //
  352. if ( IS_DGRAM_ENDPOINT(endpoint) &&
  353. endpoint->ReceiveDatagramBufferListHead.Flink != NULL ) {
  354. while ( !IsListEmpty( &endpoint->ReceiveDatagramBufferListHead ) ) {
  355. PAFD_BUFFER_HEADER afdBuffer;
  356. listEntry = RemoveHeadList( &endpoint->ReceiveDatagramBufferListHead );
  357. afdBuffer = CONTAINING_RECORD( listEntry, AFD_BUFFER_HEADER, BufferListEntry );
  358. AfdReturnBuffer( afdBuffer, endpoint->OwningProcess );
  359. }
  360. }
  361. //
  362. // Close and dereference the TDI address object on the endpoint, if
  363. // any.
  364. //
  365. if ( endpoint->AddressFileObject != NULL ) {
  366. //
  367. // Little extra precaution. It is possible that there exists
  368. // a duplicated handle in user process, so transport can in
  369. // theory call event handler with bogus endpoint pointer that
  370. // we are about to free. The event handlers for datagram
  371. // endpoints are reset in AfdCleanup.
  372. // Connection-oriented accepted endpoints cannot have address handles
  373. // in their structures because they share them with listening
  374. // endpoint (it would be a grave mistake if we tried to close
  375. // address handle owned by listening endpoint while closing connection
  376. // accepted on it).
  377. //
  378. if ( endpoint->AddressHandle != NULL &&
  379. IS_VC_ENDPOINT (endpoint)) {
  380. ASSERT (((endpoint->Type&AfdBlockTypeVcConnecting)!=AfdBlockTypeVcConnecting)
  381. || (endpoint->Common.VcConnecting.ListenEndpoint==NULL));
  382. status = AfdSetEventHandler(
  383. endpoint->AddressFileObject,
  384. TDI_EVENT_ERROR,
  385. NULL,
  386. NULL
  387. );
  388. //ASSERT( NT_SUCCESS(status) );
  389. status = AfdSetEventHandler(
  390. endpoint->AddressFileObject,
  391. TDI_EVENT_DISCONNECT,
  392. NULL,
  393. NULL
  394. );
  395. //ASSERT( NT_SUCCESS(status) );
  396. status = AfdSetEventHandler(
  397. endpoint->AddressFileObject,
  398. TDI_EVENT_RECEIVE,
  399. NULL,
  400. NULL
  401. );
  402. //ASSERT( NT_SUCCESS(status) );
  403. if (IS_TDI_EXPEDITED (endpoint)) {
  404. status = AfdSetEventHandler(
  405. endpoint->AddressFileObject,
  406. TDI_EVENT_RECEIVE_EXPEDITED,
  407. NULL,
  408. NULL
  409. );
  410. //ASSERT( NT_SUCCESS(status) );
  411. }
  412. if ( IS_TDI_BUFFERRING(endpoint) ) {
  413. status = AfdSetEventHandler(
  414. endpoint->AddressFileObject,
  415. TDI_EVENT_SEND_POSSIBLE,
  416. NULL,
  417. NULL
  418. );
  419. //ASSERT( NT_SUCCESS(status) );
  420. }
  421. else {
  422. status = AfdSetEventHandler(
  423. endpoint->AddressFileObject,
  424. TDI_EVENT_CHAINED_RECEIVE,
  425. NULL,
  426. NULL
  427. );
  428. //ASSERT( NT_SUCCESS(status) );
  429. }
  430. }
  431. ObDereferenceObject( endpoint->AddressFileObject );
  432. endpoint->AddressFileObject = NULL;
  433. endpoint->AddressDeviceObject = NULL;
  434. AfdRecordAddrDeref();
  435. }
  436. else {
  437. if (endpoint->SecurityDescriptor!=NULL) {
  438. ObDereferenceSecurityDescriptor( endpoint->SecurityDescriptor, 1 );
  439. }
  440. endpoint->SecurityDescriptor = NULL;
  441. }
  442. if ( endpoint->AddressHandle != NULL ) {
  443. #if DBG
  444. {
  445. NTSTATUS status1;
  446. OBJECT_HANDLE_FLAG_INFORMATION handleInfo;
  447. handleInfo.Inherit = FALSE;
  448. handleInfo.ProtectFromClose = FALSE;
  449. status1 = ZwSetInformationObject (
  450. endpoint->AddressHandle,
  451. ObjectHandleFlagInformation,
  452. &handleInfo,
  453. sizeof (handleInfo)
  454. );
  455. ASSERT (NT_SUCCESS (status1));
  456. }
  457. #endif
  458. status = ZwClose( endpoint->AddressHandle );
  459. ASSERT( NT_SUCCESS(status) );
  460. endpoint->AddressHandle = NULL;
  461. AfdRecordAddrClosed();
  462. }
  463. //
  464. // Remove the endpoint from the global list. Do this before any
  465. // deallocations to prevent someone else from seeing an endpoint in
  466. // an invalid state.
  467. //
  468. AfdRemoveEndpointFromList( endpoint );
  469. //
  470. // Return the quota we charged to this process when we allocated
  471. // the endpoint object.
  472. //
  473. PsReturnPoolQuota(
  474. endpoint->OwningProcess,
  475. NonPagedPool,
  476. sizeof (AFD_ENDPOINT)
  477. );
  478. AfdRecordQuotaHistory(
  479. endpoint->OwningProcess,
  480. -(LONG)sizeof (AFD_ENDPOINT),
  481. "EndpDealloc ",
  482. endpoint
  483. );
  484. AfdRecordPoolQuotaReturned(
  485. sizeof (AFD_ENDPOINT)
  486. );
  487. //
  488. // Dereference the owning process.
  489. //
  490. ObDereferenceObject( endpoint->OwningProcess );
  491. endpoint->OwningProcess = NULL;
  492. //
  493. // Dereference the listening or c-root endpoint on the endpoint, if
  494. // any.
  495. //
  496. if ( endpoint->Type == AfdBlockTypeVcConnecting &&
  497. endpoint->Common.VcConnecting.ListenEndpoint != NULL ) {
  498. PAFD_ENDPOINT listenEndpoint = endpoint->Common.VcConnecting.ListenEndpoint;
  499. ASSERT (((listenEndpoint->Type&AfdBlockTypeVcListening)==AfdBlockTypeVcListening) ||
  500. IS_CROOT_ENDPOINT (listenEndpoint));
  501. ASSERT (endpoint->LocalAddress==listenEndpoint->LocalAddress);
  502. DEREFERENCE_ENDPOINT( listenEndpoint );
  503. endpoint->Common.VcConnecting.ListenEndpoint = NULL;
  504. //
  505. // We used the local address from the listening endpoint,
  506. // simply reset it, it will be freed when listening endpoint
  507. // is freed.
  508. //
  509. endpoint->LocalAddress = NULL;
  510. endpoint->LocalAddressLength = 0;
  511. }
  512. if (IS_SAN_ENDPOINT (endpoint)) {
  513. AfdSanCleanupEndpoint (endpoint);
  514. }
  515. else if (IS_SAN_HELPER (endpoint)) {
  516. AfdSanCleanupHelper (endpoint);
  517. }
  518. //
  519. // Free local and remote address buffers.
  520. //
  521. if ( endpoint->LocalAddress != NULL ) {
  522. AFD_FREE_POOL(
  523. endpoint->LocalAddress,
  524. AFD_LOCAL_ADDRESS_POOL_TAG
  525. );
  526. endpoint->LocalAddress = NULL;
  527. }
  528. if ( IS_DGRAM_ENDPOINT(endpoint) &&
  529. endpoint->Common.Datagram.RemoteAddress != NULL ) {
  530. AFD_RETURN_REMOTE_ADDRESS(
  531. endpoint->Common.Datagram.RemoteAddress,
  532. endpoint->Common.Datagram.RemoteAddressLength
  533. );
  534. endpoint->Common.Datagram.RemoteAddress = NULL;
  535. }
  536. //
  537. // Free context and connect data buffers.
  538. //
  539. if ( endpoint->Context != NULL ) {
  540. AFD_FREE_POOL(
  541. endpoint->Context,
  542. AFD_CONTEXT_POOL_TAG
  543. );
  544. endpoint->Context = NULL;
  545. }
  546. if ( IS_VC_ENDPOINT (endpoint) &&
  547. endpoint->Common.VirtualCircuit.ConnectDataBuffers != NULL ) {
  548. AfdFreeConnectDataBuffers( endpoint->Common.VirtualCircuit.ConnectDataBuffers );
  549. }
  550. //
  551. // If there's an active EventSelect() on this endpoint, dereference
  552. // the associated event object.
  553. //
  554. if( endpoint->EventObject != NULL ) {
  555. ObDereferenceObject( endpoint->EventObject );
  556. endpoint->EventObject = NULL;
  557. }
  558. // ASSERT ( endpoint->Irp == NULL );
  559. if (endpoint->TransportInfo!=NULL) {
  560. if (InterlockedDecrement (&endpoint->TransportInfo->ReferenceCount)==0) {
  561. AfdFreeTransportInfo (endpoint->TransportInfo);
  562. }
  563. endpoint->TransportInfo = NULL;
  564. }
  565. ASSERT (endpoint->OutstandingIrpCount==0);
  566. IF_DEBUG(ENDPOINT) {
  567. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  568. "AfdFreeEndpoint: freeing endpoint at %p\n",
  569. endpoint ));
  570. }
  571. endpoint->Type = AfdBlockTypeInvalidEndpoint;
  572. }
  573. VOID
  574. AfdFreeEndpoint (
  575. IN PVOID Context
  576. )
  577. /*++
  578. Routine Description:
  579. Calls AfdFreeEndpointResources to cleanup endpoint and frees the
  580. endpoint structure itself
  581. Arguments:
  582. Context - Actually points to the endpoint's embedded AFD_WORK_ITEM
  583. structure. From this we can determine the endpoint to free.
  584. Return Value:
  585. None.
  586. --*/
  587. {
  588. PAFD_ENDPOINT endpoint;
  589. PAGED_CODE( );
  590. ASSERT( Context != NULL );
  591. InterlockedDecrement(&AfdEndpointsFreeing);
  592. endpoint = CONTAINING_RECORD(
  593. Context,
  594. AFD_ENDPOINT,
  595. WorkItem
  596. );
  597. AfdFreeEndpointResources (endpoint);
  598. //
  599. // Free the pool used for the endpoint itself.
  600. //
  601. AFD_FREE_POOL(
  602. endpoint,
  603. AFD_ENDPOINT_POOL_TAG
  604. );
  605. } // AfdFreeEndpoint
  606. PAFD_ENDPOINT
  607. AfdReuseEndpoint (
  608. VOID
  609. )
  610. /*++
  611. Routine Description:
  612. Finds a AfdFreeEndpoint work item in the list and calls
  613. AfdFreeEndpointResources to cleanup endpoint
  614. Arguments:
  615. None
  616. Return Value:
  617. Reinitialized endpoint.
  618. --*/
  619. {
  620. PAFD_ENDPOINT endpoint;
  621. PVOID Context;
  622. PAGED_CODE( );
  623. Context = AfdGetWorkerByRoutine (AfdFreeEndpoint);
  624. if (Context==NULL)
  625. return NULL;
  626. endpoint = CONTAINING_RECORD(
  627. Context,
  628. AFD_ENDPOINT,
  629. WorkItem
  630. );
  631. AfdFreeEndpointResources (endpoint);
  632. return endpoint;
  633. } // AfdReuseEndpoint
  634. #if REFERENCE_DEBUG
  635. VOID
  636. AfdDereferenceEndpoint (
  637. IN PAFD_ENDPOINT Endpoint,
  638. IN LONG LocationId,
  639. IN ULONG Param
  640. )
  641. #else
  642. VOID
  643. AfdDereferenceEndpoint (
  644. IN PAFD_ENDPOINT Endpoint
  645. )
  646. #endif
  647. /*++
  648. Routine Description:
  649. Dereferences an AFD endpoint and calls the routine to free it if
  650. appropriate.
  651. Arguments:
  652. Endpoint - a pointer to the AFD endpoint structure.
  653. Return Value:
  654. None.
  655. --*/
  656. {
  657. LONG result;
  658. #if REFERENCE_DEBUG
  659. IF_DEBUG(ENDPOINT) {
  660. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  661. "AfdDereferenceEndpoint: endpoint at %p, new refcnt %ld\n",
  662. Endpoint, Endpoint->ReferenceCount-1 ));
  663. }
  664. ASSERT( IS_AFD_ENDPOINT_TYPE( Endpoint ) );
  665. ASSERT( Endpoint->ReferenceCount > 0 );
  666. ASSERT( Endpoint->ReferenceCount != 0xDAADF00D );
  667. AFD_UPDATE_REFERENCE_DEBUG(Endpoint, Endpoint->ReferenceCount-1, LocationId, Param);
  668. //
  669. // We must hold AfdSpinLock while doing the dereference and check
  670. // for free. This is because some code makes the assumption that
  671. // the connection structure will not go away while AfdSpinLock is
  672. // held, and that code references the endpoint before releasing
  673. // AfdSpinLock. If we did the InterlockedDecrement() without the
  674. // lock held, our count may go to zero, that code may reference the
  675. // connection, and then a double free might occur.
  676. //
  677. // It is still valuable to use the interlocked routines for
  678. // increment and decrement of structures because it allows us to
  679. // avoid having to hold the spin lock for a reference.
  680. //
  681. // In NT40+ we use InterlockedCompareExchange and make sure that
  682. // we do not increment reference count if it is 0, so holding
  683. // a spinlock is no longer necessary
  684. //
  685. // Decrement the reference count; if it is 0, we may need to
  686. // free the endpoint.
  687. //
  688. #endif
  689. result = InterlockedDecrement( (PLONG)&Endpoint->ReferenceCount );
  690. if ( result == 0 ) {
  691. ASSERT( Endpoint->State == AfdEndpointStateClosing );
  692. if ((Endpoint->Type==AfdBlockTypeVcConnecting) &&
  693. (Endpoint->Common.VcConnecting.ListenEndpoint != NULL) &&
  694. (KeGetCurrentIrql()==PASSIVE_LEVEL)) {
  695. ASSERT (Endpoint->AddressHandle==NULL);
  696. //
  697. // If this is a connecting endpoint assoicated with the
  698. // listening endpoint and we already at passive level,
  699. // free the endpoint here. We can do this because in such
  700. // a case we know that reference to the transport object
  701. // is not the last one - at least one more is still in the
  702. // listening endpoint and we remove transport object reference
  703. // before dereferencing listening endpoint.
  704. //
  705. //
  706. AfdFreeEndpointResources (Endpoint);
  707. //
  708. // Free the pool used for the endpoint itself.
  709. //
  710. AFD_FREE_POOL(
  711. Endpoint,
  712. AFD_ENDPOINT_POOL_TAG
  713. );
  714. }
  715. else
  716. {
  717. //
  718. // We're going to do this by queueing a request to an executive
  719. // worker thread. We do this for several reasons: to ensure
  720. // that we're at IRQL 0 so we can free pageable memory, and to
  721. // ensure that we're in a legitimate context for a close
  722. // operation and not in conntext of event indication from
  723. // the transport driver
  724. //
  725. InterlockedIncrement(&AfdEndpointsFreeing);
  726. AfdQueueWorkItem(
  727. AfdFreeEndpoint,
  728. &Endpoint->WorkItem
  729. );
  730. }
  731. }
  732. } // AfdDereferenceEndpoint
  733. #if REFERENCE_DEBUG
  734. VOID
  735. AfdReferenceEndpoint (
  736. IN PAFD_ENDPOINT Endpoint,
  737. IN LONG LocationId,
  738. IN ULONG Param
  739. )
  740. /*++
  741. Routine Description:
  742. References an AFD endpoint.
  743. Arguments:
  744. Endpoint - a pointer to the AFD endpoint structure.
  745. Return Value:
  746. None.
  747. --*/
  748. {
  749. LONG result;
  750. ASSERT( Endpoint->ReferenceCount > 0 );
  751. ASSERT( Endpoint->ReferenceCount < 0xFFFF ||
  752. ((Endpoint->Listening ||
  753. Endpoint->afdC_Root) && Endpoint->ReferenceCount<0xFFFFFFF));
  754. result = InterlockedIncrement( (PLONG)&Endpoint->ReferenceCount );
  755. AFD_UPDATE_REFERENCE_DEBUG(Endpoint, result, LocationId, Param);
  756. IF_DEBUG(ENDPOINT) {
  757. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  758. "AfdReferenceEndpoint: endpoint at %p, new refcnt %ld\n",
  759. Endpoint, result ));
  760. }
  761. } // AfdReferenceEndpoint
  762. VOID
  763. AfdUpdateEndpoint (
  764. IN PAFD_ENDPOINT Endpoint,
  765. IN LONG LocationId,
  766. IN ULONG Param
  767. )
  768. /*++
  769. Routine Description:
  770. Update an AFD endpoint reference debug information.
  771. Arguments:
  772. Endpoint - a pointer to the AFD endpoint structure.
  773. Return Value:
  774. None.
  775. --*/
  776. {
  777. ASSERT( Endpoint->ReferenceCount > 0 );
  778. ASSERT( Endpoint->ReferenceCount < 0xFFFF ||
  779. ((Endpoint->Listening ||
  780. Endpoint->afdC_Root) && Endpoint->ReferenceCount<0xFFFFFFF));
  781. AFD_UPDATE_REFERENCE_DEBUG(Endpoint, Endpoint->ReferenceCount, LocationId, Param);
  782. } // AfdUpdateEndpoint
  783. #endif
  784. #if REFERENCE_DEBUG
  785. BOOLEAN
  786. AfdCheckAndReferenceEndpoint (
  787. IN PAFD_ENDPOINT Endpoint,
  788. IN LONG LocationId,
  789. IN ULONG Param
  790. )
  791. #else
  792. BOOLEAN
  793. AfdCheckAndReferenceEndpoint (
  794. IN PAFD_ENDPOINT Endpoint
  795. )
  796. #endif
  797. {
  798. LONG result;
  799. do {
  800. result = Endpoint->ReferenceCount;
  801. if (result<=0)
  802. break;
  803. }
  804. while (InterlockedCompareExchange ((PLONG)&Endpoint->ReferenceCount,
  805. (result+1),
  806. result)!=result);
  807. if (result>0) {
  808. #if REFERENCE_DEBUG
  809. AFD_UPDATE_REFERENCE_DEBUG(Endpoint, result+1, LocationId, Param);
  810. IF_DEBUG(ENDPOINT) {
  811. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  812. "AfdReferenceEndpoint: endpoint at %p, new refcnt %ld\n",
  813. Endpoint, result+1 ));
  814. }
  815. ASSERT( Endpoint->ReferenceCount < 0xFFFF ||
  816. ((Endpoint->Listening ||
  817. Endpoint->afdC_Root) && Endpoint->ReferenceCount<0xFFFFFFF));
  818. #endif
  819. return TRUE;
  820. }
  821. else {
  822. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_ERROR_LEVEL,
  823. "AfdCheckAndReferenceEndpoint: Endpoint %p is gone (refcount: %ld)!\n",
  824. Endpoint, result));
  825. return FALSE;
  826. }
  827. }
  828. VOID
  829. AfdRefreshEndpoint (
  830. IN PAFD_ENDPOINT Endpoint
  831. )
  832. /*++
  833. Routine Description:
  834. Prepares an AFD endpoint structure to be reused. All other
  835. references to the endpoint must be freed before this routine is
  836. called, since this routine assumes that nobody will access the old
  837. information in the endpoint structure.
  838. This fact is ensured by the state change primitive.
  839. Arguments:
  840. Endpoint - a pointer to the AFD endpoint structure.
  841. Return Value:
  842. None.
  843. --*/
  844. {
  845. AFD_ENDPOINT_STATE_FLAGS flags;
  846. ASSERT( Endpoint->Type == AfdBlockTypeVcConnecting );
  847. ASSERT( Endpoint->Common.VcConnecting.Connection == NULL );
  848. ASSERT( Endpoint->StateChangeInProgress!=0);
  849. ASSERT( Endpoint->State == AfdEndpointStateTransmitClosing );
  850. if ( Endpoint->Common.VcConnecting.ListenEndpoint != NULL ) {
  851. //
  852. // TransmitFile after SuperAccept, cleanup back to open state.
  853. //
  854. //
  855. // Dereference the listening endpoint and its address object.
  856. //
  857. PAFD_ENDPOINT listenEndpoint = Endpoint->Common.VcConnecting.ListenEndpoint;
  858. ASSERT (((listenEndpoint->Type&AfdBlockTypeVcListening)==AfdBlockTypeVcListening) ||
  859. IS_CROOT_ENDPOINT (listenEndpoint));
  860. ASSERT (Endpoint->LocalAddress==listenEndpoint->LocalAddress);
  861. ASSERT (Endpoint->AddressFileObject==listenEndpoint->AddressFileObject);
  862. DEREFERENCE_ENDPOINT( listenEndpoint );
  863. Endpoint->Common.VcConnecting.ListenEndpoint = NULL;
  864. //
  865. // Close and dereference the TDI address object on the endpoint, if
  866. // any.
  867. //
  868. ObDereferenceObject( Endpoint->AddressFileObject );
  869. Endpoint->AddressFileObject = NULL;
  870. Endpoint->AddressDeviceObject = NULL;
  871. AfdRecordAddrDeref();
  872. //
  873. // We used the local address from the listening endpoint,
  874. // simply reset it, it will be freed when listening endpoint
  875. // is freed.
  876. //
  877. Endpoint->LocalAddress = NULL;
  878. Endpoint->LocalAddressLength = 0;
  879. ASSERT (Endpoint->AddressHandle == NULL);
  880. //
  881. // Reinitialize the endpoint structure.
  882. //
  883. Endpoint->Type = AfdBlockTypeEndpoint;
  884. Endpoint->State = AfdEndpointStateOpen;
  885. }
  886. else {
  887. //
  888. // TransmitFile after SuperConnect, cleanup back to bound state.
  889. //
  890. Endpoint->Type = AfdBlockTypeEndpoint;
  891. ASSERT (Endpoint->AddressHandle!=NULL);
  892. ASSERT (Endpoint->AddressFileObject!=NULL);
  893. ASSERT (Endpoint->AddressDeviceObject!=NULL);
  894. Endpoint->State = AfdEndpointStateBound;
  895. }
  896. //
  897. // Remember if poll is pending on this endpoint, to enable cleanup
  898. // is socket gets closed
  899. //
  900. flags.EndpointStateFlags = 0; // reset
  901. flags.PollCalled = Endpoint->PollCalled;
  902. Endpoint->EndpointStateFlags = flags.EndpointStateFlags;
  903. Endpoint->DisconnectMode = 0;
  904. Endpoint->EventsActive = 0;
  905. AfdRecordEndpointsReused ();
  906. return;
  907. } // AfdRefreshEndpoint
  908. NTSTATUS
  909. AfdGetTransportInfo (
  910. IN PUNICODE_STRING TransportDeviceName,
  911. IN OUT PAFD_TRANSPORT_INFO *TransportInfo
  912. )
  913. /*++
  914. Routine Description:
  915. Returns a transport information structure corresponding to the
  916. specified TDI transport provider. Each unique transport string gets
  917. a single provider structure, so that multiple endpoints for the same
  918. transport share the same transport information structure.
  919. Arguments:
  920. TransportDeviceName - the name of the TDI transport provider.
  921. TransportInfo - place to return referenced pointer to transport info
  922. Return Value:
  923. STATUS_SUCCESS - returned transport info is valid.
  924. STATUS_INSUFFICIENT_RESOURCES - not enough memory to allocate
  925. transport info structure
  926. STATUS_OBJECT_NAME_NOT_FOUND - transport's device is not available yet
  927. --*/
  928. {
  929. PLIST_ENTRY listEntry;
  930. PAFD_TRANSPORT_INFO transportInfo;
  931. ULONG structureLength;
  932. NTSTATUS status;
  933. TDI_PROVIDER_INFO localProviderInfo;
  934. BOOLEAN resourceShared = TRUE;
  935. #ifdef _AFD_VARIABLE_STACK_
  936. CCHAR stackSize;
  937. #endif // _AFD_VARIABLE_STACK_
  938. PAGED_CODE( );
  939. //
  940. // Make sure the thread in which we execute cannot get
  941. // suspeneded in APC while we own the global resource.
  942. //
  943. KeEnterCriticalRegion ();
  944. ExAcquireResourceSharedLite( AfdResource, TRUE );
  945. //
  946. // If this is the first endpoint, we may be paged out
  947. // entirely.
  948. //
  949. if (!AfdLoaded) {
  950. //
  951. // Take the exclusive lock and page the locked sections in
  952. // if necessary
  953. //
  954. //
  955. // There should be no endpoints in the list.
  956. //
  957. ASSERT (IsListEmpty (&AfdEndpointListHead));
  958. ExReleaseResourceLite ( AfdResource);
  959. ExAcquireResourceExclusiveLite( AfdResource, TRUE );
  960. resourceShared = FALSE;
  961. if (!AfdLoaded) {
  962. //
  963. // There should be no endpoints in the list.
  964. //
  965. ASSERT (IsListEmpty (&AfdEndpointListHead));
  966. MmResetDriverPaging ((PVOID)DriverEntry);
  967. AfdLoaded = (PKEVENT)1;
  968. }
  969. }
  970. ASSERT (AfdLoaded==(PKEVENT)1);
  971. if (*TransportInfo==NULL) {
  972. ScanTransportList:
  973. //
  974. // If caller did not have transport info allocated, walk the list
  975. // of transport device names looking for an identical name.
  976. //
  977. for ( listEntry = AfdTransportInfoListHead.Flink;
  978. listEntry != &AfdTransportInfoListHead;
  979. listEntry = listEntry->Flink )
  980. {
  981. transportInfo = CONTAINING_RECORD(
  982. listEntry,
  983. AFD_TRANSPORT_INFO,
  984. TransportInfoListEntry
  985. );
  986. if ( RtlCompareUnicodeString(
  987. &transportInfo->TransportDeviceName,
  988. TransportDeviceName,
  989. TRUE ) == 0 ) {
  990. //
  991. // We found an exact match. Reference the structure
  992. // to return it to the caller
  993. //
  994. do {
  995. LONG localCount;
  996. localCount = transportInfo->ReferenceCount;
  997. if (localCount==0) {
  998. //
  999. // We hit a small window when the structure is
  1000. // about to be freed. We can't stop this from
  1001. // happenning, so we'll go on to allocate and
  1002. // requery. After all info is not valid anyway,
  1003. // thus we are just loosing on the allocation/dealocation
  1004. // code.
  1005. //
  1006. ASSERT (transportInfo->InfoValid==FALSE);
  1007. goto AllocateInfo;
  1008. }
  1009. if (InterlockedCompareExchange (
  1010. (PLONG)&transportInfo->ReferenceCount,
  1011. (localCount+1),
  1012. localCount)==localCount) {
  1013. if (transportInfo->InfoValid) {
  1014. //
  1015. // Info is valid return referenced pointer to
  1016. // the caller.
  1017. //
  1018. *TransportInfo = transportInfo;
  1019. ExReleaseResourceLite( AfdResource );
  1020. KeLeaveCriticalRegion ();
  1021. return STATUS_SUCCESS;
  1022. }
  1023. else {
  1024. //
  1025. // We found match, but info is not valid
  1026. //
  1027. goto QueryInfo;
  1028. }
  1029. }
  1030. }
  1031. while (1);
  1032. }
  1033. } // for
  1034. AllocateInfo:
  1035. if (resourceShared) {
  1036. //
  1037. // If we do not own resource exlusively, we will
  1038. // have to release and reacquire it and then
  1039. // rescan the list
  1040. //
  1041. ExReleaseResourceLite ( AfdResource);
  1042. ExAcquireResourceExclusiveLite( AfdResource, TRUE );
  1043. resourceShared = FALSE;
  1044. goto ScanTransportList;
  1045. }
  1046. //
  1047. // This is a brand new device name, allocate transport info
  1048. // structure for it.
  1049. //
  1050. structureLength = sizeof(AFD_TRANSPORT_INFO) +
  1051. TransportDeviceName->Length + sizeof(UNICODE_NULL);
  1052. transportInfo = AFD_ALLOCATE_POOL_PRIORITY(
  1053. NonPagedPool,
  1054. structureLength,
  1055. AFD_TRANSPORT_INFO_POOL_TAG,
  1056. NormalPoolPriority
  1057. );
  1058. if ( transportInfo == NULL ) {
  1059. ExReleaseResourceLite( AfdResource );
  1060. KeLeaveCriticalRegion ();
  1061. return STATUS_INSUFFICIENT_RESOURCES;
  1062. }
  1063. //
  1064. // Initialize the structure
  1065. //
  1066. transportInfo->ReferenceCount = 1;
  1067. transportInfo->InfoValid = FALSE;
  1068. #ifdef _AFD_VARIABLE_STACK_
  1069. transportInfo->StackSize = 0;
  1070. transportInfo->GetBuffer = AfdGetBufferFast;
  1071. transportInfo->GetTpInfo = AfdGetTpInfoFast;
  1072. transportInfo->CallDriver = IofCallDriver;
  1073. #endif // _AFD_VARIABLE_STACK_
  1074. //
  1075. // Fill in the transport device name.
  1076. //
  1077. transportInfo->TransportDeviceName.MaximumLength =
  1078. TransportDeviceName->Length + sizeof(WCHAR);
  1079. transportInfo->TransportDeviceName.Buffer =
  1080. (PWSTR)(transportInfo + 1);
  1081. RtlCopyUnicodeString(
  1082. &transportInfo->TransportDeviceName,
  1083. TransportDeviceName
  1084. );
  1085. //
  1086. // Insert the structure into the list so that the successive callers
  1087. // can reuse it.
  1088. //
  1089. InsertHeadList (&AfdTransportInfoListHead,
  1090. &transportInfo->TransportInfoListEntry);
  1091. }
  1092. else {
  1093. transportInfo = *TransportInfo;
  1094. //
  1095. // Caller has already referenced info in the list
  1096. // but transport device was not available at the
  1097. // time of the call. Recheck if it is valid under the lock
  1098. //
  1099. if (transportInfo->InfoValid) {
  1100. //
  1101. // Yes, it is, return success
  1102. //
  1103. ExReleaseResourceLite( AfdResource );
  1104. KeLeaveCriticalRegion ();
  1105. return STATUS_SUCCESS;
  1106. }
  1107. }
  1108. QueryInfo:
  1109. //
  1110. // Release the resource and leave critical region to let
  1111. // the IRP's in AfdQueryProviderInfo complete
  1112. //
  1113. ExReleaseResourceLite (AfdResource);
  1114. KeLeaveCriticalRegion ();
  1115. status = AfdQueryProviderInfo (TransportDeviceName,
  1116. #ifdef _AFD_VARIABLE_STACK_
  1117. &stackSize,
  1118. #endif // _AFD_VARIABLE_STACK_
  1119. &localProviderInfo);
  1120. //
  1121. // Make sure the thread in which we execute cannot get
  1122. // suspeneded in APC while we own the global resource.
  1123. //
  1124. KeEnterCriticalRegion ();
  1125. ExAcquireResourceExclusiveLite( AfdResource, TRUE );
  1126. if (NT_SUCCESS (status)) {
  1127. //
  1128. // Check if someone did not get the info in parallel with us.
  1129. //
  1130. if (!transportInfo->InfoValid) {
  1131. //
  1132. // Copy local info structure to the one in the list.
  1133. //
  1134. transportInfo->ProviderInfo = localProviderInfo;
  1135. //
  1136. // Bump the reference count on this info structure
  1137. // as we know that it is a valid TDI provider and we
  1138. // want to cache, it so it stays even of all endpoints
  1139. // that use it are gone.
  1140. //
  1141. InterlockedIncrement ((PLONG)&transportInfo->ReferenceCount);
  1142. //
  1143. // Set the flag so that everyone knows it is now valid.
  1144. //
  1145. transportInfo->InfoValid = TRUE;
  1146. #ifdef _AFD_VARIABLE_STACK_
  1147. transportInfo->StackSize = stackSize;
  1148. #endif // _AFD_VARIABLE_STACK_
  1149. }
  1150. *TransportInfo = transportInfo;
  1151. }
  1152. else {
  1153. if (status==STATUS_OBJECT_NAME_NOT_FOUND ||
  1154. status==STATUS_OBJECT_PATH_NOT_FOUND ||
  1155. status==STATUS_NO_SUCH_DEVICE) {
  1156. //
  1157. // Transport driver must not have been loaded yet
  1158. // Return transport info structure anyway
  1159. // Caller will know that info structure is not
  1160. // valid because we did not set the flag
  1161. //
  1162. *TransportInfo = transportInfo;
  1163. }
  1164. else {
  1165. //
  1166. // Something else went wrong, free the strucuture
  1167. // if it was allocated in this routine
  1168. //
  1169. if (*TransportInfo==NULL) {
  1170. if (InterlockedDecrement ((PLONG)&transportInfo->ReferenceCount)==0) {
  1171. RemoveEntryList (&transportInfo->TransportInfoListEntry);
  1172. AFD_FREE_POOL(
  1173. transportInfo,
  1174. AFD_TRANSPORT_INFO_POOL_TAG
  1175. );
  1176. }
  1177. }
  1178. }
  1179. }
  1180. ExReleaseResourceLite( AfdResource );
  1181. KeLeaveCriticalRegion ();
  1182. return status;
  1183. } // AfdGetTransportInfo
  1184. VOID
  1185. AfdFreeTransportInfo (
  1186. PAFD_TRANSPORT_INFO TransportInfo
  1187. )
  1188. {
  1189. //
  1190. // Reference count has gone to 0, we need to remove the structure
  1191. // from the global list and free it.
  1192. // Note that no code increments reference count if doesn't
  1193. // know for fact that its current reference count is above 0).
  1194. //
  1195. //
  1196. // Make sure the thread in which we execute cannot get
  1197. // suspeneded in APC while we own the global resource.
  1198. //
  1199. KeEnterCriticalRegion ();
  1200. ExAcquireResourceExclusiveLite( AfdResource, TRUE );
  1201. ASSERT (TransportInfo->ReferenceCount==0);
  1202. ASSERT (TransportInfo->InfoValid==FALSE);
  1203. RemoveEntryList (&TransportInfo->TransportInfoListEntry);
  1204. ExReleaseResourceLite( AfdResource );
  1205. KeLeaveCriticalRegion ();
  1206. AFD_FREE_POOL (TransportInfo, AFD_TRANSPORT_INFO_POOL_TAG);
  1207. }