|
|
/*++
Copyright (c) 1989-1999 Microsoft Corporation
Module Name:
connect.c
Abstract:
This module contains the code for passing on connect IRPs to TDI providers.
Author:
David Treadwell (davidtr) 2-Mar-1992
Revision History:
Vadim Eydelman (vadime) 1999 JoinLeaf implementation Datagram connect via transport Connect optimizations and syncronization with user mode code.
--*/
#include "afdp.h"
NTSTATUS AfdDoDatagramConnect ( IN PFILE_OBJECT FileObject, IN PIRP Irp, IN BOOLEAN HalfConnect );
NTSTATUS AfdRestartConnect ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context );
NTSTATUS AfdRestartDgConnect ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context );
VOID AfdSetupConnectDataBuffers ( IN PAFD_ENDPOINT Endpoint, IN PAFD_CONNECTION Connection, IN OUT PTDI_CONNECTION_INFORMATION *RequestConnectionInformation, IN OUT PTDI_CONNECTION_INFORMATION *ReturnConnectionInformation );
BOOLEAN AfdConnectionStart ( IN PAFD_ENDPOINT Endpoint );
VOID AfdEnableFailedConnectEvent( IN PAFD_ENDPOINT Endpoint );
NTSTATUS AfdRestartJoin ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context );
VOID AfdJoinInviteSetup ( PAFD_ENDPOINT RootEndpoint, PAFD_ENDPOINT LeafEndpoint );
VOID AfdConnectApcKernelRoutine ( IN struct _KAPC *Apc, IN OUT PKNORMAL_ROUTINE *NormalRoutine, IN OUT PVOID *NormalContext, IN OUT PVOID *SystemArgument1, IN OUT PVOID *SystemArgument2 );
VOID AfdConnectApcRundownRoutine ( IN struct _KAPC *Apc );
VOID AfdFinishConnect ( PAFD_ENDPOINT Endpoint, PIRP Irp, PAFD_ENDPOINT RootEndpoint );
NTSTATUS AfdRestartSuperConnect ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context );
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, AfdConnect )
#pragma alloc_text( PAGEAFD, AfdDoDatagramConnect )
#pragma alloc_text( PAGEAFD, AfdRestartConnect )
#pragma alloc_text( PAGEAFD, AfdRestartDgConnect )
#pragma alloc_text( PAGEAFD, AfdSetupConnectDataBuffers )
#pragma alloc_text( PAGEAFD, AfdEnableFailedConnectEvent )
#pragma alloc_text( PAGE, AfdJoinLeaf )
#pragma alloc_text( PAGEAFD, AfdRestartJoin )
#pragma alloc_text( PAGEAFD, AfdJoinInviteSetup )
#pragma alloc_text( PAGE, AfdConnectApcKernelRoutine )
#pragma alloc_text( PAGE, AfdConnectApcRundownRoutine )
#pragma alloc_text( PAGEAFD, AfdFinishConnect )
#pragma alloc_text( PAGE, AfdSuperConnect )
#pragma alloc_text( PAGEAFD, AfdRestartSuperConnect )
#endif
typedef struct _AFD_CONNECT_CONTEXT { TDI_CONNECTION_INFORMATION RequestConnectionInfo; TDI_CONNECTION_INFORMATION ReturnConnectionInfo; TRANSPORT_ADDRESS RemoteAddress; } AFD_CONNECT_CONTEXT, *PAFD_CONNECT_CONTEXT;
C_ASSERT ( (FIELD_OFFSET (AFD_CONNECTION, SListEntry) % MEMORY_ALLOCATION_ALIGNMENT) == 0 );
NTSTATUS FASTCALL AfdConnect ( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp )
/*++
Routine Description:
Handles the IOCTL_AFD_CONNECT IOCTL.
Arguments:
Irp - Pointer to I/O request packet.
IrpSp - pointer to the IO stack location to use for this request.
Return Value:
NTSTATUS -- Indicates whether the request was successfully queued.
--*/
{ NTSTATUS status; PAFD_ENDPOINT endpoint; PAFD_CONNECTION connection; PAFD_CONNECT_CONTEXT context; HANDLE connectEndpointHandle; PFILE_OBJECT fileObject; PTRANSPORT_ADDRESS remoteAddress; ULONG remoteAddressLength; PTDI_CONNECTION_INFORMATION requestConnectionInfo, returnConnectionInfo;
PAGED_CODE( );
//
// Initialize for proper cleanup
//
fileObject = NULL; context = NULL;
#ifdef _WIN64
if (IoIs32bitProcess (Irp)) { if (IrpSp->Parameters.DeviceIoControl.InputBufferLength< sizeof (AFD_CONNECT_JOIN_INFO32) || (IrpSp->Parameters.DeviceIoControl.OutputBufferLength!=0 && IrpSp->Parameters.DeviceIoControl.OutputBufferLength< sizeof (IO_STATUS_BLOCK32))){ status = STATUS_INVALID_PARAMETER; goto complete; } try { if( Irp->RequestorMode != KernelMode ) {
ProbeForRead( IrpSp->Parameters.DeviceIoControl.Type3InputBuffer, IrpSp->Parameters.DeviceIoControl.InputBufferLength, PROBE_ALIGNMENT32 (AFD_CONNECT_JOIN_INFO32) );
}
connectEndpointHandle = ((PAFD_CONNECT_JOIN_INFO32)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer)->ConnectEndpoint; remoteAddress = (PTRANSPORT_ADDRESS)&((PAFD_CONNECT_JOIN_INFO32)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer)->RemoteAddress; ASSERT (((ULONG_PTR)remoteAddress & (PROBE_ALIGNMENT(TRANSPORT_ADDRESS)-1))==0); remoteAddressLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength - FIELD_OFFSET (AFD_CONNECT_JOIN_INFO32, RemoteAddress); } except (AFD_EXCEPTION_FILTER (&status)) { goto complete; } } else #endif //_WIN64
{
//
// Determine where in the system buffer the request and return
// connection information structures exist. Pass pointers to
// these locations instead of the user-mode pointers in the
// tdiRequest structure so that the memory will be nonpageable.
//
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength< sizeof (AFD_CONNECT_JOIN_INFO) || (IrpSp->Parameters.DeviceIoControl.OutputBufferLength!=0 && IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (IO_STATUS_BLOCK))) { status = STATUS_INVALID_PARAMETER; goto complete; } try { PAFD_CONNECT_JOIN_INFO connectInfo;
if( Irp->RequestorMode != KernelMode ) {
ProbeForRead( IrpSp->Parameters.DeviceIoControl.Type3InputBuffer, IrpSp->Parameters.DeviceIoControl.InputBufferLength, PROBE_ALIGNMENT (AFD_CONNECT_JOIN_INFO) );
}
connectInfo = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
//
// Check for if the caller is unaware of the SAN
// provider activation and report the error.
//
if (!connectInfo->SanActive && AfdSanServiceHelper!=NULL) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL, "AFD: Process %p is being told to enable SAN on connect\n", PsGetCurrentProcessId ())); status = STATUS_INVALID_PARAMETER_12; goto complete; }
connectEndpointHandle = connectInfo->ConnectEndpoint; remoteAddress = &connectInfo->RemoteAddress; remoteAddressLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength - FIELD_OFFSET (AFD_CONNECT_JOIN_INFO, RemoteAddress); } except (AFD_EXCEPTION_FILTER (&status)) { goto complete; } }
try {
context = AFD_ALLOCATE_POOL_WITH_QUOTA (NonPagedPool, FIELD_OFFSET (AFD_CONNECT_CONTEXT, RemoteAddress) + remoteAddressLength, AFD_TDI_POOL_TAG ); // AFD_ALLOCATE_POOL_WITH_QUOTA macro sets POOL_RAISE_IF_ALLOCATION_FAILURE flag
ASSERT (context!=NULL);
Irp->AssociatedIrp.SystemBuffer = context; RtlZeroMemory (context, FIELD_OFFSET (AFD_CONNECT_CONTEXT, RemoteAddress));
RtlCopyMemory (&context->RemoteAddress, remoteAddress, remoteAddressLength); //
// Validate internal consistency of the transport address structure.
// Note that we HAVE to do this after copying since the malicious
// application can change the content of the buffer on us any time
// and our check will be bypassed.
//
if ((context->RemoteAddress.TAAddressCount!=1) || (LONG)remoteAddressLength< FIELD_OFFSET (TRANSPORT_ADDRESS, Address[0].Address[context->RemoteAddress.Address[0].AddressLength])) { ExRaiseStatus (STATUS_INVALID_PARAMETER); }
context->RequestConnectionInfo.RemoteAddress = &context->RemoteAddress; context->RequestConnectionInfo.RemoteAddressLength = remoteAddressLength;
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength>0 && Irp->RequestorMode==UserMode) { ProbeForWriteIoStatusEx ( ((PIO_STATUS_BLOCK)Irp->UserBuffer), IoIs32bitProcess (Irp)); } } except (AFD_EXCEPTION_FILTER(&status)) { goto complete; }
if (FIELD_OFFSET (TRANSPORT_ADDRESS, Address[0].Address[ context->RemoteAddress.Address[0].AddressLength]) > (LONG)remoteAddressLength) { status = STATUS_INVALID_PARAMETER; goto complete; }
fileObject = IrpSp->FileObject; endpoint = fileObject->FsContext;
if (endpoint->Type==AfdBlockTypeHelper) { //
// This is async connect which uses helper endpoint to
// communicate to AFD. Get the real endpoint.
//
status = ObReferenceObjectByHandle( connectEndpointHandle, (IrpSp->Parameters.DeviceIoControl.IoControlCode>>14) & 3, // DesiredAccess
*IoFileObjectType, // ObjectType
Irp->RequestorMode, (PVOID *)&fileObject, NULL ); if (!NT_SUCCESS (status)) { goto complete; }
if (fileObject->DeviceObject!=AfdDeviceObject) { status = STATUS_INVALID_HANDLE; goto complete_deref; } endpoint = fileObject->FsContext; IrpSp->FileObject = fileObject; } else { ObReferenceObject (fileObject); }
if ( endpoint->Type != AfdBlockTypeEndpoint && endpoint->Type != AfdBlockTypeVcConnecting && endpoint->Type != AfdBlockTypeDatagram ) { status = STATUS_INVALID_PARAMETER; goto complete_deref; }
IF_DEBUG(CONNECT) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdConnect: starting connect on endpoint %p\n", endpoint )); }
//
// If this is a datagram endpoint, simply remember the specified
// address so that we can use it on sends, receives, writes, and
// reads.
//
if ( IS_DGRAM_ENDPOINT(endpoint) ) { return AfdDoDatagramConnect( fileObject, Irp, FALSE ); }
if (!AFD_START_STATE_CHANGE (endpoint, AfdEndpointStateConnected)) { status = STATUS_INVALID_PARAMETER; goto complete_deref; } //
// If the endpoint is not bound, then this is an invalid request.
// Listening endpoints are not allowed as well.
//
if ( endpoint->Listening || endpoint->State != AfdEndpointStateBound ) { status = STATUS_INVALID_PARAMETER; goto complete_state_change; }
//
// Create a connection object to use for the connect operation.
//
status = AfdCreateConnection( &endpoint->TransportInfo->TransportDeviceName, endpoint->AddressHandle, IS_TDI_BUFFERRING(endpoint), endpoint->InLine, endpoint->OwningProcess, &connection );
if ( !NT_SUCCESS(status) ) { goto complete_state_change; }
//
// Set up a referenced pointer from the connection to the endpoint.
// Note that we set up the connection's pointer to the endpoint
// BEFORE the endpoint's pointer to the connection so that AfdPoll
// doesn't try to back reference the endpoint from the connection.
//
REFERENCE_ENDPOINT( endpoint ); connection->Endpoint = endpoint;
//
// Remember that this is now a connecting type of endpoint, and set
// up a pointer to the connection in the endpoint. This is
// implicitly a referenced pointer.
//
endpoint->Common.VcConnecting.Connection = connection; endpoint->Type = AfdBlockTypeVcConnecting;
ASSERT( IS_TDI_BUFFERRING(endpoint) == connection->TdiBufferring );
//
// Add an additional reference to the connection. This prevents the
// connection from being closed until the disconnect event handler
// is called.
//
AfdAddConnectedReference( connection );
//
// If there are connect data buffers, move them from the endpoint
// structure to the connection structure and set up the necessary
// pointers in the connection request we're going to give to the TDI
// provider. Do this in a subroutine so this routine can be pageable.
//
requestConnectionInfo = &context->RequestConnectionInfo; returnConnectionInfo = &context->ReturnConnectionInfo;
if ( endpoint->Common.VirtualCircuit.ConnectDataBuffers != NULL ) { AfdSetupConnectDataBuffers( endpoint, connection, &requestConnectionInfo, &returnConnectionInfo ); }
//
// Since we may be reissuing a connect after a previous failed connect,
// reenable the failed connect event bit.
//
AfdEnableFailedConnectEvent( endpoint );
//
// Reference the connection block so it does not go away even if
// endpoint's reference to it is removed (in cleanup)
//
REFERENCE_CONNECTION (connection);
//
// Build a TDI kernel-mode connect request in the next stack location
// of the IRP.
//
TdiBuildConnect( Irp, connection->DeviceObject, connection->FileObject, AfdRestartConnect, connection, &AfdInfiniteTimeout, requestConnectionInfo, returnConnectionInfo );
AFD_VERIFY_ADDRESS (connection, &requestConnectionInfo->RemoteAddress); //
// Call the transport to actually perform the connect operation.
//
return AfdIoCallDriver( endpoint, connection->DeviceObject, Irp );
complete_state_change: AFD_END_STATE_CHANGE (endpoint);
complete_deref: ASSERT (fileObject!=NULL); ObDereferenceObject (fileObject);
complete:
if (context!=NULL) { AFD_FREE_POOL (context, AFD_TDI_POOL_TAG); ASSERT (Irp->AssociatedIrp.SystemBuffer==context); Irp->AssociatedIrp.SystemBuffer = NULL; }
Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; IoCompleteRequest( Irp, AfdPriorityBoost );
return status;
} // AfdConnect
NTSTATUS AfdDoDatagramConnect ( IN PFILE_OBJECT FileObject, IN PIRP Irp, IN BOOLEAN HalfConnect ) { PAFD_ENDPOINT endpoint; AFD_LOCK_QUEUE_HANDLE lockHandle; NTSTATUS status; PAFD_CONNECT_CONTEXT context;
endpoint = FileObject->FsContext; context = Irp->AssociatedIrp.SystemBuffer;
if (!AFD_START_STATE_CHANGE (endpoint, AfdEndpointStateConnected)) { status = STATUS_INVALID_PARAMETER; goto complete; }
if (endpoint->State!=AfdEndpointStateBound && endpoint->State!=AfdEndpointStateConnected) { status = STATUS_INVALID_PARAMETER; goto complete_state_change; } //
// Save the remote address on the endpoint. We'll use this to
// send datagrams in the future and to compare received datagram's
// source addresses.
//
AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle ); if ((endpoint->Common.Datagram.RemoteAddress==NULL) || (endpoint->Common.Datagram.RemoteAddressLength< (ULONG)context->RequestConnectionInfo.RemoteAddressLength)) { if ( endpoint->Common.Datagram.RemoteAddress != NULL ) { AFD_RETURN_REMOTE_ADDRESS ( endpoint->Common.Datagram.RemoteAddress, endpoint->Common.Datagram.RemoteAddressLength ); endpoint->Common.Datagram.RemoteAddress = NULL; }
endpoint->Common.Datagram.RemoteAddress = AFD_ALLOCATE_REMOTE_ADDRESS ( context->RequestConnectionInfo.RemoteAddressLength);
if (endpoint->Common.Datagram.RemoteAddress == NULL) { AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle ); status = STATUS_INSUFFICIENT_RESOURCES; goto complete_state_change; } }
RtlCopyMemory( endpoint->Common.Datagram.RemoteAddress, context->RequestConnectionInfo.RemoteAddress, context->RequestConnectionInfo.RemoteAddressLength );
endpoint->Common.Datagram.RemoteAddressLength = context->RequestConnectionInfo.RemoteAddressLength;
endpoint->DisconnectMode = 0;
endpoint->Common.Datagram.HalfConnect = HalfConnect;
if (!IS_TDI_DGRAM_CONNECTION(endpoint)) { endpoint->State = AfdEndpointStateConnected;
//
// Indicate that the connect completed. Implicitly, the
// successful completion of a connect also means that the caller
// can do a send on the socket.
//
endpoint->EnableSendEvent = TRUE; AfdIndicateEventSelectEvent( endpoint, AFD_POLL_CONNECT | AFD_POLL_SEND, STATUS_SUCCESS ); AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
AfdIndicatePollEvent( endpoint, AFD_POLL_CONNECT | AFD_POLL_SEND, STATUS_SUCCESS ); status = STATUS_SUCCESS; } else {
//
// Reset the connect status to success so that the poll code will
// know if a connect failure occurs.
// Do this inline as we already hold spinlock
//
endpoint->EventsActive &= ~AFD_POLL_CONNECT_FAIL; endpoint->EventStatus[AFD_POLL_CONNECT_FAIL_BIT] = STATUS_SUCCESS;
AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
//
// Build a TDI kernel-mode connect request in the next stack location
// of the IRP.
//
TdiBuildConnect( Irp, endpoint->AddressDeviceObject, endpoint->AddressFileObject, AfdRestartDgConnect, endpoint, &AfdInfiniteTimeout, &context->RequestConnectionInfo, &context->ReturnConnectionInfo );
//
// Call the transport to actually perform the connect operation.
//
return AfdIoCallDriver( endpoint, endpoint->AddressDeviceObject, Irp ); }
complete_state_change: AFD_END_STATE_CHANGE (endpoint);
complete: ObDereferenceObject (FileObject);
AFD_FREE_POOL (context, AFD_TDI_POOL_TAG); ASSERT (Irp->AssociatedIrp.SystemBuffer==context); Irp->AssociatedIrp.SystemBuffer = NULL;
Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; IoCompleteRequest( Irp, AfdPriorityBoost );
return status;
} // AfdDoDatagramConnect
VOID AfdSetupConnectDataBuffers ( IN PAFD_ENDPOINT Endpoint, IN PAFD_CONNECTION Connection, IN OUT PTDI_CONNECTION_INFORMATION *RequestConnectionInformation, IN OUT PTDI_CONNECTION_INFORMATION *ReturnConnectionInformation ) { AFD_LOCK_QUEUE_HANDLE lockHandle;
ASSERT (Endpoint->Type!=AfdBlockTypeDatagram);
AfdAcquireSpinLock( &Endpoint->SpinLock, &lockHandle );
if ( Endpoint->Common.VirtualCircuit.ConnectDataBuffers != NULL ) { PTDI_CONNECTION_INFORMATION requestConnectionInformation, returnConnectionInformation;
ASSERT( Connection->ConnectDataBuffers == NULL );
Connection->ConnectDataBuffers = Endpoint->Common.VirtualCircuit.ConnectDataBuffers; Endpoint->Common.VirtualCircuit.ConnectDataBuffers = NULL;
requestConnectionInformation = &Connection->ConnectDataBuffers->RequestConnectionInfo, requestConnectionInformation->UserData = Connection->ConnectDataBuffers->SendConnectData.Buffer; requestConnectionInformation->UserDataLength = Connection->ConnectDataBuffers->SendConnectData.BufferLength; requestConnectionInformation->Options = Connection->ConnectDataBuffers->SendConnectOptions.Buffer; requestConnectionInformation->OptionsLength = Connection->ConnectDataBuffers->SendConnectOptions.BufferLength; requestConnectionInformation->RemoteAddress = (*RequestConnectionInformation)->RemoteAddress; requestConnectionInformation->RemoteAddressLength = (*RequestConnectionInformation)->RemoteAddressLength; *RequestConnectionInformation = requestConnectionInformation;
returnConnectionInformation = &Connection->ConnectDataBuffers->ReturnConnectionInfo; returnConnectionInformation->UserData = Connection->ConnectDataBuffers->ReceiveConnectData.Buffer; returnConnectionInformation->UserDataLength = Connection->ConnectDataBuffers->ReceiveConnectData.BufferLength; returnConnectionInformation->Options = Connection->ConnectDataBuffers->ReceiveConnectOptions.Buffer; returnConnectionInformation->OptionsLength = Connection->ConnectDataBuffers->ReceiveConnectOptions.BufferLength; returnConnectionInformation->RemoteAddress = (*ReturnConnectionInformation)->RemoteAddress; returnConnectionInformation->RemoteAddressLength = (*ReturnConnectionInformation)->RemoteAddressLength; *ReturnConnectionInformation = returnConnectionInformation; }
AfdReleaseSpinLock( &Endpoint->SpinLock, &lockHandle );
} // AfdSetupConnectDataBuffers
NTSTATUS AfdRestartConnect ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context )
/*++
Routine Description:
Handles the IOCTL_AFD_CONNECT IOCTL.
Arguments:
Irp - Pointer to I/O request packet.
IrpSp - pointer to the IO stack location to use for this request.
Return Value:
NTSTATUS -- Indicates whether the request was successfully queued.
--*/
{ PAFD_ENDPOINT endpoint; PAFD_CONNECTION connection; AFD_LOCK_QUEUE_HANDLE lockHandle; PIO_STACK_LOCATION irpSp; PFILE_OBJECT fileObject; PAFD_CONNECT_CONTEXT context;
connection = Context; ASSERT( connection->Type == AfdBlockTypeConnection );
irpSp = IoGetCurrentIrpStackLocation( Irp ); fileObject = irpSp->FileObject; ASSERT( fileObject->DeviceObject==AfdDeviceObject ); endpoint = fileObject->FsContext; ASSERT( endpoint->Type == AfdBlockTypeVcConnecting ); ASSERT( endpoint==connection->Endpoint );
context = Irp->AssociatedIrp.SystemBuffer; ASSERT( context != NULL );
IF_DEBUG(CONNECT) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdRestartConnect: connect completed, status = %X, endpoint = %p\n", Irp->IoStatus.Status, endpoint )); }
if ( connection->ConnectDataBuffers != NULL ) {
//
// If there are connect buffers on this endpoint, remember the
// size of the return connect data.
//
AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
//
// Double-check under the lock
//
if ( connection->ConnectDataBuffers != NULL ) { NTSTATUS status;
status = AfdSaveReceivedConnectData( &connection->ConnectDataBuffers, IOCTL_AFD_SET_CONNECT_DATA, connection->ConnectDataBuffers->ReturnConnectionInfo.UserData, connection->ConnectDataBuffers->ReturnConnectionInfo.UserDataLength ); ASSERT (NT_SUCCESS (status));
status = AfdSaveReceivedConnectData( &connection->ConnectDataBuffers, IOCTL_AFD_SET_CONNECT_OPTIONS, connection->ConnectDataBuffers->ReturnConnectionInfo.Options, connection->ConnectDataBuffers->ReturnConnectionInfo.OptionsLength ); ASSERT (NT_SUCCESS (status)); }
AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle ); }
//
// Indicate that the connect completed. Implicitly, the successful
// completion of a connect also means that the caller can do a send
// on the socket.
//
if ( NT_SUCCESS(Irp->IoStatus.Status)) {
//
// If the request succeeded, set the endpoint to the connected
// state. The endpoint type has already been set to
// AfdBlockTypeVcConnecting.
//
endpoint->State = AfdEndpointStateConnected; ASSERT( endpoint->Type == AfdBlockTypeVcConnecting );
//
// Remember the time that the connection started.
//
connection->ConnectTime = KeQueryInterruptTime();
} else {
AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
//
// The connect failed, so reset the type to open.
// Otherwise, we won't be able to start another connect
//
endpoint->Type = AfdBlockTypeEndpoint;
if (endpoint->Common.VcConnecting.Connection!=NULL) { ASSERT (connection==endpoint->Common.VcConnecting.Connection); endpoint->Common.VcConnecting.Connection = NULL;
//
// Manually delete the connected reference if somebody else
// hasn't already done so. We can't use
// AfdDeleteConnectedReference() because it refuses to delete
// the connected reference until the endpoint has been cleaned
// up.
//
if ( connection->ConnectedReferenceAdded ) { connection->ConnectedReferenceAdded = FALSE; AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle ); DEREFERENCE_CONNECTION( connection ); } else { AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle ); } //
// Dereference the connection block stored on the endpoint.
// This should cause the connection object reference count to go
// to zero to the connection object can be deleted.
//
DEREFERENCE_CONNECTION( connection ); } else { //
// The endpoint's reference to connection was removed
// (perhaps in cleanup);
//
AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle ); }
}
AFD_FREE_POOL (context, AFD_TDI_POOL_TAG); Irp->AssociatedIrp.SystemBuffer = NULL;
//
// If pending has be returned for this irp then mark the current
// stack as pending.
//
if ( Irp->PendingReturned ) { IoMarkIrpPending(Irp); }
AfdCompleteOutstandingIrp( endpoint, Irp );
//
// Dereference connection to account for reference we added in AfdConnect
//
DEREFERENCE_CONNECTION( connection );
//
// Try to queue kernel APC to the user thread that
// started the connection operation, so we can
// communicate the status of the connect operation to
// msafd.dll before we inform the application through
// the select or EventSelect. Otherwise, we run into the
// race condition when application learns about connect first,
// calls msafd.dll that is not aware of the completion and
// returns WSAENOTCONN.
//
if ((Irp->RequestorMode==UserMode) && // Must be user mode calls
(Irp->UserBuffer!=NULL) && // Must be interested in status
// Thread should be able to
// run APCs.
(KeInitializeApc (&endpoint->Common.VcConnecting.Apc, PsGetThreadTcb (Irp->Tail.Overlay.Thread), Irp->ApcEnvironment, AfdConnectApcKernelRoutine, AfdConnectApcRundownRoutine, (PKNORMAL_ROUTINE)NULL, KernelMode, NULL ), KeInsertQueueApc (&endpoint->Common.VcConnecting.Apc, Irp, NULL, AfdPriorityBoost))) { //
// We will complete the IRP in the APC.
//
return STATUS_MORE_PROCESSING_REQUIRED; } else { //
// APC was not necessary or did not work.
// Complete it here.
//
AfdFinishConnect (endpoint, Irp, NULL); return STATUS_SUCCESS; }
} // AfdRestartConnect
VOID AfdConnectApcKernelRoutine ( IN struct _KAPC *Apc, IN OUT PKNORMAL_ROUTINE *NormalRoutine, IN OUT PVOID *NormalContext, IN OUT PVOID *SystemArgument1, IN OUT PVOID *SystemArgument2 ) { PIRP irp; PIO_STACK_LOCATION irpSp; PAFD_ENDPOINT endpoint, rootEndpoint; #if DBG
try { #endif
//
// Validate parameters.
//
ASSERT (*NormalRoutine==NULL);
endpoint = CONTAINING_RECORD (Apc, AFD_ENDPOINT, Common.VcConnecting.Apc); ASSERT (IS_AFD_ENDPOINT_TYPE (endpoint));
irp = *SystemArgument1; ASSERT (irp->UserBuffer!=NULL && irp->RequestorMode==UserMode);
irpSp = IoGetCurrentIrpStackLocation( irp );
rootEndpoint = *SystemArgument2; ASSERT (rootEndpoint==NULL || IS_AFD_ENDPOINT_TYPE (endpoint)); //
// Update the status for the user mode caller before
// signalling events.
//
try { #ifdef _WIN64
if (IoIs32bitProcess (irp)) { ((PIO_STATUS_BLOCK32)irp->UserBuffer)->Status = (LONG)irp->IoStatus.Status; } else #endif //_WIN64
{ ((PIO_STATUS_BLOCK)irp->UserBuffer)->Status = irp->IoStatus.Status; } } except (AFD_EXCEPTION_FILTER (NULL)) { NOTHING; }
AfdFinishConnect (endpoint, irp, rootEndpoint); IoCompleteRequest (irp, AfdPriorityBoost); #if DBG
} except (AfdApcExceptionFilter (GetExceptionInformation (), __FILE__, __LINE__)) { DbgBreakPoint (); } #endif
}
VOID AfdConnectApcRundownRoutine ( IN struct _KAPC *Apc ) { PIRP irp; PAFD_ENDPOINT endpoint, rootEndpoint; #if DBG
try { #endif
endpoint = CONTAINING_RECORD (Apc, AFD_ENDPOINT, Common.VcConnecting.Apc); ASSERT (IS_AFD_ENDPOINT_TYPE (endpoint)); irp = Apc->SystemArgument1; rootEndpoint = Apc->SystemArgument2; ASSERT (rootEndpoint==NULL || IS_AFD_ENDPOINT_TYPE (endpoint)); ASSERT (irp->UserBuffer!=NULL && irp->RequestorMode==UserMode);
//
// Thread is exiting, don't bother updating user mode status.
// Just signal the events and complet the IRP.
//
AfdFinishConnect (endpoint, irp, rootEndpoint); IoCompleteRequest (irp, AfdPriorityBoost); #if DBG
} except (AfdApcExceptionFilter (GetExceptionInformation (), __FILE__, __LINE__)) { DbgBreakPoint (); } #endif
}
VOID AfdFinishConnect ( PAFD_ENDPOINT Endpoint, PIRP Irp, PAFD_ENDPOINT RootEndpoint ) { PIO_STACK_LOCATION irpSp; PFILE_OBJECT fileObject; AFD_LOCK_QUEUE_HANDLE lockHandle; ULONG eventMask;
if (NT_SUCCESS (Irp->IoStatus.Status)) { eventMask = AFD_POLL_CONNECT; } else { eventMask = AFD_POLL_CONNECT_FAIL; }
irpSp = IoGetCurrentIrpStackLocation( Irp ); fileObject = irpSp->FileObject;
if (RootEndpoint!=NULL) { AfdAcquireSpinLock (&RootEndpoint->SpinLock, &lockHandle); AfdIndicateEventSelectEvent (RootEndpoint, eventMask, Irp->IoStatus.Status); AfdReleaseSpinLock (&RootEndpoint->SpinLock, &lockHandle); AfdIndicatePollEvent (RootEndpoint, eventMask, Irp->IoStatus.Status); AFD_END_STATE_CHANGE (RootEndpoint); eventMask = 0; if (!NT_SUCCESS (Irp->IoStatus.Status)) { DEREFERENCE_ENDPOINT (RootEndpoint); } }
AfdAcquireSpinLock (&Endpoint->SpinLock, &lockHandle);
if (NT_SUCCESS (Irp->IoStatus.Status)) { eventMask |= AFD_POLL_SEND; Endpoint->EnableSendEvent = TRUE; if (Endpoint->Common.VcConnecting.Connection!=NULL) { Endpoint->Common.VcConnecting.Connection->State = AfdConnectionStateConnected; if (IS_DATA_ON_CONNECTION (Endpoint->Common.VcConnecting.Connection)) { eventMask |= AFD_POLL_RECEIVE; } } }
if (eventMask!=0) { AfdIndicateEventSelectEvent (Endpoint, eventMask, Irp->IoStatus.Status); AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle); AfdIndicatePollEvent (Endpoint, eventMask, Irp->IoStatus.Status); } else { AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle); }
AFD_END_STATE_CHANGE (Endpoint); ObDereferenceObject (fileObject); }
NTSTATUS AfdRestartDgConnect ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context )
/*++
Routine Description:
Handles the IOCTL_AFD_CONNECT IOCTL.
Arguments:
Irp - Pointer to I/O request packet.
IrpSp - pointer to the IO stack location to use for this request.
Return Value:
NTSTATUS -- Indicates whether the request was successfully queued.
--*/
{ PAFD_ENDPOINT endpoint; PIO_STACK_LOCATION irpSp; PFILE_OBJECT fileObject; AFD_LOCK_QUEUE_HANDLE lockHandle; ULONG eventMask;
endpoint = Context; ASSERT( IS_DGRAM_ENDPOINT(endpoint) );
irpSp = IoGetCurrentIrpStackLocation( Irp ); fileObject = irpSp->FileObject;
ASSERT (endpoint == fileObject->FsContext);
IF_DEBUG(CONNECT) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdRestartDgConnect: connect completed, status = %X, endpoint = %p\n", Irp->IoStatus.Status, endpoint )); }
//
// Indicate that the connect completed. Implicitly, the successful
// completion of a connect also means that the caller can do a send
// on the socket.
//
AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle); if ( NT_SUCCESS(Irp->IoStatus.Status) ) {
endpoint->State = AfdEndpointStateConnected;
endpoint->EnableSendEvent = TRUE; eventMask = AFD_POLL_CONNECT | AFD_POLL_SEND;
} else {
eventMask = AFD_POLL_CONNECT_FAIL;
} AfdIndicateEventSelectEvent (endpoint, eventMask, Irp->IoStatus.Status); AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle); AfdIndicatePollEvent (endpoint, eventMask, Irp->IoStatus.Status);
AFD_END_STATE_CHANGE (endpoint);
ASSERT (Irp->AssociatedIrp.SystemBuffer!=NULL); AFD_FREE_POOL (Irp->AssociatedIrp.SystemBuffer, AFD_TDI_POOL_TAG); Irp->AssociatedIrp.SystemBuffer = NULL;
//
// If pending has be returned for this irp then mark the current
// stack as pending.
//
if ( Irp->PendingReturned ) { IoMarkIrpPending(Irp); }
AfdCompleteOutstandingIrp( endpoint, Irp );
//
// Remove reference added in AfdConnect
//
ObDereferenceObject (fileObject);
return STATUS_SUCCESS;
} // AfdRestartDgConnect
VOID AfdEnableFailedConnectEvent( IN PAFD_ENDPOINT Endpoint ) /*++
Routine Description:
Reenables the failed connect poll bit on the specified endpoint. This is off in a separate (nonpageable) routine so that the bulk of AfdConnect() can remain pageable.
Arguments:
Endpoint - The endpoint to enable.
Return Value:
None.
--*/
{ AFD_LOCK_QUEUE_HANDLE lockHandle;
AfdAcquireSpinLock( &Endpoint->SpinLock, &lockHandle );
ASSERT( ( Endpoint->EventsActive & AFD_POLL_CONNECT ) == 0 ); Endpoint->EventsActive &= ~AFD_POLL_CONNECT_FAIL; Endpoint->EventStatus[AFD_POLL_CONNECT_FAIL_BIT] = STATUS_SUCCESS;
IF_DEBUG(EVENT_SELECT) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdConnect: Endp %08lX, Active %08lX\n", Endpoint, Endpoint->EventsActive )); }
AfdReleaseSpinLock( &Endpoint->SpinLock, &lockHandle );
} // AfdEnableFailedConnectEvent
NTSTATUS FASTCALL AfdJoinLeaf ( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp )
/*++
Routine Description:
Handles the IOCTL_AFD_JOIN_LEAF IOCTL.
Arguments:
Irp - Pointer to I/O request packet.
IrpSp - pointer to the IO stack location to use for this request.
Return Value:
NTSTATUS -- Indicates whether the request was successfully queued.
--*/
{ NTSTATUS status; PAFD_ENDPOINT leafEndpoint; PAFD_CONNECTION connection; PAFD_CONNECT_CONTEXT context; HANDLE connectEndpointHandle; HANDLE rootEndpointHandle; PFILE_OBJECT fileObject; PTRANSPORT_ADDRESS remoteAddress; ULONG remoteAddressLength; PTDI_CONNECTION_INFORMATION requestConnectionInfo, returnConnectionInfo;
PAGED_CODE( );
//
// Initialize for proper cleanup
//
fileObject = NULL; connection = NULL; context = NULL;
#ifdef _WIN64
if (IoIs32bitProcess (Irp)) { if (IrpSp->Parameters.DeviceIoControl.InputBufferLength< sizeof (AFD_CONNECT_JOIN_INFO32) || (IrpSp->Parameters.DeviceIoControl.OutputBufferLength!=0 && IrpSp->Parameters.DeviceIoControl.OutputBufferLength< sizeof (IO_STATUS_BLOCK32))){ status = STATUS_INVALID_PARAMETER; goto complete; } try { if( Irp->RequestorMode != KernelMode ) {
ProbeForRead( IrpSp->Parameters.DeviceIoControl.Type3InputBuffer, IrpSp->Parameters.DeviceIoControl.InputBufferLength, PROBE_ALIGNMENT32 (AFD_CONNECT_JOIN_INFO32) );
}
connectEndpointHandle = ((PAFD_CONNECT_JOIN_INFO32)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer)->ConnectEndpoint; rootEndpointHandle = ((PAFD_CONNECT_JOIN_INFO32)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer)->RootEndpoint; remoteAddress = (PTRANSPORT_ADDRESS)&((PAFD_CONNECT_JOIN_INFO32)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer)->RemoteAddress; ASSERT (((ULONG_PTR)remoteAddress & (PROBE_ALIGNMENT(TRANSPORT_ADDRESS)-1))==0); remoteAddressLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength - FIELD_OFFSET (AFD_CONNECT_JOIN_INFO32, RemoteAddress); } except (AFD_EXCEPTION_FILTER (&status)) { goto complete; } } else #endif //_WIN64
{
//
// Determine where in the system buffer the request and return
// connection information structures exist. Pass pointers to
// these locations instead of the user-mode pointers in the
// tdiRequest structure so that the memory will be nonpageable.
//
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength< sizeof (AFD_CONNECT_JOIN_INFO) || (IrpSp->Parameters.DeviceIoControl.OutputBufferLength!=0 && IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (IO_STATUS_BLOCK))) { status = STATUS_INVALID_PARAMETER; goto complete; } try { if( Irp->RequestorMode != KernelMode ) {
ProbeForRead( IrpSp->Parameters.DeviceIoControl.Type3InputBuffer, IrpSp->Parameters.DeviceIoControl.InputBufferLength, PROBE_ALIGNMENT (AFD_CONNECT_JOIN_INFO) );
}
connectEndpointHandle = ((PAFD_CONNECT_JOIN_INFO)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer)->ConnectEndpoint; rootEndpointHandle = ((PAFD_CONNECT_JOIN_INFO)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer)->RootEndpoint; remoteAddress = &((PAFD_CONNECT_JOIN_INFO)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer)->RemoteAddress; remoteAddressLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength - FIELD_OFFSET (AFD_CONNECT_JOIN_INFO, RemoteAddress); } except (AFD_EXCEPTION_FILTER (&status)) { goto complete; } }
try {
context = AFD_ALLOCATE_POOL_WITH_QUOTA (NonPagedPool, FIELD_OFFSET (AFD_CONNECT_CONTEXT, RemoteAddress) + remoteAddressLength, AFD_TDI_POOL_TAG ); // AFD_ALLOCATE_POOL_WITH_QUOTA macro sets POOL_RAISE_IF_ALLOCATION_FAILURE flag
ASSERT (context!=NULL);
Irp->AssociatedIrp.SystemBuffer = context; RtlZeroMemory (context, FIELD_OFFSET (AFD_CONNECT_CONTEXT, RemoteAddress));
RtlCopyMemory (&context->RemoteAddress, remoteAddress, remoteAddressLength); //
// Validate internal consistency of the transport address structure.
// Note that we HAVE to do this after copying since the malicious
// application can change the content of the buffer on us any time
// and our check will be bypassed.
//
if ((context->RemoteAddress.TAAddressCount!=1) || (LONG)remoteAddressLength< FIELD_OFFSET (TRANSPORT_ADDRESS, Address[0].Address[context->RemoteAddress.Address[0].AddressLength])) { ExRaiseStatus (STATUS_INVALID_PARAMETER); }
context->RequestConnectionInfo.RemoteAddress = &context->RemoteAddress; context->RequestConnectionInfo.RemoteAddressLength = remoteAddressLength;
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength>0 && Irp->RequestorMode==UserMode) { ProbeForWriteIoStatusEx ( ((PIO_STATUS_BLOCK)Irp->UserBuffer), IoIs32bitProcess (Irp)); } } except (AFD_EXCEPTION_FILTER(&status)) { goto complete; }
fileObject = IrpSp->FileObject; leafEndpoint = fileObject->FsContext;
if (leafEndpoint->Type==AfdBlockTypeHelper) { //
// This is async join leaf which uses helper endpoint to
// communicate to AFD. Get the real endpoint.
//
status = ObReferenceObjectByHandle( connectEndpointHandle, (IrpSp->Parameters.DeviceIoControl.IoControlCode>>14) & 3, // DesiredAccess
*IoFileObjectType, // ObjectType
Irp->RequestorMode, (PVOID *)&fileObject, NULL ); if (!NT_SUCCESS (status)) { goto complete; }
if (fileObject->DeviceObject!=AfdDeviceObject) { status = STATUS_INVALID_HANDLE; goto complete_deref; }
leafEndpoint = fileObject->FsContext; IrpSp->FileObject = fileObject; } else ObReferenceObject (fileObject);
if ( leafEndpoint->Type != AfdBlockTypeEndpoint && leafEndpoint->Type != AfdBlockTypeVcConnecting && leafEndpoint->Type != AfdBlockTypeDatagram ) { status = STATUS_INVALID_PARAMETER; goto complete_deref; }
if (rootEndpointHandle!=NULL) { //
// Root inviting leaf
//
PFILE_OBJECT rootObject; PAFD_ENDPOINT rootEndpoint;
status = ObReferenceObjectByHandle( rootEndpointHandle, (IrpSp->Parameters.DeviceIoControl.IoControlCode>>14) & 3, // DesiredAccess
*IoFileObjectType, // ObjectType
Irp->RequestorMode, (PVOID *)&rootObject, NULL ); if (!NT_SUCCESS (status)) { goto complete_deref; }
if (rootObject->DeviceObject!=AfdDeviceObject) { ObDereferenceObject (rootObject); status = STATUS_INVALID_HANDLE; goto complete_deref; }
//
// Get the endpoint structure of the file object
//
rootEndpoint = rootObject->FsContext;
if (!AFD_START_STATE_CHANGE (leafEndpoint, AfdEndpointStateConnected)) { ObDereferenceObject (rootObject); status = STATUS_INVALID_PARAMETER; goto complete_deref; }
//
// Verify root and leaf endpoint's type and states
//
if (IS_VC_ENDPOINT(rootEndpoint) && rootEndpoint->afdC_Root && rootEndpoint->State==AfdEndpointStateConnected && IS_VC_ENDPOINT(leafEndpoint) && leafEndpoint->TransportInfo==rootEndpoint->TransportInfo && leafEndpoint->State==AfdEndpointStateOpen) { //
// Create a connection object to use for the connect operation.
//
status = AfdCreateConnection( &rootEndpoint->TransportInfo->TransportDeviceName, rootEndpoint->AddressHandle, IS_TDI_BUFFERRING(rootEndpoint), leafEndpoint->InLine, leafEndpoint->OwningProcess, &connection );
//
// No more joins are allowed while this one is active
//
if (AFD_START_STATE_CHANGE (rootEndpoint, rootEndpoint->State)) { AfdJoinInviteSetup (rootEndpoint, leafEndpoint); } else { status = STATUS_INVALID_PARAMETER; }
} else { status = STATUS_INVALID_PARAMETER; }
//
// We referenced root endpoint in invite routine, so
// we no longer need reference to root file object
//
ObDereferenceObject (rootObject);
if (!NT_SUCCESS (status)) { goto complete_state_change; } } else { //
// If this is a datagram endpoint, simply remember the specified
// address so that we can use it on sends, and writes.
//
if ( IS_DGRAM_ENDPOINT(leafEndpoint) ) { if (leafEndpoint->State!=AfdEndpointStateConnected) { return AfdDoDatagramConnect( fileObject, Irp, TRUE); } else { //
// If endpoint is already connected, that connection takes
// precedence
//
status = STATUS_SUCCESS; goto complete_deref; } } else if (IS_VC_ENDPOINT (leafEndpoint)) {
if (!AFD_START_STATE_CHANGE (leafEndpoint, AfdEndpointStateConnected)) { status = STATUS_INVALID_PARAMETER; goto complete_deref; }
if (leafEndpoint->State != AfdEndpointStateBound) { status = STATUS_INVALID_PARAMETER; goto complete_state_change; } //
// Create a connection object to use for the connect operation.
//
status = AfdCreateConnection( &leafEndpoint->TransportInfo->TransportDeviceName, leafEndpoint->AddressHandle, IS_TDI_BUFFERRING(leafEndpoint), leafEndpoint->InLine, leafEndpoint->OwningProcess, &connection );
if ( !NT_SUCCESS(status) ) { goto complete_state_change; } } else { status = STATUS_INVALID_PARAMETER; goto complete_deref; } }
IF_DEBUG(CONNECT) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdJoinLeaf: starting join for endpoint %p\n", leafEndpoint )); }
//
// Set up a referenced pointer from the connection to the endpoint.
// Note that we set up the connection's pointer to the endpoint
// BEFORE the endpoint's pointer to the connection so that AfdPoll
// doesn't try to back reference the endpoint from the connection.
//
REFERENCE_ENDPOINT( leafEndpoint ); connection->Endpoint = leafEndpoint;
//
// Remember that this is now a connecting type of endpoint, and set
// up a pointer to the connection in the endpoint. This is
// implicitly a referenced pointer.
//
leafEndpoint->Common.VcConnecting.Connection = connection; leafEndpoint->Type = AfdBlockTypeVcConnecting;
ASSERT( IS_TDI_BUFFERRING(leafEndpoint) == connection->TdiBufferring );
//
// Add an additional reference to the connection. This prevents the
// connection from being closed until the disconnect event handler
// is called.
//
AfdAddConnectedReference( connection );
//
// If there are connect data buffers, move them from the endpoint
// structure to the connection structure and set up the necessary
// pointers in the connection request we're going to give to the TDI
// provider. Do this in a subroutine so this routine can be pageable.
//
requestConnectionInfo = &context->RequestConnectionInfo; returnConnectionInfo = &context->ReturnConnectionInfo;
if ( leafEndpoint->Common.VirtualCircuit.ConnectDataBuffers != NULL ) { AfdSetupConnectDataBuffers( leafEndpoint, connection, &requestConnectionInfo, &returnConnectionInfo ); }
//
// Since we may be reissuing a connect after a previous failed connect,
// reenable the failed connect event bit.
//
AfdEnableFailedConnectEvent( leafEndpoint );
REFERENCE_CONNECTION (connection); //
// Build a TDI kernel-mode connect request in the next stack location
// of the IRP.
//
TdiBuildConnect( Irp, connection->DeviceObject, connection->FileObject, AfdRestartJoin, connection, &AfdInfiniteTimeout, requestConnectionInfo, returnConnectionInfo );
AFD_VERIFY_ADDRESS (connection, &context->ReturnConnectionInfo->RemoteAddress);
//
// Call the transport to actually perform the connect operation.
//
return AfdIoCallDriver( leafEndpoint, connection->DeviceObject, Irp );
complete_state_change: AFD_END_STATE_CHANGE (leafEndpoint);
complete_deref: ObDereferenceObject (fileObject);
complete:
if (context!=NULL) { AFD_FREE_POOL (context, AFD_TDI_POOL_TAG); ASSERT (Irp->AssociatedIrp.SystemBuffer==context); Irp->AssociatedIrp.SystemBuffer = NULL; }
if (connection!=NULL) { DEREFERENCE_CONNECTION (connection); }
Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; IoCompleteRequest( Irp, AfdPriorityBoost );
return status;
} // AfdJoinLeaf
VOID AfdJoinInviteSetup ( PAFD_ENDPOINT RootEndpoint, PAFD_ENDPOINT LeafEndpoint ) { NTSTATUS status; AFD_LOCK_QUEUE_HANDLE lockHandle;
RootEndpoint->EventsActive &= ~AFD_POLL_CONNECT;
AfdAcquireSpinLock (&LeafEndpoint->SpinLock, &lockHandle); LeafEndpoint->TdiServiceFlags = RootEndpoint->TdiServiceFlags;
//
// Set up a referenced pointer to the root endpoint. This is
// necessary so that the endpoint does not go away until all
// leaf endpoints have gone away. Without this, we can free
// several shared strucutures that are associated with root
// endpoint and then attempt to use them in leaf endpoints.
//
REFERENCE_ENDPOINT (RootEndpoint); LeafEndpoint->Common.VcConnecting.ListenEndpoint = RootEndpoint;
//
// Set up a referenced pointer in the accepted endpoint to the
// TDI address object.
//
ObReferenceObject( RootEndpoint->AddressFileObject ); AfdRecordAddrRef();
LeafEndpoint->AddressFileObject = RootEndpoint->AddressFileObject; LeafEndpoint->AddressDeviceObject = RootEndpoint->AddressDeviceObject;
//
// Copy the pointer to the local address. Because we keep listen
// endpoint alive for as long as any of its connection is
// active, we can rely on the fact that address structure won't go
// away as well.
//
LeafEndpoint->LocalAddress = RootEndpoint->LocalAddress; LeafEndpoint->LocalAddressLength = RootEndpoint->LocalAddressLength; status = STATUS_SUCCESS; AfdReleaseSpinLock (&LeafEndpoint->SpinLock, &lockHandle);
} // AfdJoinInviteSetup
NTSTATUS AfdRestartJoin ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context )
/*++
Routine Description:
Handles the IOCTL_AFD_CONNECT IOCTL.
Arguments:
Irp - Pointer to I/O request packet.
IrpSp - pointer to the IO stack location to use for this request.
Return Value:
NTSTATUS -- Indicates whether the request was successfully queued.
--*/
{ PAFD_ENDPOINT endpoint, rootEndpoint; PAFD_CONNECTION connection; AFD_LOCK_QUEUE_HANDLE lockHandle; PIO_STACK_LOCATION irpSp; PFILE_OBJECT fileObject; PAFD_CONNECT_CONTEXT context;
connection = Context; ASSERT( connection->Type == AfdBlockTypeConnection );
irpSp = IoGetCurrentIrpStackLocation( Irp ); fileObject = irpSp->FileObject; ASSERT( fileObject->DeviceObject == AfdDeviceObject );
endpoint = fileObject->FsContext; ASSERT( endpoint->Type == AfdBlockTypeVcConnecting );
context = Irp->AssociatedIrp.SystemBuffer; ASSERT( context != NULL );
IF_DEBUG(CONNECT) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdRestartJoin: join completed, status = %X, " "LeafEndpoint = %p, RootEndpoint = %p\n", Irp->IoStatus.Status, endpoint, endpoint->Common.VcConnecting.ListenEndpoint )); }
//
// If this endpoint has root associated with it,
// we need to update it as well.
//
rootEndpoint = endpoint->Common.VcConnecting.ListenEndpoint; ASSERT ( rootEndpoint==NULL || (rootEndpoint->afdC_Root && (rootEndpoint->Type == AfdBlockTypeVcConnecting || rootEndpoint->Type == AfdBlockTypeVcBoth) ) );
//
// If there are connect buffers on this endpoint, remember the
// size of the return connect data.
//
if ( connection->ConnectDataBuffers != NULL ) { AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
//
// Double-check under the lock
//
if ( connection->ConnectDataBuffers != NULL ) { NTSTATUS status;
status = AfdSaveReceivedConnectData( &connection->ConnectDataBuffers, IOCTL_AFD_SET_CONNECT_DATA, connection->ConnectDataBuffers->ReturnConnectionInfo.UserData, connection->ConnectDataBuffers->ReturnConnectionInfo.UserDataLength ); ASSERT (NT_SUCCESS (status));
status = AfdSaveReceivedConnectData( &connection->ConnectDataBuffers, IOCTL_AFD_SET_CONNECT_OPTIONS, connection->ConnectDataBuffers->ReturnConnectionInfo.Options, connection->ConnectDataBuffers->ReturnConnectionInfo.OptionsLength ); ASSERT (NT_SUCCESS (status)); }
AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle ); }
//
// Indicate that the connect completed. Implicitly, the successful
// completion of a connect also means that the caller can do a send
// on the socket.
//
if ( NT_SUCCESS(Irp->IoStatus.Status) ) {
//
// If the request succeeded, set the endpoint to the connected
// state. The endpoint type has already been set to
// AfdBlockTypeVcConnecting.
//
endpoint->State = AfdEndpointStateConnected; ASSERT( endpoint->Type == AfdBlockTypeVcConnecting );
//
// Remember the time that the connection started.
//
connection->ConnectTime = KeQueryInterruptTime();
} else {
AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle ); //
// The connect failed, so reset the type to open.
// If we don't reset, we won't be able to start
// another join
//
endpoint->Type = AfdBlockTypeEndpoint;
//
// Remove references to listening endpoint and connection
// Actual dereferncing is below after we release the spinlock
if (rootEndpoint!=NULL) { endpoint->Common.VcConnecting.ListenEndpoint = NULL; //
// We used the local address from the listening endpoint,
// simply reset it, it will be freed when listening endpoint
// is freed.
//
ASSERT (endpoint->LocalAddress==rootEndpoint->LocalAddress); endpoint->LocalAddress = NULL; endpoint->LocalAddressLength = 0; }
if (endpoint->Common.VcConnecting.Connection != NULL) { endpoint->Common.VcConnecting.Connection = NULL;
//
// Manually delete the connected reference if somebody else
// hasn't already done so. We can't use
// AfdDeleteConnectedReference() because it refuses to delete
// the connected reference until the endpoint has been cleaned
// up.
//
if ( connection->ConnectedReferenceAdded ) { connection->ConnectedReferenceAdded = FALSE; AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle ); DEREFERENCE_CONNECTION( connection ); } else { AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle ); }
//
// Dereference the connection block stored on the endpoint.
// This should cause the connection object reference count to go
// to zero to the connection object can be deleted.
//
DEREFERENCE_CONNECTION( connection ); } else { AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle ); }
}
AFD_FREE_POOL (context, AFD_TDI_POOL_TAG); Irp->AssociatedIrp.SystemBuffer = NULL;
//
// If pending has be returned for this irp then mark the current
// stack as pending.
//
if ( Irp->PendingReturned ) { IoMarkIrpPending(Irp); }
AfdCompleteOutstandingIrp( endpoint, Irp );
//
// Dereference connection to account for reference
// we added in AfdConnect
//
DEREFERENCE_CONNECTION( connection );
//
// Try to queue kernel APC to the user thread that
// started the connection operation, so we can
// communicate the status of the connect operation to
// msafd.dll before we inform the application through
// the select or EventSelect. Otherwise, we run into the
// race condition when application learns about connect first,
// calls msafd.dll that is not aware of the completion and
// returns WSAENOTCONN.
//
if ((Irp->RequestorMode==UserMode) && // Must be user mode calls
(Irp->UserBuffer!=NULL) && // Must be interested in status
// Thread should be able to
// run APCs.
(KeInitializeApc (&endpoint->Common.VcConnecting.Apc, PsGetThreadTcb (Irp->Tail.Overlay.Thread), Irp->ApcEnvironment, AfdConnectApcKernelRoutine, AfdConnectApcRundownRoutine, (PKNORMAL_ROUTINE)NULL, KernelMode, NULL ), KeInsertQueueApc (&endpoint->Common.VcConnecting.Apc, Irp, rootEndpoint, AfdPriorityBoost))) { //
// We will complete the IRP in the APC.
//
return STATUS_MORE_PROCESSING_REQUIRED; } else { //
// APC was not necessary or did not work.
// Complete it here.
//
AfdFinishConnect (endpoint, Irp, rootEndpoint); return STATUS_SUCCESS; } } // AfdRestartJoin
NTSTATUS FASTCALL AfdSuperConnect ( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp )
/*++
Routine Description:
Handles the IOCTL_AFD_SUPER_CONNECT IOCTL.
Arguments:
Irp - Pointer to I/O request packet.
IrpSp - pointer to the IO stack location to use for this request.
Return Value:
NTSTATUS -- Indicates whether the request was successfully queued.
--*/
{ NTSTATUS status; PAFD_ENDPOINT endpoint; PAFD_CONNECTION connection; PAFD_BUFFER afdBuffer; PTRANSPORT_ADDRESS remoteAddress; PVOID context; PTDI_CONNECTION_INFORMATION requestConnectionInfo, returnConnectionInfo;
PAGED_CODE( );
//
// Initialize for proper cleanup
//
afdBuffer = NULL; endpoint = IrpSp->FileObject->FsContext;
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength< sizeof (TRANSPORT_ADDRESS)) { status = STATUS_BUFFER_TOO_SMALL; goto complete; }
try { if( Irp->RequestorMode != KernelMode ) {
ProbeForRead( IrpSp->Parameters.DeviceIoControl.Type3InputBuffer, IrpSp->Parameters.DeviceIoControl.InputBufferLength, PROBE_ALIGNMENT (TRANSPORT_ADDRESS) );
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength!=0) { ProbeForRead (Irp->UserBuffer, IrpSp->Parameters.DeviceIoControl.OutputBufferLength, sizeof (UCHAR)); } }
afdBuffer = AfdGetBufferRaiseOnFailure ( IrpSp->Parameters.DeviceIoControl.OutputBufferLength, IrpSp->Parameters.DeviceIoControl.InputBufferLength, endpoint->OwningProcess );
remoteAddress = afdBuffer->TdiInfo.RemoteAddress;
RtlCopyMemory (afdBuffer->TdiInfo.RemoteAddress, IrpSp->Parameters.DeviceIoControl.Type3InputBuffer, IrpSp->Parameters.DeviceIoControl.InputBufferLength); afdBuffer->TdiInfo.RemoteAddressLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; //
// Validate internal consistency of the transport address structure.
// Note that we HAVE to do this after copying since the malicious
// application can change the content of the buffer on us any time
// and our check will be bypassed.
//
if ((remoteAddress->TAAddressCount!=1) || (LONG)afdBuffer->TdiInfo.RemoteAddressLength< FIELD_OFFSET (TRANSPORT_ADDRESS, Address[0].Address[remoteAddress->Address[0].AddressLength])) { ExRaiseStatus (STATUS_INVALID_PARAMETER); }
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength>0) { RtlCopyMemory (afdBuffer->Buffer, Irp->UserBuffer, IrpSp->Parameters.DeviceIoControl.OutputBufferLength ); afdBuffer->DataLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength; } else { afdBuffer->DataLength = 0; } } except (AFD_EXCEPTION_FILTER(&status)) { goto complete; }
if (!AFD_START_STATE_CHANGE (endpoint, AfdEndpointStateConnected)) { status = STATUS_INVALID_PARAMETER; goto complete; }
//
// If the endpoint is not bound, then this is an invalid request.
// Listening endpoints are not allowed as well.
// We do not support sending data with TDI buffering transports too.
//
if ( endpoint->Type != AfdBlockTypeEndpoint || endpoint->State != AfdEndpointStateBound || endpoint->Listening || (IS_TDI_BUFFERRING (endpoint) && IrpSp->Parameters.DeviceIoControl.OutputBufferLength!=0)) { if (endpoint->State==AfdEndpointStateConnected) { status = STATUS_CONNECTION_ACTIVE; } else { status = STATUS_INVALID_PARAMETER; } goto complete_state_change; }
IF_DEBUG(CONNECT) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdSuperConnect: starting connect on endpoint %p\n", endpoint )); }
//
// Create a connection object to use for the connect operation.
//
status = AfdCreateConnection( &endpoint->TransportInfo->TransportDeviceName, endpoint->AddressHandle, IS_TDI_BUFFERRING(endpoint), endpoint->InLine, endpoint->OwningProcess, &connection );
if ( !NT_SUCCESS(status) ) { goto complete_state_change; }
//
// Set up a referenced pointer from the connection to the endpoint.
// Note that we set up the connection's pointer to the endpoint
// BEFORE the endpoint's pointer to the connection so that AfdPoll
// doesn't try to back reference the endpoint from the connection.
//
REFERENCE_ENDPOINT( endpoint ); connection->Endpoint = endpoint;
//
// Remember that this is now a connecting type of endpoint, and set
// up a pointer to the connection in the endpoint. This is
// implicitly a referenced pointer.
//
endpoint->Common.VcConnecting.Connection = connection; endpoint->Type = AfdBlockTypeVcConnecting;
ASSERT( IS_TDI_BUFFERRING(endpoint) == connection->TdiBufferring );
//
// Add an additional reference to the connection. This prevents the
// connection from being closed until the disconnect event handler
// is called.
//
AfdAddConnectedReference( connection );
//
// Since we may be reissuing a connect after a previous failed connect,
// reenable the failed connect event bit.
//
AfdEnableFailedConnectEvent( endpoint );
//
// Copy remote address to the user mode context
//
context = AfdLockEndpointContext (endpoint); if ( (((CLONG)(endpoint->Common.VcConnecting.RemoteSocketAddressOffset+ endpoint->Common.VcConnecting.RemoteSocketAddressLength)) < endpoint->ContextLength) && (endpoint->Common.VcConnecting.RemoteSocketAddressLength >= remoteAddress->Address[0].AddressLength + sizeof(u_short))) {
RtlMoveMemory ((PUCHAR)context + endpoint->Common.VcConnecting.RemoteSocketAddressOffset, &remoteAddress->Address[0].AddressType, remoteAddress->Address[0].AddressLength + sizeof(u_short)); } else { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_WARNING_LEVEL, "AfdSuperConnect: Could not copy remote address for AcceptEx on endpoint: %p, process: %p\n", endpoint, endpoint->OwningProcess)); } AfdUnlockEndpointContext (endpoint, context); //
// Reference the connection block so it does not go away even if
// endpoint's reference to it is removed (in cleanup)
//
REFERENCE_CONNECTION (connection);
//
// If there are connect data buffers, move them from the endpoint
// structure to the connection structure and set up the necessary
// pointers in the connection request we're going to give to the TDI
// provider. Do this in a subroutine so this routine can be pageable.
//
requestConnectionInfo = &afdBuffer->TdiInfo; afdBuffer->TdiInfo.UserDataLength = 0; afdBuffer->TdiInfo.UserData = NULL; afdBuffer->TdiInfo.OptionsLength = 0; afdBuffer->TdiInfo.Options = NULL; //
// Temporarily use IRP embedded in afd buffer
// for return connection information.
//
{ C_ASSERT (sizeof (TDI_CONNECTION_INFORMATION)<= sizeof (IO_STACK_LOCATION)); } returnConnectionInfo = (PTDI_CONNECTION_INFORMATION)IoGetNextIrpStackLocation (afdBuffer->Irp); RtlZeroMemory (returnConnectionInfo, sizeof (*returnConnectionInfo));
if ( endpoint->Common.VirtualCircuit.ConnectDataBuffers != NULL ) { AfdSetupConnectDataBuffers( endpoint, connection, &requestConnectionInfo, &returnConnectionInfo ); }
afdBuffer->Context = connection;
//
// Build a TDI kernel-mode connect request in the next stack location
// of the IRP.
//
TdiBuildConnect( Irp, connection->DeviceObject, connection->FileObject, AfdRestartSuperConnect, afdBuffer, &AfdInfiniteTimeout, requestConnectionInfo, returnConnectionInfo );
AFD_VERIFY_ADDRESS (connection, afdBuffer->TdiInfo.RemoteAddress);
ObReferenceObject (IrpSp->FileObject); //
// Call the transport to actually perform the connect operation.
//
return AfdIoCallDriver( endpoint, connection->DeviceObject, Irp );
complete_state_change: AFD_END_STATE_CHANGE (endpoint);
complete:
if (afdBuffer!=NULL) { AfdReturnBuffer (&afdBuffer->Header, endpoint->OwningProcess); }
Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; IoCompleteRequest( Irp, AfdPriorityBoost );
return status;
} // AfdSuperConnect
NTSTATUS AfdRestartSuperConnect ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context )
/*++
Routine Description:
Handles the IOCTL_AFD_CONNECT IOCTL.
Arguments:
Irp - Pointer to I/O request packet.
IrpSp - pointer to the IO stack location to use for this request.
Return Value:
NTSTATUS -- Indicates whether the request was successfully queued.
--*/
{ PAFD_ENDPOINT endpoint; PAFD_CONNECTION connection; AFD_LOCK_QUEUE_HANDLE lockHandle; PIO_STACK_LOCATION irpSp; PAFD_BUFFER afdBuffer;
afdBuffer = Context; connection = afdBuffer->Context; ASSERT( connection->Type == AfdBlockTypeConnection );
irpSp = IoGetCurrentIrpStackLocation( Irp ); endpoint = irpSp->FileObject->FsContext; ASSERT( endpoint->Type == AfdBlockTypeVcConnecting ); ASSERT( endpoint==connection->Endpoint );
IF_DEBUG(CONNECT) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdRestartConnect: connect completed, status = %X, endpoint = %p\n", Irp->IoStatus.Status, endpoint )); }
if ( connection->ConnectDataBuffers != NULL ) {
//
// If there are connect buffers on this endpoint, remember the
// size of the return connect data.
//
AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
//
// Double-check under the lock
//
if ( connection->ConnectDataBuffers != NULL ) { AfdSaveReceivedConnectData( &connection->ConnectDataBuffers, IOCTL_AFD_SET_CONNECT_DATA, connection->ConnectDataBuffers->ReturnConnectionInfo.UserData, connection->ConnectDataBuffers->ReturnConnectionInfo.UserDataLength );
AfdSaveReceivedConnectData( &connection->ConnectDataBuffers, IOCTL_AFD_SET_CONNECT_OPTIONS, connection->ConnectDataBuffers->ReturnConnectionInfo.Options, connection->ConnectDataBuffers->ReturnConnectionInfo.OptionsLength ); }
AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle ); }
//
// Indicate that the connect completed. Implicitly, the successful
// completion of a connect also means that the caller can do a send
// on the socket.
//
if ( NT_SUCCESS(Irp->IoStatus.Status)) {
//
// If the request succeeded, set the endpoint to the connected
// state. The endpoint type has already been set to
// AfdBlockTypeVcConnecting.
//
endpoint->State = AfdEndpointStateConnected; ASSERT( endpoint->Type == AfdBlockTypeVcConnecting );
//
// Remember the time that the connection started.
//
connection->ConnectTime = KeQueryInterruptTime();
} else {
AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
//
// The connect failed, so reset the type to open.
// Otherwise, we won't be able to start another connect
//
endpoint->Type = AfdBlockTypeEndpoint;
if (endpoint->Common.VcConnecting.Connection!=NULL) { ASSERT (connection==endpoint->Common.VcConnecting.Connection); endpoint->Common.VcConnecting.Connection = NULL;
//
// Manually delete the connected reference if somebody else
// hasn't already done so. We can't use
// AfdDeleteConnectedReference() because it refuses to delete
// the connected reference until the endpoint has been cleaned
// up.
//
if ( connection->ConnectedReferenceAdded ) { connection->ConnectedReferenceAdded = FALSE; AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle ); DEREFERENCE_CONNECTION( connection ); } else { AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle ); } //
// Dereference the connection block stored on the endpoint.
// This should cause the connection object reference count to go
// to zero to the connection object can be deleted.
//
DEREFERENCE_CONNECTION( connection ); } else { //
// The endpoint's reference to connection was removed
// (perhaps in cleanup);
//
AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle ); }
}
//
// If pending has be returned for this irp then mark the current
// stack as pending.
//
if ( Irp->PendingReturned ) { IoMarkIrpPending(Irp); }
AfdCompleteOutstandingIrp( endpoint, Irp );
AfdFinishConnect (endpoint, Irp, NULL);
if (NT_SUCCESS (Irp->IoStatus.Status) && afdBuffer->DataLength>0) { AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle); if ( !connection->CleanupBegun && !connection->AbortIndicated ) { NTSTATUS status; //
// Update count of send bytes pending on the connection.
//
connection->VcBufferredSendBytes += afdBuffer->DataLength; connection->VcBufferredSendCount += 1; AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
afdBuffer->Mdl->ByteCount = afdBuffer->DataLength; ASSERT (afdBuffer->Context == connection );
TdiBuildSend( afdBuffer->Irp, connection->DeviceObject, connection->FileObject, AfdRestartBufferSend, afdBuffer, afdBuffer->Mdl, 0, afdBuffer->DataLength );
Irp->IoStatus.Information = afdBuffer->DataLength;
//
// Call the transport to actually perform the send.
//
status = IoCallDriver( connection->DeviceObject, afdBuffer->Irp ); if (!NT_SUCCESS (status)) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; }
goto exit; } if (connection->CleanupBegun) { Irp->IoStatus.Status = STATUS_LOCAL_DISCONNECT; } else { ASSERT (connection->AbortIndicated); Irp->IoStatus.Status = STATUS_REMOTE_DISCONNECT; } AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle); }
afdBuffer->DataOffset = 0; AfdReturnBuffer (&afdBuffer->Header, endpoint->OwningProcess); //
// Dereference connection to account for reference we added in AfdConnect
//
DEREFERENCE_CONNECTION (connection);
exit: return STATUS_SUCCESS;
} // AfdRestartSuperConnect
|