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.

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