mirror of https://github.com/lianthony/NT4.0
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.
1593 lines
41 KiB
1593 lines
41 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
connect.c
|
|
|
|
Abstract:
|
|
|
|
This module implements connection logic for the loopback Transport
|
|
Provider driver for NT LAN Manager.
|
|
|
|
Author:
|
|
|
|
Chuck Lenzmeier (chuckl) 15-Aug-1991
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "loopback.h"
|
|
|
|
//
|
|
// Local declarations
|
|
//
|
|
|
|
STATIC
|
|
NTSTATUS
|
|
CompleteConnection (
|
|
IN PIRP ListenIrp,
|
|
IN PIRP ConnectIrp
|
|
);
|
|
|
|
STATIC
|
|
VOID
|
|
IndicateConnect (
|
|
IN PLOOP_ENDPOINT Endpoint
|
|
);
|
|
|
|
|
|
NTSTATUS
|
|
LoopAccept (
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine processes an Accept request.
|
|
|
|
Arguments:
|
|
|
|
Irp - Pointer to I/O request packet
|
|
|
|
IrpSp - Pointer to current stack location in IRP
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Status of request
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PTDI_REQUEST_KERNEL_ACCEPT acceptRequest;
|
|
PLOOP_CONNECTION connection;
|
|
PLOOP_ENDPOINT endpoint;
|
|
|
|
IF_DEBUG(LOOP1) DbgPrint( " Accept request\n" );
|
|
|
|
acceptRequest = (PTDI_REQUEST_KERNEL_ACCEPT)&IrpSp->Parameters;
|
|
|
|
ACQUIRE_LOOP_LOCK( "Accept initial" );
|
|
|
|
//
|
|
// Verify that the connection is in the proper state.
|
|
//
|
|
|
|
connection = (PLOOP_CONNECTION)IrpSp->FileObject->FsContext;
|
|
|
|
if ( connection == NULL ) {
|
|
RELEASE_LOOP_LOCK( "Accept control channel" );
|
|
IF_DEBUG(LOOP2) DbgPrint( " Can't Accept on control channel\n" );
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto complete;
|
|
}
|
|
|
|
if ( GET_BLOCK_STATE(connection) != BlockStateBound ) {
|
|
RELEASE_LOOP_LOCK( "Accept conn not bound" );
|
|
IF_DEBUG(LOOP2) DbgPrint( " Connection not bound\n" );
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto complete;
|
|
}
|
|
|
|
//
|
|
// There must be an indication in progress on the endpoint.
|
|
//
|
|
// *** The loopback driver does not support delayed accept on
|
|
// TdiListen, but does on connect indications.
|
|
//
|
|
|
|
endpoint = connection->Endpoint;
|
|
|
|
if ( endpoint->IndicatingConnectIrp == NULL ) {
|
|
RELEASE_LOOP_LOCK( "Endpoint not indicating connect" );
|
|
IF_DEBUG(LOOP2) DbgPrint( " Endpoint not indicating connect\n" );
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto complete;
|
|
}
|
|
|
|
//
|
|
// Link the connections together. Indicate that the connect
|
|
// indication is no longer in progress.
|
|
//
|
|
|
|
CompleteConnection( Irp, endpoint->IndicatingConnectIrp );
|
|
|
|
endpoint->IndicatingConnectIrp = NULL;
|
|
|
|
RELEASE_LOOP_LOCK( "Accept connect completed" );
|
|
|
|
IF_DEBUG(LOOP1) DbgPrint( " Accept request complete\n" );
|
|
return STATUS_SUCCESS;
|
|
|
|
complete:
|
|
|
|
//
|
|
// Complete the Accept request.
|
|
//
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest( Irp, 0 );
|
|
|
|
IF_DEBUG(LOOP1) DbgPrint( " Accept request complete\n" );
|
|
return status;
|
|
|
|
} // LoopAccept
|
|
|
|
|
|
NTSTATUS
|
|
LoopAssociateAddress (
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine processes an Associate Address request.
|
|
|
|
Arguments:
|
|
|
|
Irp - Pointer to I/O request packet
|
|
|
|
IrpSp - Pointer to current stack location in IRP
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Status of request
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PTDI_REQUEST_KERNEL_ASSOCIATE associateRequest;
|
|
PLOOP_CONNECTION connection;
|
|
PFILE_OBJECT endpointFileObject = NULL;
|
|
PLOOP_ENDPOINT endpoint;
|
|
|
|
IF_DEBUG(LOOP1) DbgPrint( " Associate request\n" );
|
|
|
|
associateRequest = (PTDI_REQUEST_KERNEL_ASSOCIATE)&IrpSp->Parameters;
|
|
|
|
//
|
|
// Translate the address handle to a pointer to the address endpoint
|
|
// file object. Get a pointer to the loopback endpoint block.
|
|
// Verify that it is really a loopback endpoint.
|
|
//
|
|
|
|
status = ObReferenceObjectByHandle (
|
|
associateRequest->AddressHandle,
|
|
0,
|
|
0,
|
|
KernelMode,
|
|
(PVOID *)&endpointFileObject,
|
|
NULL);
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
IF_DEBUG(LOOP2) DbgPrint( " Invalid endpoint handle\n" );
|
|
goto complete;
|
|
}
|
|
|
|
ACQUIRE_LOOP_LOCK( "Associate initial" );
|
|
|
|
endpoint = (PLOOP_ENDPOINT)endpointFileObject->FsContext;
|
|
status = LoopVerifyEndpoint( endpoint );
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
RELEASE_LOOP_LOCK( "Associate bad endpoint pointer" );
|
|
IF_DEBUG(LOOP2) DbgPrint( " Invalid endpoint pointer\n" );
|
|
goto complete;
|
|
}
|
|
|
|
//
|
|
// Verify that the connection is in the proper state.
|
|
//
|
|
|
|
connection = (PLOOP_CONNECTION)IrpSp->FileObject->FsContext;
|
|
|
|
if ( connection == NULL ) {
|
|
RELEASE_LOOP_LOCK( "Associate control channel" );
|
|
IF_DEBUG(LOOP2) DbgPrint( " Can't Associate on control channel\n" );
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto complete;
|
|
}
|
|
|
|
if ( GET_BLOCK_STATE(connection) != BlockStateUnbound ) {
|
|
RELEASE_LOOP_LOCK( "Associate conn not unbound" );
|
|
IF_DEBUG(LOOP2) DbgPrint( " Connection not unbound\n" );
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto complete;
|
|
}
|
|
|
|
//
|
|
// Verify that the endpoint is in the proper state.
|
|
//
|
|
|
|
if ( GET_BLOCK_STATE(endpoint) != BlockStateActive ) {
|
|
RELEASE_LOOP_LOCK( "Associate endpoint not active" );
|
|
IF_DEBUG(LOOP2) DbgPrint( " Endpoint not active\n" );
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto complete;
|
|
}
|
|
|
|
//
|
|
// Link this connection into the endpoint's connection list.
|
|
// Reference the endpoint block. Indicate that the connection has
|
|
// been bound to an address. Dereference the endpoint file object.
|
|
//
|
|
|
|
InsertTailList(
|
|
&endpoint->ConnectionList,
|
|
&connection->EndpointListEntry
|
|
);
|
|
|
|
endpoint->BlockHeader.ReferenceCount++;
|
|
IF_DEBUG(LOOP3) {
|
|
DbgPrint( " New refcnt on endpoint %lx is %lx\n",
|
|
endpoint, endpoint->BlockHeader.ReferenceCount );
|
|
}
|
|
|
|
SET_BLOCK_STATE( connection, BlockStateBound );
|
|
|
|
connection->Endpoint = endpoint;
|
|
|
|
RELEASE_LOOP_LOCK( "Associate done" );
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
complete:
|
|
|
|
//
|
|
// Dereference the endpoint file object, if necessary.
|
|
//
|
|
|
|
if ( endpointFileObject != NULL ) {
|
|
ObDereferenceObject( endpointFileObject );
|
|
}
|
|
|
|
//
|
|
// Complete the Associate request.
|
|
//
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest( Irp, 0 );
|
|
|
|
IF_DEBUG(LOOP1) DbgPrint( " Associate request complete\n" );
|
|
return status;
|
|
|
|
} // LoopAssociateAddress
|
|
|
|
|
|
NTSTATUS
|
|
LoopConnect (
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine processes a Connect request.
|
|
|
|
Arguments:
|
|
|
|
Irp - Pointer to I/O request packet
|
|
|
|
IrpSp - Pointer to current stack location in IRP
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Status of request
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PTDI_REQUEST_KERNEL_CONNECT connectRequest;
|
|
CHAR netbiosName[NETBIOS_NAME_LENGTH+1];
|
|
PLOOP_CONNECTION connection;
|
|
PLOOP_ENDPOINT remoteEndpoint;
|
|
BOOLEAN firstConnect;
|
|
|
|
IF_DEBUG(LOOP1) DbgPrint( " Connect request\n" );
|
|
|
|
//
|
|
// Parse the remote address.
|
|
//
|
|
|
|
connectRequest = (PTDI_REQUEST_KERNEL_CONNECT)&IrpSp->Parameters;
|
|
|
|
status = LoopParseAddress(
|
|
(PTA_NETBIOS_ADDRESS)connectRequest->
|
|
RequestConnectionInformation->RemoteAddress,
|
|
netbiosName
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
IF_DEBUG(LOOP2) DbgPrint( " Invalid remote address\n" );
|
|
goto complete;
|
|
}
|
|
|
|
netbiosName[NETBIOS_NAME_LENGTH] = 0; // ensure null-termination
|
|
IF_DEBUG(LOOP2) {
|
|
DbgPrint( " Address to connect to: \"%s\"\n", netbiosName );
|
|
}
|
|
|
|
//
|
|
// Make sure that the connection is in the right state.
|
|
//
|
|
|
|
ACQUIRE_LOOP_LOCK( "Connect initial" );
|
|
|
|
connection = (PLOOP_CONNECTION)IrpSp->FileObject->FsContext;
|
|
IF_DEBUG(LOOP2) {
|
|
DbgPrint( " Connection address: %lx\n", connection );
|
|
}
|
|
|
|
if ( connection == NULL ) {
|
|
RELEASE_LOOP_LOCK( "Connect control channel" );
|
|
IF_DEBUG(LOOP2) DbgPrint( " Can't Connect on control channel\n" );
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto complete;
|
|
}
|
|
|
|
if ( GET_BLOCK_STATE(connection) != BlockStateBound ) {
|
|
RELEASE_LOOP_LOCK( "Connection not bound" );
|
|
IF_DEBUG(LOOP2) DbgPrint( " Local endpoint not bound\n" );
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto complete;
|
|
}
|
|
|
|
//
|
|
// Find an endpoint with the target address.
|
|
//
|
|
|
|
remoteEndpoint = LoopFindBoundAddress( netbiosName );
|
|
|
|
if ( remoteEndpoint == NULL ) {
|
|
RELEASE_LOOP_LOCK( "Connect no such address" );
|
|
IF_DEBUG(LOOP2) DbgPrint( " Address does not exist\n" );
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto complete;
|
|
}
|
|
IF_DEBUG(LOOP2) {
|
|
DbgPrint( " Target endpoint address: %lx\n", remoteEndpoint );
|
|
}
|
|
|
|
//
|
|
// Set the connection state to Connecting, to prevent further
|
|
// connects or listens.
|
|
//
|
|
|
|
SET_BLOCK_STATE( connection, BlockStateConnecting );
|
|
|
|
//
|
|
// Determine whether this is the first active incoming Connect for
|
|
// the remote endpoint.
|
|
//
|
|
|
|
firstConnect = (BOOLEAN)( remoteEndpoint->IncomingConnectList.Flink ==
|
|
&remoteEndpoint->IncomingConnectList );
|
|
|
|
//
|
|
// Queue the Connect to the remote endpoint's Incoming Connect list,
|
|
// in order to prevent another Connect from getting ahead of this
|
|
// one.
|
|
//
|
|
|
|
InsertTailList(
|
|
&remoteEndpoint->IncomingConnectList,
|
|
&Irp->Tail.Overlay.ListEntry
|
|
);
|
|
|
|
IoMarkIrpPending( Irp );
|
|
|
|
if ( !firstConnect || (remoteEndpoint->IndicatingConnectIrp != NULL) ) {
|
|
|
|
//
|
|
// A pending Connect already exists, or a Connect indication is
|
|
// in progress. This Connect remains behind the already pending
|
|
// Connect.
|
|
//
|
|
|
|
IF_DEBUG(LOOP2) DbgPrint( " Connect already pending\n" );
|
|
|
|
RELEASE_LOOP_LOCK( "Connect connects pending" );
|
|
|
|
} else {
|
|
|
|
//
|
|
// Indicate the incoming Connect.
|
|
//
|
|
// *** Note that IndicateConnect returns with the loopback
|
|
// driver spin lock released.
|
|
//
|
|
|
|
IF_DEBUG(LOOP2) DbgPrint( " LoopConnect indicating connect\n" );
|
|
IndicateConnect( remoteEndpoint );
|
|
|
|
}
|
|
|
|
IF_DEBUG(LOOP1) DbgPrint( " Connect request complete\n" );
|
|
return status;
|
|
|
|
complete:
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest( Irp, 0 );
|
|
|
|
IF_DEBUG(LOOP1) DbgPrint( " Connect request complete\n" );
|
|
return status;
|
|
|
|
} // LoopConnect
|
|
|
|
|
|
VOID
|
|
LoopDereferenceConnection (
|
|
IN PLOOP_CONNECTION Connection
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to dereference a connection block. If the
|
|
reference count on the block goes to one, and the connection is in
|
|
the process of disconnecting, the connection block is reset to the
|
|
Bound state. If the reference count on the block goes to zero, the
|
|
connection block is deleted.
|
|
|
|
The Loopback device object's spin lock must be held when this
|
|
routine is called.
|
|
|
|
Arguments:
|
|
|
|
Connection - Supplies a pointer to a connection block
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PIRP disconnectIrp = NULL;
|
|
PIRP closeIrp = NULL;
|
|
|
|
IF_DEBUG(LOOP3) {
|
|
DbgPrint( " Dereferencing connection %lx; old refcnt %lx\n",
|
|
Connection, Connection->BlockHeader.ReferenceCount );
|
|
}
|
|
|
|
ASSERT( (LONG)Connection->BlockHeader.ReferenceCount > 0 );
|
|
|
|
if ( --Connection->BlockHeader.ReferenceCount != 0 ) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// The reference count has gone to zero. Save the address of the
|
|
// pending Disconnect IRP, if any -- we'll complete the IRP later.
|
|
// If the connection state is Disconnecting, reset it to Bound. If
|
|
// the connection state is Closed, delete it.
|
|
//
|
|
|
|
disconnectIrp = Connection->DisconnectIrp;
|
|
Connection->DisconnectIrp = NULL;
|
|
|
|
//
|
|
// If the connection state is Disconnecting, reset it to Bound or
|
|
// Unbound, depending on the state of the endpoint. If the
|
|
// connection state is Closed, delete the connection. Note that the
|
|
// connection state may also be Closing, which means that an
|
|
// inactive connection's handle has been closed. We do nothing in
|
|
// this case; instead we wait until the Close IRP arrives.
|
|
//
|
|
|
|
if ( GET_BLOCK_STATE(Connection) == BlockStateDisconnecting ) {
|
|
|
|
if ( GET_BLOCK_STATE(Connection->Endpoint) == BlockStateActive ) {
|
|
|
|
IF_DEBUG(LOOP3) {
|
|
DbgPrint( " Resetting connection %lx to Bound\n",
|
|
Connection );
|
|
}
|
|
SET_BLOCK_STATE( Connection, BlockStateBound );
|
|
|
|
} else {
|
|
|
|
PLOOP_ENDPOINT endpoint;
|
|
|
|
IF_DEBUG(LOOP3) {
|
|
DbgPrint( " Resetting connection %lx to Unbound\n",
|
|
Connection );
|
|
}
|
|
endpoint = Connection->Endpoint;
|
|
ASSERT( endpoint != NULL );
|
|
Connection->Endpoint = NULL;
|
|
|
|
SET_BLOCK_STATE( Connection, BlockStateUnbound );
|
|
|
|
RemoveEntryList( &Connection->EndpointListEntry );
|
|
LoopDereferenceEndpoint( endpoint );
|
|
|
|
}
|
|
|
|
RELEASE_LOOP_LOCK( "Reset connection done" );
|
|
|
|
} else if ( GET_BLOCK_STATE(Connection) == BlockStateClosed ) {
|
|
|
|
//
|
|
// The connection file object has been closed, so we can
|
|
// deallocate the connection block now.
|
|
//
|
|
|
|
IF_DEBUG(LOOP3) {
|
|
DbgPrint( " Deleting connection %lx\n", Connection );
|
|
}
|
|
|
|
//
|
|
// Save the address of the pending Close IRP, if any -- we'll
|
|
// complete the IRP later.
|
|
//
|
|
|
|
closeIrp = Connection->CloseIrp;
|
|
Connection->CloseIrp = NULL;
|
|
|
|
//
|
|
// Unlink the connection from the endpoint's connection list.
|
|
//
|
|
|
|
if ( Connection->Endpoint != NULL ) {
|
|
RemoveEntryList( &Connection->EndpointListEntry );
|
|
LoopDereferenceEndpoint( Connection->Endpoint );
|
|
}
|
|
|
|
//
|
|
// Unlink the connection from the device's connection list.
|
|
//
|
|
|
|
RemoveEntryList( &Connection->DeviceListEntry );
|
|
|
|
RELEASE_LOOP_LOCK( "DerefConn deleting" );
|
|
|
|
ObDereferenceObject( Connection->DeviceObject );
|
|
|
|
//
|
|
// Deallocate the connection block.
|
|
//
|
|
|
|
DEBUG SET_BLOCK_TYPE( Connection, BlockTypeGarbage );
|
|
DEBUG SET_BLOCK_STATE( Connection, BlockStateDead );
|
|
DEBUG SET_BLOCK_SIZE( Connection, -1 );
|
|
DEBUG Connection->BlockHeader.ReferenceCount = -1;
|
|
DEBUG Connection->Endpoint = NULL;
|
|
DEBUG Connection->RemoteConnection = NULL;
|
|
|
|
ExFreePool( Connection );
|
|
|
|
} else {
|
|
|
|
ASSERT( GET_BLOCK_STATE(Connection) == BlockStateClosing );
|
|
|
|
RELEASE_LOOP_LOCK( "DerefConn closing -- no action" );
|
|
|
|
}
|
|
|
|
//
|
|
// If a Disconnect IRP is pending, complete it now.
|
|
//
|
|
|
|
if ( disconnectIrp != NULL ) {
|
|
|
|
IF_DEBUG(LOOP3) {
|
|
DbgPrint( " Completing Disconnect IRP %lx\n",
|
|
disconnectIrp );
|
|
}
|
|
disconnectIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
disconnectIrp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest( disconnectIrp, 2 );
|
|
|
|
}
|
|
|
|
//
|
|
// If a Close IRP is pending, complete it now.
|
|
//
|
|
|
|
if ( closeIrp != NULL ) {
|
|
|
|
IF_DEBUG(LOOP3) {
|
|
DbgPrint( " Completing Close IRP %lx\n", closeIrp );
|
|
}
|
|
closeIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
closeIrp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest( closeIrp, 2 );
|
|
|
|
}
|
|
|
|
ACQUIRE_LOOP_LOCK( "DerefConn done" );
|
|
|
|
return;
|
|
|
|
} // LoopDereferenceConnection
|
|
|
|
|
|
NTSTATUS
|
|
LoopDisassociateAddress (
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine processes a Disassociate Address request.
|
|
|
|
Arguments:
|
|
|
|
Irp - Pointer to I/O request packet
|
|
|
|
IrpSp - Pointer to current stack location in IRP
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Status of request
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PLOOP_CONNECTION connection;
|
|
PLOOP_ENDPOINT endpoint;
|
|
|
|
IF_DEBUG(LOOP1) DbgPrint( " Disassociate request\n" );
|
|
|
|
ACQUIRE_LOOP_LOCK( "Disassociate initial" );
|
|
|
|
//
|
|
// Verify that the connection is in the proper state.
|
|
//
|
|
|
|
connection = (PLOOP_CONNECTION)IrpSp->FileObject->FsContext;
|
|
|
|
if ( connection == NULL ) {
|
|
RELEASE_LOOP_LOCK( "Disassociate control channel" );
|
|
IF_DEBUG(LOOP2) {
|
|
DbgPrint( " Can't Disassociate on control channel\n" );
|
|
}
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto complete;
|
|
}
|
|
|
|
if ( GET_BLOCK_STATE(connection) != BlockStateBound ) {
|
|
RELEASE_LOOP_LOCK( "Associate conn not bound" );
|
|
IF_DEBUG(LOOP2) DbgPrint( " Connection not bound\n" );
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto complete;
|
|
}
|
|
|
|
//
|
|
// Remove this connection from the endpoint's connection list.
|
|
// Dereference the endpoint block. Indicate that the connection is
|
|
// no longer bound to an address.
|
|
//
|
|
|
|
endpoint = connection->Endpoint;
|
|
ASSERT( endpoint != NULL );
|
|
connection->Endpoint = NULL;
|
|
|
|
SET_BLOCK_STATE( connection, BlockStateUnbound );
|
|
|
|
RemoveEntryList( &connection->EndpointListEntry );
|
|
LoopDereferenceEndpoint( endpoint );
|
|
|
|
RELEASE_LOOP_LOCK( "Disassociate done" );
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
complete:
|
|
|
|
//
|
|
// Complete the Disassociate request.
|
|
//
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest( Irp, 0 );
|
|
|
|
IF_DEBUG(LOOP1) DbgPrint( " Disassociate request complete\n" );
|
|
return status;
|
|
|
|
} // LoopDisassociate
|
|
|
|
|
|
NTSTATUS
|
|
LoopDisconnect (
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine processes a Disconnect request.
|
|
|
|
Arguments:
|
|
|
|
Irp - Pointer to I/O request packet
|
|
|
|
IrpSp - Pointer to current stack location in IRP
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Status of request
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PTDI_REQUEST_KERNEL_DISCONNECT disconnectRequest;
|
|
PLOOP_CONNECTION connection;
|
|
|
|
IF_DEBUG(LOOP1) DbgPrint( " Disconnect request\n" );
|
|
|
|
disconnectRequest = (PTDI_REQUEST_KERNEL_DISCONNECT)&IrpSp->Parameters;
|
|
connection = (PLOOP_CONNECTION)IrpSp->FileObject->FsContext;
|
|
IF_DEBUG(LOOP2) DbgPrint( " Connection: %lx\n", connection );
|
|
|
|
ACQUIRE_LOOP_LOCK( "Disconnect initial" );
|
|
|
|
if ( connection == NULL ) {
|
|
RELEASE_LOOP_LOCK( "Disconnect control channel" );
|
|
IF_DEBUG(LOOP2) {
|
|
DbgPrint( " Can't Disconnect on control channel\n" );
|
|
}
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto complete;
|
|
}
|
|
|
|
//
|
|
// If the connection state is Bound, then this Disconnect must have
|
|
// been issued from within a Connect indication.
|
|
//
|
|
|
|
if ( GET_BLOCK_STATE(connection) == BlockStateBound ) {
|
|
|
|
PIRP connectIrp = connection->Endpoint->IndicatingConnectIrp;
|
|
|
|
if ( connectIrp != NULL ) {
|
|
|
|
//
|
|
// Abort the indicating Connect.
|
|
//
|
|
|
|
connection->Endpoint->IndicatingConnectIrp = NULL;
|
|
|
|
RELEASE_LOOP_LOCK( "Disconnect abort indication" );
|
|
|
|
connectIrp->IoStatus.Status = STATUS_DISCONNECTED;
|
|
IoCompleteRequest( connectIrp, 2 );
|
|
|
|
} else {
|
|
|
|
RELEASE_LOOP_LOCK( "Disconnect bound, no indication" );
|
|
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
goto complete;
|
|
|
|
}
|
|
|
|
if ( GET_BLOCK_STATE(connection) != BlockStateActive ) {
|
|
|
|
RELEASE_LOOP_LOCK( "Disconnect closing" );
|
|
IF_DEBUG(LOOP2) DbgPrint( " Connection already disconnected\n" );
|
|
|
|
status = STATUS_SUCCESS;
|
|
goto complete;
|
|
|
|
}
|
|
|
|
//
|
|
// Set the disconnect IRP pointer in the connection. The IRP will
|
|
// be completed when the connection is actually deleted.
|
|
//
|
|
|
|
IoMarkIrpPending( Irp );
|
|
connection->DisconnectIrp = Irp;
|
|
|
|
SET_BLOCK_STATE( connection, BlockStateDisconnecting );
|
|
LoopDoDisconnect( connection, TRUE );
|
|
|
|
RELEASE_LOOP_LOCK( "Disconnect done" );
|
|
|
|
return STATUS_PENDING;
|
|
|
|
complete:
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest( Irp, 2 );
|
|
|
|
IF_DEBUG(LOOP1) DbgPrint( " Disconnect request complete\n" );
|
|
return status;
|
|
|
|
} // LoopDisconnect
|
|
|
|
|
|
VOID
|
|
LoopDoDisconnect (
|
|
IN PLOOP_CONNECTION Connection,
|
|
IN BOOLEAN ClientInitiated
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine does the work in disconnecting a connection. It is
|
|
called by LoopDisconnect and LoopDispatchClose.
|
|
|
|
The loopback device object's spin lock must be held when this
|
|
function is called. The lock is still held when the function
|
|
returns.
|
|
|
|
Arguments:
|
|
|
|
Connection - Pointer to connection block
|
|
|
|
ClientInitiated - Indicates whether the local client initiated the
|
|
disconnect, either by issuing a TdiDisconnect or by closing the
|
|
endpoint
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PLOOP_CONNECTION remoteConnection;
|
|
PLOOP_ENDPOINT endpoint;
|
|
PLIST_ENTRY listEntry;
|
|
PIRP pendingIrp;
|
|
PTDI_IND_DISCONNECT disconnectHandler;
|
|
PVOID disconnectContext;
|
|
|
|
IF_DEBUG(LOOP3) {
|
|
DbgPrint( " DoDisconnect called for connection %lx\n",
|
|
Connection );
|
|
}
|
|
|
|
//
|
|
// If there is a remote connection, run it down first.
|
|
//
|
|
|
|
remoteConnection = Connection->RemoteConnection;
|
|
Connection->RemoteConnection = NULL;
|
|
|
|
if ( (remoteConnection != NULL) &&
|
|
(GET_BLOCK_STATE(remoteConnection) == BlockStateActive) ) {
|
|
SET_BLOCK_STATE( remoteConnection, BlockStateDisconnecting );
|
|
LoopDoDisconnect( remoteConnection, FALSE );
|
|
}
|
|
|
|
//
|
|
// Abort pending receives and sends.
|
|
//
|
|
|
|
listEntry = RemoveHeadList( &Connection->PendingReceiveList );
|
|
|
|
while ( listEntry != &Connection->PendingReceiveList ) {
|
|
|
|
LoopDereferenceConnection( Connection );
|
|
|
|
RELEASE_LOOP_LOCK( "DoDisc complete Receive" );
|
|
|
|
pendingIrp = CONTAINING_RECORD(
|
|
listEntry,
|
|
IRP,
|
|
Tail.Overlay.ListEntry
|
|
);
|
|
pendingIrp->IoStatus.Status = STATUS_DISCONNECTED;
|
|
IoCompleteRequest( pendingIrp, 2 );
|
|
|
|
ACQUIRE_LOOP_LOCK( "DoDisc complete Receive done" );
|
|
|
|
listEntry = RemoveHeadList( &Connection->PendingReceiveList );
|
|
}
|
|
|
|
listEntry = RemoveHeadList( &Connection->IncomingSendList );
|
|
|
|
while ( listEntry != &Connection->IncomingSendList ) {
|
|
|
|
LoopDereferenceConnection( remoteConnection );
|
|
LoopDereferenceConnection( Connection );
|
|
|
|
RELEASE_LOOP_LOCK( "DoDisc complete Send" );
|
|
|
|
pendingIrp = CONTAINING_RECORD(
|
|
listEntry,
|
|
IRP,
|
|
Tail.Overlay.ListEntry
|
|
);
|
|
pendingIrp->IoStatus.Status = STATUS_DISCONNECTED;
|
|
IoCompleteRequest( pendingIrp, 2 );
|
|
|
|
ACQUIRE_LOOP_LOCK( "DoDisc complete Send done" );
|
|
|
|
listEntry = RemoveHeadList( &Connection->IncomingSendList );
|
|
}
|
|
|
|
//
|
|
// If this is a remotely-initiated disconnect, and the local client
|
|
// has established a disconnect event handler, call that handler
|
|
// now.
|
|
//
|
|
|
|
endpoint = Connection->Endpoint;
|
|
disconnectHandler = endpoint->DisconnectHandler;
|
|
disconnectContext = endpoint->DisconnectContext;
|
|
|
|
if ( !ClientInitiated && (disconnectHandler != NULL) ) {
|
|
RELEASE_LOOP_LOCK( "DoDisc call handler" );
|
|
(VOID)disconnectHandler(
|
|
disconnectContext,
|
|
Connection->ConnectionContext,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
TDI_DISCONNECT_ABORT
|
|
);
|
|
ACQUIRE_LOOP_LOCK( "DoDisc call handler done" );
|
|
}
|
|
|
|
//
|
|
// Dereference the connection. This will result in the completion
|
|
// of the disconnect IRP, if the reference count goes to zero.
|
|
//
|
|
|
|
LoopDereferenceConnection( Connection );
|
|
|
|
return;
|
|
|
|
} // LoopDoDisconnect
|
|
|
|
|
|
NTSTATUS
|
|
LoopListen (
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine processes a Listen request.
|
|
|
|
Arguments:
|
|
|
|
Irp - Pointer to I/O request packet
|
|
|
|
IrpSp - Pointer to current stack location in IRP
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Status of request
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PLOOP_CONNECTION connection;
|
|
PLOOP_ENDPOINT endpoint;
|
|
|
|
IrpSp; // prevent compiler warnings
|
|
|
|
IF_DEBUG(LOOP1) DbgPrint( " Listen request\n" );
|
|
|
|
connection = (PLOOP_CONNECTION)IrpSp->FileObject->FsContext;
|
|
IF_DEBUG(LOOP2) DbgPrint( " Connection address: %lx\n", connection );
|
|
|
|
//
|
|
// !!! When the DELAYED_ACCEPT bit is defined, check here to ensure
|
|
// that it isn't set by the client. The loopback driver doesn't
|
|
// support delayed accept on Listen requests.
|
|
//
|
|
|
|
//
|
|
// Make sure the connection is in the right state.
|
|
//
|
|
|
|
ACQUIRE_LOOP_LOCK( "Listen initial" );
|
|
|
|
if ( connection == NULL ) {
|
|
RELEASE_LOOP_LOCK( "Listen control channel" );
|
|
IF_DEBUG(LOOP2) DbgPrint( " Can't Listen on control channel\n" );
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto complete;
|
|
}
|
|
|
|
if ( GET_BLOCK_STATE(connection) != BlockStateBound ) {
|
|
RELEASE_LOOP_LOCK( "Listen not bound" );
|
|
IF_DEBUG(LOOP2) DbgPrint( " Connection not bound\n" );
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto complete;
|
|
}
|
|
|
|
//
|
|
// Set the connection state to Connecting, to prevent further
|
|
// connects or listens.
|
|
//
|
|
|
|
SET_BLOCK_STATE( connection, BlockStateConnecting );
|
|
|
|
endpoint = connection->Endpoint;
|
|
IF_DEBUG(LOOP2) DbgPrint( " Endpoint address: %lx\n", endpoint );
|
|
|
|
//
|
|
// Queue the Listen to the endpoint's Pending Listen list.
|
|
//
|
|
|
|
InsertTailList(
|
|
&endpoint->PendingListenList,
|
|
&Irp->Tail.Overlay.ListEntry
|
|
);
|
|
|
|
IoMarkIrpPending( Irp );
|
|
|
|
//
|
|
// Check for a pending connect.
|
|
//
|
|
|
|
if ( (endpoint->IndicatingConnectIrp != NULL) ||
|
|
(endpoint->IncomingConnectList.Flink ==
|
|
&endpoint->IncomingConnectList) ) {
|
|
|
|
//
|
|
// There is no pending Connect, or a Connect indication is
|
|
// already in progress.
|
|
//
|
|
|
|
IF_DEBUG(LOOP2) {
|
|
DbgPrint( " No pending Connect; leaving IRP %lx queued \n",
|
|
Irp );
|
|
}
|
|
|
|
RELEASE_LOOP_LOCK( "Listen no Connect" );
|
|
|
|
} else {
|
|
|
|
//
|
|
// There is a pending Connect. Call IndicateConnect to
|
|
// satisfy the Listen.
|
|
//
|
|
// *** Note that IndicateConnect returns with the loopback
|
|
// driver spin lock released.
|
|
//
|
|
|
|
IF_DEBUG(LOOP2) DbgPrint( " LoopListen indicating connect\n" );
|
|
IndicateConnect( endpoint );
|
|
|
|
}
|
|
|
|
IF_DEBUG(LOOP1) DbgPrint( " Listen request complete\n" );
|
|
return status;
|
|
|
|
complete:
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest( Irp, 2 );
|
|
|
|
IF_DEBUG(LOOP1) DbgPrint( " Listen request complete\n" );
|
|
return status;
|
|
|
|
} // LoopListen
|
|
|
|
|
|
NTSTATUS
|
|
CompleteConnection (
|
|
IN PIRP ListenIrp,
|
|
IN PIRP ConnectIrp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine completes the process of creating a connection. It
|
|
creates a connection block for each end of the connection and links
|
|
them together. The connection blocks are also linked off of their
|
|
respective endpoint blocks.
|
|
|
|
This routine must be called with the loopback device spin lock held.
|
|
The lock remains held when the function returns, although it is
|
|
released and reacquired during the function's operation.
|
|
|
|
Arguments:
|
|
|
|
ListenIrp - Pointer to IRP used for Listen request
|
|
|
|
ConnectIrp - Pointer to IRP used for Connect request
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Indicates whether the connection was successfully created
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PLOOP_CONNECTION listenerConnection;
|
|
PLOOP_CONNECTION connectorConnection;
|
|
PLOOP_ENDPOINT listenerEndpoint;
|
|
PLOOP_ENDPOINT connectorEndpoint;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PTDI_REQUEST_KERNEL parameters;
|
|
PTDI_CONNECTION_INFORMATION connInfo;
|
|
TA_NETBIOS_ADDRESS connectorAddress;
|
|
TA_NETBIOS_ADDRESS listenerAddress;
|
|
int length;
|
|
|
|
//
|
|
// Get pointers.
|
|
//
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation( ListenIrp );
|
|
listenerConnection = (PLOOP_CONNECTION)irpSp->FileObject->FsContext;
|
|
listenerEndpoint = listenerConnection->Endpoint;
|
|
irpSp = IoGetCurrentIrpStackLocation( ConnectIrp );
|
|
connectorConnection = (PLOOP_CONNECTION)irpSp->FileObject->FsContext;
|
|
connectorEndpoint = connectorConnection->Endpoint;
|
|
|
|
//
|
|
// Update the connection blocks.
|
|
//
|
|
|
|
listenerConnection->RemoteConnection = connectorConnection;
|
|
SET_BLOCK_STATE( listenerConnection, BlockStateActive );
|
|
|
|
connectorConnection->RemoteConnection = listenerConnection;
|
|
SET_BLOCK_STATE( connectorConnection, BlockStateActive );
|
|
|
|
//
|
|
// Increment the reference counts on the connections to account for
|
|
// the active link.
|
|
//
|
|
|
|
listenerConnection->BlockHeader.ReferenceCount++;
|
|
connectorConnection->BlockHeader.ReferenceCount++;
|
|
IF_DEBUG(LOOP3) {
|
|
DbgPrint( " New refcnt on connection %lx is %lx\n",
|
|
listenerConnection,
|
|
listenerConnection->BlockHeader.ReferenceCount );
|
|
DbgPrint( " New refcnt on connection %lx is %lx\n",
|
|
connectorConnection,
|
|
connectorConnection->BlockHeader.ReferenceCount );
|
|
}
|
|
|
|
//
|
|
// Save the addresses of the connector and the listener.
|
|
//
|
|
|
|
connectorAddress.TAAddressCount = 1;
|
|
connectorAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
|
|
connectorAddress.Address[0].AddressLength = sizeof(TDI_ADDRESS_NETBIOS);
|
|
connectorAddress.Address[0].Address[0].NetbiosNameType =
|
|
TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
|
|
RtlMoveMemory(
|
|
connectorAddress.Address[0].Address[0].NetbiosName,
|
|
connectorEndpoint->NetbiosName,
|
|
NETBIOS_NAME_LENGTH
|
|
);
|
|
|
|
listenerAddress.TAAddressCount = 1;
|
|
listenerAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
|
|
listenerAddress.Address[0].AddressLength = sizeof(TDI_ADDRESS_NETBIOS);
|
|
listenerAddress.Address[0].Address[0].NetbiosNameType =
|
|
TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
|
|
RtlMoveMemory(
|
|
listenerAddress.Address[0].Address[0].NetbiosName,
|
|
listenerEndpoint->NetbiosName,
|
|
NETBIOS_NAME_LENGTH
|
|
);
|
|
|
|
//
|
|
// Complete the Listen (or Accept) and Connect I/O requests.
|
|
//
|
|
|
|
RELEASE_LOOP_LOCK( "CompleteConnection complete IRPs" );
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation( ListenIrp );
|
|
parameters = (PTDI_REQUEST_KERNEL)&irpSp->Parameters;
|
|
connInfo = parameters->ReturnConnectionInformation;
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
if ( connInfo != NULL ) {
|
|
|
|
length = connInfo->RemoteAddressLength;
|
|
|
|
if ( length != 0 ) {
|
|
length = MIN( sizeof(connectorAddress), length );
|
|
RtlMoveMemory(
|
|
connInfo->RemoteAddress,
|
|
&connectorAddress,
|
|
length
|
|
);
|
|
if ( length < sizeof(connectorAddress) ) {
|
|
status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
}
|
|
|
|
connInfo->UserDataLength = 0;
|
|
connInfo->OptionsLength = 0;
|
|
|
|
}
|
|
|
|
ListenIrp->IoStatus.Status = status;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation( ConnectIrp );
|
|
parameters = (PTDI_REQUEST_KERNEL)&irpSp->Parameters;
|
|
connInfo = parameters->ReturnConnectionInformation;
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
if ( connInfo != NULL ) {
|
|
|
|
length = connInfo->RemoteAddressLength;
|
|
|
|
if ( length != 0 ) {
|
|
length = MIN( sizeof(listenerAddress), length );
|
|
RtlMoveMemory(
|
|
connInfo->RemoteAddress,
|
|
&listenerAddress,
|
|
length
|
|
);
|
|
if ( length < sizeof(listenerAddress) ) {
|
|
status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
}
|
|
|
|
connInfo->UserDataLength = 0;
|
|
connInfo->OptionsLength = 0;
|
|
|
|
}
|
|
|
|
ConnectIrp->IoStatus.Status = status;
|
|
|
|
IoCompleteRequest( ListenIrp, 2 );
|
|
IoCompleteRequest( ConnectIrp, 2 );
|
|
|
|
ACQUIRE_LOOP_LOCK( "CompleteConnection complete IRPs done" );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // CompleteConnection
|
|
|
|
|
|
VOID
|
|
IndicateConnect (
|
|
IN PLOOP_ENDPOINT Endpoint
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine does the work of indicating an incoming connect.
|
|
|
|
The loopback device object's spin lock must be held when this
|
|
function is called.
|
|
|
|
*** The lock is released when the function returns.
|
|
|
|
Arguments:
|
|
|
|
Endpoint - Pointer to receiving (listening) endpoint block
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PLIST_ENTRY listEntry;
|
|
PIRP listenIrp;
|
|
PIRP connectIrp;
|
|
PTDI_IND_CONNECT connectHandler;
|
|
PVOID connectContext;
|
|
PVOID connectionContext;
|
|
PIO_STACK_LOCATION connectIrpSp;
|
|
PLOOP_ENDPOINT connectingEndpoint;
|
|
TA_NETBIOS_ADDRESS address;
|
|
|
|
//
|
|
// Reference the endpoint to prevent it from going away while this
|
|
// routine is running.
|
|
//
|
|
|
|
Endpoint->BlockHeader.ReferenceCount++;
|
|
IF_DEBUG(LOOP3) {
|
|
DbgPrint( " New refcnt on endpoint %lx is %lx\n",
|
|
Endpoint,
|
|
Endpoint->BlockHeader.ReferenceCount );
|
|
}
|
|
|
|
//
|
|
// If the endpoint has a pending Listen, satisfy it with this
|
|
// Connect. If there is no pending Listen, and a Connect handler
|
|
// has been enabled on the endpoint, call it.
|
|
//
|
|
|
|
while ( TRUE ) {
|
|
|
|
//
|
|
// We have a Connect pending. Is there a pending Listen?
|
|
//
|
|
|
|
listEntry = RemoveHeadList( &Endpoint->PendingListenList );
|
|
|
|
if ( listEntry != &Endpoint->PendingListenList ) {
|
|
|
|
//
|
|
// Found a pending Listen. Use it to satisfy the first
|
|
// incoming Connect.
|
|
//
|
|
|
|
listenIrp = CONTAINING_RECORD(
|
|
listEntry,
|
|
IRP,
|
|
Tail.Overlay.ListEntry
|
|
);
|
|
IF_DEBUG(LOOP2) {
|
|
DbgPrint( " Listen IRP pending: %lx\n", listenIrp );
|
|
}
|
|
|
|
listEntry = RemoveHeadList(
|
|
&Endpoint->IncomingConnectList
|
|
);
|
|
ASSERT( listEntry != &Endpoint->IncomingConnectList );
|
|
connectIrp = CONTAINING_RECORD(
|
|
listEntry,
|
|
IRP,
|
|
Tail.Overlay.ListEntry
|
|
);
|
|
IF_DEBUG(LOOP2) {
|
|
DbgPrint( " Connect IRP pending: %lx\n", connectIrp );
|
|
}
|
|
|
|
CompleteConnection( listenIrp, connectIrp );
|
|
|
|
//
|
|
// Fall to bottom of loop to handle more incoming Connects.
|
|
//
|
|
|
|
} else {
|
|
|
|
//
|
|
// No pending Listen. Is there a Connection handler?
|
|
//
|
|
|
|
connectHandler = Endpoint->ConnectHandler;
|
|
connectContext = Endpoint->ConnectContext;
|
|
|
|
if ( connectHandler == NULL ) {
|
|
|
|
//
|
|
// No Connect handler. The Connect must remain queued.
|
|
//
|
|
|
|
IF_DEBUG(LOOP2) DbgPrint( " No Connect handler\n" );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// The endpoint has a Connect handler. Call it. If it
|
|
// returns STATUS_EVENT_DONE, it handled the event by
|
|
// issuing a TdiAccept or TdiDisconnect from within the
|
|
// handler. If it returns STATUS_EVENT_PENDING, it also
|
|
// returns a connection context value indicating which
|
|
// connection it will use to issue a TdiAccept or
|
|
// TdiDisconect at a later time. If it returns
|
|
// STATUS_INSUFFICIENT_RESOURCES, it can't accept a new
|
|
// connection at this time, so we need to return an error to
|
|
// the Connect.
|
|
//
|
|
// First, remove the first Connect from the Incoming Connect
|
|
// list, and make it the Indicating Connect. It must be
|
|
// removed from the list to ensure that it isn't completed
|
|
// by LoopCleanup while we're indicating it.
|
|
//
|
|
|
|
listEntry = RemoveHeadList(
|
|
&Endpoint->IncomingConnectList
|
|
);
|
|
ASSERT( listEntry != &Endpoint->IncomingConnectList );
|
|
connectIrp = CONTAINING_RECORD(
|
|
listEntry,
|
|
IRP,
|
|
Tail.Overlay.ListEntry
|
|
);
|
|
Endpoint->IndicatingConnectIrp = connectIrp;
|
|
|
|
RELEASE_LOOP_LOCK( "IndicateConnect calling handler" );
|
|
|
|
IF_DEBUG(LOOP2) {
|
|
DbgPrint( " Connect handler: %lx\n", connectHandler );
|
|
}
|
|
|
|
//
|
|
// Build a TRANSPORT_ADDRESS describing the connector.
|
|
//
|
|
|
|
connectIrpSp = IoGetCurrentIrpStackLocation( connectIrp );
|
|
connectingEndpoint =
|
|
((PLOOP_CONNECTION)connectIrpSp->FileObject->FsContext)->
|
|
Endpoint;
|
|
|
|
address.TAAddressCount = 1;
|
|
address.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
|
|
address.Address[0].AddressLength = sizeof(TDI_ADDRESS_NETBIOS);
|
|
address.Address[0].Address[0].NetbiosNameType =
|
|
TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
|
|
RtlMoveMemory(
|
|
address.Address[0].Address[0].NetbiosName,
|
|
connectingEndpoint->NetbiosName,
|
|
NETBIOS_NAME_LENGTH
|
|
);
|
|
|
|
//
|
|
// Call the Connect handler.
|
|
//
|
|
|
|
status = connectHandler(
|
|
connectContext,
|
|
sizeof(address),
|
|
&address,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
&connectionContext
|
|
);
|
|
|
|
ACQUIRE_LOOP_LOCK( "IndicateConnect after calling handler" );
|
|
|
|
if ( status == STATUS_EVENT_DONE ) {
|
|
|
|
//
|
|
// The Connect handler issued a TdiAccept or a
|
|
// TdiDisconnect, so the indicating Connect has already
|
|
// been completed.
|
|
//
|
|
// *** Note that Endpoint->IndicatingConnectIrp is
|
|
// cleared within LoopAccept or LoopDisconnect.
|
|
//
|
|
|
|
IF_DEBUG(LOOP2) {
|
|
DbgPrint( " Connect handler handled event\n" );
|
|
}
|
|
|
|
//
|
|
// Fall to bottom of loop to handle more incoming
|
|
// Connects.
|
|
//
|
|
|
|
} else if ( status == STATUS_EVENT_PENDING ) {
|
|
|
|
//
|
|
// The Connect handler has delayed the issuance of the
|
|
// TdiAccept or TdiDisconnect. Leave the indication
|
|
// pending.
|
|
//
|
|
// *** Note that Endpoint->IndicatingConnectIrp is
|
|
// cleared within LoopAccept or LoopDisconnect.
|
|
//
|
|
|
|
IF_DEBUG(LOOP2) {
|
|
DbgPrint( " Connect handler pended event\n" );
|
|
}
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
//
|
|
// The Connect handler couldn't accept the connection,
|
|
// because it was out of resources. Abort the Connect.
|
|
//
|
|
|
|
ASSERT( status == STATUS_INSUFFICIENT_RESOURCES );
|
|
|
|
IF_DEBUG(LOOP2) DbgPrint( " No resources\n" );
|
|
|
|
Endpoint->IndicatingConnectIrp = NULL;
|
|
|
|
RELEASE_LOOP_LOCK( "IndicateConnect aborting connect" );
|
|
|
|
connectIrp->IoStatus.Status = status;
|
|
IoCompleteRequest( connectIrp, 2 );
|
|
|
|
ACQUIRE_LOOP_LOCK( "IndicateConnect connect aborted" );
|
|
|
|
//
|
|
// Fall to bottom of loop to handle more incoming
|
|
// Connects.
|
|
//
|
|
|
|
}
|
|
|
|
} // pending listen?
|
|
|
|
//
|
|
// If we get here, we need to indicate the next incoming
|
|
// Connect, if there is one.
|
|
//
|
|
|
|
if ( (GET_BLOCK_STATE(Endpoint) != BlockStateActive) ||
|
|
(Endpoint->IncomingConnectList.Flink ==
|
|
&Endpoint->IncomingConnectList) ) {
|
|
|
|
//
|
|
// No more Connects, or endpoint no longer active. Leave.
|
|
//
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Process the next Connect.
|
|
//
|
|
|
|
} // while ( TRUE )
|
|
|
|
//
|
|
// Remote the endpoint reference acquired at the start of this
|
|
// routine.
|
|
//
|
|
|
|
LoopDereferenceEndpoint( Endpoint );
|
|
|
|
RELEASE_LOOP_LOCK( "IndicateConnect done" );
|
|
|
|
return;
|
|
|
|
} // IndicateConnect
|