Windows NT 4.0 source code leak
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.

1010 lines
24 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1992 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. --*/
  12. #include "afdp.h"
  13. VOID
  14. AfdFreeEndpoint (
  15. IN PVOID Context
  16. );
  17. PAFD_TRANSPORT_INFO
  18. AfdGetTransportInfo (
  19. IN PUNICODE_STRING TransportDeviceName
  20. );
  21. #ifdef ALLOC_PRAGMA
  22. #pragma alloc_text( PAGE, AfdAllocateEndpoint )
  23. #pragma alloc_text( PAGE, AfdCloseEndpoint )
  24. #pragma alloc_text( PAGE, AfdFreeEndpoint )
  25. #pragma alloc_text( PAGE, AfdGetTransportInfo )
  26. #pragma alloc_text( PAGE, AfdRefreshEndpoint )
  27. #pragma alloc_text( PAGEAFD, AfdDereferenceEndpoint )
  28. #if REFERENCE_DEBUG
  29. #pragma alloc_text( PAGEAFD, AfdReferenceEndpoint )
  30. #endif
  31. #pragma alloc_text( PAGEAFD, AfdFreeQueuedConnections )
  32. #endif
  33. NTSTATUS
  34. AfdAllocateEndpoint (
  35. OUT PAFD_ENDPOINT * NewEndpoint,
  36. IN PUNICODE_STRING TransportDeviceName,
  37. IN LONG GroupID
  38. )
  39. /*++
  40. Routine Description:
  41. Allocates and initializes a new AFD endpoint structure.
  42. Arguments:
  43. NewEndpoint - Receives a pointer to the new endpoint structure if
  44. successful.
  45. TransportDeviceName - the name of the TDI transport provider
  46. corresponding to the endpoint structure.
  47. GroupID - Identifies the group ID for the new endpoint.
  48. Return Value:
  49. NTSTATUS - The completion status.
  50. --*/
  51. {
  52. PAFD_ENDPOINT endpoint;
  53. PAFD_TRANSPORT_INFO transportInfo;
  54. NTSTATUS status;
  55. AFD_GROUP_TYPE groupType;
  56. PAGED_CODE( );
  57. DEBUG *NewEndpoint = NULL;
  58. if ( TransportDeviceName != NULL ) {
  59. //
  60. // First, make sure that the transport device name is stored globally
  61. // for AFD. Since there will typically only be a small number of
  62. // transport device names, we store the name strings once globally
  63. // for access by all endpoints.
  64. //
  65. transportInfo = AfdGetTransportInfo( TransportDeviceName );
  66. if ( transportInfo == NULL ) {
  67. return STATUS_INSUFFICIENT_RESOURCES;
  68. }
  69. }
  70. //
  71. // Validate the incoming group ID, allocate a new one if necessary.
  72. //
  73. if( !AfdGetGroup( &GroupID, &groupType ) ) {
  74. return STATUS_INVALID_PARAMETER;
  75. }
  76. //
  77. // Allocate a buffer to hold the endpoint structure.
  78. //
  79. endpoint = AFD_ALLOCATE_POOL(
  80. NonPagedPool,
  81. sizeof(AFD_ENDPOINT),
  82. AFD_ENDPOINT_POOL_TAG
  83. );
  84. if ( endpoint == NULL ) {
  85. if( GroupID != 0 ) {
  86. AfdDereferenceGroup( GroupID );
  87. }
  88. return STATUS_INSUFFICIENT_RESOURCES;
  89. }
  90. RtlZeroMemory( endpoint, sizeof(AFD_ENDPOINT) );
  91. //
  92. // Initialize the reference count to 2--one for the caller's
  93. // reference, one for the active reference.
  94. //
  95. endpoint->ReferenceCount = 2;
  96. //
  97. // Initialize the endpoint structure.
  98. //
  99. if ( TransportDeviceName == NULL ) {
  100. endpoint->Type = AfdBlockTypeHelper;
  101. endpoint->State = AfdEndpointStateInvalid;
  102. endpoint->EndpointType = AfdEndpointTypeUnknown;
  103. } else {
  104. endpoint->Type = AfdBlockTypeEndpoint;
  105. endpoint->State = AfdEndpointStateOpen;
  106. endpoint->TransportInfo = transportInfo;
  107. }
  108. endpoint->GroupID = GroupID;
  109. endpoint->GroupType = groupType;
  110. KeInitializeSpinLock( &endpoint->SpinLock );
  111. #if REFERENCE_DEBUG
  112. {
  113. PAFD_REFERENCE_DEBUG referenceDebug;
  114. referenceDebug = AFD_ALLOCATE_POOL(
  115. NonPagedPool,
  116. sizeof(AFD_REFERENCE_DEBUG) * MAX_REFERENCE,
  117. AFD_DEBUG_POOL_TAG
  118. );
  119. if ( referenceDebug != NULL ) {
  120. RtlZeroMemory( referenceDebug, sizeof(AFD_REFERENCE_DEBUG) * MAX_REFERENCE );
  121. }
  122. endpoint->CurrentReferenceSlot = -1;
  123. endpoint->ReferenceDebug = referenceDebug;
  124. }
  125. #endif
  126. #if DBG
  127. InitializeListHead( &endpoint->OutstandingIrpListHead );
  128. #endif
  129. //
  130. // Remember the process which opened the endpoint. We'll use this to
  131. // charge quota to the process as necessary. Reference the process
  132. // so that it does not go away until we have returned all charged
  133. // quota to the process.
  134. //
  135. endpoint->OwningProcess = IoGetCurrentProcess( );
  136. ObReferenceObject(endpoint->OwningProcess);
  137. //
  138. // Insert the endpoint on the global list.
  139. //
  140. AfdInsertNewEndpointInList( endpoint );
  141. //
  142. // Return a pointer to the new endpoint to the caller.
  143. //
  144. IF_DEBUG(ENDPOINT) {
  145. KdPrint(( "AfdAllocateEndpoint: new endpoint at %lx\n", endpoint ));
  146. }
  147. *NewEndpoint = endpoint;
  148. return STATUS_SUCCESS;
  149. } // AfdAllocateEndpoint
  150. VOID
  151. AfdCloseEndpoint (
  152. IN PAFD_ENDPOINT Endpoint
  153. )
  154. /*++
  155. Routine Description:
  156. Initiates the closing of an AFD endpoint structure.
  157. Arguments:
  158. Endpoint - a pointer to the AFD endpoint structure.
  159. Return Value:
  160. None.
  161. --*/
  162. {
  163. PAFD_CONNECTION connection;
  164. PAGED_CODE( );
  165. IF_DEBUG(ENDPOINT) {
  166. KdPrint(( "AfdCloseEndpoint: closing endpoint at %lx\n", Endpoint ));
  167. }
  168. if ( Endpoint->State == AfdEndpointStateClosing ) {
  169. return;
  170. }
  171. //
  172. // Set the state of the endpoint to closing and dereference to
  173. // get rid of the active reference.
  174. //
  175. Endpoint->State = AfdEndpointStateClosing;
  176. //
  177. // If there is a connection on this endpoint, dereference it here
  178. // rather than in AfdDereferenceEndpoint, because the connection
  179. // has a referenced pointer to the endpoint which must be removed
  180. // before the endpoint can dereference the connection.
  181. //
  182. connection = AFD_CONNECTION_FROM_ENDPOINT( Endpoint );
  183. if ( connection != NULL ) {
  184. DEREFERENCE_CONNECTION( Endpoint->Common.VcConnecting.Connection );
  185. }
  186. //
  187. // Dereference the endpoint to get rid of the active reference.
  188. // This will result in the endpoint storage being freed as soon
  189. // as all other references go away.
  190. //
  191. DEREFERENCE_ENDPOINT( Endpoint );
  192. } // AfdCloseEndpoint
  193. VOID
  194. AfdFreeQueuedConnections (
  195. IN PAFD_ENDPOINT Endpoint
  196. )
  197. /*++
  198. Routine Description:
  199. Frees queued connection objects on a listening AFD endpoint.
  200. Arguments:
  201. Endpoint - a pointer to the AFD endpoint structure.
  202. Return Value:
  203. None.
  204. --*/
  205. {
  206. KIRQL oldIrql;
  207. PAFD_CONNECTION connection;
  208. NTSTATUS status;
  209. ASSERT( Endpoint->Type == AfdBlockTypeVcListening );
  210. //
  211. // Free the unaccepted connections.
  212. //
  213. // We must hold AfdSpinLock to call AfdGetUnacceptedConnection,
  214. // but we may not hold it when calling AfdDereferenceConnection.
  215. //
  216. AfdAcquireSpinLock( &AfdSpinLock, &oldIrql );
  217. while ( (connection = AfdGetUnacceptedConnection( Endpoint )) != NULL ) {
  218. ASSERT( connection->Endpoint == Endpoint );
  219. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  220. AfdAbortConnection( connection );
  221. AfdAcquireSpinLock( &AfdSpinLock, &oldIrql );
  222. }
  223. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  224. //
  225. // Free the returned connections.
  226. //
  227. while ( (connection = AfdGetReturnedConnection( Endpoint, 0 )) != NULL ) {
  228. ASSERT( connection->Endpoint == Endpoint );
  229. AfdAbortConnection( connection );
  230. }
  231. //
  232. // And finally, purge the free connection queue.
  233. //
  234. while ( (connection = AfdGetFreeConnection( Endpoint )) != NULL ) {
  235. ASSERT( connection->Endpoint == NULL );
  236. DEREFERENCE_CONNECTION( connection );
  237. }
  238. return;
  239. } // AfdFreeQueuedConnections
  240. VOID
  241. AfdFreeEndpoint (
  242. IN PVOID Context
  243. )
  244. /*++
  245. Routine Description:
  246. Does the actual work to deallocate an AFD endpoint structure and
  247. associated structures. Note that all other references to the
  248. endpoint structure must be gone before this routine is called, since
  249. it frees the endpoint and assumes that nobody else will be looking
  250. at the endpoint.
  251. Arguments:
  252. Context - Actually points to the endpoint's embedded AFD_WORK_ITEM
  253. structure. From this we can determine the endpoint to free.
  254. Return Value:
  255. None.
  256. --*/
  257. {
  258. NTSTATUS status;
  259. PAFD_ENDPOINT endpoint;
  260. PLIST_ENTRY listEntry;
  261. PAFD_CONNECTION connection;
  262. PAGED_CODE( );
  263. ASSERT( Context != NULL );
  264. endpoint = CONTAINING_RECORD(
  265. Context,
  266. AFD_ENDPOINT,
  267. WorkItem
  268. );
  269. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  270. ASSERT( endpoint->ReferenceCount == 0 );
  271. ASSERT( endpoint->State == AfdEndpointStateClosing );
  272. ASSERT( endpoint->ObReferenceBias == 0 );
  273. ASSERT( KeGetCurrentIrql( ) == 0 );
  274. //
  275. // If this is a listening endpoint, then purge the endpoint of all
  276. // queued connections.
  277. //
  278. if ( endpoint->Type == AfdBlockTypeVcListening ) {
  279. AfdFreeQueuedConnections( endpoint );
  280. }
  281. //
  282. // Dereference any group ID associated with this endpoint.
  283. //
  284. if( endpoint->GroupID != 0 ) {
  285. AfdDereferenceGroup( endpoint->GroupID );
  286. }
  287. //
  288. // If we set up an owning process for the endpoint, dereference the
  289. // process.
  290. //
  291. if ( endpoint->OwningProcess != NULL ) {
  292. ObDereferenceObject( endpoint->OwningProcess );
  293. endpoint->OwningProcess = NULL;
  294. }
  295. //
  296. // If this is a bufferring datagram endpoint, remove all the
  297. // bufferred datagrams from the endpoint's list and free them.
  298. //
  299. if ( endpoint->Type == AfdBlockTypeDatagram &&
  300. endpoint->ReceiveDatagramBufferListHead.Flink != NULL ) {
  301. while ( !IsListEmpty( &endpoint->ReceiveDatagramBufferListHead ) ) {
  302. PAFD_BUFFER afdBuffer;
  303. listEntry = RemoveHeadList( &endpoint->ReceiveDatagramBufferListHead );
  304. afdBuffer = CONTAINING_RECORD( listEntry, AFD_BUFFER, BufferListEntry );
  305. AfdReturnBuffer( afdBuffer );
  306. }
  307. }
  308. //
  309. // Close and dereference the TDI address object on the endpoint, if
  310. // any.
  311. //
  312. if ( endpoint->AddressFileObject != NULL ) {
  313. ObDereferenceObject( endpoint->AddressFileObject );
  314. endpoint->AddressFileObject = NULL;
  315. AfdRecordAddrDeref();
  316. }
  317. if ( endpoint->AddressHandle != NULL ) {
  318. KeAttachProcess( AfdSystemProcess );
  319. status = ZwClose( endpoint->AddressHandle );
  320. ASSERT( NT_SUCCESS(status) );
  321. KeDetachProcess( );
  322. endpoint->AddressHandle = NULL;
  323. AfdRecordAddrClosed();
  324. }
  325. //
  326. // Remove the endpoint from the global list. Do this before any
  327. // deallocations to prevent someone else from seeing an endpoint in
  328. // an invalid state.
  329. //
  330. AfdRemoveEndpointFromList( endpoint );
  331. //
  332. // Dereference the listening endpoint on the endpoint, if
  333. // any.
  334. //
  335. if ( endpoint->Type == AfdBlockTypeVcConnecting &&
  336. endpoint->Common.VcConnecting.ListenEndpoint != NULL ) {
  337. ASSERT( endpoint->Common.VcConnecting.ListenEndpoint->Type == AfdBlockTypeVcListening );
  338. DEREFERENCE_ENDPOINT( endpoint->Common.VcConnecting.ListenEndpoint );
  339. endpoint->Common.VcConnecting.ListenEndpoint = NULL;
  340. }
  341. //
  342. // Free local and remote address buffers.
  343. //
  344. if ( endpoint->LocalAddress != NULL ) {
  345. AFD_FREE_POOL(
  346. endpoint->LocalAddress,
  347. AFD_LOCAL_ADDRESS_POOL_TAG
  348. );
  349. endpoint->LocalAddress = NULL;
  350. }
  351. if ( endpoint->Type == AfdBlockTypeDatagram &&
  352. endpoint->Common.Datagram.RemoteAddress != NULL ) {
  353. AFD_FREE_POOL(
  354. endpoint->Common.Datagram.RemoteAddress,
  355. AFD_REMOTE_ADDRESS_POOL_TAG
  356. );
  357. endpoint->Common.Datagram.RemoteAddress = NULL;
  358. }
  359. //
  360. // Free context and connect data buffers.
  361. //
  362. if ( endpoint->Context != NULL ) {
  363. AFD_FREE_POOL(
  364. endpoint->Context,
  365. AFD_CONTEXT_POOL_TAG
  366. );
  367. endpoint->Context = NULL;
  368. }
  369. if ( endpoint->ConnectDataBuffers != NULL ) {
  370. AfdFreeConnectDataBuffers( endpoint->ConnectDataBuffers );
  371. }
  372. //
  373. // If there's an active EventSelect() on this endpoint, dereference
  374. // the associated event object.
  375. //
  376. if( endpoint->EventObject != NULL ) {
  377. ObDereferenceObject( endpoint->EventObject );
  378. endpoint->EventObject = NULL;
  379. }
  380. //
  381. // Free any reusable TransmitFile info attached to the endpoint.
  382. //
  383. if( endpoint->TransmitInfo != NULL ) {
  384. AFD_FREE_POOL(
  385. endpoint->TransmitInfo,
  386. AFD_TRANSMIT_INFO_POOL_TAG
  387. );
  388. }
  389. //
  390. // Free the space that holds the endpoint itself.
  391. //
  392. IF_DEBUG(ENDPOINT) {
  393. KdPrint(( "AfdFreeEndpoint: freeing endpoint at %lx\n", endpoint ));
  394. }
  395. endpoint->Type = 0xAFDE;
  396. #if REFERENCE_DEBUG
  397. if ( endpoint->ReferenceDebug != NULL ) {
  398. AFD_FREE_POOL(
  399. endpoint->ReferenceDebug,
  400. AFD_DEBUG_POOL_TAG
  401. );
  402. }
  403. #endif
  404. //
  405. // Free the pool used for the endpoint itself.
  406. //
  407. AFD_FREE_POOL(
  408. endpoint,
  409. AFD_ENDPOINT_POOL_TAG
  410. );
  411. } // AfdFreeEndpoint
  412. #if REFERENCE_DEBUG
  413. VOID
  414. AfdDereferenceEndpoint (
  415. IN PAFD_ENDPOINT Endpoint,
  416. IN PVOID Info1,
  417. IN PVOID Info2
  418. )
  419. #else
  420. VOID
  421. AfdDereferenceEndpoint (
  422. IN PAFD_ENDPOINT Endpoint
  423. )
  424. #endif
  425. /*++
  426. Routine Description:
  427. Dereferences an AFD endpoint and calls the routine to free it if
  428. appropriate.
  429. Arguments:
  430. Endpoint - a pointer to the AFD endpoint structure.
  431. Return Value:
  432. None.
  433. --*/
  434. {
  435. LONG result;
  436. KIRQL oldIrql;
  437. #if REFERENCE_DEBUG
  438. PAFD_REFERENCE_DEBUG slot;
  439. LONG newSlot;
  440. #endif
  441. #if REFERENCE_DEBUG
  442. IF_DEBUG(ENDPOINT) {
  443. KdPrint(( "AfdDereferenceEndpoint: endpoint at %lx, new refcnt %ld\n",
  444. Endpoint, Endpoint->ReferenceCount-1 ));
  445. }
  446. ASSERT( IS_AFD_ENDPOINT_TYPE( Endpoint ) );
  447. ASSERT( Endpoint->ReferenceCount > 0 );
  448. ASSERT( Endpoint->ReferenceCount != 0xDAADF00D );
  449. if ( Endpoint->ReferenceDebug != NULL ) {
  450. newSlot = InterlockedIncrement( &Endpoint->CurrentReferenceSlot );
  451. slot = &Endpoint->ReferenceDebug[newSlot % MAX_REFERENCE];
  452. slot->Action = 0xFFFFFFFF;
  453. slot->NewCount = Endpoint->ReferenceCount - 1;
  454. slot->Info1 = Info1;
  455. slot->Info2 = Info2;
  456. }
  457. #endif
  458. //
  459. // We must hold AfdSpinLock while doing the dereference and check
  460. // for free. This is because some code makes the assumption that
  461. // the endpoint structure will not go away while AfdSpinLock is
  462. // held, and that code references the endpoint before releasing
  463. // AfdSpinLock. If we did the InterlockedDecrement() without the
  464. // lock held, our count may go to zero, that code may reference the
  465. // endpoint, and then a double free might occur.
  466. //
  467. // It is still valuable to use the interlocked routines for
  468. // increment and decrement of structures because it allows us to
  469. // avoid having to hold the spin lock for a reference.
  470. //
  471. AfdAcquireSpinLock( &AfdSpinLock, &oldIrql );
  472. //
  473. // Decrement the reference count; if it is 0, free the endpoint.
  474. //
  475. result = InterlockedDecrement( &Endpoint->ReferenceCount );
  476. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  477. if ( result == 0 ) {
  478. ASSERT( Endpoint->State == AfdEndpointStateClosing );
  479. //
  480. // We're going to do this by queueing a request to an executive
  481. // worker thread. We do this for several reasons: to ensure
  482. // that we're at IRQL 0 so we can free pageable memory, and to
  483. // ensure that we're in a legitimate context for a close
  484. // operation.
  485. //
  486. AfdQueueWorkItem(
  487. AfdFreeEndpoint,
  488. &Endpoint->WorkItem
  489. );
  490. }
  491. } // AfdDereferenceEndpoint
  492. #if REFERENCE_DEBUG
  493. VOID
  494. AfdReferenceEndpoint (
  495. IN PAFD_ENDPOINT Endpoint,
  496. IN PVOID Info1,
  497. IN PVOID Info2
  498. )
  499. /*++
  500. Routine Description:
  501. References an AFD endpoint.
  502. Arguments:
  503. Endpoint - a pointer to the AFD endpoint structure.
  504. Return Value:
  505. None.
  506. --*/
  507. {
  508. PAFD_REFERENCE_DEBUG slot;
  509. LONG newSlot;
  510. LONG result;
  511. ASSERT( Endpoint->ReferenceCount > 0 );
  512. if( Endpoint->ReferenceDebug != NULL ) {
  513. newSlot = InterlockedIncrement( &Endpoint->CurrentReferenceSlot );
  514. slot = &Endpoint->ReferenceDebug[newSlot % MAX_REFERENCE];
  515. slot->Action = 1;
  516. slot->NewCount = Endpoint->ReferenceCount + 1;
  517. slot->Info1 = Info1;
  518. slot->Info2 = Info2;
  519. }
  520. IF_DEBUG(ENDPOINT) {
  521. KdPrint(( "AfdReferenceEndpoint: endpoint at %lx, new refcnt %ld\n",
  522. Endpoint, Endpoint->ReferenceCount+1 ));
  523. }
  524. ASSERT( Endpoint->ReferenceCount < 0xFFFF );
  525. result = InterlockedIncrement( &Endpoint->ReferenceCount );
  526. } // AfdReferenceEndpoint
  527. #endif
  528. VOID
  529. AfdRefreshEndpoint (
  530. IN PAFD_ENDPOINT Endpoint
  531. )
  532. /*++
  533. Routine Description:
  534. Prepares an AFD endpoint structure to be reused. All other
  535. references to the endpoint must be freed before this routine is
  536. called, since this routine assumes that nobody will access the old
  537. information in the endpoint structure.
  538. Arguments:
  539. Endpoint - a pointer to the AFD endpoint structure.
  540. Return Value:
  541. None.
  542. --*/
  543. {
  544. NTSTATUS status;
  545. PAGED_CODE( );
  546. //
  547. // This routine must be called at low IRQL. At initial
  548. // implementation, it is only called through AfdFreeConnection in an
  549. // executive worker thread.
  550. //
  551. ASSERT( Endpoint->Type == AfdBlockTypeVcConnecting );
  552. ASSERT( Endpoint->Common.VcConnecting.Connection == NULL );
  553. ASSERT( KeGetCurrentIrql( ) < DISPATCH_LEVEL );
  554. //
  555. // Dereference the listening endpoint and its address object.
  556. //
  557. if ( Endpoint->Common.VcConnecting.ListenEndpoint != NULL ) {
  558. DEREFERENCE_ENDPOINT( Endpoint->Common.VcConnecting.ListenEndpoint );
  559. Endpoint->Common.VcConnecting.ListenEndpoint = NULL;
  560. }
  561. //
  562. // Close and dereference the TDI address object on the endpoint, if
  563. // any.
  564. //
  565. if ( Endpoint->AddressFileObject != NULL ) {
  566. ObDereferenceObject( Endpoint->AddressFileObject );
  567. Endpoint->AddressFileObject = NULL;
  568. AfdRecordAddrDeref();
  569. }
  570. if ( Endpoint->AddressHandle != NULL ) {
  571. KeAttachProcess( AfdSystemProcess );
  572. status = ZwClose( Endpoint->AddressHandle );
  573. ASSERT( NT_SUCCESS(status) );
  574. KeDetachProcess( );
  575. Endpoint->AddressHandle = NULL;
  576. AfdRecordAddrClosed();
  577. }
  578. //
  579. // Reinitialize the endpoint structure.
  580. //
  581. Endpoint->Type = AfdBlockTypeEndpoint;
  582. Endpoint->State = AfdEndpointStateOpen;
  583. Endpoint->DisconnectMode = 0;
  584. Endpoint->PollCalled = FALSE;
  585. return;
  586. } // AfdRefreshEndpoint
  587. PAFD_TRANSPORT_INFO
  588. AfdGetTransportInfo (
  589. IN PUNICODE_STRING TransportDeviceName
  590. )
  591. /*++
  592. Routine Description:
  593. Returns a transport information structure corresponding to the
  594. specified TDI transport provider. Each unique transport string gets
  595. a single provider structure, so that multiple endpoints for the same
  596. transport share the same transport information structure.
  597. Arguments:
  598. TransportDeviceName - the name of the TDI transport provider.
  599. Return Value:
  600. None.
  601. --*/
  602. {
  603. PLIST_ENTRY listEntry;
  604. PAFD_TRANSPORT_INFO transportInfo;
  605. ULONG structureLength;
  606. NTSTATUS status;
  607. HANDLE controlChannel;
  608. OBJECT_ATTRIBUTES objectAttributes;
  609. IO_STATUS_BLOCK iosb;
  610. TDI_REQUEST_KERNEL_QUERY_INFORMATION kernelQueryInfo;
  611. PAGED_CODE( );
  612. //
  613. // First walk the list of transport device names looking for an
  614. // identical name.
  615. //
  616. ExAcquireResourceExclusive( AfdResource, TRUE );
  617. for ( listEntry = AfdTransportInfoListHead.Flink;
  618. listEntry != &AfdTransportInfoListHead;
  619. listEntry = listEntry->Flink ) {
  620. transportInfo = CONTAINING_RECORD(
  621. listEntry,
  622. AFD_TRANSPORT_INFO,
  623. TransportInfoListEntry
  624. );
  625. if ( RtlCompareUnicodeString(
  626. &transportInfo->TransportDeviceName,
  627. TransportDeviceName,
  628. TRUE ) == 0 ) {
  629. //
  630. // We found an exact match. Return a pointer to the
  631. // UNICODE_STRING field of this structure.
  632. //
  633. ExReleaseResource( AfdResource );
  634. return transportInfo;
  635. }
  636. }
  637. //
  638. // There were no matches, so this is a new transport device name
  639. // which we've never seen before. Allocate a structure to hold the
  640. // new name and place the name on the global list.
  641. //
  642. structureLength = sizeof(AFD_TRANSPORT_INFO) +
  643. TransportDeviceName->Length + sizeof(WCHAR);
  644. transportInfo = AFD_ALLOCATE_POOL(
  645. NonPagedPool,
  646. structureLength,
  647. AFD_TRANSPORT_INFO_POOL_TAG
  648. );
  649. if ( transportInfo == NULL ) {
  650. ExReleaseResource( AfdResource );
  651. return NULL;
  652. }
  653. //
  654. // Set up the IRP stack location information to query the TDI
  655. // provider information.
  656. //
  657. kernelQueryInfo.QueryType = TDI_QUERY_PROVIDER_INFORMATION;
  658. kernelQueryInfo.RequestConnectionInformation = NULL;
  659. //
  660. // Open a control channel to the TDI provider.
  661. //
  662. InitializeObjectAttributes(
  663. &objectAttributes,
  664. TransportDeviceName,
  665. OBJ_CASE_INSENSITIVE, // attributes
  666. NULL,
  667. NULL
  668. );
  669. status = ZwCreateFile(
  670. &controlChannel,
  671. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  672. &objectAttributes,
  673. &iosb, // returned status information.
  674. 0, // block size (unused).
  675. 0, // file attributes.
  676. FILE_SHARE_READ | FILE_SHARE_WRITE,
  677. FILE_CREATE, // create disposition.
  678. 0, // create options.
  679. NULL,
  680. 0
  681. );
  682. if ( !NT_SUCCESS(status) ) {
  683. ExReleaseResource( AfdResource );
  684. AFD_FREE_POOL(
  685. transportInfo,
  686. AFD_TRANSPORT_INFO_POOL_TAG
  687. );
  688. return NULL;
  689. }
  690. //
  691. // Get the TDI provider information for the transport.
  692. //
  693. status = AfdIssueDeviceControl(
  694. controlChannel,
  695. NULL,
  696. &kernelQueryInfo,
  697. sizeof(kernelQueryInfo),
  698. &transportInfo->ProviderInfo,
  699. sizeof(transportInfo->ProviderInfo),
  700. TDI_QUERY_INFORMATION
  701. );
  702. if ( !NT_SUCCESS(status) ) {
  703. ExReleaseResource( AfdResource );
  704. AFD_FREE_POOL(
  705. transportInfo,
  706. AFD_TRANSPORT_INFO_POOL_TAG
  707. );
  708. ZwClose( controlChannel );
  709. return NULL;
  710. }
  711. //
  712. // Fill in the transport device name.
  713. //
  714. transportInfo->TransportDeviceName.MaximumLength =
  715. TransportDeviceName->Length + sizeof(WCHAR);
  716. transportInfo->TransportDeviceName.Buffer =
  717. (PWSTR)(transportInfo + 1);
  718. RtlCopyUnicodeString(
  719. &transportInfo->TransportDeviceName,
  720. TransportDeviceName
  721. );
  722. //
  723. // Place the transport info structure on the global list.
  724. //
  725. InsertTailList(
  726. &AfdTransportInfoListHead,
  727. &transportInfo->TransportInfoListEntry
  728. );
  729. //
  730. // Return the transport info structure to the caller.
  731. //
  732. ExReleaseResource( AfdResource );
  733. ZwClose( controlChannel );
  734. return transportInfo;
  735. } // AfdGetTransportInfo