2573 lines
77 KiB
C
2573 lines
77 KiB
C
/*++
|
||
|
||
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
|