summaryrefslogtreecommitdiffstats
path: root/private/ntos/afd/blkendp.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/afd/blkendp.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/afd/blkendp.c')
-rw-r--r--private/ntos/afd/blkendp.c1010
1 files changed, 1010 insertions, 0 deletions
diff --git a/private/ntos/afd/blkendp.c b/private/ntos/afd/blkendp.c
new file mode 100644
index 000000000..ceff093ee
--- /dev/null
+++ b/private/ntos/afd/blkendp.c
@@ -0,0 +1,1010 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ blkendp.c
+
+Abstract:
+
+ This module contains allocate, free, close, reference, and dereference
+ routines for AFD endpoints.
+
+Author:
+
+ David Treadwell (davidtr) 10-Mar-1992
+
+Revision History:
+
+--*/
+
+#include "afdp.h"
+
+VOID
+AfdFreeEndpoint (
+ IN PVOID Context
+ );
+
+PAFD_TRANSPORT_INFO
+AfdGetTransportInfo (
+ IN PUNICODE_STRING TransportDeviceName
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text( PAGE, AfdAllocateEndpoint )
+#pragma alloc_text( PAGE, AfdCloseEndpoint )
+#pragma alloc_text( PAGE, AfdFreeEndpoint )
+#pragma alloc_text( PAGE, AfdGetTransportInfo )
+#pragma alloc_text( PAGE, AfdRefreshEndpoint )
+#pragma alloc_text( PAGEAFD, AfdDereferenceEndpoint )
+#if REFERENCE_DEBUG
+#pragma alloc_text( PAGEAFD, AfdReferenceEndpoint )
+#endif
+#pragma alloc_text( PAGEAFD, AfdFreeQueuedConnections )
+#endif
+
+
+NTSTATUS
+AfdAllocateEndpoint (
+ OUT PAFD_ENDPOINT * NewEndpoint,
+ IN PUNICODE_STRING TransportDeviceName,
+ IN LONG GroupID
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates and initializes a new AFD endpoint structure.
+
+Arguments:
+
+ NewEndpoint - Receives a pointer to the new endpoint structure if
+ successful.
+
+ TransportDeviceName - the name of the TDI transport provider
+ corresponding to the endpoint structure.
+
+ GroupID - Identifies the group ID for the new endpoint.
+
+Return Value:
+
+ NTSTATUS - The completion status.
+
+--*/
+
+{
+ PAFD_ENDPOINT endpoint;
+ PAFD_TRANSPORT_INFO transportInfo;
+ NTSTATUS status;
+ AFD_GROUP_TYPE groupType;
+
+ PAGED_CODE( );
+
+ DEBUG *NewEndpoint = NULL;
+
+ if ( TransportDeviceName != NULL ) {
+ //
+ // First, make sure that the transport device name is stored globally
+ // for AFD. Since there will typically only be a small number of
+ // transport device names, we store the name strings once globally
+ // for access by all endpoints.
+ //
+
+ transportInfo = AfdGetTransportInfo( TransportDeviceName );
+
+ if ( transportInfo == NULL ) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ //
+ // Validate the incoming group ID, allocate a new one if necessary.
+ //
+
+ if( !AfdGetGroup( &GroupID, &groupType ) ) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // Allocate a buffer to hold the endpoint structure.
+ //
+
+ endpoint = AFD_ALLOCATE_POOL(
+ NonPagedPool,
+ sizeof(AFD_ENDPOINT),
+ AFD_ENDPOINT_POOL_TAG
+ );
+
+ if ( endpoint == NULL ) {
+ if( GroupID != 0 ) {
+ AfdDereferenceGroup( GroupID );
+ }
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory( endpoint, sizeof(AFD_ENDPOINT) );
+
+ //
+ // Initialize the reference count to 2--one for the caller's
+ // reference, one for the active reference.
+ //
+
+ endpoint->ReferenceCount = 2;
+
+ //
+ // Initialize the endpoint structure.
+ //
+
+ if ( TransportDeviceName == NULL ) {
+ endpoint->Type = AfdBlockTypeHelper;
+ endpoint->State = AfdEndpointStateInvalid;
+ endpoint->EndpointType = AfdEndpointTypeUnknown;
+ } else {
+ endpoint->Type = AfdBlockTypeEndpoint;
+ endpoint->State = AfdEndpointStateOpen;
+ endpoint->TransportInfo = transportInfo;
+ }
+
+ endpoint->GroupID = GroupID;
+ endpoint->GroupType = groupType;
+
+ KeInitializeSpinLock( &endpoint->SpinLock );
+
+#if REFERENCE_DEBUG
+ {
+ PAFD_REFERENCE_DEBUG referenceDebug;
+
+ referenceDebug = AFD_ALLOCATE_POOL(
+ NonPagedPool,
+ sizeof(AFD_REFERENCE_DEBUG) * MAX_REFERENCE,
+ AFD_DEBUG_POOL_TAG
+ );
+
+ if ( referenceDebug != NULL ) {
+ RtlZeroMemory( referenceDebug, sizeof(AFD_REFERENCE_DEBUG) * MAX_REFERENCE );
+ }
+
+ endpoint->CurrentReferenceSlot = -1;
+ endpoint->ReferenceDebug = referenceDebug;
+ }
+#endif
+
+#if DBG
+ InitializeListHead( &endpoint->OutstandingIrpListHead );
+#endif
+
+ //
+ // Remember the process which opened the endpoint. We'll use this to
+ // charge quota to the process as necessary. Reference the process
+ // so that it does not go away until we have returned all charged
+ // quota to the process.
+ //
+
+ endpoint->OwningProcess = IoGetCurrentProcess( );
+
+ ObReferenceObject(endpoint->OwningProcess);
+
+ //
+ // Insert the endpoint on the global list.
+ //
+
+ AfdInsertNewEndpointInList( endpoint );
+
+ //
+ // Return a pointer to the new endpoint to the caller.
+ //
+
+ IF_DEBUG(ENDPOINT) {
+ KdPrint(( "AfdAllocateEndpoint: new endpoint at %lx\n", endpoint ));
+ }
+
+ *NewEndpoint = endpoint;
+ return STATUS_SUCCESS;
+
+} // AfdAllocateEndpoint
+
+
+VOID
+AfdCloseEndpoint (
+ IN PAFD_ENDPOINT Endpoint
+ )
+
+/*++
+
+Routine Description:
+
+ Initiates the closing of an AFD endpoint structure.
+
+Arguments:
+
+ Endpoint - a pointer to the AFD endpoint structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PAFD_CONNECTION connection;
+
+ PAGED_CODE( );
+
+ IF_DEBUG(ENDPOINT) {
+ KdPrint(( "AfdCloseEndpoint: closing endpoint at %lx\n", Endpoint ));
+ }
+
+ if ( Endpoint->State == AfdEndpointStateClosing ) {
+ return;
+ }
+
+ //
+ // Set the state of the endpoint to closing and dereference to
+ // get rid of the active reference.
+ //
+
+ Endpoint->State = AfdEndpointStateClosing;
+
+ //
+ // If there is a connection on this endpoint, dereference it here
+ // rather than in AfdDereferenceEndpoint, because the connection
+ // has a referenced pointer to the endpoint which must be removed
+ // before the endpoint can dereference the connection.
+ //
+
+ connection = AFD_CONNECTION_FROM_ENDPOINT( Endpoint );
+ if ( connection != NULL ) {
+ DEREFERENCE_CONNECTION( Endpoint->Common.VcConnecting.Connection );
+ }
+
+ //
+ // Dereference the endpoint to get rid of the active reference.
+ // This will result in the endpoint storage being freed as soon
+ // as all other references go away.
+ //
+
+ DEREFERENCE_ENDPOINT( Endpoint );
+
+} // AfdCloseEndpoint
+
+
+VOID
+AfdFreeQueuedConnections (
+ IN PAFD_ENDPOINT Endpoint
+ )
+
+/*++
+
+Routine Description:
+
+ Frees queued connection objects on a listening AFD endpoint.
+
+Arguments:
+
+ Endpoint - a pointer to the AFD endpoint structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ KIRQL oldIrql;
+ PAFD_CONNECTION connection;
+ NTSTATUS status;
+
+ ASSERT( Endpoint->Type == AfdBlockTypeVcListening );
+
+ //
+ // Free the unaccepted connections.
+ //
+ // We must hold AfdSpinLock to call AfdGetUnacceptedConnection,
+ // but we may not hold it when calling AfdDereferenceConnection.
+ //
+
+ AfdAcquireSpinLock( &AfdSpinLock, &oldIrql );
+
+ while ( (connection = AfdGetUnacceptedConnection( Endpoint )) != NULL ) {
+
+ ASSERT( connection->Endpoint == Endpoint );
+ AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
+ AfdAbortConnection( connection );
+ AfdAcquireSpinLock( &AfdSpinLock, &oldIrql );
+
+ }
+
+ AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
+
+ //
+ // Free the returned connections.
+ //
+
+ while ( (connection = AfdGetReturnedConnection( Endpoint, 0 )) != NULL ) {
+
+ ASSERT( connection->Endpoint == Endpoint );
+ AfdAbortConnection( connection );
+
+ }
+
+ //
+ // And finally, purge the free connection queue.
+ //
+
+ while ( (connection = AfdGetFreeConnection( Endpoint )) != NULL ) {
+
+ ASSERT( connection->Endpoint == NULL );
+ DEREFERENCE_CONNECTION( connection );
+
+ }
+
+ return;
+
+} // AfdFreeQueuedConnections
+
+
+VOID
+AfdFreeEndpoint (
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ Does the actual work to deallocate an AFD endpoint structure and
+ associated structures. Note that all other references to the
+ endpoint structure must be gone before this routine is called, since
+ it frees the endpoint and assumes that nobody else will be looking
+ at the endpoint.
+
+Arguments:
+
+ Context - Actually points to the endpoint's embedded AFD_WORK_ITEM
+ structure. From this we can determine the endpoint to free.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NTSTATUS status;
+ PAFD_ENDPOINT endpoint;
+ PLIST_ENTRY listEntry;
+ PAFD_CONNECTION connection;
+
+ PAGED_CODE( );
+
+ ASSERT( Context != NULL );
+
+ endpoint = CONTAINING_RECORD(
+ Context,
+ AFD_ENDPOINT,
+ WorkItem
+ );
+
+ ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
+ ASSERT( endpoint->ReferenceCount == 0 );
+ ASSERT( endpoint->State == AfdEndpointStateClosing );
+ ASSERT( endpoint->ObReferenceBias == 0 );
+ ASSERT( KeGetCurrentIrql( ) == 0 );
+
+ //
+ // If this is a listening endpoint, then purge the endpoint of all
+ // queued connections.
+ //
+
+ if ( endpoint->Type == AfdBlockTypeVcListening ) {
+
+ AfdFreeQueuedConnections( endpoint );
+
+ }
+
+ //
+ // Dereference any group ID associated with this endpoint.
+ //
+
+ if( endpoint->GroupID != 0 ) {
+
+ AfdDereferenceGroup( endpoint->GroupID );
+
+ }
+
+ //
+ // If we set up an owning process for the endpoint, dereference the
+ // process.
+ //
+
+ if ( endpoint->OwningProcess != NULL ) {
+ ObDereferenceObject( endpoint->OwningProcess );
+ endpoint->OwningProcess = NULL;
+ }
+
+ //
+ // If this is a bufferring datagram endpoint, remove all the
+ // bufferred datagrams from the endpoint's list and free them.
+ //
+
+ if ( endpoint->Type == AfdBlockTypeDatagram &&
+ endpoint->ReceiveDatagramBufferListHead.Flink != NULL ) {
+
+ while ( !IsListEmpty( &endpoint->ReceiveDatagramBufferListHead ) ) {
+
+ PAFD_BUFFER afdBuffer;
+
+ listEntry = RemoveHeadList( &endpoint->ReceiveDatagramBufferListHead );
+ afdBuffer = CONTAINING_RECORD( listEntry, AFD_BUFFER, BufferListEntry );
+
+ AfdReturnBuffer( afdBuffer );
+ }
+ }
+
+ //
+ // Close and dereference the TDI address object on the endpoint, if
+ // any.
+ //
+
+ if ( endpoint->AddressFileObject != NULL ) {
+ ObDereferenceObject( endpoint->AddressFileObject );
+ endpoint->AddressFileObject = NULL;
+ AfdRecordAddrDeref();
+ }
+
+ if ( endpoint->AddressHandle != NULL ) {
+ KeAttachProcess( AfdSystemProcess );
+ status = ZwClose( endpoint->AddressHandle );
+ ASSERT( NT_SUCCESS(status) );
+ KeDetachProcess( );
+ endpoint->AddressHandle = NULL;
+ AfdRecordAddrClosed();
+ }
+
+ //
+ // Remove the endpoint from the global list. Do this before any
+ // deallocations to prevent someone else from seeing an endpoint in
+ // an invalid state.
+ //
+
+ AfdRemoveEndpointFromList( endpoint );
+
+ //
+ // Dereference the listening endpoint on the endpoint, if
+ // any.
+ //
+
+ if ( endpoint->Type == AfdBlockTypeVcConnecting &&
+ endpoint->Common.VcConnecting.ListenEndpoint != NULL ) {
+ ASSERT( endpoint->Common.VcConnecting.ListenEndpoint->Type == AfdBlockTypeVcListening );
+ DEREFERENCE_ENDPOINT( endpoint->Common.VcConnecting.ListenEndpoint );
+ endpoint->Common.VcConnecting.ListenEndpoint = NULL;
+ }
+
+ //
+ // Free local and remote address buffers.
+ //
+
+ if ( endpoint->LocalAddress != NULL ) {
+ AFD_FREE_POOL(
+ endpoint->LocalAddress,
+ AFD_LOCAL_ADDRESS_POOL_TAG
+ );
+ endpoint->LocalAddress = NULL;
+ }
+
+ if ( endpoint->Type == AfdBlockTypeDatagram &&
+ endpoint->Common.Datagram.RemoteAddress != NULL ) {
+ AFD_FREE_POOL(
+ endpoint->Common.Datagram.RemoteAddress,
+ AFD_REMOTE_ADDRESS_POOL_TAG
+ );
+ endpoint->Common.Datagram.RemoteAddress = NULL;
+ }
+
+ //
+ // Free context and connect data buffers.
+ //
+
+ if ( endpoint->Context != NULL ) {
+
+ AFD_FREE_POOL(
+ endpoint->Context,
+ AFD_CONTEXT_POOL_TAG
+ );
+ endpoint->Context = NULL;
+
+ }
+
+ if ( endpoint->ConnectDataBuffers != NULL ) {
+ AfdFreeConnectDataBuffers( endpoint->ConnectDataBuffers );
+ }
+
+ //
+ // If there's an active EventSelect() on this endpoint, dereference
+ // the associated event object.
+ //
+
+ if( endpoint->EventObject != NULL ) {
+ ObDereferenceObject( endpoint->EventObject );
+ endpoint->EventObject = NULL;
+ }
+
+ //
+ // Free any reusable TransmitFile info attached to the endpoint.
+ //
+
+ if( endpoint->TransmitInfo != NULL ) {
+
+ AFD_FREE_POOL(
+ endpoint->TransmitInfo,
+ AFD_TRANSMIT_INFO_POOL_TAG
+ );
+
+ }
+
+ //
+ // Free the space that holds the endpoint itself.
+ //
+
+ IF_DEBUG(ENDPOINT) {
+ KdPrint(( "AfdFreeEndpoint: freeing endpoint at %lx\n", endpoint ));
+ }
+
+ endpoint->Type = 0xAFDE;
+
+#if REFERENCE_DEBUG
+ if ( endpoint->ReferenceDebug != NULL ) {
+ AFD_FREE_POOL(
+ endpoint->ReferenceDebug,
+ AFD_DEBUG_POOL_TAG
+ );
+ }
+#endif
+
+ //
+ // Free the pool used for the endpoint itself.
+ //
+
+ AFD_FREE_POOL(
+ endpoint,
+ AFD_ENDPOINT_POOL_TAG
+ );
+
+} // AfdFreeEndpoint
+
+
+#if REFERENCE_DEBUG
+VOID
+AfdDereferenceEndpoint (
+ IN PAFD_ENDPOINT Endpoint,
+ IN PVOID Info1,
+ IN PVOID Info2
+ )
+#else
+VOID
+AfdDereferenceEndpoint (
+ IN PAFD_ENDPOINT Endpoint
+ )
+#endif
+
+/*++
+
+Routine Description:
+
+ Dereferences an AFD endpoint and calls the routine to free it if
+ appropriate.
+
+Arguments:
+
+ Endpoint - a pointer to the AFD endpoint structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LONG result;
+ KIRQL oldIrql;
+
+#if REFERENCE_DEBUG
+ PAFD_REFERENCE_DEBUG slot;
+ LONG newSlot;
+#endif
+
+#if REFERENCE_DEBUG
+ IF_DEBUG(ENDPOINT) {
+ KdPrint(( "AfdDereferenceEndpoint: endpoint at %lx, new refcnt %ld\n",
+ Endpoint, Endpoint->ReferenceCount-1 ));
+ }
+
+ ASSERT( IS_AFD_ENDPOINT_TYPE( Endpoint ) );
+ ASSERT( Endpoint->ReferenceCount > 0 );
+ ASSERT( Endpoint->ReferenceCount != 0xDAADF00D );
+
+ if ( Endpoint->ReferenceDebug != NULL ) {
+ newSlot = InterlockedIncrement( &Endpoint->CurrentReferenceSlot );
+ slot = &Endpoint->ReferenceDebug[newSlot % MAX_REFERENCE];
+
+ slot->Action = 0xFFFFFFFF;
+ slot->NewCount = Endpoint->ReferenceCount - 1;
+ slot->Info1 = Info1;
+ slot->Info2 = Info2;
+ }
+
+#endif
+
+ //
+ // We must hold AfdSpinLock while doing the dereference and check
+ // for free. This is because some code makes the assumption that
+ // the endpoint structure will not go away while AfdSpinLock is
+ // held, and that code references the endpoint before releasing
+ // AfdSpinLock. If we did the InterlockedDecrement() without the
+ // lock held, our count may go to zero, that code may reference the
+ // endpoint, and then a double free might occur.
+ //
+ // It is still valuable to use the interlocked routines for
+ // increment and decrement of structures because it allows us to
+ // avoid having to hold the spin lock for a reference.
+ //
+
+ AfdAcquireSpinLock( &AfdSpinLock, &oldIrql );
+
+ //
+ // Decrement the reference count; if it is 0, free the endpoint.
+ //
+
+ result = InterlockedDecrement( &Endpoint->ReferenceCount );
+
+ AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
+
+ if ( result == 0 ) {
+
+ ASSERT( Endpoint->State == AfdEndpointStateClosing );
+
+ //
+ // We're going to do this by queueing a request to an executive
+ // worker thread. We do this for several reasons: to ensure
+ // that we're at IRQL 0 so we can free pageable memory, and to
+ // ensure that we're in a legitimate context for a close
+ // operation.
+ //
+
+ AfdQueueWorkItem(
+ AfdFreeEndpoint,
+ &Endpoint->WorkItem
+ );
+
+ }
+
+} // AfdDereferenceEndpoint
+
+#if REFERENCE_DEBUG
+
+VOID
+AfdReferenceEndpoint (
+ IN PAFD_ENDPOINT Endpoint,
+ IN PVOID Info1,
+ IN PVOID Info2
+ )
+
+/*++
+
+Routine Description:
+
+ References an AFD endpoint.
+
+Arguments:
+
+ Endpoint - a pointer to the AFD endpoint structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PAFD_REFERENCE_DEBUG slot;
+ LONG newSlot;
+ LONG result;
+
+ ASSERT( Endpoint->ReferenceCount > 0 );
+
+ if( Endpoint->ReferenceDebug != NULL ) {
+ newSlot = InterlockedIncrement( &Endpoint->CurrentReferenceSlot );
+ slot = &Endpoint->ReferenceDebug[newSlot % MAX_REFERENCE];
+
+ slot->Action = 1;
+ slot->NewCount = Endpoint->ReferenceCount + 1;
+ slot->Info1 = Info1;
+ slot->Info2 = Info2;
+ }
+
+ IF_DEBUG(ENDPOINT) {
+ KdPrint(( "AfdReferenceEndpoint: endpoint at %lx, new refcnt %ld\n",
+ Endpoint, Endpoint->ReferenceCount+1 ));
+ }
+
+ ASSERT( Endpoint->ReferenceCount < 0xFFFF );
+
+ result = InterlockedIncrement( &Endpoint->ReferenceCount );
+
+} // AfdReferenceEndpoint
+#endif
+
+
+VOID
+AfdRefreshEndpoint (
+ IN PAFD_ENDPOINT Endpoint
+ )
+
+/*++
+
+Routine Description:
+
+ Prepares an AFD endpoint structure to be reused. All other
+ references to the endpoint must be freed before this routine is
+ called, since this routine assumes that nobody will access the old
+ information in the endpoint structure.
+
+Arguments:
+
+ Endpoint - a pointer to the AFD endpoint structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NTSTATUS status;
+
+ PAGED_CODE( );
+
+ //
+ // This routine must be called at low IRQL. At initial
+ // implementation, it is only called through AfdFreeConnection in an
+ // executive worker thread.
+ //
+
+ ASSERT( Endpoint->Type == AfdBlockTypeVcConnecting );
+ ASSERT( Endpoint->Common.VcConnecting.Connection == NULL );
+ ASSERT( KeGetCurrentIrql( ) < DISPATCH_LEVEL );
+
+ //
+ // Dereference the listening endpoint and its address object.
+ //
+
+ if ( Endpoint->Common.VcConnecting.ListenEndpoint != NULL ) {
+ DEREFERENCE_ENDPOINT( Endpoint->Common.VcConnecting.ListenEndpoint );
+ Endpoint->Common.VcConnecting.ListenEndpoint = NULL;
+ }
+
+ //
+ // Close and dereference the TDI address object on the endpoint, if
+ // any.
+ //
+
+ if ( Endpoint->AddressFileObject != NULL ) {
+ ObDereferenceObject( Endpoint->AddressFileObject );
+ Endpoint->AddressFileObject = NULL;
+ AfdRecordAddrDeref();
+ }
+
+ if ( Endpoint->AddressHandle != NULL ) {
+ KeAttachProcess( AfdSystemProcess );
+ status = ZwClose( Endpoint->AddressHandle );
+ ASSERT( NT_SUCCESS(status) );
+ KeDetachProcess( );
+ Endpoint->AddressHandle = NULL;
+ AfdRecordAddrClosed();
+ }
+
+ //
+ // Reinitialize the endpoint structure.
+ //
+
+ Endpoint->Type = AfdBlockTypeEndpoint;
+ Endpoint->State = AfdEndpointStateOpen;
+ Endpoint->DisconnectMode = 0;
+ Endpoint->PollCalled = FALSE;
+
+ return;
+
+} // AfdRefreshEndpoint
+
+
+PAFD_TRANSPORT_INFO
+AfdGetTransportInfo (
+ IN PUNICODE_STRING TransportDeviceName
+ )
+
+/*++
+
+Routine Description:
+
+ Returns a transport information structure corresponding to the
+ specified TDI transport provider. Each unique transport string gets
+ a single provider structure, so that multiple endpoints for the same
+ transport share the same transport information structure.
+
+Arguments:
+
+ TransportDeviceName - the name of the TDI transport provider.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY listEntry;
+ PAFD_TRANSPORT_INFO transportInfo;
+ ULONG structureLength;
+ NTSTATUS status;
+ HANDLE controlChannel;
+ OBJECT_ATTRIBUTES objectAttributes;
+ IO_STATUS_BLOCK iosb;
+ TDI_REQUEST_KERNEL_QUERY_INFORMATION kernelQueryInfo;
+
+ PAGED_CODE( );
+
+ //
+ // First walk the list of transport device names looking for an
+ // identical name.
+ //
+
+ ExAcquireResourceExclusive( AfdResource, TRUE );
+
+ for ( listEntry = AfdTransportInfoListHead.Flink;
+ listEntry != &AfdTransportInfoListHead;
+ listEntry = listEntry->Flink ) {
+
+ transportInfo = CONTAINING_RECORD(
+ listEntry,
+ AFD_TRANSPORT_INFO,
+ TransportInfoListEntry
+ );
+
+ if ( RtlCompareUnicodeString(
+ &transportInfo->TransportDeviceName,
+ TransportDeviceName,
+ TRUE ) == 0 ) {
+
+ //
+ // We found an exact match. Return a pointer to the
+ // UNICODE_STRING field of this structure.
+ //
+
+ ExReleaseResource( AfdResource );
+ return transportInfo;
+ }
+ }
+
+ //
+ // There were no matches, so this is a new transport device name
+ // which we've never seen before. Allocate a structure to hold the
+ // new name and place the name on the global list.
+ //
+
+
+ structureLength = sizeof(AFD_TRANSPORT_INFO) +
+ TransportDeviceName->Length + sizeof(WCHAR);
+
+ transportInfo = AFD_ALLOCATE_POOL(
+ NonPagedPool,
+ structureLength,
+ AFD_TRANSPORT_INFO_POOL_TAG
+ );
+
+ if ( transportInfo == NULL ) {
+ ExReleaseResource( AfdResource );
+ return NULL;
+ }
+
+ //
+ // Set up the IRP stack location information to query the TDI
+ // provider information.
+ //
+
+ kernelQueryInfo.QueryType = TDI_QUERY_PROVIDER_INFORMATION;
+ kernelQueryInfo.RequestConnectionInformation = NULL;
+
+ //
+ // Open a control channel to the TDI provider.
+ //
+
+ InitializeObjectAttributes(
+ &objectAttributes,
+ TransportDeviceName,
+ OBJ_CASE_INSENSITIVE, // attributes
+ NULL,
+ NULL
+ );
+
+ status = ZwCreateFile(
+ &controlChannel,
+ GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
+ &objectAttributes,
+ &iosb, // returned status information.
+ 0, // block size (unused).
+ 0, // file attributes.
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_CREATE, // create disposition.
+ 0, // create options.
+ NULL,
+ 0
+ );
+ if ( !NT_SUCCESS(status) ) {
+ ExReleaseResource( AfdResource );
+ AFD_FREE_POOL(
+ transportInfo,
+ AFD_TRANSPORT_INFO_POOL_TAG
+ );
+ return NULL;
+ }
+
+ //
+ // Get the TDI provider information for the transport.
+ //
+
+ status = AfdIssueDeviceControl(
+ controlChannel,
+ NULL,
+ &kernelQueryInfo,
+ sizeof(kernelQueryInfo),
+ &transportInfo->ProviderInfo,
+ sizeof(transportInfo->ProviderInfo),
+ TDI_QUERY_INFORMATION
+ );
+ if ( !NT_SUCCESS(status) ) {
+ ExReleaseResource( AfdResource );
+ AFD_FREE_POOL(
+ transportInfo,
+ AFD_TRANSPORT_INFO_POOL_TAG
+ );
+ ZwClose( controlChannel );
+ return NULL;
+ }
+
+ //
+ // Fill in the transport device name.
+ //
+
+ transportInfo->TransportDeviceName.MaximumLength =
+ TransportDeviceName->Length + sizeof(WCHAR);
+ transportInfo->TransportDeviceName.Buffer =
+ (PWSTR)(transportInfo + 1);
+
+ RtlCopyUnicodeString(
+ &transportInfo->TransportDeviceName,
+ TransportDeviceName
+ );
+
+ //
+ // Place the transport info structure on the global list.
+ //
+
+ InsertTailList(
+ &AfdTransportInfoListHead,
+ &transportInfo->TransportInfoListEntry
+ );
+
+ //
+ // Return the transport info structure to the caller.
+ //
+
+ ExReleaseResource( AfdResource );
+ ZwClose( controlChannel );
+
+ return transportInfo;
+
+} // AfdGetTransportInfo