You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
765 lines
27 KiB
765 lines
27 KiB
/*++
|
|
|
|
Copyright (c) 1989-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
close.c
|
|
|
|
Abstract:
|
|
|
|
This module contains code for cleanup and close IRPs.
|
|
|
|
Author:
|
|
|
|
David Treadwell (davidtr) 18-Mar-1992
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "afdp.h"
|
|
|
|
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, AfdClose )
|
|
#pragma alloc_text( PAGEAFD, AfdCleanup )
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
FASTCALL
|
|
AfdCleanup (
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the routine that handles Cleanup IRPs in AFD.
|
|
|
|
Arguments:
|
|
|
|
Irp - Pointer to I/O request packet.
|
|
|
|
IrpSp - pointer to the IO stack location to use for this request.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS -- Indicates whether the request was successfully queued.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PAFD_ENDPOINT endpoint;
|
|
AFD_LOCK_QUEUE_HANDLE lockHandle;
|
|
PLIST_ENTRY listEntry;
|
|
LARGE_INTEGER processExitTime;
|
|
|
|
UNREFERENCED_PARAMETER (Irp);
|
|
|
|
endpoint = IrpSp->FileObject->FsContext;
|
|
ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
|
|
|
|
IF_DEBUG(OPEN_CLOSE) {
|
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
|
|
"AfdCleanup: cleanup on file object %p, endpoint %p, connection %p\n",
|
|
IrpSp->FileObject,
|
|
endpoint,
|
|
AFD_CONNECTION_FROM_ENDPOINT( endpoint )
|
|
));
|
|
}
|
|
|
|
//
|
|
// Get the process exit time while still at low IRQL.
|
|
//
|
|
|
|
processExitTime = PsGetProcessExitTime( );
|
|
|
|
//
|
|
// Indicate that there was a local close on this endpoint. If there
|
|
// are any outstanding polls on this endpoint, they will be
|
|
// completed now.
|
|
//
|
|
AfdIndicatePollEvent(
|
|
endpoint,
|
|
AFD_POLL_LOCAL_CLOSE,
|
|
STATUS_SUCCESS
|
|
);
|
|
|
|
//
|
|
// Remember that the endpoint has been cleaned up. This is important
|
|
// because it allows AfdRestartAccept to know that the endpoint has
|
|
// been cleaned up and that it should toss the connection.
|
|
//
|
|
|
|
AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
|
|
|
|
AfdIndicateEventSelectEvent (endpoint, AFD_POLL_LOCAL_CLOSE, STATUS_SUCCESS);
|
|
|
|
ASSERT( endpoint->EndpointCleanedUp == FALSE);
|
|
endpoint->EndpointCleanedUp = TRUE;
|
|
|
|
//
|
|
// If this a datagram endpoint, cancel all IRPs and free any buffers
|
|
// of data. Note that if the state of the endpoint is just "open"
|
|
// (not bound, etc.) then we can't have any pended IRPs or datagrams
|
|
// on the endpoint. Also, the lists of IRPs and datagrams may not
|
|
// yet been initialized if the state is just open.
|
|
//
|
|
|
|
if ( IS_DGRAM_ENDPOINT(endpoint) ) {
|
|
AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
|
|
|
|
if ( endpoint->State == AfdEndpointStateBound ||
|
|
endpoint->State == AfdEndpointStateConnected) {
|
|
|
|
//
|
|
// Reset the counts of datagrams bufferred on the endpoint.
|
|
// This prevents anyone from thinking that there is bufferred
|
|
// data on the endpoint.
|
|
//
|
|
|
|
endpoint->DgBufferredReceiveCount = 0;
|
|
endpoint->DgBufferredReceiveBytes = 0;
|
|
|
|
//
|
|
// Cancel all receive datagram and peek datagram IRPs on the
|
|
// endpoint.
|
|
//
|
|
|
|
AfdCompleteIrpList(
|
|
&endpoint->ReceiveDatagramIrpListHead,
|
|
endpoint,
|
|
STATUS_CANCELLED,
|
|
AfdCleanupReceiveDatagramIrp
|
|
);
|
|
|
|
AfdCompleteIrpList(
|
|
&endpoint->PeekDatagramIrpListHead,
|
|
endpoint,
|
|
STATUS_CANCELLED,
|
|
AfdCleanupReceiveDatagramIrp
|
|
);
|
|
|
|
}
|
|
}
|
|
else if (IS_SAN_ENDPOINT (endpoint)) {
|
|
if (!IsListEmpty (&endpoint->Common.SanEndp.IrpList)) {
|
|
AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
|
|
AfdSanRestartRequestProcessing (endpoint, STATUS_CANCELLED);
|
|
}
|
|
else {
|
|
AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
|
|
}
|
|
}
|
|
else if (IS_SAN_HELPER (endpoint)) {
|
|
AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
|
|
if (endpoint->OwningProcess==IoGetCurrentProcess ()) {
|
|
AfdSanHelperCleanup (endpoint);
|
|
}
|
|
else {
|
|
ASSERT ((endpoint->Common.SanHlpr.PendingRequests & 1) != 0);
|
|
}
|
|
}
|
|
else {
|
|
PAFD_CONNECTION connection;
|
|
|
|
connection = AFD_CONNECTION_FROM_ENDPOINT( endpoint );
|
|
ASSERT( connection == NULL || connection->Type == AfdBlockTypeConnection );
|
|
|
|
//
|
|
// Reference the connection object so that it does not go away while
|
|
// we are freeing the resources
|
|
//
|
|
|
|
if (connection!=NULL) {
|
|
REFERENCE_CONNECTION (connection);
|
|
|
|
//
|
|
// If this is a connected non-datagram socket and the send side has
|
|
// not been disconnected and there is no outstanding data to be
|
|
// received, begin a graceful disconnect on the connection. If there
|
|
// is unreceived data out outstanding IO, abort the connection.
|
|
//
|
|
|
|
if ( (endpoint->State == AfdEndpointStateConnected
|
|
|| endpoint->State==AfdEndpointStateBound
|
|
|| endpoint->State==AfdEndpointStateTransmitClosing)
|
|
// Endpoint is in bound state when connection
|
|
// request is in progress, we still need
|
|
// to abort those.
|
|
|
|
&&
|
|
connection->ConnectedReferenceAdded
|
|
|
|
&&
|
|
|
|
!endpoint->afdC_Root // these are connected on bind
|
|
|
|
&&
|
|
|
|
( (endpoint->DisconnectMode & AFD_ABORTIVE_DISCONNECT) == 0)
|
|
|
|
&&
|
|
|
|
( (endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_SEND) == 0 ||
|
|
IS_DATA_ON_CONNECTION(connection) ||
|
|
IS_EXPEDITED_DATA_ON_CONNECTION(connection) ||
|
|
( !IS_TDI_BUFFERRING(endpoint) &&
|
|
connection->Common.NonBufferring.ReceiveBytesInTransport > 0 ) ||
|
|
endpoint->StateChangeInProgress)
|
|
|
|
&&
|
|
|
|
!connection->Aborted ) {
|
|
|
|
ASSERT( endpoint->Type == AfdBlockTypeVcConnecting );
|
|
|
|
if ( IS_DATA_ON_CONNECTION( connection )
|
|
|
|
||
|
|
|
|
IS_EXPEDITED_DATA_ON_CONNECTION( connection )
|
|
|
|
||
|
|
|
|
( !IS_TDI_BUFFERRING(endpoint) &&
|
|
connection->Common.NonBufferring.ReceiveBytesInTransport > 0 )
|
|
|
|
||
|
|
|
|
processExitTime.QuadPart != 0
|
|
|
|
||
|
|
|
|
endpoint->OutstandingIrpCount != 0
|
|
|
|
||
|
|
|
|
endpoint->StateChangeInProgress
|
|
|
|
||
|
|
|
|
( !IS_TDI_BUFFERRING(endpoint) &&
|
|
(!IsListEmpty( &connection->VcReceiveIrpListHead ) ||
|
|
!IsListEmpty( &connection->VcSendIrpListHead )) )
|
|
|
|
) {
|
|
|
|
#if DBG
|
|
if ( processExitTime.QuadPart != 0 ) {
|
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
|
|
"AfdCleanup: process exiting w/o closesocket, aborting endp %p\n",
|
|
endpoint ));
|
|
}
|
|
else {
|
|
if ( IS_DATA_ON_CONNECTION( connection ) ) {
|
|
if (IS_TDI_BUFFERRING(endpoint)) {
|
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
|
|
"AfdCleanup: unrecv'd data on endp %p, aborting. "
|
|
"%ld ind, %ld taken, %ld out\n",
|
|
endpoint,
|
|
connection->Common.Bufferring.ReceiveBytesIndicated,
|
|
connection->Common.Bufferring.ReceiveBytesTaken,
|
|
connection->Common.Bufferring.ReceiveBytesOutstanding ));
|
|
}
|
|
else {
|
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
|
|
"AfdCleanup: unrecv'd data (%ld) on endp %p, aborting.\n",
|
|
connection->Common.NonBufferring.BufferredReceiveBytes,
|
|
endpoint ));
|
|
}
|
|
}
|
|
|
|
if ( IS_EXPEDITED_DATA_ON_CONNECTION( connection ) ) {
|
|
if (IS_TDI_BUFFERRING(endpoint)) {
|
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
|
|
"AfdCleanup: unrecv'd exp data on endp %p, aborting. "
|
|
"%ld ind, %ld taken, %ld out\n",
|
|
endpoint,
|
|
connection->Common.Bufferring.ReceiveExpeditedBytesIndicated,
|
|
connection->Common.Bufferring.ReceiveExpeditedBytesTaken,
|
|
connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding ));
|
|
}
|
|
else {
|
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
|
|
"AfdCleanup: unrecv'd exp data (%ld) on endp %p, aborting.\n",
|
|
connection->Common.NonBufferring.BufferredExpeditedBytes,
|
|
endpoint ));
|
|
}
|
|
}
|
|
|
|
if ( !IS_TDI_BUFFERRING(endpoint) &&
|
|
connection->Common.NonBufferring.ReceiveBytesInTransport > 0 ) {
|
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
|
|
"AfdCleanup: unrecv'd data (%ld) in transport on endp %p, aborting.\n",
|
|
connection->Common.NonBufferring.ReceiveBytesInTransport,
|
|
endpoint));
|
|
}
|
|
|
|
if ( endpoint->OutstandingIrpCount != 0 ) {
|
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
|
|
"AfdCleanup: %ld IRPs %s outstanding on endpoint %p, "
|
|
"aborting.\n",
|
|
endpoint->OutstandingIrpCount,
|
|
(endpoint->StateChangeInProgress
|
|
? "(accept, connect, or transmit file)"
|
|
: ""),
|
|
endpoint ));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
|
|
|
|
(VOID)AfdBeginAbort( connection );
|
|
|
|
} else {
|
|
|
|
endpoint->DisconnectMode |= AFD_PARTIAL_DISCONNECT_RECEIVE;
|
|
AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
|
|
|
|
status = AfdBeginDisconnect( endpoint, NULL, NULL );
|
|
if (!NT_SUCCESS (status)) {
|
|
//
|
|
// If disconnect failed, we have no choice but to abort the
|
|
// connection because we cannot return error from close and
|
|
// have application try it again. If we don't abort, connection
|
|
// ends up hanging there forever.
|
|
//
|
|
(VOID)AfdBeginAbort (connection);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
|
|
}
|
|
|
|
//
|
|
// If this is a connected VC endpoint on a nonbufferring TDI provider,
|
|
// cancel all outstanding send and receive IRPs.
|
|
//
|
|
|
|
if ( !IS_TDI_BUFFERRING(endpoint) ) {
|
|
|
|
AfdCompleteIrpList(
|
|
&connection->VcReceiveIrpListHead,
|
|
endpoint,
|
|
STATUS_CANCELLED,
|
|
NULL
|
|
);
|
|
|
|
AfdCompleteIrpList(
|
|
&connection->VcSendIrpListHead,
|
|
endpoint,
|
|
STATUS_CANCELLED,
|
|
AfdCleanupSendIrp
|
|
);
|
|
}
|
|
|
|
//
|
|
// Remember that we have started cleanup on this connection.
|
|
// We know that we'll never get a request on the connection
|
|
// after we start cleanup on the connection.
|
|
//
|
|
|
|
AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
|
|
connection->CleanupBegun = TRUE;
|
|
|
|
//
|
|
// Attempt to remove the connected reference.
|
|
//
|
|
|
|
AfdDeleteConnectedReference( connection, TRUE );
|
|
AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
|
|
|
|
//
|
|
// Remove connection reference added in the beginning of this
|
|
// function. We can't access connection object after this point
|
|
// because in can be freed inside the AfdDereferenceConnection.
|
|
//
|
|
|
|
DEREFERENCE_CONNECTION (connection);
|
|
connection = NULL;
|
|
}
|
|
else {
|
|
AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
|
|
}
|
|
|
|
//
|
|
// Complete any outstanding wait for listen IRPs on the endpoint.
|
|
//
|
|
|
|
if ( (endpoint->Type & AfdBlockTypeVcListening) == AfdBlockTypeVcListening ) {
|
|
|
|
AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
|
|
while ( !IsListEmpty( &endpoint->Common.VcListening.ListeningIrpListHead ) ) {
|
|
|
|
PIRP waitForListenIrp;
|
|
PIO_STACK_LOCATION irpSp;
|
|
|
|
listEntry = RemoveHeadList( &endpoint->Common.VcListening.ListeningIrpListHead );
|
|
waitForListenIrp = CONTAINING_RECORD(
|
|
listEntry,
|
|
IRP,
|
|
Tail.Overlay.ListEntry
|
|
);
|
|
//
|
|
// Set FLink to NULL so that cancel routine won't touch the IRP.
|
|
//
|
|
|
|
listEntry->Flink = NULL;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation (waitForListenIrp);
|
|
if (irpSp->MajorFunction==IRP_MJ_INTERNAL_DEVICE_CONTROL) {
|
|
AfdCleanupSuperAccept (waitForListenIrp, STATUS_CANCELLED);
|
|
}
|
|
else {
|
|
waitForListenIrp->IoStatus.Status = STATUS_CANCELLED;
|
|
waitForListenIrp->IoStatus.Information = 0;
|
|
}
|
|
|
|
//
|
|
// Release the AFD spin lock so that we can complete the
|
|
// wait for listen IRP.
|
|
//
|
|
|
|
AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
|
|
|
|
//
|
|
// Cancel the IRP.
|
|
//
|
|
|
|
//
|
|
// Reset the cancel routine in the IRP.
|
|
//
|
|
|
|
if ( IoSetCancelRoutine( waitForListenIrp, 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( waitForListenIrp->Cancel );
|
|
IoReleaseCancelSpinLock( cancelIrql );
|
|
|
|
}
|
|
|
|
IoCompleteRequest( waitForListenIrp, AfdPriorityBoost );
|
|
|
|
//
|
|
// Reacquire the AFD spin lock for the next pass through the
|
|
// loop.
|
|
//
|
|
|
|
AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
|
|
}
|
|
|
|
//
|
|
// Free all queued (free, unaccepted, and returned) connections
|
|
// on the endpoint.
|
|
//
|
|
|
|
AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
|
|
AfdFreeQueuedConnections( endpoint );
|
|
endpoint->Common.VcListening.FailedConnectionAdds = 0;
|
|
}
|
|
}
|
|
|
|
if (endpoint->RoutingQueryReferenced) {
|
|
AfdCleanupRoutingChange (endpoint);
|
|
}
|
|
|
|
|
|
AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
|
|
while (!IsListEmpty (&endpoint->RequestList)) {
|
|
PAFD_REQUEST_CONTEXT requestCtx;
|
|
listEntry = RemoveHeadList (&endpoint->RequestList);
|
|
listEntry->Flink = NULL;
|
|
AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
|
|
requestCtx = CONTAINING_RECORD (listEntry,
|
|
AFD_REQUEST_CONTEXT,
|
|
EndpointListLink);
|
|
(*requestCtx->CleanupRoutine) (endpoint, requestCtx);
|
|
AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
|
|
}
|
|
|
|
if ( endpoint->Irp != NULL) {
|
|
|
|
PIRP transmitIrp;
|
|
KIRQL cancelIrql;
|
|
|
|
//
|
|
// Release the endpoint and acquire the cancel spinlock
|
|
// and then the enpoint spinlock.
|
|
//
|
|
|
|
AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
|
|
|
|
IoAcquireCancelSpinLock( &cancelIrql );
|
|
AfdAcquireSpinLockAtDpcLevel( &endpoint->SpinLock, &lockHandle );
|
|
|
|
//
|
|
// Make sure there is still a transmit IRP.
|
|
//
|
|
|
|
transmitIrp = endpoint->Irp;
|
|
|
|
if ( transmitIrp != NULL ) {
|
|
PDRIVER_CANCEL cancelRoutine;
|
|
|
|
// indicate that it has to be cancelled
|
|
transmitIrp->Cancel = TRUE;
|
|
cancelRoutine = IoSetCancelRoutine( transmitIrp, NULL );
|
|
if ( cancelRoutine != NULL ) {
|
|
|
|
//
|
|
// The IRP needs to be canceled. Release the
|
|
// endpoint spinlock. The value in endpoint->Irp can
|
|
// now change, but the IRP cannot be completed while the
|
|
// cancel spinlock is held since we set the cancel flag
|
|
// in the IRP.
|
|
//
|
|
|
|
AfdReleaseSpinLockFromDpcLevel( &endpoint->SpinLock, &lockHandle );
|
|
|
|
transmitIrp->CancelIrql = cancelIrql;
|
|
cancelRoutine ( NULL, transmitIrp );
|
|
}
|
|
else {
|
|
// The IRP has not been completely setup yet
|
|
// and will be cancelled in the dispatch routine
|
|
AfdReleaseSpinLockFromDpcLevel( &endpoint->SpinLock, &lockHandle );
|
|
IoReleaseCancelSpinLock( cancelIrql );
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// The IRP has been completed or canceled. Release the locks
|
|
// and continue.
|
|
//
|
|
|
|
AfdReleaseSpinLockFromDpcLevel( &endpoint->SpinLock, &lockHandle );
|
|
IoReleaseCancelSpinLock( cancelIrql );
|
|
}
|
|
|
|
} else {
|
|
AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
|
|
}
|
|
|
|
//
|
|
// Reset relevant event handlers on the endpoint. This prevents
|
|
// getting indications after we free the endpoint and connection
|
|
// objects. We should not be able to get new connects after this
|
|
// handle has been cleaned up.
|
|
//
|
|
// Note that these calls can fail if, for example, DHCP changes the
|
|
// host's IP address while the endpoint is active.
|
|
//
|
|
//
|
|
|
|
if ((endpoint->AddressHandle != NULL) && (endpoint->State != AfdEndpointStateOpen)) {
|
|
|
|
if (endpoint->Listening) {
|
|
|
|
status = AfdSetEventHandler(
|
|
endpoint->AddressFileObject,
|
|
TDI_EVENT_CONNECT,
|
|
NULL,
|
|
NULL
|
|
);
|
|
// ASSERT(NT_SUCCESS(status));
|
|
|
|
if (IS_TDI_ADDRESS_SECURITY(endpoint)) {
|
|
status = AfdUnbind(endpoint);
|
|
// ASSERT(NT_SUCCESS(status));
|
|
}
|
|
|
|
} else if (IS_VC_ENDPOINT(endpoint)) {
|
|
|
|
//
|
|
// Connection-oriented accepted endpoints cannot have address handles
|
|
// in their structures because they share them with listening
|
|
// endpoint. So, this is an endpoint on which connect was done.
|
|
// We need to call AfdUnbind() on it to allow other endpoints to
|
|
// bind to the address held by this endpoint.
|
|
// We cannot wait for final dereference on address file object for
|
|
// unbind to take place, because that can be delayed till all
|
|
// endpoint ref counts go to 0. So, we must do explicit unbind here
|
|
//
|
|
|
|
if (IS_TDI_ADDRESS_SECURITY (endpoint)) {
|
|
status = AfdUnbind(endpoint);
|
|
// ASSERT(NT_SUCCESS(status));
|
|
}
|
|
|
|
} else if (IS_DGRAM_ENDPOINT(endpoint)) {
|
|
|
|
status = AfdSetEventHandler(
|
|
endpoint->AddressFileObject,
|
|
TDI_EVENT_RECEIVE_DATAGRAM,
|
|
NULL,
|
|
NULL
|
|
);
|
|
// ASSERT(NT_SUCCESS(status));
|
|
|
|
status = AfdSetEventHandler(
|
|
endpoint->AddressFileObject,
|
|
TDI_EVENT_ERROR_EX,
|
|
NULL,
|
|
NULL
|
|
);
|
|
// ASSERT(NT_SUCCESS(status));
|
|
|
|
status = AfdSetEventHandler(
|
|
endpoint->AddressFileObject,
|
|
TDI_EVENT_ERROR,
|
|
NULL,
|
|
NULL
|
|
);
|
|
// ASSERT(NT_SUCCESS(status));
|
|
|
|
//
|
|
// We need to call AfdUnbind() on this endpoint to allow other endpoints to
|
|
// bind to the address held by this endpoint.
|
|
// We cannot wait for final dereference on address file object for
|
|
// unbind to take place, because that can be delayed till all
|
|
// endpoint ref counts go to 0. So, we must do explicit unbind here
|
|
//
|
|
|
|
if (IS_TDI_ADDRESS_SECURITY (endpoint)) {
|
|
status = AfdUnbind(endpoint);
|
|
// ASSERT(NT_SUCCESS(status));
|
|
}
|
|
|
|
}
|
|
|
|
} // if (endpoint->State != AfdEndpointStateOpen)
|
|
|
|
InterlockedIncrement(&AfdEndpointsCleanedUp);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // AfdCleanup
|
|
|
|
|
|
NTSTATUS
|
|
FASTCALL
|
|
AfdClose (
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the routine that handles Close IRPs in AFD. It
|
|
dereferences the endpoint specified in the IRP, which will result in
|
|
the endpoint being freed when all other references go away.
|
|
|
|
Arguments:
|
|
|
|
Irp - Pointer to I/O request packet.
|
|
|
|
IrpSp - pointer to the IO stack location to use for this request.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS -- Indicates whether the request was successfully queued.
|
|
|
|
--*/
|
|
|
|
{
|
|
PAFD_ENDPOINT endpoint;
|
|
PAFD_CONNECTION connection;
|
|
|
|
UNREFERENCED_PARAMETER (Irp);
|
|
PAGED_CODE( );
|
|
|
|
endpoint = IrpSp->FileObject->FsContext;
|
|
ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
|
|
|
|
IF_DEBUG(OPEN_CLOSE) {
|
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
|
|
"AfdClose: closing file object %p, endpoint %p\n",
|
|
IrpSp->FileObject, endpoint ));
|
|
}
|
|
|
|
IF_DEBUG(ENDPOINT) {
|
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
|
|
"AfdClose: closing endpoint at %p\n",
|
|
endpoint ));
|
|
}
|
|
|
|
connection = AFD_CONNECTION_FROM_ENDPOINT (endpoint);
|
|
|
|
//
|
|
// If there is a connection on this endpoint, dereference it here
|
|
// rather than in AfdDereferenceEndpoint, because the connection
|
|
// has a referenced pointer to the endpoint which must be removed
|
|
// before the endpoint can dereference the connection.
|
|
//
|
|
|
|
if (connection != NULL) {
|
|
endpoint->Common.VcConnecting.Connection = NULL;
|
|
DEREFERENCE_CONNECTION (connection);
|
|
//
|
|
// This is to simplify debugging.
|
|
// If connection is not being closed by the transport
|
|
// we want to be able to find it in the debugger faster
|
|
// then thru !poolfind AfdC.
|
|
//
|
|
endpoint->WorkItem.Context = connection;
|
|
}
|
|
else if (IS_SAN_ENDPOINT (endpoint) &&
|
|
endpoint->Common.SanEndp.SwitchContext!=NULL) {
|
|
PVOID requestCtx;
|
|
endpoint->Common.SanEndp.FileObject = NULL;
|
|
requestCtx = AFD_SWITCH_MAKE_REQUEST_CONTEXT(
|
|
((ULONG)0xFFFFFFFF),
|
|
AFD_SWITCH_REQUEST_CLOSE);
|
|
IoSetIoCompletion (
|
|
endpoint->Common.SanEndp.SanHlpr->Common.SanHlpr.IoCompletionPort,// Port
|
|
endpoint->Common.SanEndp.SwitchContext, // Key
|
|
requestCtx, // ApcContext
|
|
STATUS_SUCCESS, // Status
|
|
0, // Information
|
|
FALSE // ChargeQuota
|
|
);
|
|
}
|
|
|
|
//
|
|
// Set the state of the endpoint to closing and dereference to
|
|
// get rid of the active reference.
|
|
//
|
|
|
|
ASSERT (endpoint->State!=AfdEndpointStateClosing);
|
|
endpoint->State = AfdEndpointStateClosing;
|
|
|
|
//
|
|
// Dereference the endpoint to get rid of the active reference.
|
|
// This will result in the endpoint storage being freed as soon
|
|
// as all other references go away.
|
|
//
|
|
|
|
DEREFERENCE_ENDPOINT( endpoint );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // AfdClose
|