1474 lines
36 KiB
C
1474 lines
36 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
accept.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the handling code for IOCTL_AFD_ACCEPT.
|
||
|
||
Author:
|
||
|
||
David Treadwell (davidtr) 21-Feb-1992
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "afdp.h"
|
||
|
||
NTSTATUS
|
||
AfdAcceptCore (
|
||
IN PAFD_ENDPOINT ListenEndpoint,
|
||
IN PAFD_ENDPOINT AcceptEndpoint,
|
||
IN ULONG Sequence
|
||
);
|
||
|
||
VOID
|
||
AfdDoListenBacklogReplenish (
|
||
IN PVOID Context
|
||
);
|
||
|
||
VOID
|
||
AfdReplenishListenBacklog (
|
||
IN PAFD_ENDPOINT Endpoint
|
||
);
|
||
|
||
NTSTATUS
|
||
AfdRestartSuperAcceptGetAddress (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Context
|
||
);
|
||
|
||
NTSTATUS
|
||
AfdRestartSuperAcceptListen (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Context
|
||
);
|
||
|
||
NTSTATUS
|
||
AfdRestartSuperAcceptReceive (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Context
|
||
);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text( PAGE, AfdAccept )
|
||
#pragma alloc_text( PAGE, AfdSuperAccept )
|
||
#pragma alloc_text( PAGEAFD, AfdDeferAccept )
|
||
#pragma alloc_text( PAGE, AfdDoListenBacklogReplenish )
|
||
#pragma alloc_text( PAGEAFD, AfdAcceptCore )
|
||
#pragma alloc_text( PAGE, AfdReplenishListenBacklog )
|
||
#pragma alloc_text( PAGEAFD, AfdInitiateListenBacklogReplenish )
|
||
#pragma alloc_text( PAGEAFD, AfdRestartSuperAcceptListen )
|
||
#pragma alloc_text( PAGEAFD, AfdRestartSuperAcceptGetAddress )
|
||
#pragma alloc_text( PAGEAFD, AfdRestartSuperAcceptReceive )
|
||
#endif
|
||
|
||
|
||
NTSTATUS
|
||
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 endpoint;
|
||
PFILE_OBJECT acceptEndpointFileObject;
|
||
PAFD_ENDPOINT acceptEndpoint;
|
||
PAFD_CONNECTION connection;
|
||
|
||
PAGED_CODE( );
|
||
|
||
//
|
||
// Set up local variables.
|
||
//
|
||
|
||
endpoint = IrpSp->FileObject->FsContext;
|
||
ASSERT( endpoint->Type == AfdBlockTypeVcListening );
|
||
acceptInfo = Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
//
|
||
// Make sure that this request is valid.
|
||
//
|
||
|
||
if ( endpoint->Type != AfdBlockTypeVcListening ||
|
||
IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
||
sizeof(AFD_ACCEPT_INFO) ) {
|
||
status = STATUS_INVALID_PARAMETER;
|
||
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(
|
||
&endpoint->Common.VcListening.FailedConnectionAdds
|
||
);
|
||
|
||
AfdReplenishListenBacklog( endpoint );
|
||
|
||
//
|
||
// Obtain a pointer to the endpoint on which we're going to
|
||
// accept the connection.
|
||
//
|
||
|
||
status = ObReferenceObjectByHandle(
|
||
acceptInfo->AcceptHandle,
|
||
0L, // DesiredAccess
|
||
*IoFileObjectType,
|
||
KernelMode,
|
||
(PVOID *)&acceptEndpointFileObject,
|
||
NULL
|
||
);
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
goto complete;
|
||
}
|
||
|
||
acceptEndpoint = acceptEndpointFileObject->FsContext;
|
||
|
||
//
|
||
// We may have a file object that is not an AFD endpoint. Make sure
|
||
// that this is an actual AFD endpoint.
|
||
//
|
||
|
||
if ( acceptEndpoint->Type != AfdBlockTypeEndpoint ) {
|
||
status = STATUS_INVALID_PARAMETER;
|
||
ObDereferenceObject( acceptEndpointFileObject );
|
||
goto complete;
|
||
}
|
||
|
||
ASSERT( InterlockedIncrement( &acceptEndpoint->ObReferenceBias ) > 0 );
|
||
|
||
IF_DEBUG(ACCEPT) {
|
||
KdPrint(( "AfdAccept: file object %lx, accept endpoint %lx, "
|
||
"listen endpoint %lx\n",
|
||
acceptEndpointFileObject, acceptEndpoint, endpoint ));
|
||
}
|
||
|
||
status = AfdAcceptCore( endpoint, acceptEndpoint, acceptInfo->Sequence );
|
||
|
||
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
||
|
||
ObDereferenceObject( acceptEndpointFileObject );
|
||
|
||
complete:
|
||
|
||
Irp->IoStatus.Status = status;
|
||
ASSERT( Irp->CancelRoutine == NULL );
|
||
|
||
IoCompleteRequest( Irp, AfdPriorityBoost );
|
||
|
||
return status;
|
||
|
||
} // AfdAccept
|
||
|
||
|
||
NTSTATUS
|
||
AfdAcceptCore (
|
||
IN PAFD_ENDPOINT ListenEndpoint,
|
||
IN PAFD_ENDPOINT AcceptEndpoint,
|
||
IN ULONG Sequence
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Performs the key functions of associating a connection accepted
|
||
on a listening endpoint with a new endpoint.
|
||
|
||
Arguments:
|
||
|
||
ListenEndpoint - the listening endpoint for the connection.
|
||
|
||
AcceptEndpoint - the new endpoint with which to associate the
|
||
connectuion.
|
||
|
||
Sequence - the sequence number which identifies the accepted
|
||
connection.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if the operation was completed successfully, or a
|
||
failure status code if there was an error.
|
||
|
||
--*/
|
||
|
||
{
|
||
PAFD_CONNECTION connection;
|
||
KIRQL oldIrql;
|
||
ULONG eventsActive;
|
||
|
||
//
|
||
// Fail if the accepting endpoint is not in the correct state.
|
||
//
|
||
|
||
if ( AcceptEndpoint->State != AfdEndpointStateOpen ) {
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// Store the local address of the accept endpoint from the listening
|
||
// endpoint. This keeps the address unusable as long as the accept
|
||
// endpoint is active.
|
||
//
|
||
// If the endpoint already has a local address structure that is
|
||
// sufficiently large, reuse it.
|
||
//
|
||
|
||
if ( AcceptEndpoint->LocalAddress != NULL &&
|
||
AcceptEndpoint->LocalAddressLength <
|
||
ListenEndpoint->LocalAddressLength ) {
|
||
|
||
AFD_FREE_POOL(
|
||
AcceptEndpoint->LocalAddress,
|
||
AFD_LOCAL_ADDRESS_POOL_TAG
|
||
);
|
||
AcceptEndpoint->LocalAddress = NULL;
|
||
}
|
||
|
||
if ( AcceptEndpoint->LocalAddress == NULL ) {
|
||
|
||
AcceptEndpoint->LocalAddress = AFD_ALLOCATE_POOL(
|
||
NonPagedPool,
|
||
ListenEndpoint->LocalAddressLength,
|
||
AFD_LOCAL_ADDRESS_POOL_TAG
|
||
);
|
||
}
|
||
|
||
AcceptEndpoint->LocalAddressLength = ListenEndpoint->LocalAddressLength;
|
||
|
||
|
||
if ( AcceptEndpoint->LocalAddress == NULL ) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
RtlCopyMemory(
|
||
AcceptEndpoint->LocalAddress,
|
||
ListenEndpoint->LocalAddress,
|
||
ListenEndpoint->LocalAddressLength
|
||
);
|
||
|
||
//
|
||
// Find the connection on which the accept is being performed.
|
||
//
|
||
|
||
connection = AfdGetReturnedConnection( ListenEndpoint, Sequence );
|
||
|
||
if ( connection == NULL ) {
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
ASSERT( connection->Type == AfdBlockTypeConnection );
|
||
|
||
//
|
||
// Reenable the accept event bit, and if there are additional
|
||
// unaccepted connections on the endpoint, post another event.
|
||
//
|
||
|
||
AfdAcquireSpinLock( &ListenEndpoint->SpinLock, &oldIrql );
|
||
|
||
ListenEndpoint->EventsActive &= ~AFD_POLL_ACCEPT;
|
||
|
||
IF_DEBUG(EVENT_SELECT) {
|
||
KdPrint((
|
||
"AfdAcceptCore: Endp %08lX, Active %08lX\n",
|
||
ListenEndpoint,
|
||
ListenEndpoint->EventsActive
|
||
));
|
||
}
|
||
|
||
if( !IsListEmpty( &ListenEndpoint->Common.VcListening.UnacceptedConnectionListHead ) ) {
|
||
|
||
AfdIndicateEventSelectEvent(
|
||
ListenEndpoint,
|
||
AFD_POLL_ACCEPT_BIT,
|
||
STATUS_SUCCESS
|
||
);
|
||
|
||
}
|
||
|
||
AfdReleaseSpinLock( &ListenEndpoint->SpinLock, oldIrql );
|
||
|
||
//
|
||
// Recheck the state of the accepting endpoint under the guard
|
||
// of the endpoint's spinlock.
|
||
//
|
||
|
||
AfdAcquireSpinLock( &AcceptEndpoint->SpinLock, &oldIrql );
|
||
|
||
if ( AcceptEndpoint->State != AfdEndpointStateOpen ||
|
||
AcceptEndpoint->EndpointCleanedUp ) {
|
||
AfdReleaseSpinLock( &AcceptEndpoint->SpinLock, oldIrql );
|
||
|
||
//
|
||
// The accepted endpoint has been closed, so go ahead and
|
||
// abort the incoming connection.
|
||
//
|
||
|
||
AfdAbortConnection( connection );
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// 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->TdiBufferring = ListenEndpoint->TdiBufferring;
|
||
|
||
//
|
||
// 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.
|
||
//
|
||
|
||
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 the endpoint to the connected state.
|
||
//
|
||
|
||
AcceptEndpoint->State = AfdEndpointStateConnected;
|
||
|
||
//
|
||
// 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;
|
||
|
||
//
|
||
// Setup the active event bits on the accepted endpoint. We'll start with
|
||
// the ones in the listening endpoint, as these are the OR of all active
|
||
// bits for the listening endpoint and all unaccepted connections.
|
||
//
|
||
// Note that we don't actually signal the events here, as the DLL will
|
||
// invoke WSAEventSelect() if necessary on the socket while processing
|
||
// the accept() API.
|
||
//
|
||
|
||
eventsActive = ListenEndpoint->EventsActive;
|
||
|
||
if( eventsActive & AFD_POLL_RECEIVE ) {
|
||
|
||
if( !IS_DATA_ON_CONNECTION( connection ) &&
|
||
( !AcceptEndpoint->InLine ||
|
||
!IS_EXPEDITED_DATA_ON_CONNECTION( connection ) ) ) {
|
||
|
||
eventsActive &= ~AFD_POLL_RECEIVE;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if( eventsActive & AFD_POLL_RECEIVE_EXPEDITED ) {
|
||
|
||
if( AcceptEndpoint->InLine ||
|
||
!IS_EXPEDITED_DATA_ON_CONNECTION( connection ) ) {
|
||
|
||
eventsActive &= ~AFD_POLL_RECEIVE_EXPEDITED;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if( eventsActive & AFD_POLL_DISCONNECT ) {
|
||
|
||
if( !connection->DisconnectIndicated ) {
|
||
|
||
eventsActive &= ~AFD_POLL_DISCONNECT;
|
||
}
|
||
|
||
}
|
||
|
||
if( eventsActive & AFD_POLL_ABORT ) {
|
||
|
||
if( !connection->AbortIndicated ) {
|
||
|
||
eventsActive &= ~AFD_POLL_ABORT;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
AcceptEndpoint->EventsActive = eventsActive | AFD_POLL_SEND;
|
||
|
||
IF_DEBUG(EVENT_SELECT) {
|
||
KdPrint((
|
||
"AfdAcceptCore: Endp %08lX, Active %08lX\n",
|
||
AcceptEndpoint,
|
||
AcceptEndpoint->EventsActive
|
||
));
|
||
}
|
||
|
||
AfdReleaseSpinLock( &AcceptEndpoint->SpinLock, oldIrql );
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
} // 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.
|
||
|
||
--*/
|
||
|
||
{
|
||
PAFD_WORK_ITEM afdWorkItem;
|
||
|
||
//
|
||
// Reference the endpoint so that it won't go away until we're
|
||
// done with it.
|
||
//
|
||
|
||
REFERENCE_ENDPOINT( Endpoint );
|
||
|
||
//
|
||
// Queue a work item to an executive worker thread.
|
||
//
|
||
|
||
afdWorkItem = AfdAllocateWorkItem();
|
||
ASSERT( afdWorkItem != NULL );
|
||
|
||
afdWorkItem->Context = Endpoint;
|
||
|
||
AfdQueueWorkItem(
|
||
AfdDoListenBacklogReplenish,
|
||
afdWorkItem
|
||
);
|
||
|
||
} // 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;
|
||
PAFD_WORK_ITEM afdWorkItem;
|
||
|
||
PAGED_CODE( );
|
||
|
||
ASSERT( Context != NULL );
|
||
|
||
afdWorkItem = Context;
|
||
endpoint = (PAFD_ENDPOINT)afdWorkItem->Context;
|
||
|
||
AfdFreeWorkItem( afdWorkItem );
|
||
|
||
ASSERT( endpoint->Type == AfdBlockTypeVcListening );
|
||
|
||
//
|
||
// If the endpoint's state changed, don't replenish the backlog.
|
||
//
|
||
|
||
if ( endpoint->State != AfdEndpointStateListening ) {
|
||
DEREFERENCE_ENDPOINT( endpoint );
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Fill up the free connection backlog.
|
||
//
|
||
|
||
AfdReplenishListenBacklog( endpoint );
|
||
|
||
//
|
||
// Clean up and return.
|
||
//
|
||
|
||
DEREFERENCE_ENDPOINT( endpoint );
|
||
|
||
return;
|
||
|
||
} // AfdDoListenBacklogReplenish
|
||
|
||
|
||
VOID
|
||
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:
|
||
|
||
None--any errors are ignored and the backlog may be refilled
|
||
at a later time.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
LONG result;
|
||
|
||
PAGED_CODE( );
|
||
|
||
ASSERT( Endpoint->Type == AfdBlockTypeVcListening );
|
||
|
||
|
||
//
|
||
// 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(ACCEPT) {
|
||
KdPrint(( "AfdReplenishListenBacklog: AfdAddFreeConnection failed: %X, "
|
||
"fail count = %ld\n", status,
|
||
Endpoint->Common.VcListening.FailedConnectionAdds ));
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
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;
|
||
|
||
} // AfdReplenishListenBacklog
|
||
|
||
|
||
NTSTATUS
|
||
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;
|
||
PAFD_SUPER_ACCEPT_INFO superAcceptInfo = NULL;
|
||
NTSTATUS status;
|
||
PIO_STACK_LOCATION nextIrpSp;
|
||
|
||
PAGED_CODE( );
|
||
|
||
//
|
||
// Set up local variables.
|
||
//
|
||
|
||
listenEndpoint = IrpSp->FileObject->FsContext;
|
||
superAcceptInfo = Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
//
|
||
// 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->Type != AfdBlockTypeVcListening
|
||
|
||
||
|
||
|
||
IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
||
sizeof(AFD_SUPER_ACCEPT_INFO)
|
||
|
||
||
|
||
|
||
IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
||
sizeof(AFD_SUPER_ACCEPT_INFO) + superAcceptInfo->LocalAddressLength
|
||
|
||
||
|
||
|
||
Irp->MdlAddress == NULL
|
||
|
||
||
|
||
|
||
IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
||
superAcceptInfo->ReceiveDataLength +
|
||
superAcceptInfo->LocalAddressLength +
|
||
superAcceptInfo->RemoteAddressLength ) {
|
||
|
||
#if DBG
|
||
if( listenEndpoint->Type != AfdBlockTypeVcListening ) {
|
||
KdPrint((
|
||
"AfdSuperAccept: non-listening endpoint @ %08lX\n",
|
||
listenEndpoint
|
||
));
|
||
}
|
||
#endif
|
||
|
||
superAcceptInfo = NULL;
|
||
status = STATUS_INVALID_PARAMETER;
|
||
goto complete;
|
||
}
|
||
|
||
//
|
||
// Obtain a pointer to the endpoint on which we're going to
|
||
// accept the connection.
|
||
//
|
||
|
||
status = ObReferenceObjectByHandle(
|
||
superAcceptInfo->AcceptHandle,
|
||
0L, // DesiredAccess
|
||
*IoFileObjectType,
|
||
KernelMode,
|
||
&superAcceptInfo->AcceptFileObject,
|
||
NULL
|
||
);
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
superAcceptInfo = NULL;
|
||
goto complete;
|
||
}
|
||
|
||
acceptFileObject = superAcceptInfo->AcceptFileObject;
|
||
acceptEndpoint = acceptFileObject->FsContext;
|
||
|
||
superAcceptInfo->AcceptEndpoint = acceptEndpoint;
|
||
|
||
//
|
||
// We may have a file object that is not an AFD endpoint. Make sure
|
||
// that this is an actual AFD endpoint.
|
||
//
|
||
|
||
if ( acceptEndpoint->Type != AfdBlockTypeEndpoint ) {
|
||
status = STATUS_INVALID_PARAMETER;
|
||
goto complete;
|
||
}
|
||
|
||
ASSERT( InterlockedIncrement( &acceptEndpoint->ObReferenceBias ) > 0 );
|
||
|
||
//
|
||
// 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 );
|
||
|
||
//
|
||
// Start off by building a AFD_WAIT_FOR_LISTEN_LIFO IRP, using the current
|
||
// IRP and the next stack location on it.
|
||
//
|
||
|
||
nextIrpSp = IoGetNextIrpStackLocation( Irp );
|
||
|
||
Irp->AssociatedIrp.SystemBuffer = &superAcceptInfo->ListenResponseInfo;
|
||
nextIrpSp->FileObject = IrpSp->FileObject;
|
||
nextIrpSp->DeviceObject = IoGetRelatedDeviceObject( IrpSp->FileObject );
|
||
nextIrpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
|
||
|
||
|
||
nextIrpSp->Parameters.DeviceIoControl.OutputBufferLength =
|
||
sizeof(AFD_LISTEN_RESPONSE_INFO) + superAcceptInfo->RemoteAddressLength;
|
||
nextIrpSp->Parameters.DeviceIoControl.InputBufferLength = 0;
|
||
nextIrpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_AFD_WAIT_FOR_LISTEN_LIFO;
|
||
|
||
IoSetCompletionRoutine(
|
||
Irp,
|
||
AfdRestartSuperAcceptListen,
|
||
superAcceptInfo,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE
|
||
);
|
||
|
||
//
|
||
// Perform the listen wait. We'll continue processing from the
|
||
// completion routine.
|
||
//
|
||
|
||
IoCallDriver( IrpSp->DeviceObject, Irp );
|
||
|
||
return STATUS_PENDING;
|
||
|
||
complete:
|
||
|
||
if ( superAcceptInfo != NULL ) {
|
||
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
||
|
||
ObDereferenceObject( superAcceptInfo->AcceptFileObject );
|
||
}
|
||
|
||
Irp->IoStatus.Information = 0;
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest( Irp, 0 );
|
||
|
||
return status;
|
||
|
||
} // AfdSuperAccept
|
||
|
||
|
||
NTSTATUS
|
||
AfdRestartSuperAcceptListen (
|
||
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 the super accept request information.
|
||
|
||
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;
|
||
PAFD_ENDPOINT acceptEndpoint;
|
||
PAFD_CONNECTION connection;
|
||
PAFD_SUPER_ACCEPT_INFO superAcceptInfo;
|
||
NTSTATUS status;
|
||
PIO_STACK_LOCATION irpSp;
|
||
ULONG bytesCopied;
|
||
PMDL mdl;
|
||
|
||
//
|
||
// Initialize some locals.
|
||
//
|
||
|
||
superAcceptInfo = Context;
|
||
irpSp = IoGetCurrentIrpStackLocation( Irp );
|
||
listenEndpoint = irpSp->FileObject->FsContext;
|
||
acceptEndpoint = superAcceptInfo->AcceptEndpoint;
|
||
|
||
//
|
||
// If pending has been returned for this irp then mark the current
|
||
// stack as pending.
|
||
//
|
||
|
||
if ( Irp->PendingReturned ) {
|
||
IoMarkIrpPending( Irp );
|
||
}
|
||
|
||
//
|
||
// Fix up the system buffer pointer in the IRP.
|
||
//
|
||
|
||
ASSERT( Irp->AssociatedIrp.SystemBuffer == &superAcceptInfo->ListenResponseInfo );
|
||
Irp->AssociatedIrp.SystemBuffer = superAcceptInfo;
|
||
|
||
//
|
||
// If the IRP failed, quit processing.
|
||
//
|
||
|
||
if ( !NT_SUCCESS(Irp->IoStatus.Status) ) {
|
||
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
||
|
||
ObDereferenceObject( superAcceptInfo->AcceptFileObject );
|
||
InterlockedDecrement(
|
||
&listenEndpoint->Common.VcListening.FailedConnectionAdds
|
||
);
|
||
return Irp->IoStatus.Status;
|
||
}
|
||
|
||
//
|
||
// Copy over the address information to the user's buffer.
|
||
//
|
||
|
||
status = TdiCopyBufferToMdl(
|
||
&superAcceptInfo->ListenResponseInfo.RemoteAddress,
|
||
0,
|
||
superAcceptInfo->RemoteAddressLength,
|
||
Irp->MdlAddress,
|
||
superAcceptInfo->ReceiveDataLength +
|
||
superAcceptInfo->LocalAddressLength,
|
||
&bytesCopied
|
||
);
|
||
if ( !NT_SUCCESS(status) ) {
|
||
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
||
|
||
ObDereferenceObject( superAcceptInfo->AcceptFileObject );
|
||
InterlockedDecrement(
|
||
&listenEndpoint->Common.VcListening.FailedConnectionAdds
|
||
);
|
||
Irp->IoStatus.Status = status;
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Now do the actual connection acceptance.
|
||
//
|
||
|
||
status = AfdAcceptCore(
|
||
listenEndpoint,
|
||
acceptEndpoint,
|
||
superAcceptInfo->ListenResponseInfo.Sequence
|
||
);
|
||
if ( !NT_SUCCESS(status) ) {
|
||
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
||
|
||
ObDereferenceObject( superAcceptInfo->AcceptFileObject );
|
||
InterlockedDecrement(
|
||
&listenEndpoint->Common.VcListening.FailedConnectionAdds
|
||
);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// The AFD connection object should now be in the endpoiont.
|
||
//
|
||
|
||
connection = AFD_CONNECTION_FROM_ENDPOINT( acceptEndpoint );
|
||
ASSERT( connection != NULL );
|
||
|
||
//
|
||
// The endpoint is now connected and ready to go. Get the local
|
||
// address for the connection. We'll need an MDL to map the portion
|
||
// of the user buffer that will receive the local address.
|
||
//
|
||
|
||
mdl = IoAllocateMdl(
|
||
(PCHAR)MmGetMdlVirtualAddress( Irp->MdlAddress ) + superAcceptInfo->ReceiveDataLength,
|
||
superAcceptInfo->LocalAddressLength,
|
||
FALSE,
|
||
FALSE,
|
||
NULL
|
||
);
|
||
if ( mdl == NULL ) {
|
||
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
||
|
||
ObDereferenceObject( superAcceptInfo->AcceptFileObject );
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// Set up this new MDL to describe the appropriate portion of the
|
||
// buffer.
|
||
//
|
||
|
||
IoBuildPartialMdl(
|
||
Irp->MdlAddress,
|
||
mdl,
|
||
(PCHAR)MmGetMdlVirtualAddress( Irp->MdlAddress ) + superAcceptInfo->ReceiveDataLength,
|
||
superAcceptInfo->LocalAddressLength
|
||
);
|
||
|
||
//
|
||
// Set up the IRP to query the local address of this endpoint. We'll
|
||
// hold on to the original MDL value in the AcceptHandle field, which
|
||
// we don't need any longer.
|
||
//
|
||
|
||
superAcceptInfo->AcceptHandle = (HANDLE)Irp->MdlAddress;
|
||
Irp->MdlAddress = mdl;
|
||
|
||
TdiBuildQueryInformation(
|
||
Irp,
|
||
connection->DeviceObject,
|
||
connection->FileObject,
|
||
AfdRestartSuperAcceptGetAddress,
|
||
superAcceptInfo,
|
||
TDI_QUERY_ADDRESS_INFO,
|
||
Irp->MdlAddress
|
||
);
|
||
|
||
//
|
||
// Perform the local address query. We'll continue processing from
|
||
// the completion routine.
|
||
//
|
||
|
||
IoCallDriver( connection->DeviceObject, Irp );
|
||
|
||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
||
} // AfdRestartSuperAcceptListen
|
||
|
||
|
||
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 super accept request information.
|
||
|
||
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_SUPER_ACCEPT_INFO superAcceptInfo;
|
||
PAFD_ENDPOINT acceptEndpoint;
|
||
PIO_STACK_LOCATION nextIrpSp;
|
||
PFILE_OBJECT acceptFileObject;
|
||
PMDL partialMdl;
|
||
|
||
//
|
||
// Initialize some locals.
|
||
//
|
||
|
||
superAcceptInfo = Context;
|
||
acceptEndpoint = superAcceptInfo->AcceptEndpoint;
|
||
acceptFileObject = superAcceptInfo->AcceptFileObject;
|
||
|
||
//
|
||
// If pending has been returned for this irp then mark the current
|
||
// stack as pending.
|
||
//
|
||
|
||
if ( Irp->PendingReturned ) {
|
||
IoMarkIrpPending( Irp );
|
||
}
|
||
|
||
//
|
||
// Free the MDL we temporarily allocated and fix up the MDL pointer
|
||
// in the IRP.
|
||
//
|
||
|
||
IoFreeMdl( Irp->MdlAddress );
|
||
|
||
Irp->MdlAddress = (PMDL)superAcceptInfo->AcceptHandle;
|
||
|
||
//
|
||
// If the caller didn't want to receive any data on the connection,
|
||
// or if the query for the local address failed, then we're done
|
||
// now.
|
||
//
|
||
|
||
if ( superAcceptInfo->ReceiveDataLength == 0 ||
|
||
!NT_SUCCESS( Irp->IoStatus.Status ) ) {
|
||
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
||
|
||
ObDereferenceObject( superAcceptInfo->AcceptFileObject );
|
||
Irp->IoStatus.Information = 0;
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// Create a partial MDL describing the portion of the user's buffer
|
||
// to be used for receive data. Note that we cannot use the entire
|
||
// user's buffer, as the end of the buffer is used for the local and
|
||
// remote addresses.
|
||
//
|
||
|
||
partialMdl = IoAllocateMdl(
|
||
MmGetMdlVirtualAddress( Irp->MdlAddress ),
|
||
superAcceptInfo->ReceiveDataLength,
|
||
FALSE, // SecondaryBuffer
|
||
FALSE, // ChargeQuota
|
||
NULL // Irp
|
||
);
|
||
|
||
if( partialMdl == NULL ) {
|
||
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
||
|
||
ObDereferenceObject( superAcceptInfo->AcceptFileObject );
|
||
Irp->IoStatus.Information = 0;
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
IoBuildPartialMdl(
|
||
Irp->MdlAddress,
|
||
partialMdl,
|
||
MmGetMdlVirtualAddress( Irp->MdlAddress ),
|
||
superAcceptInfo->ReceiveDataLength
|
||
);
|
||
|
||
Irp->MdlAddress = partialMdl;
|
||
|
||
//
|
||
// 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 = acceptFileObject;
|
||
nextIrpSp->DeviceObject = IoGetRelatedDeviceObject( acceptFileObject );
|
||
nextIrpSp->MajorFunction = IRP_MJ_READ;
|
||
|
||
nextIrpSp->Parameters.Read.Length = superAcceptInfo->ReceiveDataLength;
|
||
nextIrpSp->Parameters.Read.Key = 0;
|
||
nextIrpSp->Parameters.Read.ByteOffset.QuadPart = 0;
|
||
|
||
IoSetCompletionRoutine(
|
||
Irp,
|
||
AfdRestartSuperAcceptReceive,
|
||
superAcceptInfo,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE
|
||
);
|
||
|
||
//
|
||
// Perform the receive. We'll continue processing from
|
||
// the completion routine.
|
||
//
|
||
|
||
IoCallDriver( nextIrpSp->DeviceObject, Irp );
|
||
|
||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
||
} // 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 super accept request information.
|
||
|
||
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_SUPER_ACCEPT_INFO superAcceptInfo;
|
||
PIO_STACK_LOCATION nextIrpSp;
|
||
PFILE_OBJECT acceptFileObject;
|
||
|
||
//
|
||
// Initialize some locals.
|
||
//
|
||
|
||
superAcceptInfo = Context;
|
||
acceptFileObject = superAcceptInfo->AcceptFileObject;
|
||
|
||
//
|
||
// If pending has been returned for this irp then mark the current
|
||
// stack as pending.
|
||
//
|
||
|
||
if ( Irp->PendingReturned ) {
|
||
IoMarkIrpPending( Irp );
|
||
}
|
||
|
||
//
|
||
// Free the partial MDL we temporarily allocated and fix up the
|
||
// MDL pointer in the IRP.
|
||
//
|
||
|
||
IoFreeMdl( Irp->MdlAddress );
|
||
|
||
Irp->MdlAddress = (PMDL)superAcceptInfo->AcceptHandle;
|
||
|
||
//
|
||
// Dereference the accept file object and tell IO to complete this IRP.
|
||
//
|
||
|
||
#if DBG
|
||
{
|
||
PAFD_ENDPOINT endpoint;
|
||
|
||
endpoint = ((PFILE_OBJECT)superAcceptInfo->AcceptFileObject)->FsContext;
|
||
ASSERT( endpoint != NULL );
|
||
ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
|
||
|
||
ASSERT( InterlockedDecrement( &endpoint->ObReferenceBias ) >= 0 );
|
||
}
|
||
#endif
|
||
|
||
ObDereferenceObject( superAcceptInfo->AcceptFileObject );
|
||
return STATUS_SUCCESS;
|
||
|
||
} // AfdRestartSuperAcceptReceive
|
||
|
||
|
||
NTSTATUS
|
||
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;
|
||
KIRQL oldIrql;
|
||
|
||
PAGED_CODE( );
|
||
|
||
//
|
||
// Set up local variables.
|
||
//
|
||
|
||
endpoint = IrpSp->FileObject->FsContext;
|
||
ASSERT( endpoint->Type == AfdBlockTypeVcListening );
|
||
deferAcceptInfo = Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
//
|
||
// Make sure that this request is valid.
|
||
//
|
||
|
||
if( endpoint->Type != AfdBlockTypeVcListening ||
|
||
IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
||
sizeof(AFD_DEFER_ACCEPT_INFO) ) {
|
||
|
||
status = STATUS_INVALID_PARAMETER;
|
||
goto complete;
|
||
|
||
}
|
||
|
||
//
|
||
// Find the specified connection. If it cannot be found, then this
|
||
// is a bogus request.
|
||
//
|
||
|
||
connection = AfdGetReturnedConnection(
|
||
endpoint,
|
||
deferAcceptInfo->Sequence
|
||
);
|
||
|
||
if( connection == NULL ) {
|
||
|
||
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 ) {
|
||
|
||
//
|
||
// Abort the connection.
|
||
//
|
||
|
||
AfdAbortConnection( connection );
|
||
|
||
//
|
||
// Reenable the accept event bit, and if there are additional
|
||
// unaccepted connections on the endpoint, post another event.
|
||
//
|
||
|
||
AfdAcquireSpinLock( &endpoint->SpinLock, &oldIrql );
|
||
|
||
endpoint->EventsActive &= ~AFD_POLL_ACCEPT;
|
||
|
||
IF_DEBUG(EVENT_SELECT) {
|
||
KdPrint((
|
||
"AfdDeferAccept: Endp %08lX, Active %08lX\n",
|
||
endpoint,
|
||
endpoint->EventsActive
|
||
));
|
||
}
|
||
|
||
if( !IsListEmpty( &endpoint->Common.VcListening.UnacceptedConnectionListHead ) ) {
|
||
|
||
AfdIndicateEventSelectEvent(
|
||
endpoint,
|
||
AFD_POLL_ACCEPT_BIT,
|
||
STATUS_SUCCESS
|
||
);
|
||
|
||
}
|
||
|
||
AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
|
||
|
||
//
|
||
// 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;
|
||
|
||
ExInterlockedInsertHeadList(
|
||
&endpoint->Common.VcListening.UnacceptedConnectionListHead,
|
||
&connection->ListEntry,
|
||
&AfdSpinLock
|
||
);
|
||
|
||
}
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
complete:
|
||
|
||
Irp->IoStatus.Status = status;
|
||
ASSERT( Irp->CancelRoutine == NULL );
|
||
|
||
IoCompleteRequest( Irp, AfdPriorityBoost );
|
||
|
||
return status;
|
||
|
||
} // AfdDeferAccept
|
||
|