3241 lines
95 KiB
C
3241 lines
95 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1989-1999 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
accept.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the handling code for IOCTL_AFD_ACCEPT.
|
|||
|
as well as IOCTL_AFD_SUPER_ACCEPT
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
David Treadwell (davidtr) 21-Feb-1992
|
|||
|
|
|||
|
Revision History:
|
|||
|
Vadim Eydelman (vadime) 1999 - No spinlock performance path in super accept,
|
|||
|
general code restructuring.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "afdp.h"
|
|||
|
|
|||
|
VOID
|
|||
|
AfdDoListenBacklogReplenish (
|
|||
|
IN PVOID Context
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdReplenishListenBacklog (
|
|||
|
IN PAFD_ENDPOINT Endpoint
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
AfdReportConnectionAllocationFailure (
|
|||
|
PAFD_ENDPOINT Endpoint,
|
|||
|
NTSTATUS Status
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdContinueSuperAccept (
|
|||
|
IN PIRP Irp,
|
|||
|
PAFD_CONNECTION Connection
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdRestartSuperAcceptGetAddress (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID Context
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdRestartSuperAcceptReceive (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID Context
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdRestartDelayedAccept (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID Context
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
AfdSuperAcceptApcKernelRoutine (
|
|||
|
IN struct _KAPC *Apc,
|
|||
|
IN OUT PKNORMAL_ROUTINE *NormalRoutine,
|
|||
|
IN OUT PVOID *NormalContext,
|
|||
|
IN OUT PVOID *SystemArgument1,
|
|||
|
IN OUT PVOID *SystemArgument2
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
AfdSuperAcceptApcRundownRoutine (
|
|||
|
IN struct _KAPC *Apc
|
|||
|
);
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text( PAGEAFD, AfdAccept )
|
|||
|
#pragma alloc_text( PAGEAFD, AfdSuperAccept )
|
|||
|
#pragma alloc_text( PAGEAFD, AfdDeferAccept )
|
|||
|
#pragma alloc_text( PAGE, AfdDoListenBacklogReplenish )
|
|||
|
#pragma alloc_text( PAGEAFD, AfdSetupAcceptEndpoint )
|
|||
|
#pragma alloc_text( PAGE, AfdReplenishListenBacklog )
|
|||
|
#pragma alloc_text( PAGEAFD, AfdReportConnectionAllocationFailure )
|
|||
|
#pragma alloc_text( PAGEAFD, AfdInitiateListenBacklogReplenish )
|
|||
|
#pragma alloc_text( PAGEAFD, AfdRestartSuperAccept )
|
|||
|
#pragma alloc_text( PAGEAFD, AfdRestartSuperAcceptListen )
|
|||
|
#pragma alloc_text( PAGEAFD, AfdContinueSuperAccept )
|
|||
|
#pragma alloc_text( PAGEAFD, AfdServiceSuperAccept )
|
|||
|
#pragma alloc_text( PAGEAFD, AfdRestartSuperAcceptGetAddress )
|
|||
|
#pragma alloc_text( PAGEAFD, AfdRestartSuperAcceptReceive )
|
|||
|
#pragma alloc_text( PAGE, AfdSuperAcceptApcKernelRoutine )
|
|||
|
#pragma alloc_text( PAGE, AfdSuperAcceptApcRundownRoutine )
|
|||
|
#pragma alloc_text( PAGEAFD, AfdCancelSuperAccept )
|
|||
|
#pragma alloc_text( PAGEAFD, AfdCleanupSuperAccept )
|
|||
|
#pragma alloc_text( PAGEAFD, AfdRestartDelayedAccept)
|
|||
|
#pragma alloc_text( PAGEAFD, AfdRestartDelayedSuperAccept)
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Macros to make the super accept restart code more maintainable.
|
|||
|
//
|
|||
|
|
|||
|
#define AfdRestartSuperAcceptInfo DeviceIoControl
|
|||
|
|
|||
|
// Used while IRP is in AFD queue (otherwise AfdAcceptFileObject
|
|||
|
// is stored as completion routine context).
|
|||
|
#define AfdAcceptFileObject Type3InputBuffer
|
|||
|
// Used when IRP is passed to the transport (otherwise MdlAddress
|
|||
|
// is stored in the IRP itself).
|
|||
|
#define AfdMdlAddress Type3InputBuffer
|
|||
|
|
|||
|
#define AfdReceiveDataLength OutputBufferLength
|
|||
|
#define AfdRemoteAddressLength InputBufferLength
|
|||
|
#define AfdLocalAddressLength IoControlCode
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Similar macros for delayed accept restart code.
|
|||
|
//
|
|||
|
#define AfdRestartDelayedAcceptInfo DeviceIoControl
|
|||
|
#define AfdSystemBuffer Type3InputBuffer
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
FASTCALL
|
|||
|
AfdAccept (
|
|||
|
IN PIRP Irp,
|
|||
|
IN PIO_STACK_LOCATION IrpSp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Accepts an incoming connection. The connection is identified by the
|
|||
|
sequence number returned in the wait for listen IRP, and then
|
|||
|
associated with the endpoint specified in this request. When this
|
|||
|
request completes, the connection is fully established and ready for
|
|||
|
data transfer.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Irp - a pointer to a transmit file IRP.
|
|||
|
|
|||
|
IrpSp - Our stack location for this IRP.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if the request was completed successfully, or a
|
|||
|
failure status code if there was an error.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
PAFD_ACCEPT_INFO acceptInfo;
|
|||
|
PAFD_ENDPOINT listenEndpoint;
|
|||
|
PFILE_OBJECT acceptFileObject;
|
|||
|
PAFD_ENDPOINT acceptEndpoint;
|
|||
|
PAFD_CONNECTION connection;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Set up local variables.
|
|||
|
//
|
|||
|
|
|||
|
listenEndpoint = IrpSp->FileObject->FsContext;
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
|
|||
|
#ifdef _WIN64
|
|||
|
if (IoIs32bitProcess (Irp)) {
|
|||
|
PAFD_ACCEPT_INFO newSystemBuffer;
|
|||
|
PAFD_ACCEPT_INFO32 oldSystemBuffer = Irp->AssociatedIrp.SystemBuffer;
|
|||
|
|
|||
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|||
|
sizeof(AFD_ACCEPT_INFO32) ) {
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
goto complete;
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
newSystemBuffer = ExAllocatePoolWithQuota (NonPagedPool, sizeof (AFD_ACCEPT_INFO));
|
|||
|
|
|||
|
}
|
|||
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
status = GetExceptionCode ();
|
|||
|
goto complete;
|
|||
|
}
|
|||
|
|
|||
|
newSystemBuffer->AcceptHandle = oldSystemBuffer->AcceptHandle;
|
|||
|
newSystemBuffer->Sequence = oldSystemBuffer->Sequence;
|
|||
|
|
|||
|
ExFreePool (Irp->AssociatedIrp.SystemBuffer);
|
|||
|
Irp->AssociatedIrp.SystemBuffer = newSystemBuffer;
|
|||
|
IrpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof (AFD_ACCEPT_INFO);
|
|||
|
}
|
|||
|
#endif // _WIN64
|
|||
|
|
|||
|
acceptInfo = Irp->AssociatedIrp.SystemBuffer;
|
|||
|
|
|||
|
//
|
|||
|
// Make sure that this request is valid.
|
|||
|
//
|
|||
|
|
|||
|
if ( !listenEndpoint->Listening ||
|
|||
|
IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|||
|
sizeof(AFD_ACCEPT_INFO) ||
|
|||
|
Irp->MdlAddress!=NULL) {
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
goto complete;
|
|||
|
}
|
|||
|
|
|||
|
ASSERT ((listenEndpoint->Type & AfdBlockTypeVcListening)==AfdBlockTypeVcListening);
|
|||
|
|
|||
|
//
|
|||
|
// Check for if the caller is unaware of the SAN
|
|||
|
// provider activation and report the error.
|
|||
|
//
|
|||
|
if (!acceptInfo->SanActive && AfdSanServiceHelper!=NULL) {
|
|||
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
|
|||
|
"AFD: Process %p is being told to enable SAN on accept\n",
|
|||
|
PsGetCurrentProcessId ()));
|
|||
|
status = STATUS_INVALID_PARAMETER_12;
|
|||
|
goto complete;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Add another free connection to replace the one we're accepting.
|
|||
|
// Also, add extra to account for past failures in calls to
|
|||
|
// AfdAddFreeConnection().
|
|||
|
//
|
|||
|
|
|||
|
InterlockedIncrement(
|
|||
|
&listenEndpoint->Common.VcListening.FailedConnectionAdds
|
|||
|
);
|
|||
|
|
|||
|
AfdReplenishListenBacklog( listenEndpoint );
|
|||
|
|
|||
|
//
|
|||
|
// Obtain a pointer to the endpoint on which we're going to
|
|||
|
// accept the connection.
|
|||
|
//
|
|||
|
|
|||
|
status = ObReferenceObjectByHandle(
|
|||
|
acceptInfo->AcceptHandle,
|
|||
|
(IrpSp->Parameters.DeviceIoControl.IoControlCode>>14) & 3,
|
|||
|
// DesiredAccess
|
|||
|
*IoFileObjectType,
|
|||
|
Irp->RequestorMode,
|
|||
|
(PVOID *)&acceptFileObject,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if ( !NT_SUCCESS(status) ) {
|
|||
|
goto complete;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// We may have a file object that is not an AFD endpoint. Make sure
|
|||
|
// that this is an actual AFD endpoint.
|
|||
|
//
|
|||
|
|
|||
|
if ( acceptFileObject->DeviceObject!=AfdDeviceObject) {
|
|||
|
status = STATUS_INVALID_HANDLE;
|
|||
|
goto complete_deref;
|
|||
|
}
|
|||
|
|
|||
|
acceptEndpoint = acceptFileObject->FsContext;
|
|||
|
if (acceptEndpoint->TransportInfo!=listenEndpoint->TransportInfo) {
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
goto complete_deref;
|
|||
|
}
|
|||
|
|
|||
|
ASSERT( InterlockedIncrement( &acceptEndpoint->ObReferenceBias ) > 0 );
|
|||
|
|
|||
|
IF_DEBUG(ACCEPT) {
|
|||
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
|
|||
|
"AfdAccept: file object %p, accept endpoint %p, listen endpoint %p\n",
|
|||
|
acceptFileObject, acceptEndpoint, listenEndpoint ));
|
|||
|
}
|
|||
|
|
|||
|
if (AFD_START_STATE_CHANGE (acceptEndpoint, AfdEndpointStateConnected)) {
|
|||
|
if (acceptEndpoint->State!=AfdEndpointStateOpen) {
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
else {
|
|||
|
AFD_LOCK_QUEUE_HANDLE lockHandle;
|
|||
|
AfdAcquireSpinLock (&listenEndpoint->SpinLock, &lockHandle);
|
|||
|
connection = AfdGetReturnedConnection (listenEndpoint,
|
|||
|
acceptInfo->Sequence);
|
|||
|
if (connection==NULL) {
|
|||
|
AfdReleaseSpinLock (&listenEndpoint->SpinLock, &lockHandle);
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
else if (connection->SanConnection) {
|
|||
|
Irp->Tail.Overlay.DriverContext[3] = acceptInfo->AcceptHandle;
|
|||
|
IrpSp->Parameters.AfdRestartSuperAcceptInfo.AfdAcceptFileObject = acceptFileObject;
|
|||
|
IrpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength = 0;
|
|||
|
IrpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength = 0;
|
|||
|
IrpSp->Parameters.AfdRestartSuperAcceptInfo.AfdRemoteAddressLength = 0;
|
|||
|
status = AfdSanAcceptCore (Irp, acceptFileObject, connection, &lockHandle);
|
|||
|
if (status==STATUS_PENDING) {
|
|||
|
return STATUS_PENDING;
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
status = AfdAcceptCore (Irp, acceptEndpoint, connection);
|
|||
|
AfdReleaseSpinLock (&listenEndpoint->SpinLock, &lockHandle);
|
|||
|
|
|||
|
AFD_RETURN_REMOTE_ADDRESS (
|
|||
|
connection->RemoteAddress,
|
|||
|
connection->RemoteAddressLength
|
|||
|
);
|
|||
|
connection->RemoteAddress = NULL;
|
|||
|
|
|||
|
if (status==STATUS_SUCCESS) {
|
|||
|
NOTHING;
|
|||
|
}
|
|||
|
else if (status==STATUS_PENDING) {
|
|||
|
|
|||
|
//
|
|||
|
// Remember that a TDI accept has started on this endpoint.
|
|||
|
//
|
|||
|
|
|||
|
InterlockedIncrement(
|
|||
|
&listenEndpoint->Common.VcListening.TdiAcceptPendingCount
|
|||
|
);
|
|||
|
|
|||
|
IrpSp->Parameters.AfdRestartDelayedAcceptInfo.AfdSystemBuffer =
|
|||
|
Irp->AssociatedIrp.SystemBuffer;
|
|||
|
Irp->AssociatedIrp.SystemBuffer = NULL;
|
|||
|
|
|||
|
ASSERT (Irp->MdlAddress==NULL);
|
|||
|
|
|||
|
IoSetCompletionRoutine(
|
|||
|
Irp,
|
|||
|
AfdRestartDelayedAccept,
|
|||
|
acceptFileObject,
|
|||
|
TRUE,
|
|||
|
TRUE,
|
|||
|
TRUE
|
|||
|
);
|
|||
|
|
|||
|
AfdIoCallDriver (
|
|||
|
acceptEndpoint,
|
|||
|
acceptEndpoint->Common.VcConnecting.Connection->DeviceObject,
|
|||
|
Irp
|
|||
|
);
|
|||
|
|
|||
|
return STATUS_PENDING;
|
|||
|
}
|
|||
|
else {
|
|||
|
AfdAbortConnection (connection);
|
|||
|
ASSERT (status==STATUS_CANCELLED);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
AFD_END_STATE_CHANGE (acceptEndpoint);
|
|||
|
}
|
|||
|
else {
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
|||
|
|
|||
|
complete_deref:
|
|||
|
ObDereferenceObject( acceptFileObject );
|
|||
|
|
|||
|
complete:
|
|||
|
|
|||
|
Irp->IoStatus.Status = status;
|
|||
|
ASSERT( Irp->CancelRoutine == NULL );
|
|||
|
|
|||
|
IoCompleteRequest( Irp, AfdPriorityBoost );
|
|||
|
|
|||
|
return status;
|
|||
|
|
|||
|
} // AfdAccept
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdAcceptCore (
|
|||
|
IN PIRP AcceptIrp,
|
|||
|
IN PAFD_ENDPOINT AcceptEndpoint,
|
|||
|
IN PAFD_CONNECTION Connection
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Performs the key functions of associating a connection accepted
|
|||
|
on a listening endpoint with a new endpoint.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
AcceptIrp - Irp used for accept operation
|
|||
|
|
|||
|
AcceptEndpoint - the new endpoint with which to associate the
|
|||
|
connectuion.
|
|||
|
|
|||
|
Connection - the connection being accepted.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if the operation was completed successfully,
|
|||
|
STATUS_PENDING if IRP was passed further to the transport
|
|||
|
failure status code if there was an error.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAFD_ENDPOINT listenEndpoint;
|
|||
|
NTSTATUS status;
|
|||
|
PIO_STACK_LOCATION irpSp;
|
|||
|
AFD_LOCK_QUEUE_HANDLE lockHandle;
|
|||
|
|
|||
|
irpSp = IoGetCurrentIrpStackLocation (AcceptIrp);
|
|||
|
listenEndpoint = irpSp->FileObject->FsContext;
|
|||
|
|
|||
|
//
|
|||
|
// Reenable the accept event bit, and if there are additional
|
|||
|
// unaccepted connections on the endpoint, post another event.
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
listenEndpoint->EventsActive &= ~AFD_POLL_ACCEPT;
|
|||
|
|
|||
|
IF_DEBUG(EVENT_SELECT) {
|
|||
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
|
|||
|
"AfdAcceptCore: Endp %08lX, Active %08lX\n",
|
|||
|
listenEndpoint,
|
|||
|
listenEndpoint->EventsActive
|
|||
|
));
|
|||
|
}
|
|||
|
|
|||
|
if( !IsListEmpty( &listenEndpoint->Common.VcListening.UnacceptedConnectionListHead ) ) {
|
|||
|
|
|||
|
AfdIndicateEventSelectEvent(
|
|||
|
listenEndpoint,
|
|||
|
AFD_POLL_ACCEPT,
|
|||
|
STATUS_SUCCESS
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Do not release the listening endpoint spinlock here.
|
|||
|
// We are going to be chaning connection object which assumes
|
|||
|
// protection from listening endpoint spinlock until it is associated
|
|||
|
// with accept endpoint (this plugs nasty racing conditions when
|
|||
|
// receive is indicated rigth before connection object is updated, so
|
|||
|
// it takes listening endpoint spinlock, and rigth before it queues
|
|||
|
// the buffer to the connection object, it gets associated with accept
|
|||
|
// endpoint and AcceptEx'es receive does not notice the buffer because
|
|||
|
// it takes accept endpoint spinlock)
|
|||
|
//
|
|||
|
// AfdReleaseSpinLock( &ListenEndpoint->SpinLock, &lockHandle );
|
|||
|
|
|||
|
//
|
|||
|
// Check the state of the accepting endpoint under the guard
|
|||
|
// of the endpoint's spinlock.
|
|||
|
//
|
|||
|
|
|||
|
AfdAcquireSpinLockAtDpcLevel( &AcceptEndpoint->SpinLock, &lockHandle);
|
|||
|
status = AfdSetupAcceptEndpoint (listenEndpoint, AcceptEndpoint, Connection);
|
|||
|
if (status==STATUS_SUCCESS) {
|
|||
|
|
|||
|
|
|||
|
if (IS_DELAYED_ACCEPTANCE_ENDPOINT (listenEndpoint)) {
|
|||
|
PTDI_CONNECTION_INFORMATION requestConnectionInformation;
|
|||
|
|
|||
|
if( Connection->ConnectDataBuffers != NULL ) {
|
|||
|
|
|||
|
//
|
|||
|
// We allocated extra space at the end of the connect data
|
|||
|
// buffers structure. We'll use this for the
|
|||
|
// TDI_CONNECTION_INFORMATION structure that holds response
|
|||
|
// connect data and options. Not pretty, but the fastest
|
|||
|
// and easiest way to accomplish this.
|
|||
|
//
|
|||
|
|
|||
|
requestConnectionInformation =
|
|||
|
&Connection->ConnectDataBuffers->RequestConnectionInfo;
|
|||
|
|
|||
|
RtlZeroMemory(
|
|||
|
requestConnectionInformation,
|
|||
|
sizeof(*requestConnectionInformation)
|
|||
|
);
|
|||
|
|
|||
|
requestConnectionInformation->UserData =
|
|||
|
Connection->ConnectDataBuffers->SendConnectData.Buffer;
|
|||
|
requestConnectionInformation->UserDataLength =
|
|||
|
Connection->ConnectDataBuffers->SendConnectData.BufferLength;
|
|||
|
requestConnectionInformation->Options =
|
|||
|
Connection->ConnectDataBuffers->SendConnectOptions.Buffer;
|
|||
|
requestConnectionInformation->OptionsLength =
|
|||
|
Connection->ConnectDataBuffers->SendConnectOptions.BufferLength;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
requestConnectionInformation = NULL;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
TdiBuildAccept(
|
|||
|
AcceptIrp,
|
|||
|
Connection->DeviceObject,
|
|||
|
Connection->FileObject,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
requestConnectionInformation,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
status = STATUS_PENDING;
|
|||
|
}
|
|||
|
else {
|
|||
|
//
|
|||
|
// Set the endpoint to the connected state.
|
|||
|
//
|
|||
|
|
|||
|
AcceptEndpoint->State = AfdEndpointStateConnected;
|
|||
|
Connection->State = AfdConnectionStateConnected;
|
|||
|
|
|||
|
//
|
|||
|
// Set events active field base on data accumulated on the connection.
|
|||
|
//
|
|||
|
|
|||
|
if( IS_DATA_ON_CONNECTION( Connection ) ||
|
|||
|
( AcceptEndpoint->InLine &&
|
|||
|
IS_EXPEDITED_DATA_ON_CONNECTION( Connection ) ) ) {
|
|||
|
|
|||
|
AcceptEndpoint->EventsActive |= AFD_POLL_RECEIVE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if( !AcceptEndpoint->InLine &&
|
|||
|
IS_EXPEDITED_DATA_ON_CONNECTION( Connection ) ) {
|
|||
|
|
|||
|
AcceptEndpoint->EventsActive |= AFD_POLL_RECEIVE_EXPEDITED;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
AcceptEndpoint->EventsActive |= AFD_POLL_SEND;
|
|||
|
|
|||
|
if( Connection->DisconnectIndicated ) {
|
|||
|
|
|||
|
AcceptEndpoint->EventsActive |= AFD_POLL_DISCONNECT;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if( Connection->AbortIndicated ) {
|
|||
|
|
|||
|
AcceptEndpoint->EventsActive |= AFD_POLL_ABORT;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
IF_DEBUG(EVENT_SELECT) {
|
|||
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
|
|||
|
"AfdAcceptCore: Endp %08lX, Active %08lX\n",
|
|||
|
AcceptEndpoint,
|
|||
|
AcceptEndpoint->EventsActive
|
|||
|
));
|
|||
|
}
|
|||
|
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
AfdReleaseSpinLockFromDpcLevel( &AcceptEndpoint->SpinLock, &lockHandle);
|
|||
|
return status;
|
|||
|
} // AfdAcceptCore
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
AfdInitiateListenBacklogReplenish (
|
|||
|
IN PAFD_ENDPOINT Endpoint
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Queues a work item to begin replenishing the listen backlog
|
|||
|
on a listening endpoint.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Endpoint - the listening endpoint on which to replenish the
|
|||
|
backlog.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
AFD_LOCK_QUEUE_HANDLE lockHandle;
|
|||
|
|
|||
|
//
|
|||
|
// Check if backlog replenish is active already.
|
|||
|
//
|
|||
|
AfdAcquireSpinLock (&Endpoint->SpinLock, &lockHandle);
|
|||
|
if (!Endpoint->Common.VcListening.BacklogReplenishActive) {
|
|||
|
|
|||
|
Endpoint->Common.VcListening.BacklogReplenishActive = TRUE;
|
|||
|
//
|
|||
|
// Reference the endpoint so that it won't go away until we're
|
|||
|
// done with it.
|
|||
|
//
|
|||
|
|
|||
|
REFERENCE_ENDPOINT( Endpoint );
|
|||
|
|
|||
|
|
|||
|
AfdQueueWorkItem(
|
|||
|
AfdDoListenBacklogReplenish,
|
|||
|
&Endpoint->WorkItem
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle);
|
|||
|
return;
|
|||
|
} // AfdInitiateListenBacklogReplenish
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
AfdDoListenBacklogReplenish (
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The worker routine for replenishing the listen backlog on a
|
|||
|
listening endpoint. This routine only runs in the context of
|
|||
|
an executive worker thread.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - Points to an AFD_WORK_ITEM structure. The Context field
|
|||
|
of this structure points to the endpoint on which to replenish
|
|||
|
the listen backlog.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAFD_ENDPOINT endpoint;
|
|||
|
|
|||
|
PAGED_CODE( );
|
|||
|
|
|||
|
endpoint = CONTAINING_RECORD(
|
|||
|
Context,
|
|||
|
AFD_ENDPOINT,
|
|||
|
WorkItem
|
|||
|
);
|
|||
|
|
|||
|
ASSERT( endpoint->Type == AfdBlockTypeVcListening ||
|
|||
|
endpoint->Type == AfdBlockTypeVcBoth );
|
|||
|
|
|||
|
ASSERT (endpoint->Common.VcListening.BacklogReplenishActive == TRUE);
|
|||
|
//
|
|||
|
// It is ok to do this without spinlock protection
|
|||
|
// because only one thread can do this at a time
|
|||
|
// inside of the worker routine.
|
|||
|
//
|
|||
|
endpoint->Common.VcListening.BacklogReplenishActive = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// If the endpoint's state changed, don't replenish the backlog.
|
|||
|
//
|
|||
|
|
|||
|
if ( endpoint->Listening ) {
|
|||
|
NTSTATUS status;
|
|||
|
//
|
|||
|
// Fill up the free connection backlog.
|
|||
|
//
|
|||
|
|
|||
|
status = AfdReplenishListenBacklog( endpoint );
|
|||
|
if (!NT_SUCCESS (status)) {
|
|||
|
//
|
|||
|
// If we failed, try to notify application
|
|||
|
//
|
|||
|
AfdReportConnectionAllocationFailure (endpoint, status);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Clean up and return.
|
|||
|
//
|
|||
|
|
|||
|
DEREFERENCE_ENDPOINT( endpoint );
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} // AfdDoListenBacklogReplenish
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdReplenishListenBacklog (
|
|||
|
IN PAFD_ENDPOINT Endpoint
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Does the actual work of filling up the listen backlog on a listening
|
|||
|
endpoint.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Endpoint - the listening endpoint on which to replenish the
|
|||
|
listen backlog.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - if new connection was allocated or we already
|
|||
|
had enough
|
|||
|
status of conneciton allocation failure otherwise
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
LONG result;
|
|||
|
|
|||
|
PAGED_CODE( );
|
|||
|
|
|||
|
ASSERT( Endpoint->Type == AfdBlockTypeVcListening ||
|
|||
|
Endpoint->Type == AfdBlockTypeVcBoth );
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Decrement the count of failed connection additions.
|
|||
|
//
|
|||
|
|
|||
|
result = InterlockedDecrement(
|
|||
|
&Endpoint->Common.VcListening.FailedConnectionAdds
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Continue opening new free conections until we've hit the
|
|||
|
// backlog or a connection open fails.
|
|||
|
//
|
|||
|
// If the result of the decrement is negative, then we are either
|
|||
|
// all set on the connection count or else have available extra
|
|||
|
// connection objects on the listening endpoint. These connections
|
|||
|
// have been reused from prior connections which have now
|
|||
|
// terminated.
|
|||
|
//
|
|||
|
|
|||
|
while ( result >= 0 ) {
|
|||
|
|
|||
|
status = AfdAddFreeConnection( Endpoint );
|
|||
|
|
|||
|
if ( !NT_SUCCESS(status) ) {
|
|||
|
|
|||
|
InterlockedIncrement(
|
|||
|
&Endpoint->Common.VcListening.FailedConnectionAdds
|
|||
|
);
|
|||
|
|
|||
|
IF_DEBUG(LISTEN) {
|
|||
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
|
|||
|
"AfdReplenishListenBacklog: AfdAddFreeConnection failed: %X, fail count = %ld\n", status,
|
|||
|
Endpoint->Common.VcListening.FailedConnectionAdds ));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Return connection allocation failure to the application
|
|||
|
// if it cares to know (posted accept request).
|
|||
|
//
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
result = InterlockedDecrement(
|
|||
|
&Endpoint->Common.VcListening.FailedConnectionAdds
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Correct the counter to reflect the number of connections
|
|||
|
// we have available. Then just return from here.
|
|||
|
//
|
|||
|
|
|||
|
InterlockedIncrement(
|
|||
|
&Endpoint->Common.VcListening.FailedConnectionAdds
|
|||
|
);
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
|
|||
|
} // AfdReplenishListenBacklog
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
AfdReportConnectionAllocationFailure (
|
|||
|
PAFD_ENDPOINT Endpoint,
|
|||
|
NTSTATUS Status
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Reports connection allocation failure to the application by
|
|||
|
failing then first wait for listen irp in the queue (if application
|
|||
|
has AcceptEx or blockin accept outstanding, it will get this notification).
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Endpoint - the listening endpoint on which to report an error
|
|||
|
Status - status code to report
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
--*/
|
|||
|
{
|
|||
|
AFD_LOCK_QUEUE_HANDLE lockHandle;
|
|||
|
|
|||
|
AfdAcquireSpinLock (&Endpoint->SpinLock, &lockHandle);
|
|||
|
if ((Endpoint->Common.VcListening.FailedConnectionAdds>0) &&
|
|||
|
IsListEmpty (&Endpoint->Common.VcListening.UnacceptedConnectionListHead) &&
|
|||
|
!IsListEmpty (&Endpoint->Common.VcListening.ListeningIrpListHead)) {
|
|||
|
PIRP irp;
|
|||
|
PIO_STACK_LOCATION irpSp;
|
|||
|
|
|||
|
irp = CONTAINING_RECORD (Endpoint->Common.VcListening.ListeningIrpListHead.Flink,
|
|||
|
IRP,
|
|||
|
Tail.Overlay.ListEntry);
|
|||
|
irpSp = IoGetCurrentIrpStackLocation (irp);
|
|||
|
RemoveEntryList (&irp->Tail.Overlay.ListEntry);
|
|||
|
irp->Tail.Overlay.ListEntry.Flink = NULL;
|
|||
|
|
|||
|
AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle);
|
|||
|
|
|||
|
if (IoSetCancelRoutine (irp, NULL)==NULL) {
|
|||
|
KIRQL cancelIrql;
|
|||
|
//
|
|||
|
// If the cancel routine was NULL then cancel routine
|
|||
|
// may be running. Wait on the cancel spinlock until
|
|||
|
// the cancel routine is done.
|
|||
|
//
|
|||
|
// Note: The cancel routine will not find the IRP
|
|||
|
// since it is not in the list.
|
|||
|
//
|
|||
|
|
|||
|
IoAcquireCancelSpinLock( &cancelIrql );
|
|||
|
ASSERT( irp->Cancel );
|
|||
|
IoReleaseCancelSpinLock( cancelIrql );
|
|||
|
}
|
|||
|
if (irpSp->MajorFunction==IRP_MJ_INTERNAL_DEVICE_CONTROL) {
|
|||
|
AfdCleanupSuperAccept (irp, Status);
|
|||
|
}
|
|||
|
else {
|
|||
|
irp->IoStatus.Status = Status;
|
|||
|
irp->IoStatus.Information = 0;
|
|||
|
}
|
|||
|
IoCompleteRequest (irp, AfdPriorityBoost);
|
|||
|
}
|
|||
|
else {
|
|||
|
AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
FASTCALL
|
|||
|
AfdSuperAccept (
|
|||
|
IN PIRP Irp,
|
|||
|
IN PIO_STACK_LOCATION IrpSp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Initial entrypoint for handling super accept IRPs. A super accept
|
|||
|
combines several operations for high-performance connection
|
|||
|
acceptance. The combined operations are waiting for an incoming
|
|||
|
connection, accepting it, retrieving the local and remote socket
|
|||
|
addresses, and receiving the first chunk of data on the connection.
|
|||
|
|
|||
|
This routine verifies parameters, initializes data structures to be
|
|||
|
used for the request, and initiates the I/O.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Irp - a pointer to a transmit file IRP.
|
|||
|
|
|||
|
IrpSp - Our stack location for this IRP.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_PENDING if the request was initiated successfully, or a
|
|||
|
failure status code if there was an error.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAFD_ENDPOINT listenEndpoint;
|
|||
|
PAFD_ENDPOINT acceptEndpoint;
|
|||
|
PFILE_OBJECT acceptFileObject;
|
|||
|
HANDLE acceptHandle;
|
|||
|
ULONG receiveDataLength, localAddressLength, remoteAddressLength;
|
|||
|
BOOLEAN sanActive;
|
|||
|
#ifndef i386
|
|||
|
BOOLEAN fixAddressAlignment;
|
|||
|
#endif
|
|||
|
NTSTATUS status;
|
|||
|
ULONG totalLength;
|
|||
|
PSINGLE_LIST_ENTRY listEntry;
|
|||
|
PAFD_CONNECTION connection;
|
|||
|
AFD_LOCK_QUEUE_HANDLE lockHandle;
|
|||
|
|
|||
|
//
|
|||
|
// Set up local variables.
|
|||
|
//
|
|||
|
|
|||
|
listenEndpoint = IrpSp->FileObject->FsContext;
|
|||
|
acceptFileObject = NULL;
|
|||
|
acceptEndpoint = NULL;
|
|||
|
|
|||
|
#ifdef _WIN64
|
|||
|
if (IoIs32bitProcess (Irp)) {
|
|||
|
PAFD_SUPER_ACCEPT_INFO32 superAcceptInfo32;
|
|||
|
superAcceptInfo32 = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
|
|||
|
|
|||
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|||
|
sizeof(AFD_SUPER_ACCEPT_INFO32) ) {
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
goto complete;
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
if (Irp->RequestorMode!=KernelMode) {
|
|||
|
ProbeForRead (superAcceptInfo32,
|
|||
|
sizeof (*superAcceptInfo32),
|
|||
|
PROBE_ALIGNMENT32 (AFD_SUPER_ACCEPT_INFO32));
|
|||
|
}
|
|||
|
|
|||
|
acceptHandle = superAcceptInfo32->AcceptHandle;
|
|||
|
receiveDataLength = superAcceptInfo32->ReceiveDataLength;
|
|||
|
localAddressLength = superAcceptInfo32->LocalAddressLength;
|
|||
|
remoteAddressLength = superAcceptInfo32->RemoteAddressLength;
|
|||
|
sanActive = superAcceptInfo32->SanActive;
|
|||
|
fixAddressAlignment = superAcceptInfo32->FixAddressAlignment;
|
|||
|
}
|
|||
|
except (AFD_EXCEPTION_FILTER (&status)) {
|
|||
|
goto complete;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
#endif // _WIN64
|
|||
|
{
|
|||
|
PAFD_SUPER_ACCEPT_INFO superAcceptInfo;
|
|||
|
superAcceptInfo = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
|
|||
|
try {
|
|||
|
if (Irp->RequestorMode!=KernelMode) {
|
|||
|
ProbeForRead (superAcceptInfo,
|
|||
|
sizeof (*superAcceptInfo),
|
|||
|
PROBE_ALIGNMENT (AFD_SUPER_ACCEPT_INFO));
|
|||
|
}
|
|||
|
acceptHandle = superAcceptInfo->AcceptHandle;
|
|||
|
receiveDataLength = superAcceptInfo->ReceiveDataLength;
|
|||
|
localAddressLength = superAcceptInfo->LocalAddressLength;
|
|||
|
remoteAddressLength = superAcceptInfo->RemoteAddressLength;
|
|||
|
sanActive = superAcceptInfo->SanActive;
|
|||
|
#ifndef i386
|
|||
|
fixAddressAlignment = superAcceptInfo->FixAddressAlignment;
|
|||
|
#endif
|
|||
|
}
|
|||
|
except (AFD_EXCEPTION_FILTER (&status)) {
|
|||
|
goto complete;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Check for if the caller is unaware of the SAN
|
|||
|
// provider activation and report the error.
|
|||
|
//
|
|||
|
if (!sanActive && AfdSanServiceHelper!=NULL) {
|
|||
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
|
|||
|
"AFD: Process %p is being told to enable SAN on AcceptEx\n",
|
|||
|
PsGetCurrentProcessId ()));
|
|||
|
status = STATUS_INVALID_PARAMETER_12;
|
|||
|
goto complete;
|
|||
|
}
|
|||
|
//
|
|||
|
// Validate the input information. The input buffer must be large
|
|||
|
// enough to hold all the input information, plus some extra to use
|
|||
|
// here to hold the local address. The output buffer must be
|
|||
|
// non-NULL and large enough to hold the specified information.
|
|||
|
//
|
|||
|
//
|
|||
|
|
|||
|
if ( !listenEndpoint->Listening
|
|||
|
|
|||
|
||
|
|||
|
|
|||
|
remoteAddressLength < (ULONG)FIELD_OFFSET (TRANSPORT_ADDRESS,
|
|||
|
Address[0].Address)
|
|||
|
|
|||
|
||
|
|||
|
|
|||
|
//
|
|||
|
// Do the check in such a manner that integer overflow
|
|||
|
// (which is not enabled by the compiler) does not
|
|||
|
// affect the validity of the result.
|
|||
|
//
|
|||
|
(totalLength=IrpSp->Parameters.DeviceIoControl.OutputBufferLength)<
|
|||
|
receiveDataLength
|
|||
|
|
|||
|
||
|
|||
|
|
|||
|
(totalLength-=receiveDataLength) < localAddressLength
|
|||
|
|
|||
|
||
|
|||
|
|
|||
|
(totalLength-=localAddressLength) < remoteAddressLength
|
|||
|
|
|||
|
) {
|
|||
|
|
|||
|
if( !listenEndpoint->Listening ) {
|
|||
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
|
|||
|
"AfdSuperAccept: non-listening endpoint @ %08lX\n",
|
|||
|
listenEndpoint
|
|||
|
));
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
else {
|
|||
|
status = STATUS_BUFFER_TOO_SMALL;
|
|||
|
}
|
|||
|
|
|||
|
goto complete;
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
if (IoAllocateMdl(Irp->UserBuffer,
|
|||
|
IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
|
|||
|
FALSE, // Secondary buffer
|
|||
|
TRUE, // Charge quota
|
|||
|
Irp
|
|||
|
)==NULL) {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
goto complete;
|
|||
|
}
|
|||
|
|
|||
|
MmProbeAndLockPages (Irp->MdlAddress, Irp->RequestorMode, IoWriteAccess);
|
|||
|
}
|
|||
|
except (AFD_EXCEPTION_FILTER (&status)) {
|
|||
|
goto complete;
|
|||
|
}
|
|||
|
|
|||
|
ASSERT ((listenEndpoint->Type & AfdBlockTypeVcListening) == AfdBlockTypeVcListening);
|
|||
|
//
|
|||
|
// Obtain a pointer to the endpoint on which we're going to
|
|||
|
// accept the connection.
|
|||
|
//
|
|||
|
|
|||
|
status = ObReferenceObjectByHandle(
|
|||
|
acceptHandle,
|
|||
|
(IrpSp->Parameters.DeviceIoControl.IoControlCode>>14) & 3,
|
|||
|
// DesiredAccess
|
|||
|
*IoFileObjectType,
|
|||
|
Irp->RequestorMode,
|
|||
|
&acceptFileObject,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if ( !NT_SUCCESS(status) ) {
|
|||
|
goto complete;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// We may have a file object that is not an AFD endpoint. Make sure
|
|||
|
// that this is an actual AFD endpoint.
|
|||
|
//
|
|||
|
|
|||
|
if (acceptFileObject->DeviceObject!= AfdDeviceObject) {
|
|||
|
status = STATUS_INVALID_HANDLE;
|
|||
|
goto complete;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
acceptEndpoint = acceptFileObject->FsContext;
|
|||
|
ASSERT( InterlockedIncrement( &acceptEndpoint->ObReferenceBias ) > 0 );
|
|||
|
|
|||
|
|
|||
|
if (!AFD_START_STATE_CHANGE (acceptEndpoint, AfdEndpointStateConnected)) {
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
goto complete;
|
|||
|
}
|
|||
|
|
|||
|
if (acceptEndpoint->TransportInfo!=listenEndpoint->TransportInfo ||
|
|||
|
acceptEndpoint->State != AfdEndpointStateOpen ) {
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
goto complete_state_change;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#ifndef i386
|
|||
|
acceptEndpoint->Common.VcConnecting.FixAddressAlignment = fixAddressAlignment;
|
|||
|
#endif
|
|||
|
Irp->Tail.Overlay.DriverContext[3] = acceptHandle;
|
|||
|
|
|||
|
//
|
|||
|
// Save common IRP parameters in our stack location so
|
|||
|
// we can retreive them when necessary
|
|||
|
//
|
|||
|
|
|||
|
IrpSp->Parameters.AfdRestartSuperAcceptInfo.AfdAcceptFileObject = acceptFileObject;
|
|||
|
IrpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength = receiveDataLength;
|
|||
|
IrpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength = localAddressLength;
|
|||
|
IrpSp->Parameters.AfdRestartSuperAcceptInfo.AfdRemoteAddressLength = remoteAddressLength;
|
|||
|
|
|||
|
//
|
|||
|
// Add another free connection to replace the one we're accepting.
|
|||
|
// Also, add extra to account for past failures in calls to
|
|||
|
// AfdAddFreeConnection().
|
|||
|
//
|
|||
|
|
|||
|
InterlockedIncrement(
|
|||
|
&listenEndpoint->Common.VcListening.FailedConnectionAdds
|
|||
|
);
|
|||
|
|
|||
|
status = AfdReplenishListenBacklog( listenEndpoint );
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Save the IRP, so that accept enpoint cleanup can find it.
|
|||
|
// Note, that even if found, the cleanup won't touch the IRP
|
|||
|
// until cancel routine is set in it.
|
|||
|
//
|
|||
|
ASSERT (acceptEndpoint->Irp==NULL);
|
|||
|
acceptEndpoint->Irp = Irp;
|
|||
|
|
|||
|
//
|
|||
|
// Get free connection from the list, if none is available,
|
|||
|
// or direct super accept is disabled, go through the regular
|
|||
|
// listen-accept path.
|
|||
|
//
|
|||
|
|
|||
|
if (AfdDisableDirectSuperAccept ||
|
|||
|
IS_DELAYED_ACCEPTANCE_ENDPOINT (listenEndpoint) ||
|
|||
|
ExQueryDepthSList (&listenEndpoint->Common.VcListening.PreacceptedConnectionsListHead)
|
|||
|
> AFD_MAXIMUM_FREE_CONNECTIONS ||
|
|||
|
((listEntry = InterlockedPopEntrySList (
|
|||
|
&listenEndpoint->Common.VcListening.FreeConnectionListHead
|
|||
|
))==NULL)) {
|
|||
|
|
|||
|
//
|
|||
|
// Setup super accept IRP to be put into the wait for
|
|||
|
// listen queue. Internal device control distinguishes this
|
|||
|
// from the regular wait for listen IRPs that come directly
|
|||
|
// from the application.
|
|||
|
//
|
|||
|
IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|||
|
|
|||
|
//
|
|||
|
// Mark this IRP as pending since we are going to return
|
|||
|
// STATUS_PENDING no matter what (sometimes the actual
|
|||
|
// status is hidden very deep inside the call stack and
|
|||
|
// it is impossible to propagate it all the way up).
|
|||
|
//
|
|||
|
IoMarkIrpPending (Irp);
|
|||
|
|
|||
|
AfdWaitForListen (Irp, IrpSp);
|
|||
|
|
|||
|
//
|
|||
|
// If connection allocation failed above, we need to report
|
|||
|
// this to application. We delay this call in case there is
|
|||
|
// already a preaccepted connection, so the allocation failure
|
|||
|
// is not important.
|
|||
|
//
|
|||
|
if (!NT_SUCCESS (status)) {
|
|||
|
AfdReportConnectionAllocationFailure (listenEndpoint, status);
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_PENDING;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get connection object of the list entry
|
|||
|
//
|
|||
|
connection = CONTAINING_RECORD(
|
|||
|
listEntry,
|
|||
|
AFD_CONNECTION,
|
|||
|
SListEntry
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Stuff special constant into the connection object accept IRP
|
|||
|
// pointer, so that cancel routine does not complete the IRP
|
|||
|
// while we are still looking at it, but in the same time we
|
|||
|
// can detect that the IRP was cancelled (cancel routine will
|
|||
|
// replace the -1 with NULL to indicate that it has been ran).
|
|||
|
// This technique avoids extra spinlock acquire/release and
|
|||
|
// associated IRQL raise/lower on an extremely performance-sensitive
|
|||
|
// code path.
|
|||
|
//
|
|||
|
|
|||
|
connection->AcceptIrp = (PIRP)-1;
|
|||
|
Irp->Tail.Overlay.DriverContext[0] = connection;
|
|||
|
|
|||
|
//
|
|||
|
// We are going to pend this Irp, so mark it as pending
|
|||
|
// and set up the cancel routine.
|
|||
|
//
|
|||
|
|
|||
|
IoMarkIrpPending (Irp);
|
|||
|
|
|||
|
IoSetCancelRoutine( Irp, AfdCancelSuperAccept );
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Check if the IRP has already been canceled.
|
|||
|
// If the cancel routine ran, it just reset the connection
|
|||
|
// object accept pointer to NULL (instead of -1 that we stuffed
|
|||
|
// in it above), but it did not complete the IRP.
|
|||
|
//
|
|||
|
|
|||
|
if ( !Irp->Cancel &&
|
|||
|
(InterlockedCompareExchangePointer (
|
|||
|
(PVOID *)&connection->AcceptIrp,
|
|||
|
Irp,
|
|||
|
(PVOID)-1)==(PVOID)-1)) {
|
|||
|
//
|
|||
|
// Can't touch the IRP after this point since it may have already
|
|||
|
// been canceled.
|
|||
|
//
|
|||
|
DEBUG Irp = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Push the connection and associated Irp/endpoint
|
|||
|
// onto preaccepted connection list.
|
|||
|
//
|
|||
|
|
|||
|
if (InterlockedPushEntrySList(
|
|||
|
&listenEndpoint->Common.VcListening.PreacceptedConnectionsListHead,
|
|||
|
&connection->SListEntry
|
|||
|
)==NULL) {
|
|||
|
|
|||
|
//
|
|||
|
// This is the first Irp in the list, we need to check
|
|||
|
// if there are any unaccepted connections that we
|
|||
|
// can use to satisfy super accept.
|
|||
|
//
|
|||
|
|
|||
|
AfdAcquireSpinLock (&listenEndpoint->SpinLock, &lockHandle);
|
|||
|
|
|||
|
if (!listenEndpoint->EndpointCleanedUp) {
|
|||
|
LIST_ENTRY irpList;
|
|||
|
InitializeListHead (&irpList);
|
|||
|
|
|||
|
//
|
|||
|
// First see if there is an unaccepted connection
|
|||
|
//
|
|||
|
while (!IsListEmpty (&listenEndpoint->Common.VcListening.UnacceptedConnectionListHead)) {
|
|||
|
connection = CONTAINING_RECORD(
|
|||
|
listenEndpoint->Common.VcListening.UnacceptedConnectionListHead.Flink,
|
|||
|
AFD_CONNECTION,
|
|||
|
ListEntry
|
|||
|
);
|
|||
|
RemoveEntryList (&connection->ListEntry);
|
|||
|
//
|
|||
|
// Now make sure we still have super accept irp
|
|||
|
//
|
|||
|
if (AfdServiceSuperAccept (listenEndpoint, connection, &lockHandle, &irpList)) {
|
|||
|
//
|
|||
|
// The routine has found and completed super accept IRP
|
|||
|
// Reaquire a spinlock and continue searching for more.
|
|||
|
//
|
|||
|
AfdAcquireSpinLock (&listenEndpoint->SpinLock, &lockHandle);
|
|||
|
}
|
|||
|
else {
|
|||
|
//
|
|||
|
// No super accept Irps, put connection back onto the list
|
|||
|
// while we are still holding the lock and bail out.
|
|||
|
//
|
|||
|
InsertHeadList (&listenEndpoint->Common.VcListening.UnacceptedConnectionListHead,
|
|||
|
&connection->ListEntry);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
AfdReleaseSpinLock (&listenEndpoint->SpinLock, &lockHandle);
|
|||
|
|
|||
|
//
|
|||
|
// Complete failed super accept IRPs (if any)
|
|||
|
//
|
|||
|
if (!IsListEmpty (&irpList)) {
|
|||
|
KIRQL cancelIrql;
|
|||
|
//
|
|||
|
// Make sure cancel routines will
|
|||
|
// not access the completed IRPs
|
|||
|
//
|
|||
|
IoAcquireCancelSpinLock (&cancelIrql);
|
|||
|
IoReleaseCancelSpinLock (cancelIrql);
|
|||
|
while (!IsListEmpty (&irpList)) {
|
|||
|
PIRP irp;
|
|||
|
irp = CONTAINING_RECORD (irpList.Flink, IRP, Tail.Overlay.ListEntry);
|
|||
|
RemoveEntryList (&irp->Tail.Overlay.ListEntry);
|
|||
|
IoCompleteRequest (irp, AfdPriorityBoost);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
AfdReleaseSpinLock (&listenEndpoint->SpinLock, &lockHandle);
|
|||
|
AfdFreeQueuedConnections (listenEndpoint);
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
USHORT depth =
|
|||
|
ExQueryDepthSList (&listenEndpoint->Common.VcListening.PreacceptedConnectionsListHead);
|
|||
|
|
|||
|
if (depth > listenEndpoint->Common.VcListening.MaxExtraConnections) {
|
|||
|
//
|
|||
|
// Update under the lock, so we do not corrupt
|
|||
|
// other fields in the same memory access granularity unit.
|
|||
|
// This should be infrequent operation anyway.
|
|||
|
//
|
|||
|
AfdAcquireSpinLock (&listenEndpoint->SpinLock, &lockHandle);
|
|||
|
listenEndpoint->Common.VcListening.MaxExtraConnections = depth;
|
|||
|
AfdReleaseSpinLock (&listenEndpoint->SpinLock, &lockHandle);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
//
|
|||
|
// Reset and call the cancel routine, since
|
|||
|
// even if cancel routine ran, it could not complete
|
|||
|
// the irp because it was not set in the connection
|
|||
|
// object. Note that cancel routine is done with the IRP
|
|||
|
// once it releases cancel spinlock which we acquire here.
|
|||
|
//
|
|||
|
AfdCleanupSuperAccept (Irp, STATUS_CANCELLED);
|
|||
|
if (IoSetCancelRoutine (Irp, NULL)==NULL) {
|
|||
|
KIRQL cancelIrql;
|
|||
|
IoAcquireCancelSpinLock (&cancelIrql);
|
|||
|
IoReleaseCancelSpinLock (cancelIrql);
|
|||
|
}
|
|||
|
|
|||
|
IoCompleteRequest (Irp, AfdPriorityBoost);
|
|||
|
|
|||
|
//
|
|||
|
// We have to return pending because we have already
|
|||
|
// marked the Irp as pending.
|
|||
|
//
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_PENDING;
|
|||
|
|
|||
|
complete_state_change:
|
|||
|
AFD_END_STATE_CHANGE (acceptEndpoint);
|
|||
|
|
|||
|
complete:
|
|||
|
|
|||
|
if ( acceptFileObject != NULL ) {
|
|||
|
if (acceptEndpoint!=NULL) {
|
|||
|
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
|||
|
}
|
|||
|
ObDereferenceObject( acceptFileObject );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free MDL here as IO system can't do it if it is
|
|||
|
// not locked.
|
|||
|
//
|
|||
|
if (Irp->MdlAddress!=NULL) {
|
|||
|
if (Irp->MdlAddress->MdlFlags & MDL_PAGES_LOCKED) {
|
|||
|
MmUnlockPages (Irp->MdlAddress);
|
|||
|
}
|
|||
|
|
|||
|
IoFreeMdl (Irp->MdlAddress);
|
|||
|
Irp->MdlAddress = NULL;
|
|||
|
}
|
|||
|
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
Irp->IoStatus.Status = status;
|
|||
|
IoCompleteRequest( Irp, 0 );
|
|||
|
|
|||
|
return status;
|
|||
|
|
|||
|
} // AfdSuperAccept
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdRestartSuperAccept (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The completion routine for the AFD wait for listen IRP portion
|
|||
|
of a super accept.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - the devoce object on which the request is completing.
|
|||
|
|
|||
|
Irp - The super accept IRP.
|
|||
|
|
|||
|
Context - points to accept file object.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if the I/O system should complete the super accept
|
|||
|
request, or STATUS_MORE_PROCESSING_REQUIRED if the super accept
|
|||
|
request is still being processed.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAFD_ENDPOINT listenEndpoint;
|
|||
|
PFILE_OBJECT acceptFileObject;
|
|||
|
PAFD_ENDPOINT acceptEndpoint;
|
|||
|
PAFD_CONNECTION connection;
|
|||
|
|
|||
|
PIO_STACK_LOCATION irpSp;
|
|||
|
AFD_LOCK_QUEUE_HANDLE lockHandle;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize some locals.
|
|||
|
//
|
|||
|
|
|||
|
irpSp = IoGetCurrentIrpStackLocation( Irp );
|
|||
|
|
|||
|
listenEndpoint = irpSp->FileObject->FsContext;
|
|||
|
|
|||
|
acceptFileObject = Context;
|
|||
|
acceptEndpoint = acceptFileObject->FsContext;
|
|||
|
ASSERT (IS_AFD_ENDPOINT_TYPE (acceptEndpoint));
|
|||
|
|
|||
|
connection = acceptEndpoint->Common.VcConnecting.Connection;
|
|||
|
ASSERT (connection->Type==AfdBlockTypeConnection);
|
|||
|
ASSERT (connection->Endpoint==acceptEndpoint);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Overwrite listen file object with accept file object
|
|||
|
// since we won't be using listen file object anymore,
|
|||
|
// while we still need to deference accept file object
|
|||
|
// upon IRP completion.
|
|||
|
//
|
|||
|
irpSp->FileObject = acceptFileObject;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Fix up the MDL pointer in the IRP.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT (Irp->MdlAddress==NULL);
|
|||
|
Irp->MdlAddress = irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdMdlAddress;
|
|||
|
|
|||
|
//
|
|||
|
// If pending has been returned for this irp then mark the current
|
|||
|
// stack as pending.
|
|||
|
//
|
|||
|
|
|||
|
if ( Irp->PendingReturned ) {
|
|||
|
IoMarkIrpPending( Irp );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Remember that a TDI accept has completed on this endpoint.
|
|||
|
//
|
|||
|
|
|||
|
InterlockedDecrement(
|
|||
|
&listenEndpoint->Common.VcListening.TdiAcceptPendingCount
|
|||
|
);
|
|||
|
|
|||
|
connection->ConnectTime = KeQueryInterruptTime();
|
|||
|
|
|||
|
if ( NT_SUCCESS(Irp->IoStatus.Status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Set the endpoint to the connected state.
|
|||
|
//
|
|||
|
|
|||
|
AfdAcquireSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
|
|||
|
|
|||
|
acceptEndpoint->State = AfdEndpointStateConnected;
|
|||
|
connection->State = AfdConnectionStateConnected;
|
|||
|
acceptEndpoint->EventsActive |= AFD_POLL_SEND;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Reference connection to prevent it from going away during
|
|||
|
// accept process as the result of transmit file completion.
|
|||
|
// (transmit file can now occur at any time since we
|
|||
|
// marked the endpoint as connected and about to end state change)
|
|||
|
//
|
|||
|
REFERENCE_CONNECTION (connection);
|
|||
|
|
|||
|
AfdReleaseSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
|
|||
|
AFD_END_STATE_CHANGE(acceptEndpoint);
|
|||
|
|
|||
|
return AfdContinueSuperAccept (Irp, connection);
|
|||
|
}
|
|||
|
else {
|
|||
|
//
|
|||
|
// If the accept failed, treat it like an abortive disconnect.
|
|||
|
// This way the application still gets a new endpoint, but it gets
|
|||
|
// told about the reset.
|
|||
|
//
|
|||
|
|
|||
|
AFD_END_STATE_CHANGE(acceptEndpoint);
|
|||
|
AfdDisconnectEventHandler(
|
|||
|
NULL,
|
|||
|
connection,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
TDI_DISCONNECT_ABORT
|
|||
|
);
|
|||
|
|
|||
|
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
|||
|
ObDereferenceObject( acceptFileObject );
|
|||
|
|
|||
|
//
|
|||
|
// Check if we have secondary MDL for local address query and
|
|||
|
// free it.
|
|||
|
//
|
|||
|
if (Irp->MdlAddress->Next!=NULL) {
|
|||
|
//
|
|||
|
// We never lock pages for this one (they are locked
|
|||
|
// as part of main MDL).
|
|||
|
//
|
|||
|
ASSERT (irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength>0);
|
|||
|
ASSERT ((Irp->MdlAddress->Next->MdlFlags & MDL_PAGES_LOCKED)==0);
|
|||
|
IoFreeMdl (Irp->MdlAddress->Next);
|
|||
|
Irp->MdlAddress->Next = NULL;
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
} // AfdRestartSuperAccept
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
AfdRestartSuperAcceptListen (
|
|||
|
IN PIRP Irp,
|
|||
|
IN PAFD_CONNECTION Connection
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The completion routine for the AFD wait for listen IRP portion
|
|||
|
of a super accept.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Irp - The super accept IRP.
|
|||
|
|
|||
|
Connection - points to the connection object
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAFD_ENDPOINT acceptEndpoint;
|
|||
|
PIO_STACK_LOCATION irpSp;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize some locals.
|
|||
|
//
|
|||
|
|
|||
|
irpSp = IoGetCurrentIrpStackLocation( Irp );
|
|||
|
|
|||
|
acceptEndpoint = irpSp->FileObject->FsContext;
|
|||
|
ASSERT (IS_AFD_ENDPOINT_TYPE (acceptEndpoint));
|
|||
|
AFD_END_STATE_CHANGE(acceptEndpoint);
|
|||
|
|
|||
|
//
|
|||
|
// Fix up the system buffer and MDL pointers in the IRP.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT (Irp->MdlAddress==NULL);
|
|||
|
ASSERT (Irp->AssociatedIrp.SystemBuffer == NULL);
|
|||
|
Irp->MdlAddress = irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdMdlAddress;
|
|||
|
|
|||
|
//
|
|||
|
// This routine shouldn't have been called if accept failed
|
|||
|
//
|
|||
|
ASSERT ( NT_SUCCESS(Irp->IoStatus.Status) );
|
|||
|
|
|||
|
//
|
|||
|
// Reference connection to prevent it from going away during
|
|||
|
// accept process as the result of transmit file completion.
|
|||
|
// (transmit file can now occur at any time since we
|
|||
|
// marked the endpoint as connected and about to end state change)
|
|||
|
//
|
|||
|
REFERENCE_CONNECTION (Connection);
|
|||
|
|
|||
|
status = AfdContinueSuperAccept (Irp, Connection);
|
|||
|
|
|||
|
//
|
|||
|
// If completion routine return anything other
|
|||
|
// than STATUS_MORE_PROCESSING_REQUIRED, the IRP
|
|||
|
// is ready to be completed. Otherwise, is was
|
|||
|
// reused to call transport driver and will be completed
|
|||
|
// by the driver. Note that in the latter case
|
|||
|
// the IRP cannot be touched because
|
|||
|
// it could have been completed inside of the
|
|||
|
// completion routine or by the driver before the
|
|||
|
// completion routine returned.
|
|||
|
//
|
|||
|
if (status!=STATUS_MORE_PROCESSING_REQUIRED) {
|
|||
|
IoCompleteRequest (Irp, AfdPriorityBoost);
|
|||
|
}
|
|||
|
|
|||
|
} // AfdRestartSuperAcceptListen
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdRestartDelayedSuperAccept (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The completion routine for the AFD wait for delayed accept IRP portion
|
|||
|
of a super accept.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - the devoce object on which the request is completing.
|
|||
|
|
|||
|
Irp - The super accept IRP.
|
|||
|
|
|||
|
Context - points to accept file object
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if the I/O system should complete the super accept
|
|||
|
request, or STATUS_MORE_PROCESSING_REQUIRED if the super accept
|
|||
|
request is still being processed.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAFD_ENDPOINT listenEndpoint;
|
|||
|
PFILE_OBJECT acceptFileObject;
|
|||
|
PAFD_ENDPOINT acceptEndpoint;
|
|||
|
PAFD_CONNECTION connection;
|
|||
|
|
|||
|
PIO_STACK_LOCATION irpSp;
|
|||
|
AFD_LOCK_QUEUE_HANDLE lockHandle;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize some locals.
|
|||
|
//
|
|||
|
|
|||
|
irpSp = IoGetCurrentIrpStackLocation( Irp );
|
|||
|
|
|||
|
listenEndpoint = irpSp->FileObject->FsContext;
|
|||
|
acceptFileObject = Context;
|
|||
|
acceptEndpoint = acceptFileObject->FsContext;
|
|||
|
ASSERT (IS_AFD_ENDPOINT_TYPE (acceptEndpoint));
|
|||
|
|
|||
|
//
|
|||
|
// Overwrite listen file object with accept file object
|
|||
|
// since we won't be using listen file object anymore,
|
|||
|
// while we still need to deference accept file object
|
|||
|
// upon IRP completion.
|
|||
|
//
|
|||
|
irpSp->FileObject = acceptFileObject;
|
|||
|
|
|||
|
//
|
|||
|
// Fix up the MDL pointer in the IRP.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT (Irp->MdlAddress==NULL);
|
|||
|
Irp->MdlAddress = irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdMdlAddress;
|
|||
|
|
|||
|
AfdCompleteOutstandingIrp (acceptEndpoint, Irp);
|
|||
|
|
|||
|
//
|
|||
|
// If pending has been returned for this irp then mark the current
|
|||
|
// stack as pending.
|
|||
|
//
|
|||
|
|
|||
|
if ( Irp->PendingReturned ) {
|
|||
|
IoMarkIrpPending( Irp );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Remember that a TDI accept has completed on this endpoint.
|
|||
|
//
|
|||
|
|
|||
|
InterlockedDecrement(
|
|||
|
&listenEndpoint->Common.VcListening.TdiAcceptPendingCount
|
|||
|
);
|
|||
|
|
|||
|
AfdAcquireSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
|
|||
|
//
|
|||
|
// The AFD connection object should now be in the endpoiont.
|
|||
|
//
|
|||
|
|
|||
|
connection = AFD_CONNECTION_FROM_ENDPOINT( acceptEndpoint );
|
|||
|
if (connection!=NULL) {
|
|||
|
//
|
|||
|
// If the IRP failed, quit processing.
|
|||
|
//
|
|||
|
|
|||
|
if ( NT_SUCCESS(Irp->IoStatus.Status) ) {
|
|||
|
|
|||
|
acceptEndpoint->State = AfdEndpointStateConnected;
|
|||
|
connection->State = AfdConnectionStateConnected;
|
|||
|
acceptEndpoint->EventsActive |= AFD_POLL_SEND;
|
|||
|
|
|||
|
//
|
|||
|
// Reference connection to prevent it from going away during
|
|||
|
// accept process as the result of transmit file completion.
|
|||
|
// (transmit file can now occur at any time since we
|
|||
|
// marked the endpoint as connected and about to end state change)
|
|||
|
//
|
|||
|
REFERENCE_CONNECTION (connection);
|
|||
|
|
|||
|
AfdReleaseSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
|
|||
|
AFD_END_STATE_CHANGE(acceptEndpoint);
|
|||
|
|
|||
|
return AfdContinueSuperAccept (Irp, connection);
|
|||
|
|
|||
|
}
|
|||
|
else {
|
|||
|
//
|
|||
|
// If the accept failed, treat it like an abortive disconnect.
|
|||
|
// This way the application still gets a new endpoint, but it gets
|
|||
|
// told about the reset.
|
|||
|
//
|
|||
|
|
|||
|
AfdReleaseSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
|
|||
|
|
|||
|
AFD_END_STATE_CHANGE(acceptEndpoint);
|
|||
|
AfdDisconnectEventHandler(
|
|||
|
NULL,
|
|||
|
connection,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
TDI_DISCONNECT_ABORT
|
|||
|
);
|
|||
|
|
|||
|
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
|||
|
ObDereferenceObject( acceptFileObject );
|
|||
|
//
|
|||
|
// After dereferencing file object we shouldn't be accessing it
|
|||
|
// or associated endpoint structure
|
|||
|
//
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
// this could happed if transmit file cleaned up the object
|
|||
|
// really quickly somehow,
|
|||
|
AfdReleaseSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
|
|||
|
|
|||
|
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
|||
|
ObDereferenceObject( acceptFileObject );
|
|||
|
//
|
|||
|
// After dereferencing file object we shouldn't be accessing it
|
|||
|
// or associated endpoint structure
|
|||
|
//
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check if we have secondary MDL for local address query and
|
|||
|
// free it.
|
|||
|
//
|
|||
|
if (Irp->MdlAddress->Next!=NULL) {
|
|||
|
//
|
|||
|
// We never lock pages for this one (they are locked
|
|||
|
// as part of main MDL).
|
|||
|
//
|
|||
|
ASSERT (irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength>0);
|
|||
|
ASSERT ((Irp->MdlAddress->Next->MdlFlags & MDL_PAGES_LOCKED)==0);
|
|||
|
IoFreeMdl (Irp->MdlAddress->Next);
|
|||
|
Irp->MdlAddress->Next = NULL;
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
|
|||
|
} // AfdRestartDelayedSuperAccept
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdContinueSuperAccept (
|
|||
|
IN PIRP Irp,
|
|||
|
PAFD_CONNECTION Connection
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Continues super accept IRP processing after the initial accept
|
|||
|
phase by requesting local address and/or first portion of the
|
|||
|
received data.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Irp - a pointer to the super accept IRP
|
|||
|
Connection - pointer to the accepted connection
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
STATUS_SUCCESS if Irp processing is completed
|
|||
|
STATUS_MORE_PROCESSING_REQUIRED if it submits another request
|
|||
|
and processing will ocurr in the completion routine.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAFD_ENDPOINT acceptEndpoint;
|
|||
|
PIO_STACK_LOCATION irpSp;
|
|||
|
ULONG length;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Initialize locals
|
|||
|
//
|
|||
|
irpSp = IoGetCurrentIrpStackLocation (Irp);
|
|||
|
acceptEndpoint = irpSp->FileObject->FsContext;
|
|||
|
|
|||
|
//
|
|||
|
// See if we need to get local address.
|
|||
|
//
|
|||
|
if (irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength>0) {
|
|||
|
|
|||
|
ASSERT (Irp->MdlAddress->Next!=NULL);
|
|||
|
|
|||
|
//
|
|||
|
// Get the MDL that describes local address part of the user buffer
|
|||
|
// The oritinal mdl chain address is safe in our stack location
|
|||
|
//
|
|||
|
Irp->MdlAddress = Irp->MdlAddress->Next;
|
|||
|
|
|||
|
//
|
|||
|
// Unchain the address MDL from the receive MDL - we will
|
|||
|
// free it upon completion of the address query operation
|
|||
|
//
|
|||
|
((PMDL)irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdMdlAddress)->Next = NULL;
|
|||
|
|
|||
|
ASSERT (irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength
|
|||
|
== MmGetMdlByteCount (Irp->MdlAddress));
|
|||
|
|
|||
|
IoBuildPartialMdl (
|
|||
|
irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdMdlAddress,
|
|||
|
Irp->MdlAddress,
|
|||
|
MmGetMdlVirtualAddress (Irp->MdlAddress),
|
|||
|
MmGetMdlByteCount (Irp->MdlAddress)
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
TdiBuildQueryInformation(
|
|||
|
Irp,
|
|||
|
Connection->DeviceObject,
|
|||
|
Connection->FileObject,
|
|||
|
AfdRestartSuperAcceptGetAddress,
|
|||
|
Connection,
|
|||
|
TDI_QUERY_ADDRESS_INFO,
|
|||
|
Irp->MdlAddress
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Perform the local address query. We'll continue processing from
|
|||
|
// the completion routine.
|
|||
|
//
|
|||
|
|
|||
|
AfdIoCallDriver( acceptEndpoint, Connection->DeviceObject, Irp );
|
|||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|||
|
}
|
|||
|
//
|
|||
|
// See if want to get first portion of the data
|
|||
|
//
|
|||
|
else if (irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength>0) {
|
|||
|
PIO_STACK_LOCATION nextIrpSp;
|
|||
|
|
|||
|
ASSERT (Irp->MdlAddress->Next==NULL);
|
|||
|
//
|
|||
|
// Get the length of the receive portion of the buffer
|
|||
|
// and save the length of the MDL to restore in the completion routine
|
|||
|
// Set the length of the MDL to match that of the receive request
|
|||
|
//
|
|||
|
|
|||
|
length = irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength;
|
|||
|
irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength =
|
|||
|
MmGetMdlByteCount (Irp->MdlAddress);
|
|||
|
Irp->MdlAddress->ByteCount = length;
|
|||
|
|
|||
|
//
|
|||
|
// Prepare the IRP to be used to receive the first chunk of data on
|
|||
|
// the connection.
|
|||
|
//
|
|||
|
// Also note that we send ourselves an IRP_MJ_READ IRP because
|
|||
|
// the I/O subsystem has already probed & locked the output buffer,
|
|||
|
// which just happens to look just like an IRP_MJ_READ IRP.
|
|||
|
//
|
|||
|
|
|||
|
nextIrpSp = IoGetNextIrpStackLocation( Irp );
|
|||
|
|
|||
|
nextIrpSp->FileObject = irpSp->FileObject;
|
|||
|
nextIrpSp->DeviceObject = IoGetRelatedDeviceObject( nextIrpSp->FileObject );
|
|||
|
nextIrpSp->MajorFunction = IRP_MJ_READ;
|
|||
|
|
|||
|
nextIrpSp->Parameters.Read.Length = length;
|
|||
|
nextIrpSp->Parameters.Read.Key = 0;
|
|||
|
nextIrpSp->Parameters.Read.ByteOffset.QuadPart = 0;
|
|||
|
|
|||
|
|
|||
|
IoSetCompletionRoutine(
|
|||
|
Irp,
|
|||
|
AfdRestartSuperAcceptReceive,
|
|||
|
Connection,
|
|||
|
TRUE,
|
|||
|
TRUE,
|
|||
|
TRUE
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Perform the receive. We'll continue processing from
|
|||
|
// the completion routine.
|
|||
|
//
|
|||
|
|
|||
|
AfdIoCallDriver( acceptEndpoint, nextIrpSp->DeviceObject, Irp );
|
|||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
|
|||
|
if (Connection->AbortIndicated && NT_SUCCESS (Irp->IoStatus.Status)) {
|
|||
|
Irp->IoStatus.Status = STATUS_CONNECTION_RESET;
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS (Irp->IoStatus.Status) &&
|
|||
|
(Connection->RemoteAddress!=NULL) &&
|
|||
|
(KeInitializeApc (&acceptEndpoint->Common.VcConnecting.Apc,
|
|||
|
PsGetThreadTcb (Irp->Tail.Overlay.Thread),
|
|||
|
Irp->ApcEnvironment,
|
|||
|
AfdSuperAcceptApcKernelRoutine,
|
|||
|
AfdSuperAcceptApcRundownRoutine,
|
|||
|
(PKNORMAL_ROUTINE)NULL,
|
|||
|
KernelMode,
|
|||
|
NULL
|
|||
|
),
|
|||
|
KeInsertQueueApc (&acceptEndpoint->Common.VcConnecting.Apc,
|
|||
|
Irp,
|
|||
|
Connection,
|
|||
|
AfdPriorityBoost))) {
|
|||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|||
|
}
|
|||
|
else {
|
|||
|
//
|
|||
|
// Dereference the accept file object and tell IO to complete this IRP.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
|||
|
|
|||
|
ObDereferenceObject( irpSp->FileObject );
|
|||
|
|
|||
|
//
|
|||
|
// After dereferencing file object we shouldn't be accessing it
|
|||
|
// or associated endpoint structure
|
|||
|
//
|
|||
|
DEREFERENCE_CONNECTION (Connection);
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdRestartSuperAcceptGetAddress (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The completion routine for the AFD wait for query local address
|
|||
|
portion of a super accept.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - the devoce object on which the request is completing.
|
|||
|
|
|||
|
Irp - The super accept IRP.
|
|||
|
|
|||
|
Context - points to the accepted connection
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if the I/O system should complete the super accept
|
|||
|
request, or STATUS_MORE_PROCESSING_REQUIRED if the super accept
|
|||
|
request is still being processed.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAFD_ENDPOINT acceptEndpoint;
|
|||
|
PAFD_CONNECTION connection;
|
|||
|
|
|||
|
PIO_STACK_LOCATION irpSp;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Initialize some locals.
|
|||
|
//
|
|||
|
|
|||
|
irpSp = IoGetCurrentIrpStackLocation (Irp);
|
|||
|
|
|||
|
acceptEndpoint = irpSp->FileObject->FsContext;
|
|||
|
ASSERT (IS_AFD_ENDPOINT_TYPE (acceptEndpoint));
|
|||
|
|
|||
|
connection = Context;
|
|||
|
ASSERT (connection->Type==AfdBlockTypeConnection);
|
|||
|
ASSERT (connection->Endpoint==acceptEndpoint);
|
|||
|
|
|||
|
AfdCompleteOutstandingIrp (acceptEndpoint, Irp);
|
|||
|
|
|||
|
//
|
|||
|
// If pending has been returned for this irp then mark the current
|
|||
|
// stack as pending.
|
|||
|
//
|
|||
|
|
|||
|
if ( Irp->PendingReturned ) {
|
|||
|
IoMarkIrpPending( Irp );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
ASSERT (Irp->MdlAddress->MdlFlags & MDL_PARTIAL);
|
|||
|
IoFreeMdl( Irp->MdlAddress );
|
|||
|
|
|||
|
//
|
|||
|
// Fix up the MDL pointer in the IRP and set local address length
|
|||
|
// to 0 to use the common routine for receive part of the super
|
|||
|
// accept Irp
|
|||
|
//
|
|||
|
|
|||
|
Irp->MdlAddress = irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdMdlAddress;
|
|||
|
|
|||
|
if (NT_SUCCESS (Irp->IoStatus.Status)) {
|
|||
|
#ifndef i386
|
|||
|
if (acceptEndpoint->Common.VcConnecting.FixAddressAlignment) {
|
|||
|
PTDI_ADDRESS_INFO addressInfo = (PVOID)
|
|||
|
((PUCHAR)MmGetSystemAddressForMdl(Irp->MdlAddress)
|
|||
|
+ irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength);
|
|||
|
USHORT addressLength = addressInfo->Address.Address[0].AddressLength+sizeof(USHORT);
|
|||
|
USHORT UNALIGNED *pAddrLength = (PVOID)
|
|||
|
((PUCHAR)addressInfo
|
|||
|
+irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength
|
|||
|
-sizeof(USHORT));
|
|||
|
RtlMoveMemory (addressInfo,
|
|||
|
&addressInfo->Address.Address[0].AddressType,
|
|||
|
addressLength);
|
|||
|
*pAddrLength = addressLength;
|
|||
|
}
|
|||
|
#endif // ifndef i386
|
|||
|
irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength = 0;
|
|||
|
return AfdContinueSuperAccept (Irp, connection);
|
|||
|
}
|
|||
|
else {
|
|||
|
//
|
|||
|
// Dereference the accept file object and tell IO to complete this IRP.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
|||
|
|
|||
|
ObDereferenceObject( irpSp->FileObject );
|
|||
|
//
|
|||
|
// After dereferencing file object we shouldn't be accessing it
|
|||
|
// or associated endpoint structure
|
|||
|
//
|
|||
|
DEREFERENCE_CONNECTION (connection);
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
} // AfdRestartSuperAcceptGetAddress
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdRestartSuperAcceptReceive (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The completion routine for the AFD receive portion of a super accept.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - the devoce object on which the request is completing.
|
|||
|
|
|||
|
Irp - The super accept IRP.
|
|||
|
|
|||
|
Context - points to the accepted connection
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if the I/O system should complete the super accept
|
|||
|
request, or STATUS_MORE_PROCESSING_REQUIRED if the super accept
|
|||
|
request is still being processed.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAFD_ENDPOINT acceptEndpoint;
|
|||
|
PAFD_CONNECTION connection;
|
|||
|
|
|||
|
PIO_STACK_LOCATION irpSp;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize some locals.
|
|||
|
//
|
|||
|
|
|||
|
irpSp = IoGetCurrentIrpStackLocation (Irp);
|
|||
|
|
|||
|
acceptEndpoint = irpSp->FileObject->FsContext;
|
|||
|
ASSERT (IS_AFD_ENDPOINT_TYPE (acceptEndpoint));
|
|||
|
|
|||
|
connection = Context;
|
|||
|
ASSERT (connection->Type == AfdBlockTypeConnection);
|
|||
|
ASSERT (connection->Endpoint==acceptEndpoint);
|
|||
|
|
|||
|
AfdCompleteOutstandingIrp (acceptEndpoint, Irp);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Restore MDL length so that IO system can properly unmap
|
|||
|
// and unlock it when it completes the IRP
|
|||
|
//
|
|||
|
|
|||
|
ASSERT (Irp->MdlAddress!=NULL);
|
|||
|
ASSERT (Irp->MdlAddress->Next==NULL);
|
|||
|
Irp->MdlAddress->ByteCount =
|
|||
|
irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength;
|
|||
|
|
|||
|
//
|
|||
|
// If pending has been returned for this irp then mark the current
|
|||
|
// stack as pending.
|
|||
|
//
|
|||
|
|
|||
|
if ( Irp->PendingReturned ) {
|
|||
|
IoMarkIrpPending( Irp );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
if (NT_SUCCESS (Irp->IoStatus.Status) &&
|
|||
|
(connection->RemoteAddress!=NULL) &&
|
|||
|
(KeInitializeApc (&acceptEndpoint->Common.VcConnecting.Apc,
|
|||
|
PsGetThreadTcb (Irp->Tail.Overlay.Thread),
|
|||
|
Irp->ApcEnvironment,
|
|||
|
AfdSuperAcceptApcKernelRoutine,
|
|||
|
AfdSuperAcceptApcRundownRoutine,
|
|||
|
(PKNORMAL_ROUTINE)NULL,
|
|||
|
KernelMode,
|
|||
|
NULL
|
|||
|
),
|
|||
|
KeInsertQueueApc (&acceptEndpoint->Common.VcConnecting.Apc,
|
|||
|
Irp,
|
|||
|
connection,
|
|||
|
AfdPriorityBoost))) {
|
|||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|||
|
}
|
|||
|
else {
|
|||
|
//
|
|||
|
// Dereference the accept file object and tell IO to complete this IRP.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
|||
|
|
|||
|
ObDereferenceObject( irpSp->FileObject );
|
|||
|
|
|||
|
//
|
|||
|
// After dereferencing file object we shouldn't be accessing it
|
|||
|
// or associated endpoint structure
|
|||
|
//
|
|||
|
DEREFERENCE_CONNECTION (connection);
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
} // AfdRestartSuperAcceptReceive
|
|||
|
|
|||
|
VOID
|
|||
|
AfdSuperAcceptApcKernelRoutine (
|
|||
|
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;
|
|||
|
PAFD_CONNECTION connection;
|
|||
|
PVOID context;
|
|||
|
|
|||
|
PAGED_CODE ();
|
|||
|
#if DBG
|
|||
|
try {
|
|||
|
#endif
|
|||
|
|
|||
|
ASSERT (*NormalRoutine == NULL);
|
|||
|
|
|||
|
endpoint = CONTAINING_RECORD (Apc, AFD_ENDPOINT, Common.VcConnecting.Apc);
|
|||
|
ASSERT (IS_AFD_ENDPOINT_TYPE (endpoint));
|
|||
|
|
|||
|
irp = *SystemArgument1;
|
|||
|
irpSp = IoGetCurrentIrpStackLocation( irp );
|
|||
|
ASSERT (irpSp->FileObject->FsContext==endpoint);
|
|||
|
|
|||
|
connection = *SystemArgument2;
|
|||
|
ASSERT( connection->Type == AfdBlockTypeConnection );
|
|||
|
|
|||
|
ASSERT (connection->Endpoint==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 >=
|
|||
|
connection->RemoteAddress->Address[0].AddressLength +
|
|||
|
sizeof(u_short))) {
|
|||
|
|
|||
|
RtlMoveMemory ((PUCHAR)context +
|
|||
|
endpoint->Common.VcConnecting.RemoteSocketAddressOffset,
|
|||
|
&connection->RemoteAddress->Address[0].AddressType,
|
|||
|
connection->RemoteAddress->Address[0].AddressLength +
|
|||
|
sizeof(u_short));
|
|||
|
}
|
|||
|
else {
|
|||
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_WARNING_LEVEL,
|
|||
|
"AfdSuperAcceptApcKernelRoutine: Could not copy remote address for AcceptEx on endpoint: %p, process: %p\n",
|
|||
|
endpoint, endpoint->OwningProcess));
|
|||
|
}
|
|||
|
AfdUnlockEndpointContext (endpoint, context);
|
|||
|
|
|||
|
AFD_RETURN_REMOTE_ADDRESS (
|
|||
|
connection->RemoteAddress,
|
|||
|
connection->RemoteAddressLength
|
|||
|
);
|
|||
|
connection->RemoteAddress = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Dereference the accept file object and tell IO to complete this IRP.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT( InterlockedDecrement( &endpoint->ObReferenceBias ) >= 0 );
|
|||
|
|
|||
|
ObDereferenceObject( irpSp->FileObject );
|
|||
|
|
|||
|
//
|
|||
|
// After dereferencing file object we shouldn't be accessing it
|
|||
|
// or associated endpoint structure
|
|||
|
//
|
|||
|
DEREFERENCE_CONNECTION (connection);
|
|||
|
|
|||
|
IoCompleteRequest (irp, AfdPriorityBoost);
|
|||
|
#if DBG
|
|||
|
}
|
|||
|
except (AfdApcExceptionFilter (
|
|||
|
GetExceptionInformation(),
|
|||
|
(LPSTR)__FILE__,
|
|||
|
(LONG)__LINE__)) {
|
|||
|
DbgBreakPoint ();
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
AfdSuperAcceptApcRundownRoutine (
|
|||
|
IN struct _KAPC *Apc
|
|||
|
)
|
|||
|
{
|
|||
|
PIRP irp;
|
|||
|
PIO_STACK_LOCATION irpSp;
|
|||
|
PAFD_ENDPOINT endpoint;
|
|||
|
PAFD_CONNECTION connection;
|
|||
|
|
|||
|
PAGED_CODE ();
|
|||
|
|
|||
|
endpoint = CONTAINING_RECORD (Apc, AFD_ENDPOINT, Common.VcConnecting.Apc);
|
|||
|
ASSERT (IS_AFD_ENDPOINT_TYPE (endpoint));
|
|||
|
|
|||
|
irp = Apc->SystemArgument1;
|
|||
|
irpSp = IoGetCurrentIrpStackLocation( irp );
|
|||
|
ASSERT (irpSp->FileObject->FsContext==endpoint);
|
|||
|
|
|||
|
connection = Apc->SystemArgument2;
|
|||
|
ASSERT( connection->Type == AfdBlockTypeConnection );
|
|||
|
|
|||
|
ASSERT (connection->Endpoint==endpoint);
|
|||
|
|
|||
|
//
|
|||
|
// Dereference the accept file object and tell IO to complete this IRP.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT( InterlockedDecrement( &endpoint->ObReferenceBias ) >= 0 );
|
|||
|
|
|||
|
ObDereferenceObject( irpSp->FileObject );
|
|||
|
|
|||
|
//
|
|||
|
// After dereferencing file object we shouldn't be accessing it
|
|||
|
// or associated endpoint structure
|
|||
|
//
|
|||
|
DEREFERENCE_CONNECTION (connection);
|
|||
|
|
|||
|
IoCompleteRequest (irp, AfdPriorityBoost);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
FASTCALL
|
|||
|
AfdDeferAccept (
|
|||
|
IN PIRP Irp,
|
|||
|
IN PIO_STACK_LOCATION IrpSp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Defers acceptance of an incoming connection for which an
|
|||
|
AFD_WAIT_FOR_LISTEN IOCTL has already completed. The caller
|
|||
|
may specify that the connection be deferred for later acceptance
|
|||
|
or rejected totally.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Irp - a pointer to a transmit file IRP.
|
|||
|
|
|||
|
IrpSp - Our stack location for this IRP.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if the request was completed successfully, or a
|
|||
|
failure status code if there was an error.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
PAFD_DEFER_ACCEPT_INFO deferAcceptInfo;
|
|||
|
PAFD_ENDPOINT endpoint;
|
|||
|
PAFD_CONNECTION connection;
|
|||
|
AFD_LOCK_QUEUE_HANDLE lockHandle;
|
|||
|
|
|||
|
//
|
|||
|
// Set up local variables.
|
|||
|
//
|
|||
|
|
|||
|
endpoint = IrpSp->FileObject->FsContext;
|
|||
|
deferAcceptInfo = Irp->AssociatedIrp.SystemBuffer;
|
|||
|
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Make sure that this request is valid.
|
|||
|
//
|
|||
|
|
|||
|
if( !endpoint->Listening ||
|
|||
|
IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|||
|
sizeof(AFD_DEFER_ACCEPT_INFO) ) {
|
|||
|
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
goto complete;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ASSERT ((endpoint->Type & AfdBlockTypeVcListening) == AfdBlockTypeVcListening);
|
|||
|
|
|||
|
AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
|
|||
|
//
|
|||
|
// Find the specified connection. If it cannot be found, then this
|
|||
|
// is a bogus request.
|
|||
|
//
|
|||
|
|
|||
|
connection = AfdGetReturnedConnection(
|
|||
|
endpoint,
|
|||
|
deferAcceptInfo->Sequence
|
|||
|
);
|
|||
|
|
|||
|
if( connection == NULL ) {
|
|||
|
|
|||
|
AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
goto complete;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ASSERT( connection->Type == AfdBlockTypeConnection );
|
|||
|
|
|||
|
//
|
|||
|
// If this is a request to reject the accepted connection, then
|
|||
|
// abort the connection. Otherwise (this is a request to defer
|
|||
|
// acceptance until later) then insert the connection at the *head*
|
|||
|
// of the endpoint's unaccepted connection queue.
|
|||
|
//
|
|||
|
|
|||
|
if( deferAcceptInfo->Reject ) {
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Reenable the accept event bit, and if there are additional
|
|||
|
// unaccepted connections on the endpoint, post another event.
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
endpoint->EventsActive &= ~AFD_POLL_ACCEPT;
|
|||
|
|
|||
|
IF_DEBUG(EVENT_SELECT) {
|
|||
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
|
|||
|
"AfdDeferAccept: Endp %08lX, Active %08lX\n",
|
|||
|
endpoint,
|
|||
|
endpoint->EventsActive
|
|||
|
));
|
|||
|
}
|
|||
|
|
|||
|
if( !IsListEmpty( &endpoint->Common.VcListening.UnacceptedConnectionListHead ) ) {
|
|||
|
|
|||
|
AfdIndicateEventSelectEvent(
|
|||
|
endpoint,
|
|||
|
AFD_POLL_ACCEPT,
|
|||
|
STATUS_SUCCESS
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Special handling for SAN connections
|
|||
|
//
|
|||
|
if (connection->SanConnection) {
|
|||
|
PIRP connectIrp;
|
|||
|
//
|
|||
|
// Snag the connect indication IRP
|
|||
|
//
|
|||
|
connectIrp = connection->ConnectIrp;
|
|||
|
ASSERT (connectIrp!=NULL);
|
|||
|
connection->ConnectIrp = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// We can now release listen endpoint spinlock
|
|||
|
// The cancel routine will not find IRP in the connection
|
|||
|
//
|
|||
|
if (IoSetCancelRoutine (connectIrp, NULL)==NULL) {
|
|||
|
KIRQL cancelIrql;
|
|||
|
AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
|
|||
|
//
|
|||
|
// Cancel routine is running, make sure
|
|||
|
// it finishes before proceeding further
|
|||
|
//
|
|||
|
IoAcquireCancelSpinLock (&cancelIrql);
|
|||
|
IoReleaseCancelSpinLock (cancelIrql);
|
|||
|
connectIrp->IoStatus.Status = STATUS_CANCELLED;
|
|||
|
}
|
|||
|
else {
|
|||
|
AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
|
|||
|
connectIrp->IoStatus.Status = STATUS_CONNECTION_REFUSED;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Return the connection and complete SAN provider IRP
|
|||
|
//
|
|||
|
|
|||
|
connection->Endpoint = NULL;
|
|||
|
connection->SanConnection = FALSE;
|
|||
|
|
|||
|
AfdSanReleaseConnection (endpoint, connection, FALSE);
|
|||
|
DEREFERENCE_ENDPOINT (endpoint);
|
|||
|
|
|||
|
connectIrp->IoStatus.Information = 0;
|
|||
|
IoCompleteRequest (connectIrp, AfdPriorityBoost);
|
|||
|
}
|
|||
|
else {
|
|||
|
AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
|
|||
|
|
|||
|
//
|
|||
|
// Abort the connection.
|
|||
|
//
|
|||
|
|
|||
|
AfdAbortConnection( connection );
|
|||
|
|
|||
|
//
|
|||
|
// Add another free connection to replace the one we're rejecting.
|
|||
|
// Also, add extra to account for past failures in calls to
|
|||
|
// AfdAddFreeConnection().
|
|||
|
//
|
|||
|
|
|||
|
InterlockedIncrement(
|
|||
|
&endpoint->Common.VcListening.FailedConnectionAdds
|
|||
|
);
|
|||
|
|
|||
|
AfdReplenishListenBacklog( endpoint );
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Restore the connection's state before putting it back
|
|||
|
// on the queue.
|
|||
|
//
|
|||
|
|
|||
|
connection->State = AfdConnectionStateUnaccepted;
|
|||
|
|
|||
|
InsertHeadList(
|
|||
|
&endpoint->Common.VcListening.UnacceptedConnectionListHead,
|
|||
|
&connection->ListEntry
|
|||
|
);
|
|||
|
AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
|
|||
|
}
|
|||
|
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
|
|||
|
complete:
|
|||
|
|
|||
|
Irp->IoStatus.Status = status;
|
|||
|
ASSERT( Irp->CancelRoutine == NULL );
|
|||
|
|
|||
|
IoCompleteRequest( Irp, AfdPriorityBoost );
|
|||
|
|
|||
|
return status;
|
|||
|
|
|||
|
} // AfdDeferAccept
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdRestartDelayedAccept (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The completion routine for the AFD wait for delayed accept IRP portion
|
|||
|
of an accept.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - the devoce object on which the request is completing.
|
|||
|
|
|||
|
Irp - The accept IRP.
|
|||
|
|
|||
|
Context - points to accept file object
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if the I/O system should complete the super accept
|
|||
|
request, or STATUS_MORE_PROCESSING_REQUIRED if the super accept
|
|||
|
request is still being processed.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PIO_STACK_LOCATION irpSp;
|
|||
|
PFILE_OBJECT acceptFileObject;
|
|||
|
PAFD_ENDPOINT acceptEndpoint;
|
|||
|
PAFD_CONNECTION connection;
|
|||
|
PAFD_ENDPOINT listenEndpoint;
|
|||
|
AFD_LOCK_QUEUE_HANDLE lockHandle;
|
|||
|
|
|||
|
acceptFileObject = Context;
|
|||
|
acceptEndpoint = acceptFileObject->FsContext;
|
|||
|
|
|||
|
irpSp = IoGetCurrentIrpStackLocation (Irp);
|
|||
|
listenEndpoint = irpSp->FileObject->FsContext;
|
|||
|
|
|||
|
//
|
|||
|
// Remember that a TDI accept has completed on this endpoint.
|
|||
|
//
|
|||
|
|
|||
|
InterlockedDecrement(
|
|||
|
&listenEndpoint->Common.VcListening.TdiAcceptPendingCount
|
|||
|
);
|
|||
|
|
|||
|
AfdCompleteOutstandingIrp (acceptEndpoint, Irp);
|
|||
|
|
|||
|
if ( Irp->PendingReturned ) {
|
|||
|
IoMarkIrpPending( Irp );
|
|||
|
}
|
|||
|
|
|||
|
AfdAcquireSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
|
|||
|
//
|
|||
|
// The AFD connection object should now be in the endpoiont.
|
|||
|
//
|
|||
|
|
|||
|
connection = AFD_CONNECTION_FROM_ENDPOINT( acceptEndpoint );
|
|||
|
if (connection!=NULL) {
|
|||
|
if (NT_SUCCESS (Irp->IoStatus.Status)) {
|
|||
|
acceptEndpoint->State = AfdEndpointStateConnected;
|
|||
|
connection->State = AfdConnectionStateConnected;
|
|||
|
acceptEndpoint->EventsActive |= AFD_POLL_SEND;
|
|||
|
acceptEndpoint->EnableSendEvent = TRUE;
|
|||
|
AfdReleaseSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
|
|||
|
AFD_END_STATE_CHANGE (acceptEndpoint);
|
|||
|
}
|
|||
|
else {
|
|||
|
//
|
|||
|
// If the accept failed, treat it like an abortive disconnect.
|
|||
|
// This way the application still gets a new endpoint, but it gets
|
|||
|
// told about the reset.
|
|||
|
//
|
|||
|
REFERENCE_CONNECTION (connection);
|
|||
|
|
|||
|
AfdReleaseSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
|
|||
|
|
|||
|
AFD_END_STATE_CHANGE (acceptEndpoint);
|
|||
|
|
|||
|
AfdDisconnectEventHandler(
|
|||
|
NULL,
|
|||
|
connection,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
TDI_DISCONNECT_ABORT
|
|||
|
);
|
|||
|
DEREFERENCE_CONNECTION (connection);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
|||
|
|
|||
|
ObDereferenceObject( acceptFileObject );
|
|||
|
|
|||
|
Irp->AssociatedIrp.SystemBuffer = irpSp->Parameters.AfdRestartDelayedAcceptInfo.AfdSystemBuffer;
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
AfdCleanupSuperAccept (
|
|||
|
IN PIRP Irp,
|
|||
|
IN NTSTATUS Status
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Cleans up a super accept IRP and prepeares it for completion
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Irp - the IRP to cleanup.
|
|||
|
Status - failure status
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PAFD_ENDPOINT listenEndpoint;
|
|||
|
PFILE_OBJECT acceptFileObject;
|
|||
|
PAFD_ENDPOINT acceptEndpoint;
|
|||
|
PIO_STACK_LOCATION irpSp;
|
|||
|
AFD_LOCK_QUEUE_HANDLE lockHandle;
|
|||
|
|
|||
|
ASSERT (!NT_SUCCESS (Status));
|
|||
|
//
|
|||
|
// Initialize some locals.
|
|||
|
//
|
|||
|
|
|||
|
irpSp = IoGetCurrentIrpStackLocation (Irp);
|
|||
|
listenEndpoint = irpSp->FileObject->FsContext;
|
|||
|
|
|||
|
//
|
|||
|
// Reduce the count of failed connection adds on the listening
|
|||
|
// endpoint to account for this connection object which we're
|
|||
|
// adding back onto the queue once it is pulled from pre-accepted connection
|
|||
|
// list.
|
|||
|
//
|
|||
|
InterlockedDecrement (&listenEndpoint->Common.VcListening.FailedConnectionAdds);
|
|||
|
|
|||
|
|
|||
|
acceptFileObject = irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdAcceptFileObject;
|
|||
|
acceptEndpoint = acceptFileObject->FsContext;
|
|||
|
ASSERT (IS_AFD_ENDPOINT_TYPE (acceptEndpoint));
|
|||
|
|
|||
|
//
|
|||
|
// Cleanup super accept IRP out of endpoint.
|
|||
|
//
|
|||
|
AfdAcquireSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
|
|||
|
ASSERT (acceptEndpoint->Irp==Irp); // May need to remove this assert
|
|||
|
// in the future.
|
|||
|
acceptEndpoint->Irp = NULL;
|
|||
|
AfdReleaseSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
|
|||
|
|
|||
|
//
|
|||
|
// Mark the end of state change letting the endpoint
|
|||
|
// to be used again in state change operation (e.g. accept).
|
|||
|
//
|
|||
|
|
|||
|
AFD_END_STATE_CHANGE (acceptEndpoint);
|
|||
|
|
|||
|
//
|
|||
|
// Dereference accept file object
|
|||
|
//
|
|||
|
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
|||
|
|
|||
|
ObDereferenceObject( acceptFileObject );
|
|||
|
|
|||
|
//
|
|||
|
// Check if we have secondary MDL for local address query and
|
|||
|
// free it.
|
|||
|
//
|
|||
|
if (Irp->MdlAddress->Next!=NULL) {
|
|||
|
//
|
|||
|
// We never lock pages for this one (they are locked
|
|||
|
// as part of main MDL).
|
|||
|
//
|
|||
|
ASSERT (irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength>0);
|
|||
|
ASSERT ((Irp->MdlAddress->Next->MdlFlags & MDL_PAGES_LOCKED)==0);
|
|||
|
IoFreeMdl (Irp->MdlAddress->Next);
|
|||
|
Irp->MdlAddress->Next = NULL;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Set the status specified in the IRP and return
|
|||
|
// The caller will eventually complete it.
|
|||
|
//
|
|||
|
|
|||
|
Irp->IoStatus.Status = Status;
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
AfdCancelSuperAccept (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Cancels a super accept IRP that is pended in AFD.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - not used.
|
|||
|
|
|||
|
Irp - the IRP to cancel.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAFD_CONNECTION connection;
|
|||
|
|
|||
|
connection = Irp->Tail.Overlay.DriverContext[0];
|
|||
|
ASSERT (connection->Type==AfdBlockTypeConnection);
|
|||
|
ASSERT (connection->Endpoint==NULL);
|
|||
|
//
|
|||
|
// If IRP is in the connection object, cleanup and complete it
|
|||
|
//
|
|||
|
if (InterlockedExchangePointer (
|
|||
|
(PVOID *)&connection->AcceptIrp,
|
|||
|
NULL)==Irp) {
|
|||
|
IoReleaseCancelSpinLock( Irp->CancelIrql );
|
|||
|
AfdCleanupSuperAccept (Irp, STATUS_CANCELLED);
|
|||
|
IoCompleteRequest( Irp, AfdPriorityBoost );
|
|||
|
|
|||
|
}
|
|||
|
else {
|
|||
|
IoReleaseCancelSpinLock( Irp->CancelIrql );
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
AfdServiceSuperAccept (
|
|||
|
IN PAFD_ENDPOINT Endpoint,
|
|||
|
IN PAFD_CONNECTION Connection,
|
|||
|
IN PAFD_LOCK_QUEUE_HANDLE LockHandle,
|
|||
|
OUT PLIST_ENTRY AcceptIrpList
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Attemts to satisfy super accept irp using the incoming
|
|||
|
connection. This routine must be called with listening endpoint
|
|||
|
spinlock held.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Endpoint - listening endpoint on which connection is
|
|||
|
being accepted
|
|||
|
Connection - connection being accepted.
|
|||
|
AcceptIrpList - returns a list of accept Irps which were failed and
|
|||
|
need to be completed after listening endpoint spinlock
|
|||
|
is released.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE - the super accept IRP was found and is in the head of the list
|
|||
|
FALSE - no usable super accept IRP exists.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
{
|
|||
|
PSINGLE_LIST_ENTRY listEntry;
|
|||
|
PIRP acceptIrp;
|
|||
|
PAFD_CONNECTION oldConnection;
|
|||
|
|
|||
|
//
|
|||
|
// Keep removing super accept IRPs while there are any there
|
|||
|
//
|
|||
|
while ((listEntry = InterlockedPopEntrySList (
|
|||
|
&Endpoint->Common.VcListening.PreacceptedConnectionsListHead
|
|||
|
))!=NULL) {
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
//
|
|||
|
// Find the connection pointer from the list entry and return a
|
|||
|
// pointer to the connection object.
|
|||
|
//
|
|||
|
|
|||
|
oldConnection = CONTAINING_RECORD(
|
|||
|
listEntry,
|
|||
|
AFD_CONNECTION,
|
|||
|
SListEntry
|
|||
|
);
|
|||
|
|
|||
|
acceptIrp = InterlockedExchangePointer ((PVOID *)&oldConnection->AcceptIrp, NULL);
|
|||
|
//
|
|||
|
// Check if there is accept irp associated with
|
|||
|
// this connection, if not just put it back on the free list
|
|||
|
// (the IRP must have been cancelled)
|
|||
|
//
|
|||
|
if (acceptIrp!=NULL) {
|
|||
|
if (IoSetCancelRoutine (acceptIrp, NULL)!=NULL) {
|
|||
|
|
|||
|
PFILE_OBJECT acceptFileObject;
|
|||
|
PAFD_ENDPOINT acceptEndpoint;
|
|||
|
PIO_STACK_LOCATION irpSp;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize some locals.
|
|||
|
//
|
|||
|
|
|||
|
irpSp = IoGetCurrentIrpStackLocation (acceptIrp);
|
|||
|
acceptFileObject = irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdAcceptFileObject;
|
|||
|
acceptEndpoint = acceptFileObject->FsContext;
|
|||
|
ASSERT (IS_AFD_ENDPOINT_TYPE (acceptEndpoint));
|
|||
|
|
|||
|
//
|
|||
|
// Check if super accept Irp has enough space for
|
|||
|
// the remote address
|
|||
|
//
|
|||
|
if (Connection->RemoteAddressLength>
|
|||
|
irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdRemoteAddressLength) {
|
|||
|
|
|||
|
status = STATUS_BUFFER_TOO_SMALL;
|
|||
|
|
|||
|
}
|
|||
|
//
|
|||
|
// Check if we have enough system PTE's to map
|
|||
|
// the buffer.
|
|||
|
//
|
|||
|
else if ((status = AfdMapMdlChain (acceptIrp->MdlAddress)),
|
|||
|
!NT_SUCCESS (status)) {
|
|||
|
NOTHING;
|
|||
|
}
|
|||
|
else if (Connection->SanConnection) {
|
|||
|
status = AfdSanAcceptCore (acceptIrp, acceptFileObject, Connection, LockHandle);
|
|||
|
if (status==STATUS_PENDING) {
|
|||
|
//
|
|||
|
// Accept IRP is pending waiting for Switch
|
|||
|
// completion notification
|
|||
|
// Release old connection object
|
|||
|
//
|
|||
|
ASSERT (oldConnection->Endpoint==NULL);
|
|||
|
InterlockedPushEntrySList (
|
|||
|
&Endpoint->Common.VcListening.FreeConnectionListHead,
|
|||
|
&oldConnection->SListEntry);
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
else {
|
|||
|
//
|
|||
|
// Something failed, we need to complete accept IRP
|
|||
|
//
|
|||
|
ASSERT (NT_ERROR (status));
|
|||
|
AfdCleanupSuperAccept (acceptIrp, status);
|
|||
|
IoCompleteRequest (acceptIrp, AfdPriorityBoost);
|
|||
|
//
|
|||
|
// This connection has already been diassociated from endpoint.
|
|||
|
// If backlog is below the level we need, put it on the free
|
|||
|
// list, otherwise, get rid of it.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT (oldConnection->Endpoint==NULL);
|
|||
|
if (InterlockedIncrement (&Endpoint->Common.VcListening.FailedConnectionAdds)>0) {
|
|||
|
InterlockedDecrement (&Endpoint->Common.VcListening.FailedConnectionAdds);
|
|||
|
InterlockedPushEntrySList (
|
|||
|
&Endpoint->Common.VcListening.FreeConnectionListHead,
|
|||
|
&oldConnection->SListEntry);
|
|||
|
}
|
|||
|
else {
|
|||
|
DEREFERENCE_CONNECTION (oldConnection);
|
|||
|
}
|
|||
|
}
|
|||
|
//
|
|||
|
// Complete previously failed accept irps if any.
|
|||
|
//
|
|||
|
while (!IsListEmpty (AcceptIrpList)) {
|
|||
|
PIRP irp;
|
|||
|
irp = CONTAINING_RECORD (AcceptIrpList->Flink, IRP, Tail.Overlay.ListEntry);
|
|||
|
RemoveEntryList (&irp->Tail.Overlay.ListEntry);
|
|||
|
IoCompleteRequest (irp, AfdPriorityBoost);
|
|||
|
}
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
//
|
|||
|
// Allocate MDL for local address query if requested
|
|||
|
//
|
|||
|
else if ((irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength>0) &&
|
|||
|
(IoAllocateMdl ((PUCHAR)acceptIrp->UserBuffer+irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength,
|
|||
|
irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength,
|
|||
|
TRUE,
|
|||
|
FALSE,
|
|||
|
acceptIrp)==NULL)){
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
else {
|
|||
|
//
|
|||
|
// Copy over the address information to the user's buffer.
|
|||
|
//
|
|||
|
#ifndef i386
|
|||
|
if (acceptEndpoint->Common.VcConnecting.FixAddressAlignment) {
|
|||
|
USHORT addressLength =
|
|||
|
Connection->RemoteAddress->Address[0].AddressLength
|
|||
|
+ sizeof (USHORT);
|
|||
|
USHORT UNALIGNED *pAddrLength = (PVOID)
|
|||
|
((PUCHAR)MmGetSystemAddressForMdl (acceptIrp->MdlAddress)
|
|||
|
+ irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength
|
|||
|
+ irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength
|
|||
|
+ irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdRemoteAddressLength
|
|||
|
- sizeof (USHORT));
|
|||
|
RtlMoveMemory (
|
|||
|
(PUCHAR)MmGetSystemAddressForMdl (acceptIrp->MdlAddress)
|
|||
|
+ irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength
|
|||
|
+ irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength,
|
|||
|
&Connection->RemoteAddress->Address[0].AddressType,
|
|||
|
addressLength);
|
|||
|
*pAddrLength = addressLength;
|
|||
|
}
|
|||
|
else
|
|||
|
#endif
|
|||
|
{
|
|||
|
RtlMoveMemory (
|
|||
|
(PUCHAR)MmGetSystemAddressForMdl (acceptIrp->MdlAddress)
|
|||
|
+ irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength
|
|||
|
+ irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength,
|
|||
|
Connection->RemoteAddress,
|
|||
|
Connection->RemoteAddressLength);
|
|||
|
}
|
|||
|
status = AfdAcceptCore (acceptIrp, acceptEndpoint, Connection);
|
|||
|
if (status==STATUS_SUCCESS) {
|
|||
|
AfdReleaseSpinLock (&Endpoint->SpinLock, LockHandle);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Decrement counter to account for connection being
|
|||
|
// returned to the free pool. No need to do this because
|
|||
|
// we are picking up a connection from the free pool
|
|||
|
// InterlockedDecrement (&Endpoint->Common.VcListening.FailedConnectionAdds);
|
|||
|
//
|
|||
|
ASSERT (oldConnection->Endpoint==NULL);
|
|||
|
InterlockedPushEntrySList (
|
|||
|
&Endpoint->Common.VcListening.FreeConnectionListHead,
|
|||
|
&oldConnection->SListEntry);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Complete previously failed accept irps if any.
|
|||
|
//
|
|||
|
while (!IsListEmpty (AcceptIrpList)) {
|
|||
|
PIRP irp;
|
|||
|
irp = CONTAINING_RECORD (AcceptIrpList->Flink, IRP, Tail.Overlay.ListEntry);
|
|||
|
RemoveEntryList (&irp->Tail.Overlay.ListEntry);
|
|||
|
IoCompleteRequest (irp, AfdPriorityBoost);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Make irp look like it is completed by the
|
|||
|
// transport.
|
|||
|
//
|
|||
|
acceptIrp->IoStatus.Status = STATUS_SUCCESS;
|
|||
|
irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdMdlAddress = acceptIrp->MdlAddress;
|
|||
|
acceptIrp->MdlAddress = NULL;
|
|||
|
irpSp->FileObject = acceptFileObject;
|
|||
|
|
|||
|
//
|
|||
|
// Call completion routine directly to simulate
|
|||
|
// completion by the transport stack
|
|||
|
//
|
|||
|
AfdRestartSuperAcceptListen (acceptIrp, Connection);
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
else {
|
|||
|
ASSERT (status!=STATUS_PENDING);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else { // if (IoSetCancelRoutine (accpetIrp, NULL)!=NULL)
|
|||
|
status = STATUS_CANCELLED;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Cleanup the IRP and insert it into the completion list
|
|||
|
//
|
|||
|
AfdCleanupSuperAccept (acceptIrp, status);
|
|||
|
InsertTailList (AcceptIrpList,
|
|||
|
&acceptIrp->Tail.Overlay.ListEntry);
|
|||
|
} // if (acceptIrp!=NULL)
|
|||
|
else {
|
|||
|
status = STATUS_CANCELLED;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// This connection has already been diassociated from endpoint.
|
|||
|
// If backlog is below the level we need, put it on the free
|
|||
|
// list, otherwise, get rid of it.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT (oldConnection->Endpoint==NULL);
|
|||
|
if (Endpoint->Common.VcListening.FailedConnectionAdds>=0 &&
|
|||
|
status!=STATUS_INSUFFICIENT_RESOURCES &&
|
|||
|
ExQueryDepthSList (&Endpoint->Common.VcListening.FreeConnectionListHead)<AFD_MAXIMUM_FREE_CONNECTIONS) {
|
|||
|
InterlockedPushEntrySList (
|
|||
|
&Endpoint->Common.VcListening.FreeConnectionListHead,
|
|||
|
&oldConnection->SListEntry);
|
|||
|
}
|
|||
|
else {
|
|||
|
InterlockedIncrement (&Endpoint->Common.VcListening.FailedConnectionAdds);
|
|||
|
DEREFERENCE_CONNECTION (oldConnection);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdSetupAcceptEndpoint (
|
|||
|
PAFD_ENDPOINT ListenEndpoint,
|
|||
|
PAFD_ENDPOINT AcceptEndpoint,
|
|||
|
PAFD_CONNECTION Connection
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Sets up the accept endpoint to get ready to accept connection
|
|||
|
(copies parameters of the listening endpoint on which connection
|
|||
|
was indicated)
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ListenEndpoint - endpoint on which connection was indicated
|
|||
|
AcceptEndpoint - endpoint on which to accept the connection
|
|||
|
Connection - connection to accept
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - endpoint state/parameters adjusted OK
|
|||
|
STATUS_CANCELLED - endpoint has already been cleaned up.
|
|||
|
|
|||
|
Note:
|
|||
|
Both accepting and listening endpoint spinlocks must be held when
|
|||
|
calling this routine.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
//
|
|||
|
// Check the state of the accepting endpoint.
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
if ( AcceptEndpoint->EndpointCleanedUp ) {
|
|||
|
return STATUS_CANCELLED;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Remove super accept IRP from the endpoint
|
|||
|
//
|
|||
|
AcceptEndpoint->Irp = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Note that the returned connection structure already has a
|
|||
|
// referenced pointer to the listening endpoint. Rather than
|
|||
|
// removing the reference here, only to re-add it later, we'll
|
|||
|
// just not touch the reference count.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT( Connection->Endpoint == ListenEndpoint );
|
|||
|
|
|||
|
//
|
|||
|
// Set up the accept endpoint's type, and remember blocking
|
|||
|
// characteristics of the TDI provider.
|
|||
|
//
|
|||
|
|
|||
|
AcceptEndpoint->Type = AfdBlockTypeVcConnecting;
|
|||
|
AcceptEndpoint->TdiServiceFlags = ListenEndpoint->TdiServiceFlags;
|
|||
|
|
|||
|
ASSERT (AcceptEndpoint->TransportInfo == ListenEndpoint->TransportInfo);
|
|||
|
ASSERT (AcceptEndpoint->TransportInfo->ReferenceCount>0);
|
|||
|
|
|||
|
//
|
|||
|
// Place the connection on the endpoint we'll accept it on. It is
|
|||
|
// still referenced from when it was created.
|
|||
|
//
|
|||
|
|
|||
|
AcceptEndpoint->Common.VcConnecting.Connection = Connection;
|
|||
|
|
|||
|
//
|
|||
|
// Set up a referenced pointer from the connection to the accept
|
|||
|
// endpoint. Note that we actually already have a refernce to
|
|||
|
// the endpoint by the virtue of its file object
|
|||
|
//
|
|||
|
|
|||
|
REFERENCE_ENDPOINT( AcceptEndpoint );
|
|||
|
Connection->Endpoint = AcceptEndpoint;
|
|||
|
|
|||
|
//
|
|||
|
// Set up a referenced pointer to the listening endpoint. This is
|
|||
|
// necessary so that the endpoint does not go away until all
|
|||
|
// accepted endpoints have gone away. Without this, a connect
|
|||
|
// indication could occur on a TDI address object held open
|
|||
|
// by an accepted endpoint after the listening endpoint has
|
|||
|
// been closed and the memory for it deallocated.
|
|||
|
//
|
|||
|
// Note that, since we didn't remove the reference above, we don't
|
|||
|
// need to add it here.
|
|||
|
//
|
|||
|
|
|||
|
AcceptEndpoint->Common.VcConnecting.ListenEndpoint = ListenEndpoint;
|
|||
|
|
|||
|
//
|
|||
|
// Set up a referenced pointer in the accepted endpoint to the
|
|||
|
// TDI address object.
|
|||
|
//
|
|||
|
|
|||
|
ObReferenceObject( ListenEndpoint->AddressFileObject );
|
|||
|
AfdRecordAddrRef();
|
|||
|
|
|||
|
AcceptEndpoint->AddressFileObject = ListenEndpoint->AddressFileObject;
|
|||
|
AcceptEndpoint->AddressDeviceObject = ListenEndpoint->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.
|
|||
|
//
|
|||
|
AcceptEndpoint->LocalAddress = ListenEndpoint->LocalAddress;
|
|||
|
AcceptEndpoint->LocalAddressLength = ListenEndpoint->LocalAddressLength;
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|